1717
1818import logging
1919import sys
20- from argparse import ArgumentParser , FileType , RawDescriptionHelpFormatter
20+ from argparse import ArgumentParser , BooleanOptionalAction , FileType , RawDescriptionHelpFormatter
21+ from collections .abc import Sequence
2122from itertools import chain
22- from typing import TYPE_CHECKING , Any , Dict , List , NoReturn , Optional , Sequence , TextIO , Type , Union
23+ from typing import TYPE_CHECKING , Any , NoReturn , Optional , TextIO , Union
2324
2425from cyclonedx .model import Property
2526from cyclonedx .output import make_outputter
3536from .utils .args import argparse_type4enum , choices4enum
3637
3738if TYPE_CHECKING : # pragma: no cover
38- from argparse import Action
39-
4039 from cyclonedx .model .bom import Bom
4140 from cyclonedx .model .component import Component
4241
4342 from . import BomBuilder
4443
45- BooleanOptionalAction : Optional [Type [Action ]]
46-
47- if sys .version_info >= (3 , 9 ):
48- from argparse import BooleanOptionalAction
49- else :
50- BooleanOptionalAction = None
44+ OPTION_OUTPUT_STDOUT = '-'
5145
5246
5347class Command :
@@ -74,61 +68,61 @@ def make_argument_parser(cls, sco: ArgumentParser, **kwargs: Any) -> ArgumentPar
7468 action = 'store_true' ,
7569 dest = 'short_purls' ,
7670 default = False )
77- op .add_argument ('-o' , '--outfile' ,
78- metavar = '<file>' ,
79- help = 'Output file path for your SBOM'
80- ' (set to "-" to output to <stdout>)'
81- ' (default: %(default)s)' ,
82- type = FileType ('wt' , encoding = 'utf8' ),
83- dest = 'outfile' ,
84- default = '-' )
85- op .add_argument ('--sv' , '--schema-version' ,
71+ op .add_argument ('--schema-version' , # DEPRECATED
8672 metavar = '<version>' ,
87- help = 'The CycloneDX schema version for your SBOM'
88- f' {{choices: { ", " .join (sorted ((v .to_version () for v in SchemaVersion ), reverse = True ))} }}'
89- ' (default: %(default)s)' ,
90- dest = 'schema_version' ,
73+ help = 'DEPRECATED alias for option "--spec-version".' ,
74+ dest = 'spec_version' ,
9175 choices = SchemaVersion ,
9276 type = SchemaVersion .from_version ,
9377 default = SchemaVersion .V1_5 .to_version ())
78+ op .add_argument ('--sv' , '--spec-version' ,
79+ metavar = '<version>' ,
80+ help = 'Which version of CycloneDX to use.'
81+ f' {{choices: { ", " .join (sorted ((v .to_version () for v in SchemaVersion ), reverse = True ))} }}'
82+ ' (default: %(default)s)' ,
83+ dest = 'spec_version' ,
84+ choices = SchemaVersion ,
85+ type = SchemaVersion .from_version ,
86+ default = SchemaVersion .V1_5 .to_version ())
87+ op .add_argument ('--output-reproducible' ,
88+ help = 'Whether to go the extra mile and make the output reproducible.\n '
89+ 'This might result in loss of time- and random-based values.' ,
90+ action = 'store_true' ,
91+ dest = 'output_reproducible' ,
92+ default = False )
9493 op .add_argument ('--of' , '--output-format' ,
9594 metavar = '<format>' ,
96- help = 'The output format for your SBOM '
97- f' { choices4enum (OutputFormat )} '
98- ' (default: %(default)s)' ,
95+ help = 'Which output format to use. '
96+ f' { choices4enum (OutputFormat )} '
97+ ' (default: %(default)s)' ,
9998 dest = 'output_format' ,
10099 choices = OutputFormat ,
101100 type = argparse_type4enum (OutputFormat ),
102101 default = OutputFormat .JSON .name )
103- op .add_argument ('--output-reproducible' ,
104- help = 'Whether to go the extra mile and make the output reproducible.\n '
105- 'This might result in loss of time- and random-based-values.' ,
106- action = 'store_true' ,
107- dest = 'output_reproducible' ,
108- default = False )
109- if BooleanOptionalAction :
110- op .add_argument ('--validate' ,
111- help = 'Whether validate the result before outputting'
112- ' (default: %(default)s)' ,
113- action = BooleanOptionalAction ,
114- dest = 'should_validate' ,
115- default = True )
116- else :
117- vg = op .add_mutually_exclusive_group ()
118- vg .add_argument ('--validate' ,
119- help = 'Validate the result before outputting'
120- ' (default: %(default)s)' ,
121- action = 'store_true' ,
122- dest = 'should_validate' ,
123- default = True )
124- vg .add_argument ('--no-validate' ,
125- help = 'Do not validate the result before outputting' ,
126- dest = 'should_validate' ,
127- action = 'store_false' )
102+ op .add_argument ('--outfile' , # DEPRECATED
103+ metavar = '<file>' ,
104+ help = 'DEPRECATED alias for "--output-file".' ,
105+ type = FileType ('wt' , encoding = 'utf8' ),
106+ dest = 'output_file' ,
107+ default = OPTION_OUTPUT_STDOUT )
108+ op .add_argument ('-o' , '--output-file' ,
109+ metavar = '<file>' ,
110+ help = 'Path to the output file.'
111+ f' (set to "{ OPTION_OUTPUT_STDOUT } " to output to <stdout>)'
112+ ' (default: %(default)s)' ,
113+ type = FileType ('wt' , encoding = 'utf8' ),
114+ dest = 'output_file' ,
115+ default = OPTION_OUTPUT_STDOUT )
116+ op .add_argument ('--validate' ,
117+ help = 'Whether to validate resulting BOM before outputting.'
118+ ' (default: %(default)s)' ,
119+ action = BooleanOptionalAction ,
120+ dest = 'should_validate' ,
121+ default = True )
128122
129- scbbc : Type ['BomBuilder' ]
123+ scbbc : type ['BomBuilder' ]
130124 sct : str
131- scta : List [str ]
125+ scta : list [str ]
132126 for scbbc , sct , * scta in (
133127 (EnvironmentBB , 'environment' , 'env' , 'venv' ),
134128 (RequirementsBB , 'requirements' ),
@@ -150,28 +144,28 @@ def make_argument_parser(cls, sco: ArgumentParser, **kwargs: Any) -> ArgumentPar
150144
151145 __OWN_ARGS = {
152146 # the arg keywords from __init__()
153- 'logger' , 'short_purls' , 'output_format' , 'schema_version ' , 'output_reproducible' , 'should_validate' ,
147+ 'logger' , 'short_purls' , 'output_format' , 'spec_version ' , 'output_reproducible' , 'should_validate' ,
154148 # the arg keywords from __call__()
155- 'outfile '
149+ 'output_file '
156150 }
157151
158152 @classmethod
159- def _clean_kwargs (cls , kwargs : Dict [str , Any ]) -> Dict [str , Any ]:
153+ def _clean_kwargs (cls , kwargs : dict [str , Any ]) -> dict [str , Any ]:
160154 return {k : kwargs [k ] for k in kwargs if k not in cls .__OWN_ARGS }
161155
162156 def __init__ (self , * ,
163157 logger : logging .Logger ,
164158 short_purls : bool ,
165159 output_format : OutputFormat ,
166- schema_version : SchemaVersion ,
160+ spec_version : SchemaVersion ,
167161 output_reproducible : bool ,
168162 should_validate : bool ,
169- _bbc : Type ['BomBuilder' ],
163+ _bbc : type ['BomBuilder' ],
170164 ** kwargs : Any ) -> None :
171165 self ._logger = logger
172166 self ._short_purls = short_purls
173167 self ._output_format = output_format
174- self ._schema_version = schema_version
168+ self ._spec_version = spec_version
175169 self ._output_reproducible = output_reproducible
176170 self ._should_validate = should_validate
177171 self ._bbc = _bbc (** self ._clean_kwargs (kwargs ),
@@ -206,17 +200,17 @@ def _validate(self, output: str) -> bool:
206200 self ._logger .warning ('Validation skipped.' )
207201 return False
208202
209- self ._logger .info ('Validating result to schema : %s/%s' ,
210- self ._schema_version .to_version (), self ._output_format .name )
203+ self ._logger .info ('Validating result to spec : %s/%s' ,
204+ self ._spec_version .to_version (), self ._output_format .name )
211205
212206 validation_error = make_schemabased_validator (
213207 self ._output_format ,
214- self ._schema_version
208+ self ._spec_version
215209 ).validate_str (output )
216210 if validation_error :
217211 self ._logger .debug ('Validation Errors: %r' , validation_error .data )
218212 self ._logger .error ('The result is invalid to schema '
219- f'{ self ._schema_version .to_version ()} /{ self ._output_format .name } ' )
213+ f'{ self ._spec_version .to_version ()} /{ self ._output_format .name } ' )
220214 self ._logger .warning ('Please report the issue and provide all input data to: '
221215 'https://github.com/CycloneDX/cyclonedx-python/issues/new?'
222216 'template=ValidationError-report.md&'
@@ -225,14 +219,14 @@ def _validate(self, output: str) -> bool:
225219 self ._logger .debug ('result is schema-valid' )
226220 return True
227221
228- def _write (self , output : str , outfile : TextIO ) -> int :
229- self ._logger .info ('Writing to: %s' , outfile .name )
230- written = outfile .write (output )
231- self ._logger .debug ('Wrote %i bytes to %s' , written , outfile .name )
222+ def _write (self , output : str , output_file : TextIO ) -> int :
223+ self ._logger .info ('Writing to: %s' , output_file .name )
224+ written = output_file .write (output )
225+ self ._logger .debug ('Wrote %i bytes to %s' , written , output_file .name )
232226 return written
233227
234228 def _make_output (self , bom : 'Bom' ) -> str :
235- self ._logger .info ('Serializing SBOM: %s/%s' , self ._schema_version .to_version (), self ._output_format .name )
229+ self ._logger .info ('Serializing SBOM: %s/%s' , self ._spec_version .to_version (), self ._output_format .name )
236230
237231 if self ._output_reproducible :
238232 bom .metadata .properties .add (Property (name = PropertyName .Reproducible .value ,
@@ -244,22 +238,22 @@ def _make_output(self, bom: 'Bom') -> str:
244238 return make_outputter (
245239 bom ,
246240 self ._output_format ,
247- self ._schema_version
241+ self ._spec_version
248242 ).output_as_string (indent = 2 )
249243
250244 def _make_bom (self , ** kwargs : Any ) -> 'Bom' :
251245 self ._logger .info ('Generating SBOM ...' )
252246 return self ._bbc (** self ._clean_kwargs (kwargs ))
253247
254248 def __call__ (self ,
255- outfile : TextIO ,
249+ output_file : TextIO ,
256250 ** kwargs : Any ) -> None :
257251 bom = self ._make_bom (** kwargs )
258252 self ._shorten_purls (bom )
259253 output = self ._make_output (bom )
260254 del bom
261255 self ._validate (output )
262- self ._write (output , outfile )
256+ self ._write (output , output_file )
263257
264258
265259def run (* , argv : Optional [Sequence [str ]] = None , ** kwargs : Any ) -> Union [int , NoReturn ]:
0 commit comments