diff options
| -rw-r--r-- | crates/mozart-core/src/platform.rs | 17 | ||||
| -rw-r--r-- | crates/mozart/src/commands.rs | 13 | ||||
| -rw-r--r-- | crates/mozart/src/commands/bump.rs | 5 | ||||
| -rw-r--r-- | crates/mozart/src/commands/global.rs | 4 | ||||
| -rw-r--r-- | crates/mozart/src/main.rs | 35 |
5 files changed, 66 insertions, 8 deletions
diff --git a/crates/mozart-core/src/platform.rs b/crates/mozart-core/src/platform.rs index 317a75f..819d8c9 100644 --- a/crates/mozart-core/src/platform.rs +++ b/crates/mozart-core/src/platform.rs @@ -265,6 +265,23 @@ pub fn parse_platform_info(output: &str) -> Vec<PlatformPackage> { } } +/// Detect PHP version and binary path for `--version` display. +/// +/// Returns `(PHP_VERSION, PHP_BINARY)` by running a single PHP invocation. +/// Returns `None` if PHP is not available. +pub fn detect_php_version_and_binary() -> Option<(String, String)> { + let output = std::process::Command::new("php") + .args(["-r", r#"echo PHP_VERSION, "\n", PHP_BINARY;"#]) + .output() + .ok()?; + if !output.status.success() { + return None; + } + let stdout = String::from_utf8(output.stdout).ok()?; + let mut lines = stdout.lines(); + Some((lines.next()?.to_owned(), lines.next()?.to_owned())) +} + /// Try to detect the installed PHP version by running `php --version`. pub fn detect_php_version() -> Option<String> { let output = std::process::Command::new("php") diff --git a/crates/mozart/src/commands.rs b/crates/mozart/src/commands.rs index 968763f..e633526 100644 --- a/crates/mozart/src/commands.rs +++ b/crates/mozart/src/commands.rs @@ -35,10 +35,14 @@ pub mod update; pub mod validate; #[derive(clap::Parser)] -#[command(name = "mozart", version, about = "A PHP dependency manager")] +#[command(name = "mozart", about = "A PHP dependency manager")] pub struct Cli { #[command(subcommand)] - pub command: Commands, + pub command: Option<Commands>, + + /// Display version information + #[arg(short = 'V', long = "version")] + pub version: bool, /// Increase the verbosity of messages: 1 for normal, 2 for more verbose, 3 for debug #[arg(short, long, action = clap::ArgAction::Count, global = true)] @@ -238,7 +242,7 @@ impl Commands { } } -#[tracing::instrument(skip(cli), fields(command = cli.command.name()))] +#[tracing::instrument(skip(cli), fields(command = cli.command.as_ref().map(|c| c.name()).unwrap_or("none")))] pub async fn execute(cli: &Cli) -> anyhow::Result<()> { let console = mozart_core::console::Console::new( cli.verbose, @@ -247,7 +251,8 @@ pub async fn execute(cli: &Cli) -> anyhow::Result<()> { cli.no_ansi, cli.no_interaction, ); - match &cli.command { + let command = cli.command.as_ref().expect("command must be set"); + match command { Commands::About(args) => about::execute(args, cli, &console).await, Commands::Archive(args) => archive::execute(args, cli, &console).await, Commands::Audit(args) => audit::execute(args, cli, &console).await, diff --git a/crates/mozart/src/commands/bump.rs b/crates/mozart/src/commands/bump.rs index b322dbe..e1b5f63 100644 --- a/crates/mozart/src/commands/bump.rs +++ b/crates/mozart/src/commands/bump.rs @@ -311,12 +311,13 @@ mod tests { fn make_cli(working_dir: &std::path::Path) -> super::super::Cli { super::super::Cli { - command: super::super::Commands::Bump(BumpArgs { + command: Some(super::super::Commands::Bump(BumpArgs { packages: vec![], dev_only: false, no_dev_only: false, dry_run: false, - }), + })), + version: false, verbose: 0, profile: false, no_plugins: false, diff --git a/crates/mozart/src/commands/global.rs b/crates/mozart/src/commands/global.rs index 97d56d2..dfa4fc2 100644 --- a/crates/mozart/src/commands/global.rs +++ b/crates/mozart/src/commands/global.rs @@ -221,7 +221,7 @@ mod tests { fn test_global_args_has_correct_command() { // Verify GlobalArgs parses correctly through the CLI let cli = Cli::try_parse_from(["mozart", "global", "require", "vendor/package"]).unwrap(); - if let Commands::Global(args) = cli.command { + if let Some(Commands::Global(args)) = cli.command { assert_eq!(args.command_name, "require"); assert_eq!(args.args, vec!["vendor/package"]); } else { @@ -234,7 +234,7 @@ mod tests { // Verify hyphen values in trailing args are accepted let cli = Cli::try_parse_from(["mozart", "global", "require", "vendor/pkg", "--no-update"]) .unwrap(); - if let Commands::Global(args) = cli.command { + if let Some(Commands::Global(args)) = cli.command { assert_eq!(args.command_name, "require"); assert!(args.args.contains(&"--no-update".to_string())); } else { diff --git a/crates/mozart/src/main.rs b/crates/mozart/src/main.rs index ed7c4ad..8201d87 100644 --- a/crates/mozart/src/main.rs +++ b/crates/mozart/src/main.rs @@ -40,6 +40,41 @@ fn init_tracing(profile: bool, verbose: u8, quiet: bool) { #[tokio::main] async fn main() { let cli = commands::Cli::parse(); + + if cli.version { + let build_date = option_env!("MOZART_BUILD_DATE").unwrap_or("source"); + // Line 1 (stdout): getLongVersion() equivalent + println!( + "{}", + mozart_core::console_format!( + "<info>Mozart</info> version <comment>{}</comment> {}", + env!("CARGO_PKG_VERSION"), + build_date + ) + ); + // Line 2 (stderr): PHP version + binary path (matches Composer's output) + let (php_version, php_binary) = mozart_core::platform::detect_php_version_and_binary() + .unwrap_or_else(|| ("not found".into(), "php".into())); + eprintln!( + "{}", + mozart_core::console_format!( + "<info>PHP</info> version <comment>{}</comment> ({})", + php_version, + php_binary + ) + ); + // Line 3 (stderr): diagnose hint + eprintln!("Run the \"diagnose\" command to get more detailed diagnostics output."); + return; + } + + let Some(ref _cmd) = cli.command else { + use clap::CommandFactory; + commands::Cli::command().print_help().ok(); + println!(); + return; + }; + init_tracing(cli.profile, cli.verbose, cli.quiet); match commands::execute(&cli).await { Ok(()) => {} |
