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