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().any(|arg| arg == "--markdown-help") {
60 foundry_cli_markdown::print_help_markdown::<C>();
61 std::process::exit(0);
62 }
63 }
64
65 pub fn init(&self) -> eyre::Result<()> {
67 let shell = self.shell();
69 match shell.color_choice() {
71 ColorChoice::Auto => {}
72 ColorChoice::Always => yansi::enable(),
73 ColorChoice::Never => yansi::disable(),
74 }
75 shell.set();
76
77 if self.threads.is_some() {
79 self.force_init_thread_pool()?;
80 }
81
82 if IS_NIGHTLY_VERSION
84 && !self.json
85 && std::env::var_os("FOUNDRY_DISABLE_NIGHTLY_WARNING").is_none()
86 {
87 let _ = sh_warn!("{}", NIGHTLY_VERSION_WARNING_MESSAGE);
88 }
89
90 Ok(())
91 }
92
93 pub fn shell(&self) -> Shell {
95 let mode = match self.quiet {
96 true => OutputMode::Quiet,
97 false => OutputMode::Normal,
98 };
99 let color = self.json.then_some(ColorChoice::Never).or(self.color).unwrap_or_default();
100 let format = if self.json {
101 OutputFormat::Json
102 } else if self.md {
103 OutputFormat::Markdown
104 } else {
105 OutputFormat::Text
106 };
107
108 Shell::new_with(format, mode, color, self.verbosity)
109 }
110
111 pub fn force_init_thread_pool(&self) -> eyre::Result<()> {
113 init_thread_pool(self.threads.unwrap_or(0))
114 }
115
116 #[track_caller]
118 pub fn tokio_runtime(&self) -> tokio::runtime::Runtime {
119 let mut builder = tokio::runtime::Builder::new_multi_thread();
120 if let Some(threads) = self.threads
121 && threads > 0
122 {
123 builder.worker_threads(threads);
124 }
125 builder.enable_all().build().expect("failed to create tokio runtime")
126 }
127
128 #[track_caller]
130 pub fn block_on<F: std::future::Future>(&self, future: F) -> F::Output {
131 self.tokio_runtime().block_on(future)
132 }
133}
134
135pub fn init_thread_pool(threads: usize) -> eyre::Result<()> {
137 rayon::ThreadPoolBuilder::new()
138 .thread_name(|i| format!("foundry-{i}"))
139 .num_threads(threads)
140 .build_global()?;
141 Ok(())
142}