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 serde::{Deserialize, Serialize};
7
8#[derive(Clone, Debug, Default, Serialize, Deserialize, Parser)]
10pub struct GlobalArgs {
11 #[arg(help_heading = "Display options", global = true, short, long, verbatim_doc_comment, conflicts_with = "quiet", action = ArgAction::Count)]
24 verbosity: Verbosity,
25
26 #[arg(help_heading = "Display options", global = true, short, long, alias = "silent")]
28 quiet: bool,
29
30 #[arg(help_heading = "Display options", global = true, long, alias = "format-json", conflicts_with_all = &["quiet", "color"])]
32 json: bool,
33
34 #[arg(
36 help_heading = "Display options",
37 global = true,
38 long,
39 alias = "markdown",
40 conflicts_with = "json"
41 )]
42 md: bool,
43
44 #[arg(help_heading = "Display options", global = true, long, value_enum)]
46 color: Option<ColorChoice>,
47
48 #[arg(global = true, long, short = 'j', visible_alias = "jobs")]
50 threads: Option<usize>,
51}
52
53impl GlobalArgs {
54 pub fn check_markdown_help<C: clap::CommandFactory>() {
59 if std::env::args().take_while(|a| a != "--").any(|a| a == "--markdown-help") {
60 foundry_cli_markdown::print_help_markdown::<C>();
62 std::process::exit(0);
63 }
64 }
65
66 pub fn init(&self) -> eyre::Result<()> {
68 let shell = self.shell();
70 match shell.color_choice() {
72 ColorChoice::Auto => {}
73 ColorChoice::Always => yansi::enable(),
74 ColorChoice::Never => yansi::disable(),
75 }
76 shell.set();
77
78 if self.threads.is_some() {
80 self.force_init_thread_pool()?;
81 }
82
83 if IS_NIGHTLY_VERSION
85 && !self.json
86 && std::env::var_os("FOUNDRY_DISABLE_NIGHTLY_WARNING").is_none()
87 {
88 let _ = sh_warn!("{}", NIGHTLY_VERSION_WARNING_MESSAGE);
89 }
90
91 Ok(())
92 }
93
94 pub fn shell(&self) -> Shell {
96 let mode = match self.quiet {
97 true => OutputMode::Quiet,
98 false => OutputMode::Normal,
99 };
100 let color = self.json.then_some(ColorChoice::Never).or(self.color).unwrap_or_default();
101 let format = if self.json {
102 OutputFormat::Json
103 } else if self.md {
104 OutputFormat::Markdown
105 } else {
106 OutputFormat::Text
107 };
108
109 Shell::new_with(format, mode, color, self.verbosity)
110 }
111
112 pub fn force_init_thread_pool(&self) -> eyre::Result<()> {
114 init_thread_pool(self.threads.unwrap_or(0))
115 }
116
117 #[track_caller]
119 pub fn tokio_runtime(&self) -> tokio::runtime::Runtime {
120 let mut builder = tokio::runtime::Builder::new_multi_thread();
121 if let Some(threads) = self.threads
122 && threads > 0
123 {
124 builder.worker_threads(threads);
125 }
126 builder.enable_all().build().expect("failed to create tokio runtime")
127 }
128
129 #[track_caller]
131 pub fn block_on<F: std::future::Future>(&self, future: F) -> F::Output {
132 self.tokio_runtime().block_on(future)
133 }
134}
135
136pub fn init_thread_pool(threads: usize) -> eyre::Result<()> {
138 rayon::ThreadPoolBuilder::new()
139 .thread_name(|i| format!("foundry-{i}"))
140 .num_threads(threads)
141 .build_global()?;
142 Ok(())
143}