Skip to main content

turbopack_cli/
arguments.rs

1use std::{
2    net::IpAddr,
3    path::{Path, PathBuf},
4    str::FromStr,
5};
6
7use anyhow::anyhow;
8use bincode::{Decode, Encode};
9use clap::{Args, Parser, ValueEnum};
10use turbo_tasks::trace::TraceRawVcs;
11use turbopack_core::issue::IssueSeverity;
12
13#[derive(Debug, Parser)]
14#[clap(author, version, about, long_about = None)]
15pub enum Arguments {
16    Build(BuildArguments),
17    Dev(DevArguments),
18}
19
20impl Arguments {
21    /// The directory of the application. see [CommonArguments]::dir
22    pub fn dir(&self) -> Option<&Path> {
23        match self {
24            Arguments::Build(args) => args.common.dir.as_deref(),
25            Arguments::Dev(args) => args.common.dir.as_deref(),
26        }
27    }
28
29    /// The number of worker threads to use. see [CommonArguments]::worker_threads
30    pub fn worker_threads(&self) -> Option<usize> {
31        match self {
32            Arguments::Build(args) => args.common.worker_threads,
33            Arguments::Dev(args) => args.common.worker_threads,
34        }
35    }
36}
37
38#[turbo_tasks::task_input]
39#[derive(Copy, Clone, Debug, ValueEnum, PartialEq, Eq, Hash, TraceRawVcs, Encode, Decode)]
40pub enum Target {
41    Browser,
42    Node,
43}
44
45#[derive(Debug, Args, Clone)]
46pub struct CommonArguments {
47    /// The entrypoints of the project. Resolved relative to the project's
48    /// directory (`--dir`).
49    #[clap(value_parser)]
50    pub entries: Option<Vec<String>>,
51
52    /// The directory of the application.
53    /// If no directory is provided, the current directory will be used.
54    #[clap(short, long, value_parser)]
55    pub dir: Option<PathBuf>,
56
57    /// The root directory of the project. Nothing outside of this directory can
58    /// be accessed. e. g. the monorepo root.
59    /// If no directory is provided, `dir` will be used.
60    #[clap(long, value_parser)]
61    pub root: Option<PathBuf>,
62
63    /// Filter by issue severity.
64    #[clap(short, long)]
65    pub log_level: Option<IssueSeverityCliOption>,
66
67    /// Show all log messages without limit.
68    #[clap(long)]
69    pub show_all: bool,
70
71    /// Expand the log details.
72    #[clap(long)]
73    pub log_detail: bool,
74
75    /// Whether to enable full task stats recording in Turbo Engine.
76    #[clap(long)]
77    pub full_stats: bool,
78
79    /// Whether to build for the `browser` or `node`
80    #[clap(long)]
81    pub target: Option<Target>,
82
83    /// Number of worker threads to use for parallel processing
84    #[clap(long)]
85    pub worker_threads: Option<usize>,
86
87    /// Enable filesystem-backed persistent caching.
88    /// Cache is stored at `<cache-dir>/<git-version>`.
89    #[clap(long)]
90    pub persistent_caching: bool,
91
92    /// Directory to store the persistent cache.
93    /// Defaults to `.turbopack/cache` relative to the project directory.
94    #[clap(long)]
95    pub cache_dir: Option<PathBuf>,
96    // Enable experimental garbage collection with the provided memory limit in
97    // MB.
98    // #[clap(long)]
99    // pub memory_limit: Option<usize>,
100}
101
102#[derive(Debug, Args)]
103#[clap(author, version, about, long_about = None)]
104pub struct DevArguments {
105    #[clap(flatten)]
106    pub common: CommonArguments,
107
108    /// The port number on which to start the application
109    /// Note: setting env PORT allows to configure port without explicit cli
110    /// args. However, this is temporary measure to conform with existing
111    /// next.js devserver and can be removed in the future.
112    #[clap(short, long, value_parser, default_value_t = 3000, env = "PORT")]
113    pub port: u16,
114
115    /// Hostname on which to start the application
116    #[clap(short = 'H', long, value_parser, default_value = "0.0.0.0")]
117    pub hostname: IpAddr,
118
119    /// Compile all, instead of only compiling referenced assets when their
120    /// parent asset is requested
121    #[clap(long)]
122    pub eager_compile: bool,
123
124    /// Don't open the browser automatically when the dev server has started.
125    #[clap(long)]
126    pub no_open: bool,
127
128    // ==
129    // = Inherited options from next-dev, need revisit later.
130    // ==
131    /// If port is not explicitly specified, use different port if it's already
132    /// in use.
133    #[clap(long)]
134    pub allow_retry: bool,
135}
136
137#[derive(Debug, Args)]
138#[clap(author, version, about, long_about = None)]
139pub struct BuildArguments {
140    #[clap(flatten)]
141    pub common: CommonArguments,
142
143    /// Don't generate sourcemaps.
144    #[clap(long)]
145    pub no_sourcemap: bool,
146
147    /// Don't minify build output.
148    #[clap(long)]
149    pub no_minify: bool,
150
151    /// Don't perform scope hoisting.
152    #[clap(long)]
153    pub no_scope_hoist: bool,
154
155    /// Drop the `TurboTasks` object upon exit. By default we intentionally leak this memory, as
156    /// we're about to exit the process anyways, but that can cause issues with valgrind or other
157    /// leak detectors.
158    #[clap(long, hide = true)]
159    pub force_memory_cleanup: bool,
160}
161
162#[derive(Clone, Copy, PartialEq, Eq, Debug)]
163pub struct IssueSeverityCliOption(pub IssueSeverity);
164
165impl ValueEnum for IssueSeverityCliOption {
166    fn value_variants<'a>() -> &'a [Self] {
167        const VARIANTS: [IssueSeverityCliOption; 8] = [
168            IssueSeverityCliOption(IssueSeverity::Bug),
169            IssueSeverityCliOption(IssueSeverity::Fatal),
170            IssueSeverityCliOption(IssueSeverity::Error),
171            IssueSeverityCliOption(IssueSeverity::Warning),
172            IssueSeverityCliOption(IssueSeverity::Hint),
173            IssueSeverityCliOption(IssueSeverity::Note),
174            IssueSeverityCliOption(IssueSeverity::Suggestion),
175            IssueSeverityCliOption(IssueSeverity::Info),
176        ];
177        &VARIANTS
178    }
179
180    fn to_possible_value<'a>(&self) -> Option<clap::builder::PossibleValue> {
181        Some(clap::builder::PossibleValue::new(self.0.as_str()).help(self.0.as_help_str()))
182    }
183}
184
185impl FromStr for IssueSeverityCliOption {
186    type Err = anyhow::Error;
187
188    fn from_str(s: &str) -> Result<Self, Self::Err> {
189        <IssueSeverityCliOption as clap::ValueEnum>::from_str(s, true).map_err(|s| anyhow!("{}", s))
190    }
191}