From 3db52920de0009b1bed5fe6e9bcc684712853b61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Arg=C3=A9rus?= Date: Sat, 11 Feb 2023 13:31:29 +0100 Subject: [PATCH 1/2] Fix clippy::uninlined_format_args lint https://rust-lang.github.io/rust-clippy/master/#uninlined_format_args This lint was promoted from "pedantic" in Rust 1.67.0. It was subsequently [demoted to "pedantic" again](https://github.com/rust-lang/rust/pull/107743) in 1.67.1, so one solution would be to just use another version for now. It does however seem likely that it will be reintroduced at some point, so applying the fix. https://github.com/rust-lang/rust-clippy/pull/10265 --- kuksa_databroker/databroker-cli/src/main.rs | 52 ++++++++----------- .../examples/perf_setter.rs | 16 +++--- .../examples/perf_subscriber.rs | 6 +-- kuksa_databroker/databroker/build.rs | 2 +- kuksa_databroker/databroker/src/broker.rs | 2 +- .../databroker/src/grpc/kuksa_val_v1/val.rs | 5 +- .../src/grpc/sdv_databroker_v1/broker.rs | 2 +- kuksa_databroker/databroker/src/main.rs | 4 +- .../databroker/src/query/compiler.rs | 27 ++++------ .../databroker/src/query/executor.rs | 40 +++++--------- kuksa_databroker/databroker/src/vss.rs | 4 +- 11 files changed, 65 insertions(+), 95 deletions(-) diff --git a/kuksa_databroker/databroker-cli/src/main.rs b/kuksa_databroker/databroker-cli/src/main.rs index e20474370..d917e2e91 100644 --- a/kuksa_databroker/databroker-cli/src/main.rs +++ b/kuksa_databroker/databroker-cli/src/main.rs @@ -94,7 +94,7 @@ async fn connect( } Err(err) => { set_disconnected_prompt(interface); - writeln!(interface, "{}", err).unwrap(); + writeln!(interface, "{err}").unwrap(); None } } @@ -132,7 +132,7 @@ async fn main() -> Result<(), Box> { let addr = std::env::var("KUKSA_DATA_BROKER_ADDR").unwrap_or_else(|_| "127.0.0.1".to_owned()); let port = std::env::var("KUKSA_DATA_BROKER_PORT").unwrap_or_else(|_| "55555".to_owned()); - let mut uri = match addr_to_uri(format!("{}:{}", addr, port)) { + let mut uri = match addr_to_uri(format!("{addr}:{port}")) { Some(uri) => uri, None => return Err(Box::new(ParseError {}).into()), }; @@ -154,10 +154,10 @@ async fn main() -> Result<(), Box> { let (cmd, args) = split_first_word(&line); match cmd { "help" => { - println!("{} commands:", APP_NAME); + println!("{APP_NAME} commands:"); println!(); for &(cmd, help) in CLI_COMMANDS { - println!(" {:15} - {}", cmd, help); + println!(" {cmd:15} - {help}"); } println!(); } @@ -270,15 +270,11 @@ async fn main() -> Result<(), Box> { ) { Some(error) => { println!( - "-> Error setting id {}: {:?}", - id, error + "-> Error setting id {id}: {error:?}" ) } None => { - println!( - "-> Error setting id {}", - id - ) + println!("-> Error setting id {id}") } } } @@ -367,15 +363,11 @@ async fn main() -> Result<(), Box> { ) { Some(error) => { println!( - "-> Error setting id {}: {:?}", - id, error + "-> Error setting id {id}: {error:?}" ) } None => { - println!( - "-> Error setting id {}", - id - ) + println!("-> Error setting id {id}") } } } @@ -417,8 +409,7 @@ async fn main() -> Result<(), Box> { tonic::Request::new(proto::v1::SubscribeRequest { query }); match client.subscribe(args).await { Ok(response) => { - let sub_id = - format!("subscription{}", subscription_nbr); + let sub_id = format!("subscription{subscription_nbr}"); subscription_nbr += 1; tokio::spawn(async move { let mut stream = response.into_inner(); @@ -441,8 +432,7 @@ async fn main() -> Result<(), Box> { } writeln!( iface, - "-> {}:\n{}", - sub_id, output + "-> {sub_id}:\n{output}" ) .unwrap(); } @@ -531,7 +521,7 @@ async fn main() -> Result<(), Box> { break; } ReadResult::Signal(sig) => { - println!("received signal: {:?}", sig); + println!("received signal: {sig:?}"); } } } @@ -778,9 +768,9 @@ where let real_delimiter = ", "; let mut delimiter = ""; for value in array { - write!(f, "{}", delimiter)?; + write!(f, "{delimiter}")?; delimiter = real_delimiter; - write!(f, "{}", value)?; + write!(f, "{value}")?; } f.write_str("]") } @@ -790,32 +780,32 @@ impl fmt::Display for DisplayDatapoint { match &self.0.value { Some(value) => match value { proto::v1::datapoint::Value::BoolValue(value) => { - f.write_fmt(format_args!("{}", value)) + f.write_fmt(format_args!("{value}")) } proto::v1::datapoint::Value::FailureValue(failure) => f.write_fmt(format_args!( "( {:?} )", proto::v1::datapoint::Failure::from_i32(*failure).unwrap() )), proto::v1::datapoint::Value::Int32Value(value) => { - f.write_fmt(format_args!("{}", value)) + f.write_fmt(format_args!("{value}")) } proto::v1::datapoint::Value::Int64Value(value) => { - f.write_fmt(format_args!("{}", value)) + f.write_fmt(format_args!("{value}")) } proto::v1::datapoint::Value::Uint32Value(value) => { - f.write_fmt(format_args!("{}", value)) + f.write_fmt(format_args!("{value}")) } proto::v1::datapoint::Value::Uint64Value(value) => { - f.write_fmt(format_args!("{}", value)) + f.write_fmt(format_args!("{value}")) } proto::v1::datapoint::Value::FloatValue(value) => { - f.write_fmt(format_args!("{:.2}", value)) + f.write_fmt(format_args!("{value:.2}")) } proto::v1::datapoint::Value::DoubleValue(value) => { - f.write_fmt(format_args!("{}", value)) + f.write_fmt(format_args!("{value}")) } proto::v1::datapoint::Value::StringValue(value) => { - f.write_fmt(format_args!("'{}'", value)) + f.write_fmt(format_args!("'{value}'")) } proto::v1::datapoint::Value::StringArray(array) => display_array(f, &array.values), proto::v1::datapoint::Value::BoolArray(array) => display_array(f, &array.values), diff --git a/kuksa_databroker/databroker-examples/examples/perf_setter.rs b/kuksa_databroker/databroker-examples/examples/perf_setter.rs index e767614da..66b25a576 100644 --- a/kuksa_databroker/databroker-examples/examples/perf_setter.rs +++ b/kuksa_databroker/databroker-examples/examples/perf_setter.rs @@ -59,7 +59,7 @@ async fn run_streaming_set_test(iterations: i32, n_th_message: i32) { { Ok(metadata) => metadata.into_inner().results["Vehicle.ADAS.ABS.Error"], Err(err) => { - println!("Couldn't retrieve metadata: {:?}", err); + println!("Couldn't retrieve metadata: {err:?}"); -1 } }; @@ -108,7 +108,7 @@ async fn run_streaming_set_test(iterations: i32, n_th_message: i32) { Ok(_) => { eprintln!("START"); } - Err(err) => eprint!("{}", err), + Err(err) => eprint!("{err}"), }; let mut n: i32 = 0; @@ -135,7 +135,7 @@ async fn run_streaming_set_test(iterations: i32, n_th_message: i32) { } n += 1; } - Err(err) => eprint!("{}", err), + Err(err) => eprint!("{err}"), }; } @@ -144,7 +144,7 @@ async fn run_streaming_set_test(iterations: i32, n_th_message: i32) { Ok(_) => { eprintln!("\rEND "); } - Err(err) => eprint!("{}", err), + Err(err) => eprint!("{err}"), }; (n, n_id) @@ -153,7 +153,7 @@ async fn run_streaming_set_test(iterations: i32, n_th_message: i32) { let (n, n_id) = feeder.await.unwrap(); match sender.await { Ok(_) => {} - Err(err) => eprint!("{}", err), + Err(err) => eprint!("{err}"), }; let seconds = now.elapsed().as_secs_f64(); @@ -167,10 +167,10 @@ async fn run_streaming_set_test(iterations: i32, n_th_message: i32) { n_id, n_id as f64 / seconds ); - println!("Completed in {:.3} s", seconds); + println!("Completed in {seconds:.3} s"); } Err(err) => { - println!("{}", err); + println!("{err}"); } } } @@ -194,7 +194,7 @@ async fn main() -> Result<(), Box> { None => DEFAULT_NTH_MESSAGE, }; - println!("INPUT: Set {} times", iterations); + println!("INPUT: Set {iterations} times"); // run_set_test(iterations).await; run_streaming_set_test(iterations, queue_size).await; diff --git a/kuksa_databroker/databroker-examples/examples/perf_subscriber.rs b/kuksa_databroker/databroker-examples/examples/perf_subscriber.rs index c2b2d1f49..44bc52cee 100644 --- a/kuksa_databroker/databroker-examples/examples/perf_subscriber.rs +++ b/kuksa_databroker/databroker-examples/examples/perf_subscriber.rs @@ -45,7 +45,7 @@ async fn main() -> Result<(), Box> { match value { proto::v1::datapoint::Value::FailureValue(reason) => { if started { - eprintln!("-> Failure: {:?}", reason); + eprintln!("-> Failure: {reason:?}"); } } proto::v1::datapoint::Value::StringValue(string_value) => { @@ -66,7 +66,7 @@ async fn main() -> Result<(), Box> { n, n as f64 / seconds ); - eprintln!("Completed in {:.3} s", seconds); + eprintln!("Completed in {seconds:.3} s"); } } _ => { @@ -105,7 +105,7 @@ async fn main() -> Result<(), Box> { } } Err(err) => { - eprintln!("{}", err); + eprintln!("{err}"); } } diff --git a/kuksa_databroker/databroker/build.rs b/kuksa_databroker/databroker/build.rs index 7309a4b7a..189497f7a 100644 --- a/kuksa_databroker/databroker/build.rs +++ b/kuksa_databroker/databroker/build.rs @@ -36,7 +36,7 @@ fn main() -> Result<()> { Ok(ok) => Ok(ok), Err(e) => { // Swallow the errors for now (enable with -vv) - eprintln!("vergen failed: {}", e); + eprintln!("vergen failed: {e}"); Ok(()) } } diff --git a/kuksa_databroker/databroker/src/broker.rs b/kuksa_databroker/databroker/src/broker.rs index 99719b702..5d5cee4b9 100644 --- a/kuksa_databroker/databroker/src/broker.rs +++ b/kuksa_databroker/databroker/src/broker.rs @@ -961,7 +961,7 @@ impl DataBroker { let stream = ReceiverStream::new(receiver); Ok(stream) } - Err(e) => Err(QueryError::CompilationError(format!("{:?}", e))), + Err(e) => Err(QueryError::CompilationError(format!("{e:?}"))), } } diff --git a/kuksa_databroker/databroker/src/grpc/kuksa_val_v1/val.rs b/kuksa_databroker/databroker/src/grpc/kuksa_val_v1/val.rs index d99c6ec45..99138cf3d 100644 --- a/kuksa_databroker/databroker/src/grpc/kuksa_val_v1/val.rs +++ b/kuksa_databroker/databroker/src/grpc/kuksa_val_v1/val.rs @@ -196,8 +196,7 @@ impl proto::val_server::Val for broker::DataBroker { }, None => { return Err(tonic::Status::invalid_argument(format!( - "Invalid Field (id: {})", - id + "Invalid Field (id: {id})" ))) } }; @@ -212,7 +211,7 @@ impl proto::val_server::Val for broker::DataBroker { } Err(e) => Err(tonic::Status::new( tonic::Code::InvalidArgument, - format!("{:?}", e), + format!("{e:?}"), )), } } diff --git a/kuksa_databroker/databroker/src/grpc/sdv_databroker_v1/broker.rs b/kuksa_databroker/databroker/src/grpc/sdv_databroker_v1/broker.rs index a14992184..cad89d54c 100644 --- a/kuksa_databroker/databroker/src/grpc/sdv_databroker_v1/broker.rs +++ b/kuksa_databroker/databroker/src/grpc/sdv_databroker_v1/broker.rs @@ -146,7 +146,7 @@ impl proto::broker_server::Broker for broker::DataBroker { debug!("Subscribed to new query"); Ok(Response::new(Box::pin(stream))) } - Err(e) => Err(Status::new(Code::InvalidArgument, format!("{:?}", e))), + Err(e) => Err(Status::new(Code::InvalidArgument, format!("{e:?}"))), } } diff --git a/kuksa_databroker/databroker/src/main.rs b/kuksa_databroker/databroker/src/main.rs index 8bb41598e..a0fd7fd1c 100644 --- a/kuksa_databroker/databroker/src/main.rs +++ b/kuksa_databroker/databroker/src/main.rs @@ -110,7 +110,7 @@ const DATAPOINTS: &[( fn init_logging() { let mut output = String::from("Init logging from RUST_LOG"); let filter = EnvFilter::try_from_default_env().unwrap_or_else(|err| { - output.write_fmt(format_args!(" ({})", err)).unwrap(); + output.write_fmt(format_args!(" ({err})")).unwrap(); // If no environment variable set, this is the default EnvFilter::new("info") }); @@ -306,7 +306,7 @@ async fn main() -> Result<(), Box> { .await { Ok(_) => {} - Err(e) => println!("{:?}", e), + Err(e) => println!("{e:?}"), } } } diff --git a/kuksa_databroker/databroker/src/query/compiler.rs b/kuksa_databroker/databroker/src/query/compiler.rs index 195025908..9712c15f9 100644 --- a/kuksa_databroker/databroker/src/query/compiler.rs +++ b/kuksa_databroker/databroker/src/query/compiler.rs @@ -163,8 +163,7 @@ pub fn compile_expr( Ok(left_expr) => (Box::new(left_expr), Box::new(right_expr)), Err(_) => { return Err(CompilationError::TypeError(format!( - "left side is incompatible with right side in expression \"{}\"", - expr + "left side is incompatible with right side in expression \"{expr}\"" ))) } }, @@ -172,8 +171,7 @@ pub fn compile_expr( Ok(right_expr) => (Box::new(left_expr), Box::new(right_expr)), Err(_) => { return Err(CompilationError::TypeError(format!( - "right side is incompatible with left side in expression \"{}\"", - expr + "right side is incompatible with left side in expression \"{expr}\"" ))) } }, @@ -222,8 +220,7 @@ pub fn compile_expr( }), ), _ => return Err(CompilationError::TypeError(format!( - "right side is incompatible with left side in expression \"{}\"", - expr + "right side is incompatible with left side in expression \"{expr}\"" ))) }, } @@ -232,8 +229,7 @@ pub fn compile_expr( } _ => { return Err(CompilationError::TypeError(format!( - "right side is incompatible with left side in expression \"{}\"", - expr + "right side is incompatible with left side in expression \"{expr}\"" ))) } } @@ -295,10 +291,9 @@ pub fn compile_expr( "OR requires boolean expressions on both sides".to_string(), )), }, - operator => Err(CompilationError::UnsupportedOperator(format!( - "{}", - operator, - ))), + operator => Err(CompilationError::UnsupportedOperator( + format!("{operator}",), + )), } } ast::Expr::Nested(e) => compile_expr(e, input, output), @@ -309,8 +304,7 @@ pub fn compile_expr( operator: UnaryOperator::Not, }), operator => Err(CompilationError::UnsupportedOperator(format!( - "Unsupported unary operator \"{}\"", - operator + "Unsupported unary operator \"{operator}\"" ))), }, @@ -326,8 +320,7 @@ pub fn compile_expr( high: Box::new(compile_expr(high, input, output)?), }), operator => Err(CompilationError::UnsupportedOperator(format!( - "Unsupported operator \"{}\"", - operator + "Unsupported operator \"{operator}\"" ))), } } @@ -476,6 +469,6 @@ pub fn compile( )) } } - Err(e) => Err(CompilationError::ParseError(format!("{}", e))), + Err(e) => Err(CompilationError::ParseError(format!("{e}"))), } } diff --git a/kuksa_databroker/databroker/src/query/executor.rs b/kuksa_databroker/databroker/src/query/executor.rs index 71950d347..e28f7305b 100644 --- a/kuksa_databroker/databroker/src/query/executor.rs +++ b/kuksa_databroker/databroker/src/query/executor.rs @@ -60,7 +60,7 @@ impl CompiledQuery { let name = match e { Expr::Datapoint { name, data_type: _ } => name.clone(), Expr::Alias { alias, .. } => alias.clone(), - _ => format!("field_{}", index), + _ => format!("field_{index}"), }; match e.execute(input) { Ok(value) => fields.push((name, value)), @@ -128,36 +128,31 @@ fn execute_binary_operation( Operator::Or => match (&left_value, &right_value) { (DataValue::Bool(left), DataValue::Bool(right)) => Ok(DataValue::Bool(*left || *right)), _ => Err(ExecutionError::TypeError(format!( - "OR is only possible with boolean expressions, tried \"{:?} OR {:?}\"", - left_value, right_value + "OR is only possible with boolean expressions, tried \"{left_value:?} OR {right_value:?}\"" ))), }, Operator::And => match (&left_value, &right_value) { (DataValue::Bool(left), DataValue::Bool(right)) => Ok(DataValue::Bool(*left && *right)), _ => Err(ExecutionError::TypeError(format!( - "AND is only possible with boolean expressions, tried \"{:?} AND {:?}\"", - left_value, right_value + "AND is only possible with boolean expressions, tried \"{left_value:?} AND {right_value:?}\"" ))), }, Operator::Eq => match left_value.equals(&right_value) { Ok(equals) => Ok(DataValue::Bool(equals)), Err(_) => Err(ExecutionError::CastError(format!( - "comparison {:?} = {:?} isn't supported", - left_value, right_value + "comparison {left_value:?} = {right_value:?} isn't supported" ))), }, Operator::NotEq => match left_value.equals(&right_value) { Ok(equals) => Ok(DataValue::Bool(!equals)), // Negate equals Err(_) => Err(ExecutionError::CastError(format!( - "comparison {:?} != {:?} isn't supported", - left_value, right_value + "comparison {left_value:?} != {right_value:?} isn't supported" ))), }, Operator::Gt => match left_value.greater_than(&right_value) { Ok(greater_than) => Ok(DataValue::Bool(greater_than)), Err(_) => Err(ExecutionError::CastError(format!( - "comparison {:?} > {:?} isn't supported", - left_value, right_value + "comparison {left_value:?} > {right_value:?} isn't supported" ))), }, Operator::Ge => match left_value.greater_than(&right_value) { @@ -168,22 +163,19 @@ fn execute_binary_operation( match left_value.equals(&right_value) { Ok(equals) => Ok(DataValue::Bool(equals)), Err(_) => Err(ExecutionError::CastError(format!( - "comparison {:?} >= {:?} isn't supported", - left_value, right_value + "comparison {left_value:?} >= {right_value:?} isn't supported" ))), } } } Err(_) => Err(ExecutionError::CastError(format!( - "comparison {:?} >= {:?} isn't supported", - left_value, right_value + "comparison {left_value:?} >= {right_value:?} isn't supported" ))), }, Operator::Lt => match left_value.less_than(&right_value) { Ok(less_than) => Ok(DataValue::Bool(less_than)), Err(_) => Err(ExecutionError::CastError(format!( - "comparison {:?} < {:?} isn't supported", - left_value, right_value + "comparison {left_value:?} < {right_value:?} isn't supported" ))), }, Operator::Le => match left_value.less_than(&right_value) { @@ -194,15 +186,13 @@ fn execute_binary_operation( match left_value.equals(&right_value) { Ok(equals) => Ok(DataValue::Bool(equals)), Err(_) => Err(ExecutionError::CastError(format!( - "comparison {:?} <= {:?} isn't supported", - left_value, right_value + "comparison {left_value:?} <= {right_value:?} isn't supported" ))), } } } Err(_) => Err(ExecutionError::CastError(format!( - "comparison {:?} <= {:?} isn't supported", - left_value, right_value + "comparison {left_value:?} <= {right_value:?} isn't supported" ))), }, } @@ -246,8 +236,7 @@ fn execute_between_operation( }, Ok(data_value) => { return Err(ExecutionError::TypeError(format!( - "comparison BETWEEN {:?} AND ... not supported", - data_value + "comparison BETWEEN {data_value:?} AND ... not supported" ))) } Err(e) => return Err(e), @@ -268,8 +257,7 @@ fn execute_between_operation( }, Ok(data_value) => { return Err(ExecutionError::TypeError(format!( - "comparison BETWEEN ... AND {:?} not supported", - data_value + "comparison BETWEEN ... AND {data_value:?} not supported" ))) } Err(e) => return Err(e), @@ -396,7 +384,7 @@ fn executor_test() { for (i, (name, value)) in fields.iter().enumerate() { assert_eq!(name, &expected[i].0); assert_eq!(value, &expected[i].1); - println!("{}: {:?}", name, value) + println!("{name}: {value:?}") } } diff --git a/kuksa_databroker/databroker/src/vss.rs b/kuksa_databroker/databroker/src/vss.rs index 1e36da0b9..3df9dbf02 100644 --- a/kuksa_databroker/databroker/src/vss.rs +++ b/kuksa_databroker/databroker/src/vss.rs @@ -146,7 +146,7 @@ pub enum Error { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - Error::ParseError(error) => write!(f, "{}", error), + Error::ParseError(error) => write!(f, "{error}"), } } } @@ -365,7 +365,7 @@ fn add_entry( EntryType::Branch => match entry.children { Some(children) => { for (name, child) in children { - add_entry(entries, format!("{}.{}", path, name), child)?; + add_entry(entries, format!("{path}.{name}"), child)?; } Ok(()) } From f13b12c5989b48ddb06053166865e2189daaaad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Arg=C3=A9rus?= Date: Sat, 11 Feb 2023 12:28:18 +0100 Subject: [PATCH 2/2] Better error messages in createbom * Handle empty license field * Instead of aborting on first issue, print all problematic licenses / crates * Add a bit more structure --- .../createbom/bomutil/maplicensefile.py | 4 +- kuksa_databroker/createbom/createbom.py | 173 ++++++++++++------ 2 files changed, 115 insertions(+), 62 deletions(-) mode change 100644 => 100755 kuksa_databroker/createbom/createbom.py diff --git a/kuksa_databroker/createbom/bomutil/maplicensefile.py b/kuksa_databroker/createbom/bomutil/maplicensefile.py index 17ff8f2db..f854ab2b0 100644 --- a/kuksa_databroker/createbom/bomutil/maplicensefile.py +++ b/kuksa_databroker/createbom/bomutil/maplicensefile.py @@ -17,7 +17,7 @@ # SPDX-License-Identifier: Apache-2.0 ######################################################################## -'''Mapping of liense identifiers of cargo license to the filenames of the actual license texts.''' +"""Mapping of license identifiers of cargo license to the filenames of the actual license texts.""" MAP = { "Apache-2.0": "Apache-2.0.txt.gz", @@ -28,5 +28,5 @@ "BSD-2-Clause": "BSD-2-Clause.txt.gz", "CC0-1.0": "CC0-1.0.txt.gz", "WTFPL": "WTFPL.txt.gz", - "Zlib": "Zlib.txt.gz" + "Zlib": "Zlib.txt.gz", } diff --git a/kuksa_databroker/createbom/createbom.py b/kuksa_databroker/createbom/createbom.py old mode 100644 new mode 100755 index c7f7fad9a..5fad0641b --- a/kuksa_databroker/createbom/createbom.py +++ b/kuksa_databroker/createbom/createbom.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python +#!/usr/bin/env python3 ######################################################################## # Copyright (c) 2022 Robert Bosch GmbH # @@ -17,12 +17,12 @@ # SPDX-License-Identifier: Apache-2.0 ######################################################################## -''' -Thid will generate a list of all dependencies and licenses of a +""" +This script will generate a list of all dependencies and licenses of a Rust project. It will create a folder called thirdparty in that project folder containing a list of dependencies and a copy of each license used in dependencies -''' +""" import argparse import sys @@ -33,66 +33,119 @@ from subprocess import check_output, CalledProcessError -from bomutil import maplicensefile +from bomutil.maplicensefile import MAP as supported_licenses from bomutil import quirks -def extract_license_list(all_license_list, component): - '''Extract valid licenses for each dependency. We most of the time - do not care whether it is "AND" or "OR" currently, we currently assume we are - compatible to all "OR" variants, and thus include all''' - component = quirks.apply_quirks(component) - licenses = re.split(r'\s*AND\s*|\s*OR\s*|\(|\)', component["license"]) - licenses = list(filter(None, licenses)) - print(f"Licenses for {component['name']}: {licenses}") - - del component['license_file'] - - for license_id in licenses: - if license_id not in maplicensefile.MAP: - print(f"BOM creation failed, can not find license text for {license_id} \ - used in dependency {component['name']}") - sys.exit(-100) - if maplicensefile.MAP[license_id] not in license_list: - all_license_list.append(maplicensefile.MAP[license_id]) - -parser = argparse.ArgumentParser() -parser.add_argument("dir", help="Rust project directory") -args = parser.parse_args() - -sourcepath = os.path.abspath(args.dir) -targetpath = os.path.join(sourcepath,"thirdparty") - -print(f"Generating BOM for project in {sourcepath}") -if os.path.exists(targetpath): - print(f"Folder {targetpath} already exists. Remove it before running this script.") - sys.exit(-2) +class LicenseException(Exception): + pass -try: - cargo_output=check_output(\ - ["cargo", "license", "--json", "--avoid-build-deps", "--current-dir", sourcepath]) -except CalledProcessError as e: - print(f"Error running cargo license: {e}") - sys.exit(-1) +class CargoLicenseException(Exception): + pass -licensedict=json.loads(cargo_output) - -license_list = [] -for entry in licensedict: - extract_license_list(license_list,entry) - -# Exporting -os.mkdir(targetpath) - -for licensefile in license_list: - print(f"Copying {licensefile[:-2]}") - with gzip.open("licensestore/"+licensefile, 'rb') as inf: - content = inf.read() - with open(os.path.join(targetpath,licensefile[:-3]),'wb') as outf: - outf.write(content) - -print("Writing thirdparty_components.txt") -with open(os.path.join(targetpath,"thirdparty_components.txt"),'w',encoding="utf-8") as jsonout: - json.dump(licensedict,jsonout, indent=4) +def extract_license_ids(crate): + """Extract valid licenses for each dependency. We most of the time + do not care whether it is "AND" or "OR" currently, we currently assume we are + compatible to all "OR" variants, and thus include all""" + crate = quirks.apply_quirks(crate) + license = crate["license"] + + if license: + license_ids = re.split(r"\s*AND\s*|\s*OR\s*|\(|\)", license) + license_ids = list(filter(None, license_ids)) + return license_ids + else: + err = f"No license specified for dependency {crate['name']}" + raise LicenseException(err) + + +def generate_bom(source_path, target_path): + try: + cargo_output = check_output( + [ + "cargo", + "license", + "--json", + "--avoid-build-deps", + "--current-dir", + source_path, + ] + ) + except CalledProcessError as e: + raise CargoLicenseException(f"Error running cargo license: {e}") + + crates = json.loads(cargo_output) + + license_files = set() + errors = [] + for crate in crates: + try: + license_ids = extract_license_ids(crate) + print(f"Licenses for {crate['name']}: {license_ids}") + for license_id in license_ids: + if license_id in supported_licenses: + license_file = supported_licenses[license_id] + license_files.add(license_file) + else: + err = ( + f"Could not find license text for {license_id}" + f" used in dependency {crate['name']}" + ) + errors.append(err) + + except LicenseException as e: + errors.append(e) + + if errors: + for error in errors: + print(error) + raise LicenseException("BOM creation failed, unresolved licenses detected") + + # Exporting + os.mkdir(target_path) + + for license_file in license_files: + print(f"Copying {license_file[:-2]}") + with gzip.open("licensestore/" + license_file, "rb") as inf: + content = inf.read() + with open(os.path.join(target_path, license_file[:-3]), "wb") as outf: + outf.write(content) + + print("Writing thirdparty_components.txt") + with open( + os.path.join(target_path, "thirdparty_components.txt"), "w", encoding="utf-8" + ) as jsonout: + json.dump(crates, jsonout, indent=4) + + +def main(args=None): + parser = argparse.ArgumentParser() + parser.add_argument("dir", help="Rust project directory") + args = parser.parse_args(args) + + source_path = os.path.abspath(args.dir) + target_path = os.path.join(source_path, "thirdparty") + + if os.path.exists(target_path): + print( + f"Folder {target_path} already exists. Remove it before running this script." + ) + return -2 + + print(f"Generating BOM for project in {source_path}") + try: + generate_bom(source_path, target_path) + except LicenseException as e: + print(f"Error: {e}") + return -100 + except CargoLicenseException as e: + print(f"Error: {e}") + return -1 + + +if __name__ == "__main__": + import sys + + sys.exit(main(sys.argv[1:]))