11use cargo_cyclonedx:: {
22 config:: {
3- CdxExtension , CustomPrefix , Features , IncludedDependencies , LicenseParserOptions ,
4- OutputOptions , ParseMode , Pattern , PlatformSuffix , Prefix , PrefixError , SbomConfig , Target ,
3+ Describe , Features , FilenameOverride , FilenameOverrideError , FilenamePattern ,
4+ IncludedDependencies , LicenseParserOptions , OutputOptions , ParseMode , PlatformSuffix ,
5+ SbomConfig , Target ,
56 } ,
67 format:: Format ,
78 platform:: host_platform,
89} ;
910use clap:: { ArgAction , ArgGroup , Parser } ;
11+ use cyclonedx_bom:: models:: bom:: SpecVersion ;
1012use std:: collections:: HashSet ;
1113use std:: iter:: FromIterator ;
1214use std:: path;
@@ -23,23 +25,26 @@ pub enum Opts {
2325#[ derive( Parser , Debug ) ]
2426#[ clap( version) ]
2527#[ clap( group( ArgGroup :: new( "dependencies-group" ) . required( false ) . args( & [ "all" , "top-level" ] ) ) ) ]
26- #[ clap( group( ArgGroup :: new( "prefix-or-pattern-group" ) . required( false ) . args( & [ "output-prefix" , "output-pattern" ] ) ) ) ]
2728pub struct Args {
2829 /// Path to Cargo.toml
29- #[ clap( long = "manifest-path" , value_name = "PATH" ) ]
30+ #[ clap( long = "manifest-path" , value_name = "PATH" , value_hint = clap :: ValueHint :: FilePath ) ]
3031 pub manifest_path : Option < path:: PathBuf > ,
3132
3233 /// Output BOM format: json, xml
3334 #[ clap( long = "format" , short = 'f' , value_name = "FORMAT" ) ]
3435 pub format : Option < Format > ,
3536
36- /// Use verbose output (-vv very verbose/build.rs output)
37+ // the ValueEnum derive provides ample help text
38+ #[ clap( long = "describe" ) ]
39+ pub describe : Option < Describe > ,
40+
41+ /// Use verbose output (-vv for debug logging, -vvv for tracing)
3742 #[ clap( long = "verbose" , short = 'v' , action = clap:: ArgAction :: Count ) ]
3843 pub verbose : u8 ,
3944
40- /// No output printed to stdout
41- #[ clap( long = "quiet" , short = 'q' ) ]
42- pub quiet : bool ,
45+ /// Disable progress reports (-qq to suppress warnings)
46+ #[ clap( long = "quiet" , short = 'q' , action = clap :: ArgAction :: Count ) ]
47+ pub quiet : u8 ,
4348
4449 // `--all-features`, `--no-default-features` and `--features`
4550 // are not mutually exclusive in Cargo, so we keep the same behavior here too.
@@ -55,7 +60,7 @@ pub struct Args {
5560 #[ clap( long = "features" , short = 'F' ) ]
5661 pub features : Vec < String > ,
5762
58- /// The target to generate the SBOM for, or 'all' for all targets.
63+ /// The target platform to generate the SBOM for, or 'all' for all targets.
5964 #[ clap(
6065 long = "target" ,
6166 long_help = "The target to generate the SBOM for, e.g. 'x86_64-unknown-linux-gnu'.
@@ -64,7 +69,7 @@ Defaults to the host target, as printed by 'rustc -vV'"
6469 ) ]
6570 pub target : Option < String > ,
6671
67- /// Include the target platform of the BOM in the filename. Implies --output-cdx
72+ /// Include the target platform of the BOM in the filename
6873 #[ clap( long = "target-in-filename" ) ]
6974 pub target_in_filename : bool ,
7075
@@ -76,27 +81,13 @@ Defaults to the host target, as printed by 'rustc -vV'"
7681 #[ clap( name = "top-level" , long = "top-level" , conflicts_with = "all" ) ]
7782 pub top_level : bool ,
7883
79- /// Prepend file extension with .cdx
80- #[ clap( long = "output-cdx" ) ]
81- pub output_cdx : bool ,
82-
83- /// Prefix patterns to use for the filename: bom, package, binary, cargo-target
84- /// Values other than 'bom' imply --output-cdx
85- #[ clap(
86- name = "output-pattern" ,
87- long = "output-pattern" ,
88- value_name = "PATTERN"
89- ) ]
90- pub output_pattern : Option < Pattern > ,
91-
92- /// Custom prefix string to use for the filename
84+ /// Custom string to use for the output filename
9385 #[ clap(
94- name = "output-prefix" ,
95- long = "output-prefix" ,
96- value_name = "FILENAME_PREFIX" ,
97- conflicts_with = "output-pattern"
86+ long = "override-filename" ,
87+ value_name = "FILENAME" ,
88+ conflicts_with = "describe"
9889 ) ]
99- pub output_prefix : Option < String > ,
90+ pub filename_override : Option < String > ,
10091
10192 /// Reject the deprecated '/' separator for licenses, treating 'MIT/Apache-2.0' as an error
10293 #[ clap( long = "license-strict" ) ]
@@ -105,6 +96,10 @@ Defaults to the host target, as printed by 'rustc -vV'"
10596 /// Add license names which will not be warned about when parsing them as a SPDX expression fails
10697 #[ clap( long = "license-accept-named" , action=ArgAction :: Append ) ]
10798 pub license_accept_named : Vec < String > ,
99+
100+ /// The CycloneDX specification version to output: `1.3` or `1.4`. Defaults to 1.3
101+ #[ clap( long = "spec-version" ) ]
102+ pub spec_version : Option < SpecVersion > ,
108103}
109104
110105impl Args {
@@ -115,15 +110,6 @@ impl Args {
115110 _ => None ,
116111 } ;
117112
118- let prefix = match ( self . output_pattern , & self . output_prefix ) {
119- ( Some ( pattern) , _) => Some ( Prefix :: Pattern ( pattern) ) ,
120- ( _, Some ( prefix) ) => {
121- let prefix = CustomPrefix :: new ( prefix) ?;
122- Some ( Prefix :: Custom ( prefix) )
123- }
124- ( _, _) => None ,
125- } ;
126-
127113 let features =
128114 if !self . all_features && !self . no_default_features && self . features . is_empty ( ) {
129115 None
@@ -156,37 +142,23 @@ impl Args {
156142 Target :: SingleTarget ( target_string)
157143 } ) ;
158144
159- let mut cdx_extension = match self . output_cdx {
160- true => Some ( CdxExtension :: Included ) ,
161- false => None ,
162- } ;
163-
164145 let platform_suffix = match self . target_in_filename {
165146 true => PlatformSuffix :: Included ,
166147 false => PlatformSuffix :: NotIncluded ,
167148 } ;
168149
169- // according to the CycloneDX spec, the file has either be called 'bom.xml'
170- // or include the .cdx extension:
171- // https://cyclonedx.org/specification/overview/#recognized-file-patterns
172- if self . target_in_filename {
173- cdx_extension = Some ( CdxExtension :: Included )
174- }
175- // Ditto for any kind of prefix or anything not named 'bom'
176- if prefix. is_some ( ) {
177- cdx_extension = Some ( CdxExtension :: Included )
150+ let filename_pattern = match & self . filename_override {
151+ Some ( string) => {
152+ let name_override = FilenameOverride :: new ( string) ?;
153+ FilenamePattern :: Custom ( name_override)
154+ }
155+ None => FilenamePattern :: CrateName ,
178156 } ;
179157
180- let output_options =
181- if cdx_extension. is_none ( ) && prefix. is_none ( ) && !self . target_in_filename {
182- None
183- } else {
184- Some ( OutputOptions {
185- cdx_extension : cdx_extension. unwrap_or_default ( ) ,
186- prefix : prefix. unwrap_or_default ( ) ,
187- platform_suffix,
188- } )
189- } ;
158+ let output_options = Some ( OutputOptions {
159+ filename : filename_pattern,
160+ platform_suffix,
161+ } ) ;
190162
191163 let license_parser = Some ( LicenseParserOptions {
192164 mode : match self . license_strict {
@@ -196,21 +168,26 @@ impl Args {
196168 accept_named : HashSet :: from_iter ( self . license_accept_named . clone ( ) ) ,
197169 } ) ;
198170
171+ let describe = self . describe . clone ( ) ;
172+ let spec_version = self . spec_version . clone ( ) ;
173+
199174 Ok ( SbomConfig {
200175 format : self . format ,
201176 included_dependencies,
202177 output_options,
203178 features,
204179 target,
205180 license_parser,
181+ describe,
182+ spec_version,
206183 } )
207184 }
208185}
209186
210187#[ derive( Error , Debug , PartialEq , Eq ) ]
211188pub enum ArgsError {
212- #[ error( "Invalid prefix from CLI " ) ]
213- CustomPrefixError ( #[ from] PrefixError ) ,
189+ #[ error( "Invalid filename " ) ]
190+ FilenameOverrideError ( #[ from] FilenameOverrideError ) ,
214191}
215192
216193#[ cfg( test) ]
0 commit comments