sbom_tools/cli/
convert.rs1use std::path::{Path, PathBuf};
8
9use anyhow::Result;
10
11use crate::parsers::parse_sbom_str;
12use crate::pipeline::{exit_codes, read_input};
13use crate::serialization::emit::{self, EmitError, EmitTarget};
14
15pub fn run_convert(
22 file: &Path,
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 = read_input(file)?;
36 let mut sbom = parse_sbom_str(&raw_json)?;
37
38 if preserve {
39 emit::preserve_source_json(&raw_json, &mut sbom);
40 }
41
42 let (output, report) = match emit::emit(&sbom, emit_target) {
43 Ok(result) => result,
44 Err(EmitError::Unsupported(fmt)) => {
45 eprintln!("error: emitting to {fmt} is not yet implemented.");
46 return Ok(exit_codes::ERROR);
47 }
48 Err(e) => return Err(e.into()),
49 };
50
51 if !quiet {
53 eprint!("{}", report.render());
54 if report.is_lossy() {
55 eprintln!(
56 " Note: conversion is lossy ({} field type(s) dropped). Re-run with --preserve to retain format-specific blocks where possible.",
57 report.dropped_count()
58 );
59 }
60 }
61
62 match output_file {
63 Some(path) => {
64 std::fs::write(path, &output)?;
65 if !quiet {
66 eprintln!("Converted SBOM written to {}", path.display());
67 }
68 }
69 None => {
70 println!("{output}");
71 }
72 }
73
74 Ok(exit_codes::SUCCESS)
75}