Skip to main content

tracel_xtask/
lib.rs

1pub mod commands;
2pub mod context;
3pub mod environment;
4pub mod logging;
5pub mod utils;
6mod versions;
7
8// re-exports
9pub mod prelude {
10    pub use anyhow;
11    pub use clap;
12    pub use derive_more;
13    pub use env_logger;
14    pub use rand;
15    pub use serde_json;
16    pub use ureq;
17
18    pub mod macros {
19        pub use tracel_xtask_macros::base_commands;
20        pub use tracel_xtask_macros::declare_command_args;
21        pub use tracel_xtask_macros::extend_command_args;
22        pub use tracel_xtask_macros::extend_subcommands;
23        pub use tracel_xtask_macros::extend_targets;
24    }
25
26    pub use crate::XtaskArgs;
27    pub use crate::commands as base_commands;
28    pub use crate::commands::Target;
29    pub use crate::commands::build::BuildCmdArgs;
30    pub use crate::commands::bump::BumpCmdArgs;
31    pub use crate::commands::bump::BumpSubCommand;
32    pub use crate::commands::check::CheckCmdArgs;
33    pub use crate::commands::check::CheckSubCommand;
34    pub use crate::commands::clean::CleanCmdArgs;
35    pub use crate::commands::compile::CompileCmdArgs;
36    pub use crate::commands::container::ContainerCmdArgs;
37    pub use crate::commands::container::ContainerSubCommand;
38    pub use crate::commands::coverage::CoverageCmdArgs;
39    pub use crate::commands::dependencies::DependenciesCmdArgs;
40    pub use crate::commands::dependencies::DependenciesSubCommand;
41    pub use crate::commands::doc::DocCmdArgs;
42    pub use crate::commands::doc::DocSubCommand;
43    pub use crate::commands::docker_compose::DockerComposeCmdArgs;
44    pub use crate::commands::docker_compose::DockerComposeSubCommand;
45    pub use crate::commands::fix::FixCmdArgs;
46    pub use crate::commands::fix::FixSubCommand;
47    pub use crate::commands::host::HostCmdArgs;
48    pub use crate::commands::host::HostSubCommand;
49    pub use crate::commands::infra::InfraCmdArgs;
50    pub use crate::commands::infra::InfraSubCommand;
51    pub use crate::commands::publish::PublishCmdArgs;
52    pub use crate::commands::secrets::SecretsCmdArgs;
53    pub use crate::commands::secrets::SecretsSubCommand;
54    pub use crate::commands::test::TestCmdArgs;
55    pub use crate::commands::test::TestSubCommand;
56    pub use crate::commands::validate::ValidateCmdArgs;
57    pub use crate::commands::vulnerabilities::VulnerabilitiesCmdArgs;
58    pub use crate::commands::vulnerabilities::VulnerabilitiesSubCommand;
59    pub use crate::context::Context;
60    pub use crate::endgroup;
61    pub use crate::environment::Environment;
62    pub use crate::environment::EnvironmentIndex;
63    pub use crate::environment::EnvironmentName;
64    pub use crate::environment::ExplicitIndex;
65    pub use crate::group;
66    pub use crate::group_info;
67    pub use crate::handle_cleanup;
68    pub use crate::init_xtask;
69    pub use crate::parse_args;
70    pub use crate::register_cleanup;
71    pub use crate::utils as base_utils;
72    pub use crate::utils::aws;
73    pub use crate::utils::cargo::ensure_cargo_crate_is_installed;
74    pub use crate::utils::cleanup::CLEANUP_HANDLER;
75    pub use crate::utils::git;
76    pub use crate::utils::helpers;
77    pub use crate::utils::process;
78    pub use crate::utils::process::random_port;
79    pub use crate::utils::process::run_process;
80    pub use crate::utils::process::run_process_for_package;
81    pub use crate::utils::process::run_process_for_workspace;
82    pub use crate::utils::prompt::ask_once;
83    pub use crate::utils::rustup::is_current_toolchain_nightly;
84    pub use crate::utils::rustup::rustup_add_component;
85    pub use crate::utils::rustup::rustup_add_target;
86    pub use crate::utils::rustup::rustup_get_installed_targets;
87    pub use crate::utils::terraform;
88    pub use crate::utils::time::format_duration;
89    // does not re-export strum has it is incompatible with strum macros expansions
90}
91
92use std::fmt::Display;
93
94use clap::{CommandFactory as _, FromArgMatches as _};
95use environment::EnvironmentName;
96use prelude::Environment;
97
98use crate::context::Context;
99use crate::logging::init_logger;
100
101#[macro_use]
102extern crate log;
103
104const HELP_PREFIX: &str = "💡 Help";
105const XTASK_CLI_ENVVAR: &str = "XTASK_CLI";
106
107#[derive(clap::Parser)]
108#[command(author, version, about, long_about = None)]
109pub struct XtaskArgs<C: clap::Subcommand + Display> {
110    /// Enable code coverage for Rust code if available (see coverage command for more info).
111    #[arg(long)]
112    pub enable_coverage: bool,
113    /// Set environment.
114    #[arg(short = 'e', long = "env_name", default_value_t = EnvironmentName::default())]
115    pub environment_name: EnvironmentName,
116    /// Set environment index, must be between 1 and 255 inclusive
117    #[arg(short = 'i', long = "env_index", default_value_t = 1, value_parser = clap::value_parser!(u8).range(1..=255))]
118    pub environment_index: u8,
119    /// Set context.
120    #[arg(short = 'c', long, default_value_t = Context::default())]
121    pub context: Context,
122    #[command(subcommand)]
123    pub command: C,
124}
125
126pub fn parse_args<C>() -> anyhow::Result<(XtaskArgs<C>, Environment)>
127where
128    C: clap::Subcommand + std::fmt::Display,
129{
130    // init logs early
131    init_logger().init();
132    // Let clap do its normal parsing/help/version handling but with our help screen prefix
133    let mut cmd = XtaskArgs::<C>::command();
134    if std::env::var(XTASK_CLI_ENVVAR).is_ok() {
135        add_help_prefix(&mut cmd);
136    }
137    let matches = cmd.get_matches();
138    let args = XtaskArgs::<C>::from_arg_matches(&matches)?;
139    let env = Environment::new(args.environment_name.clone(), args.environment_index);
140    Ok((args, env))
141}
142
143pub fn init_xtask<C: clap::Subcommand + Display>(
144    config: (XtaskArgs<C>, Environment),
145) -> anyhow::Result<(XtaskArgs<C>, Environment)> {
146    let args = config.0;
147    let env = config.1;
148    if std::env::var(XTASK_CLI_ENVVAR).is_ok() {
149        eprintln!("⚡️ {}", args.command);
150    }
151    group_info!("Environment: {}", env.long());
152    env.load(None)?;
153    group_info!("Context: {}", args.context);
154    // code coverage
155    if args.enable_coverage {
156        group_info!("Enabling coverage support...");
157        setup_coverage()?;
158    }
159    Ok((args, env))
160}
161
162fn setup_coverage() -> anyhow::Result<()> {
163    unsafe {
164        std::env::set_var("RUSTFLAGS", "-Cinstrument-coverage");
165        std::env::set_var("LLVM_PROFILE_FILE", "burn-%p-%m.profraw");
166    }
167    Ok(())
168}
169
170fn add_help_prefix(cmd: &mut clap::Command) {
171    let mut owned = std::mem::take(cmd);
172    owned = owned.before_help(HELP_PREFIX).before_long_help(HELP_PREFIX);
173    // Recurse into subcommands to append the help prefix
174    for sub in owned.get_subcommands_mut() {
175        add_help_prefix(sub);
176    }
177    *cmd = owned;
178}