foundry_cli/opts/
global.rs1use clap::{ArgAction, Parser};
2use foundry_common::{
3 shell::{ColorChoice, OutputFormat, OutputMode, Shell, Verbosity},
4 version::{IS_NIGHTLY_VERSION, NIGHTLY_VERSION_WARNING_MESSAGE},
5};
6use foundry_config::{Config, figment::Profile};
7use serde::{Deserialize, Serialize};
8
9#[derive(Clone, Debug, Default, Serialize, Deserialize, Parser)]
11pub struct GlobalArgs {
12 #[arg(help_heading = "Display options", global = true, short, long, verbatim_doc_comment, conflicts_with = "quiet", action = ArgAction::Count)]
25 verbosity: Verbosity,
26
27 #[arg(help_heading = "Display options", global = true, short, long, alias = "silent")]
29 quiet: bool,
30
31 #[arg(help_heading = "Display options", global = true, long, alias = "format-json", conflicts_with_all = &["quiet", "color"])]
33 json: bool,
34
35 #[arg(
37 help_heading = "Display options",
38 global = true,
39 long,
40 alias = "markdown",
41 conflicts_with = "json"
42 )]
43 md: bool,
44
45 #[arg(help_heading = "Display options", global = true, long, value_enum)]
47 color: Option<ColorChoice>,
48
49 #[arg(global = true, long, short = 'j', visible_alias = "jobs")]
51 threads: Option<usize>,
52
53 #[arg(global = true, long, value_name = "PROFILE")]
55 profile: Option<Profile>,
56}
57
58impl GlobalArgs {
59 pub fn check_markdown_help<C: clap::CommandFactory>() {
64 if std::env::args_os().take_while(|a| a != "--").any(|a| a == "--markdown-help") {
65 foundry_cli_markdown::print_help_markdown::<C>();
67 std::process::exit(0);
68 }
69 }
70
71 pub fn init(&self) -> eyre::Result<()> {
73 if let Some(profile) = &self.profile
74 && let Err(selected) = Config::try_set_selected_profile(profile.clone())
75 {
76 eyre::bail!(
77 "configuration profile was already initialized as `{selected}`, cannot select \
78 `{profile}`"
79 );
80 }
81 let _ = Config::selected_profile();
82
83 let shell = self.shell();
85 match shell.color_choice() {
87 ColorChoice::Auto => {}
88 ColorChoice::Always => yansi::enable(),
89 ColorChoice::Never => yansi::disable(),
90 }
91 shell.set();
92
93 if self.threads.is_some() {
95 self.force_init_thread_pool()?;
96 }
97
98 if IS_NIGHTLY_VERSION
100 && !self.json
101 && std::env::var_os("FOUNDRY_DISABLE_NIGHTLY_WARNING").is_none()
102 {
103 let _ = sh_warn!("{}", NIGHTLY_VERSION_WARNING_MESSAGE);
104 }
105
106 Ok(())
107 }
108
109 pub fn shell(&self) -> Shell {
111 let mode = match self.quiet {
112 true => OutputMode::Quiet,
113 false => OutputMode::Normal,
114 };
115 let color = self.json.then_some(ColorChoice::Never).or(self.color).unwrap_or_default();
116 let format = if self.json {
117 OutputFormat::Json
118 } else if self.md {
119 OutputFormat::Markdown
120 } else {
121 OutputFormat::Text
122 };
123
124 Shell::new_with(format, mode, color, self.verbosity)
125 }
126
127 pub fn force_init_thread_pool(&self) -> eyre::Result<()> {
129 init_thread_pool(self.threads.unwrap_or(0))
130 }
131
132 #[track_caller]
134 pub fn tokio_runtime(&self) -> tokio::runtime::Runtime {
135 let mut builder = tokio::runtime::Builder::new_multi_thread();
136 if let Some(threads) = self.threads
137 && threads > 0
138 {
139 builder.worker_threads(threads);
140 }
141 builder.enable_all().build().expect("failed to create tokio runtime")
142 }
143
144 #[track_caller]
146 pub fn block_on<F: std::future::Future>(&self, future: F) -> F::Output {
147 self.tokio_runtime().block_on(future)
148 }
149}
150
151pub fn init_thread_pool(threads: usize) -> eyre::Result<()> {
153 rayon::ThreadPoolBuilder::new()
154 .thread_name(|i| format!("foundry-{i}"))
155 .num_threads(threads)
156 .build_global()?;
157 Ok(())
158}