sbom_tools/cli/
convert.rs1use std::path::PathBuf;
8
9use anyhow::Result;
10
11use crate::parsers::parse_sbom;
12use crate::pipeline::exit_codes;
13use crate::serialization::emit::{self, EmitError, EmitTarget};
14
15pub fn run_convert(
22 file: &PathBuf,
23 target: &str,
24 output_file: Option<&PathBuf>,
25 preserve: bool,
26 quiet: bool,
27) -> Result<i32> {
28 let Some(emit_target) = EmitTarget::parse(target) else {
29 eprintln!("error: unknown conversion target '{target}'. Supported: cyclonedx, spdx.");
30 return Ok(exit_codes::ERROR);
31 };
32
33 let raw_json = std::fs::read_to_string(file)?;
34 let mut sbom = parse_sbom(file)?;
35
36 if preserve {
37 emit::preserve_source_json(&raw_json, &mut sbom);
38 }
39
40 let (output, report) = match emit::emit(&sbom, emit_target) {
41 Ok(result) => result,
42 Err(EmitError::Unsupported(fmt)) => {
43 eprintln!("error: emitting to {fmt} is not yet implemented.");
44 return Ok(exit_codes::ERROR);
45 }
46 Err(e) => return Err(e.into()),
47 };
48
49 if !quiet {
51 eprint!("{}", report.render());
52 if report.is_lossy() {
53 eprintln!(
54 " Note: conversion is lossy ({} field type(s) dropped). Re-run with --preserve to retain format-specific blocks where possible.",
55 report.dropped_count()
56 );
57 }
58 }
59
60 match output_file {
61 Some(path) => {
62 std::fs::write(path, &output)?;
63 if !quiet {
64 eprintln!("Converted SBOM written to {}", path.display());
65 }
66 }
67 None => {
68 println!("{output}");
69 }
70 }
71
72 Ok(exit_codes::SUCCESS)
73}