Skip to content
Merged
124 changes: 65 additions & 59 deletions crates/tauri-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,28 +65,23 @@ impl FromStr for ConfigValue {
let path = PathBuf::from(config);
let raw =
read_to_string(&path).fs_context("failed to read configuration file", path.clone())?;
match path.extension() {
Some(ext) if ext == "toml" => {
Ok(Self(::toml::from_str(&raw).with_context(|| {
format!("failed to parse config at {} as TOML", path.display())
})?))
}
Some(ext) if ext == "json5" => {
Ok(Self(::json5::from_str(&raw).with_context(|| {
format!("failed to parse config at {} as JSON5", path.display())
})?))
}
// treat all other extensions as json
_ => Ok(Self(
// from tauri-utils/src/config/parse.rs:
// we also want to support **valid** json5 in the .json extension
// if the json5 is not valid the serde_json error for regular json will be returned.
Comment on lines -79 to -83
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since the logic is still the same we should probably keep the comments as well

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@KushalMeghani1644 can you copy these comments over as well?

Copy link
Contributor Author

@KushalMeghani1644 KushalMeghani1644 Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yes! I missed these! though Now I have added them back now. Sorry for the inconsistency

match ::json5::from_str(&raw) {
Ok(json5) => json5,
Err(_) => serde_json::from_str(&raw)
.with_context(|| format!("failed to parse config at {} as JSON", path.display()))?,
},
)),

// treat all other extensions as json
// from tauri-utils/src/config/parse.rs:
// we also want to support **valid** json5 in the .json extension
// if the json5 is not valid the serde_json error for regular json will be returned.
match path.extension().and_then(|ext| ext.to_str()) {
Some("toml") => Ok(Self(::toml::from_str(&raw).with_context(|| {
format!("failed to parse config at {} as TOML", path.display())
})?)),
Some("json5") => Ok(Self(::json5::from_str(&raw).with_context(|| {
format!("failed to parse config at {} as JSON5", path.display())
})?)),
_ => Ok(Self(match ::json5::from_str(&raw) {
Ok(json5) => json5,
Err(_) => serde_json::from_str(&raw)
.with_context(|| format!("failed to parse config at {} as JSON", path.display()))?,
})),
}
}
}
Expand Down Expand Up @@ -178,6 +173,13 @@ fn format_error<I: CommandFactory>(err: clap::Error) -> clap::Error {
err.format(&mut app)
}

fn get_verbosity(cli_verbose: u8) -> u8 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verbosity consistency: Introduced a helper function to centralize verbosity parsing from environment variables and CLI flags, ensuring predictable logging levels across all subcommands.

This function is only used once, where the code was inlined before. I don't mind having this in a separate function but wanted to mention this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made this function because the logic may be reused (e.g. if we later need verbosity in other commands),
but I’m fine inlining it if preferred.

std::env::var("TAURI_CLI_VERBOSITY")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(cli_verbose)
}

/// Run the Tauri CLI with the passed arguments, exiting if an error occurs.
///
/// The passed arguments should have the binary argument(s) stripped out before being passed.
Expand Down Expand Up @@ -222,23 +224,17 @@ where
Err(e) => e.exit(),
};

let verbosity_number = std::env::var("TAURI_CLI_VERBOSITY")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(cli.verbose);
// set the verbosity level so subsequent CLI calls (xcode-script, android-studio-script) refer to it
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add back those comments? Not sure why you removed them

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could swear all your marked comments were added back... Maybe it's time for me to retire lol

Copy link
Contributor Author

@KushalMeghani1644 KushalMeghani1644 Nov 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops! I overlooked these comments, I shall stop using neovim... Jokes aside, I will have them added back through another Pr (since this is merged).

let verbosity_number = get_verbosity(cli.verbose);
std::env::set_var("TAURI_CLI_VERBOSITY", verbosity_number.to_string());

let mut builder = Builder::from_default_env();
let init_res = builder
if let Err(err) = builder
.format_indent(Some(12))
.filter(None, verbosity_level(verbosity_number).to_level_filter())
// golbin spams an insane amount of really technical logs on the debug level so we're reducing one level
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

.filter(
Some("goblin"),
verbosity_level(verbosity_number.saturating_sub(1)).to_level_filter(),
)
// handlebars is not that spammy but its debug logs are typically far from being helpful
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

.filter(
Some("handlebars"),
verbosity_level(verbosity_number.saturating_sub(1)).to_level_filter(),
Expand All @@ -250,7 +246,6 @@ where
is_command_output = action == "stdout" || action == "stderr";
if !is_command_output {
let style = Style::new().fg_color(Some(AnsiColor::Green.into())).bold();

write!(f, "{style}{action:>12}{style:#} ")?;
}
} else {
Expand All @@ -264,15 +259,13 @@ where

if !is_command_output && log::log_enabled!(Level::Debug) {
let style = Style::new().fg_color(Some(AnsiColor::Black.into()));

write!(f, "[{style}{}{style:#}] ", record.target())?;
}

writeln!(f, "{}", record.args())
})
.try_init();

if let Err(err) = init_res {
.try_init()
{
eprintln!("Failed to attach logger: {err}");
}

Expand Down Expand Up @@ -305,7 +298,7 @@ fn verbosity_level(num: u8) -> Level {
match num {
0 => Level::Info,
1 => Level::Debug,
2.. => Level::Trace,
_ => Level::Trace,
}
}

Expand All @@ -321,8 +314,6 @@ fn prettyprint_level(lvl: Level) -> &'static str {
}

pub trait CommandExt {
// The `pipe` function sets the stdout and stderr to properly
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

// show the command output in the Node.js wrapper.
fn piped(&mut self) -> std::io::Result<ExitStatus>;
fn output_ok(&mut self) -> crate::Result<Output>;
}
Expand All @@ -332,18 +323,25 @@ impl CommandExt for Command {
self.stdin(os_pipe::dup_stdin()?);
self.stdout(os_pipe::dup_stdout()?);
self.stderr(os_pipe::dup_stderr()?);

let program = self.get_program().to_string_lossy().into_owned();
log::debug!(action = "Running"; "Command `{} {}`", program, self.get_args().map(|arg| arg.to_string_lossy()).fold(String::new(), |acc, arg| format!("{acc} {arg}")));
let args = self
.get_args()
.map(|a| a.to_string_lossy())
.collect::<Vec<_>>()
.join(" ");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i wonder if that's slower than fold but i agree that it's easier on the eyes.


log::debug!(action = "Running"; "Command `{program} {args}`");
self.status()
}

fn output_ok(&mut self) -> crate::Result<Output> {
let program = self.get_program().to_string_lossy().into_owned();
let args = self
.get_args()
.map(|arg| arg.to_string_lossy())
.fold(String::new(), |acc, arg| format!("{acc} {arg}"));
.map(|a| a.to_string_lossy())
.collect::<Vec<_>>()
.join(" ");
let cmdline = format!("{program} {args}");
log::debug!(action = "Running"; "Command `{cmdline}`");

Expand All @@ -359,16 +357,17 @@ impl CommandExt for Command {
let stdout_lines_ = stdout_lines.clone();
std::thread::spawn(move || {
let mut line = String::new();
let mut lines = stdout_lines_.lock().unwrap();
loop {
line.clear();
match stdout.read_line(&mut line) {
Ok(0) => break,
Ok(_) => {
log::debug!(action = "stdout"; "{}", line.trim_end());
lines.extend(line.as_bytes().to_vec());
if let Ok(mut lines) = stdout_lines_.lock() {
loop {
line.clear();
match stdout.read_line(&mut line) {
Ok(0) => break,
Ok(_) => {
log::debug!(action = "stdout"; "{}", line.trim_end());
lines.extend(line.as_bytes());
}
Err(_) => (),
}
Err(_) => (),
}
}
});
Expand All @@ -378,16 +377,17 @@ impl CommandExt for Command {
let stderr_lines_ = stderr_lines.clone();
std::thread::spawn(move || {
let mut line = String::new();
let mut lines = stderr_lines_.lock().unwrap();
loop {
line.clear();
match stderr.read_line(&mut line) {
Ok(0) => break,
Ok(_) => {
log::debug!(action = "stderr"; "{}", line.trim_end());
lines.extend(line.as_bytes().to_vec());
if let Ok(mut lines) = stderr_lines_.lock() {
loop {
line.clear();
match stderr.read_line(&mut line) {
Ok(0) => break,
Ok(_) => {
log::debug!(action = "stderr"; "{}", line.trim_end());
lines.extend(line.as_bytes());
}
Err(_) => (),
}
Err(_) => (),
}
}
});
Expand Down Expand Up @@ -423,4 +423,10 @@ mod tests {
fn verify_cli() {
Cli::command().debug_assert();
}

#[test]
fn help_output_includes_build() {
let help = Cli::command().render_help().to_string();
assert!(help.contains("Build"));
}
Comment on lines +427 to +431
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm kinda failing to see the value of this test but it's not technically wrong so fair enough i guess

}
Loading