xref: /aosp_15_r20/external/bazelbuild-rules_rust/crate_universe/src/cli.rs (revision d4726bddaa87cc4778e7472feed243fa4b6c267f)
1 //! Command line interface entry points and utilities
2 
3 mod generate;
4 mod query;
5 mod splice;
6 mod vendor;
7 
8 use clap::Parser;
9 use tracing::{Level, Subscriber};
10 use tracing_subscriber::fmt::format::{Format, Full};
11 use tracing_subscriber::fmt::time::SystemTime;
12 use tracing_subscriber::fmt::{FormatEvent, FormatFields};
13 use tracing_subscriber::registry::LookupSpan;
14 use tracing_subscriber::FmtSubscriber;
15 
16 pub use self::generate::GenerateOptions;
17 pub use self::query::QueryOptions;
18 pub use self::splice::SpliceOptions;
19 pub use self::vendor::VendorOptions;
20 
21 // Entrypoints
22 pub use generate::generate;
23 pub use query::query;
24 pub use splice::splice;
25 pub use vendor::vendor;
26 
27 #[derive(Parser, Debug)]
28 #[clap(
29     name = "cargo-bazel",
30     about = "crate_universe` is a collection of tools which use Cargo to generate build targets for Bazel.",
31     version
32 )]
33 pub enum Options {
34     /// Generate Bazel Build files from a Cargo manifest.
35     Generate(GenerateOptions),
36 
37     /// Splice together disjoint Cargo and Bazel info into a single Cargo workspace manifest.
38     Splice(SpliceOptions),
39 
40     /// Query workspace info to determine whether or not a repin is needed.
41     Query(QueryOptions),
42 
43     /// Vendor BUILD files to the workspace with either repository definitions or `cargo vendor` generated sources.
44     Vendor(VendorOptions),
45 }
46 
47 // Convenience wrappers to avoid dependencies in the binary
48 pub type Result<T> = anyhow::Result<T>;
49 
parse_args() -> Options50 pub fn parse_args() -> Options {
51     Options::parse()
52 }
53 
54 const EXPECTED_LOGGER_NAMES: [&str; 4] = ["Generate", "Splice", "Query", "Vendor"];
55 
56 /// A wrapper for the tracing-subscriber default [FormatEvent]
57 /// that prepends the name of the active CLI option.
58 struct LoggingFormatEvent {
59     name: String,
60     base: Format<Full, SystemTime>,
61 }
62 
63 impl<S, N> FormatEvent<S, N> for LoggingFormatEvent
64 where
65     S: Subscriber + for<'a> LookupSpan<'a>,
66     N: for<'a> FormatFields<'a> + 'static,
67 {
format_event( &self, ctx: &tracing_subscriber::fmt::FmtContext<'_, S, N>, mut writer: tracing_subscriber::fmt::format::Writer<'_>, event: &tracing::Event<'_>, ) -> std::fmt::Result68     fn format_event(
69         &self,
70         ctx: &tracing_subscriber::fmt::FmtContext<'_, S, N>,
71         mut writer: tracing_subscriber::fmt::format::Writer<'_>,
72         event: &tracing::Event<'_>,
73     ) -> std::fmt::Result {
74         write!(writer, "{} ", self.name)?;
75         self.base.format_event(ctx, writer, event)
76     }
77 }
78 
79 impl LoggingFormatEvent {
new(name: &str) -> Self80     fn new(name: &str) -> Self {
81         Self {
82             name: name.to_owned(),
83             base: Format::default(),
84         }
85     }
86 }
87 
88 /// Initialize logging for one of the cli options.
init_logging(name: &str)89 pub fn init_logging(name: &str) {
90     if !EXPECTED_LOGGER_NAMES.contains(&name) {
91         panic!(
92             "Unexpected logger name {}, use of one of {:?}",
93             name, EXPECTED_LOGGER_NAMES
94         );
95     }
96 
97     // a builder for `FmtSubscriber`.
98     let subscriber = FmtSubscriber::builder()
99         // all spans/events with a level higher than TRACE (e.g, debug, info, warn, etc.)
100         // will be written to stdout.
101         .with_max_level(
102             std::env::var("CARGO_BAZEL_DEBUG")
103                 .map(|_| Level::DEBUG)
104                 .unwrap_or(Level::INFO),
105         )
106         .event_format(LoggingFormatEvent::new(name))
107         // completes the builder.
108         .finish();
109 
110     tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");
111 }
112