diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-05-05 12:50:43 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-05-05 12:55:09 +0900 |
| commit | 78a627f9b839e902faec6e5f7fee4ec19fc0e4b8 (patch) | |
| tree | 9438a91dc70e87ce78091377f571316ecf1a2a7b /crates | |
| parent | a55ad1cc44c12836eca5652d231902968e04eea1 (diff) | |
| download | php-mozart-78a627f9b839e902faec6e5f7fee4ec19fc0e4b8.tar.gz php-mozart-78a627f9b839e902faec6e5f7fee4ec19fc0e4b8.tar.zst php-mozart-78a627f9b839e902faec6e5f7fee4ec19fc0e4b8.zip | |
refactor(depends): share execution path with prohibits via do_execute
Mirror composer's BaseDependencyCommand::doExecute by collapsing the
duplicated working-dir/load/lookup/print pipeline in depends.rs and
prohibits.rs into a single dependency::do_execute helper driven by an
`inverted` flag. The clap arg structs stay in their per-command modules
and just forward to the shared entry point.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates')
| -rw-r--r-- | crates/mozart/src/commands/dependency.rs | 154 | ||||
| -rw-r--r-- | crates/mozart/src/commands/depends.rs | 67 | ||||
| -rw-r--r-- | crates/mozart/src/commands/prohibits.rs | 109 |
3 files changed, 177 insertions, 153 deletions
diff --git a/crates/mozart/src/commands/dependency.rs b/crates/mozart/src/commands/dependency.rs index d044432..19e9430 100644 --- a/crates/mozart/src/commands/dependency.rs +++ b/crates/mozart/src/commands/dependency.rs @@ -6,9 +6,161 @@ use indexmap::IndexSet; use std::collections::BTreeMap; -use std::path::Path; +use std::path::{Path, PathBuf}; use anyhow::Result; +use mozart_core::console_format; + +// ───────────────────────────────────────────────────────────────────────────── +// Shared command entry point +// ───────────────────────────────────────────────────────────────────────────── + +/// Inputs for [`do_execute`], collected from the `depends` / `prohibits` CLI args. +pub struct DoExecuteArgs<'a> { + pub package: &'a str, + /// Version constraint string (only set for `prohibits`). + pub version: Option<&'a str>, + pub recursive: bool, + pub tree: bool, + pub locked: bool, + /// `true` for `prohibits` (why-not), `false` for `depends` (why). + pub inverted: bool, +} + +/// Shared implementation for `depends` (why) and `prohibits` (why-not). +/// +/// Mirrors `BaseDependencyCommand::doExecute` in Composer: a single function +/// driven by `inverted` to switch between "who depends on X?" and +/// "who prevents X version V from being installed?". +pub fn do_execute( + cli: &super::Cli, + console: &mozart_core::console::Console, + args: DoExecuteArgs<'_>, +) -> Result<()> { + let DoExecuteArgs { + package, + version, + recursive, + tree, + locked, + inverted, + } = args; + + let working_dir = match &cli.working_dir { + Some(dir) => PathBuf::from(dir), + None => std::env::current_dir()?, + }; + + let packages = load_packages(&working_dir, locked)?; + + if packages.is_empty() { + console.write_error( + "No dependencies installed. Try running mozart install or update, or use --locked.", + ); + return Err(mozart_core::exit_code::bail_silent( + mozart_core::exit_code::GENERAL_ERROR, + )); + } + + let target = package.to_lowercase(); + + let target_known = packages.iter().any(|p| p.name.to_lowercase() == target); + if !target_known { + if !inverted && mozart_core::platform::is_platform_package(&target) { + anyhow::bail!( + "Could not find platform package \"{}\". Is PHP available?", + package + ); + } + anyhow::bail!("Could not find package \"{}\" in your project", package); + } + + let constraint = match version { + Some(v) => Some( + mozart_semver::VersionConstraint::parse(v) + .map_err(|e| anyhow::anyhow!("Invalid version constraint '{}': {}", v, e))?, + ), + None => None, + }; + + let recursive = tree || recursive; + let needles = vec![target]; + + let results = get_dependents( + &packages, + &needles, + constraint.as_ref(), + inverted, + recursive, + )?; + + if results.is_empty() { + if inverted { + console.write_stdout( + &console_format!( + "<info>{} {} can be installed.</info>", + package, + version.unwrap_or("") + ), + mozart_core::console::Verbosity::Normal, + ); + return Ok(()); + } + console.info(&format!( + "There is no installed package depending on \"{}\"", + package + )); + return Err(mozart_core::exit_code::bail_silent( + mozart_core::exit_code::GENERAL_ERROR, + )); + } + + if tree { + print_tree(&results, 0, console); + } else { + print_table(&results, console); + } + + if !inverted { + return Ok(()); + } + + // Resolution hint: pick the right composer command based on whether the + // package sits in root's `require`, `require-dev`, or neither. + let needle_lower = package.to_lowercase(); + let composer_command = packages + .iter() + .find(|p| p.is_root) + .map(|root| { + if root + .require + .keys() + .any(|k| k.to_lowercase() == needle_lower) + { + "require" + } else if root + .require_dev + .keys() + .any(|k| k.to_lowercase() == needle_lower) + { + "require --dev" + } else { + "update" + } + }) + .unwrap_or("update"); + + console.info(&format!( + "Not finding what you were looking for? Try calling `composer {} \"{}:{}\" --dry-run` to get another view on the problem.", + composer_command, + package, + version.unwrap_or("") + )); + + Err(mozart_core::exit_code::bail_silent( + mozart_core::exit_code::GENERAL_ERROR, + )) +} // ───────────────────────────────────────────────────────────────────────────── // Core types diff --git a/crates/mozart/src/commands/depends.rs b/crates/mozart/src/commands/depends.rs index 514ce11..9324b82 100644 --- a/crates/mozart/src/commands/depends.rs +++ b/crates/mozart/src/commands/depends.rs @@ -1,5 +1,4 @@ use clap::Args; -use std::path::PathBuf; #[derive(Args)] pub struct DependsArgs { @@ -24,58 +23,16 @@ pub async fn execute( cli: &super::Cli, console: &mozart_core::console::Console, ) -> anyhow::Result<()> { - let working_dir = match &cli.working_dir { - Some(dir) => PathBuf::from(dir), - None => std::env::current_dir()?, - }; - - let packages = super::dependency::load_packages(&working_dir, args.locked)?; - - if packages.is_empty() { - console.write_error( - "No dependencies installed. Try running mozart install or update, or use --locked.", - ); - return Err(mozart_core::exit_code::bail_silent( - mozart_core::exit_code::GENERAL_ERROR, - )); - } - - let target = args.package.to_lowercase(); - - // Verify the target package is known - let target_known = packages.iter().any(|p| p.name.to_lowercase() == target); - if !target_known && mozart_core::platform::is_platform_package(&target) { - anyhow::bail!( - "Could not find platform package \"{}\". Is PHP available?", - args.package - ); - } - if !target_known { - anyhow::bail!( - "Could not find package \"{}\" in your project", - args.package - ); - } - - let recursive = args.tree || args.recursive; - let needles = vec![target]; - let results = super::dependency::get_dependents(&packages, &needles, None, false, recursive)?; - - if results.is_empty() { - console.info(&format!( - "There is no installed package depending on \"{}\"", - args.package - )); - return Err(mozart_core::exit_code::bail_silent( - mozart_core::exit_code::GENERAL_ERROR, - )); - } - - if args.tree { - super::dependency::print_tree(&results, 0, console); - } else { - super::dependency::print_table(&results, console); - } - - Ok(()) + super::dependency::do_execute( + cli, + console, + super::dependency::DoExecuteArgs { + package: &args.package, + version: None, + recursive: args.recursive, + tree: args.tree, + locked: args.locked, + inverted: false, + }, + ) } diff --git a/crates/mozart/src/commands/prohibits.rs b/crates/mozart/src/commands/prohibits.rs index 8eb4166..4bb00e4 100644 --- a/crates/mozart/src/commands/prohibits.rs +++ b/crates/mozart/src/commands/prohibits.rs @@ -1,6 +1,4 @@ use clap::Args; -use mozart_core::console_format; -use std::path::PathBuf; #[derive(Args)] pub struct ProhibitsArgs { @@ -28,99 +26,16 @@ pub async fn execute( cli: &super::Cli, console: &mozart_core::console::Console, ) -> anyhow::Result<()> { - let working_dir = match &cli.working_dir { - Some(dir) => PathBuf::from(dir), - None => std::env::current_dir()?, - }; - - let packages = super::dependency::load_packages(&working_dir, args.locked)?; - - if packages.is_empty() { - console.write_error( - "No dependencies installed. Try running mozart install or update, or use --locked.", - ); - return Err(mozart_core::exit_code::bail_silent( - mozart_core::exit_code::GENERAL_ERROR, - )); - } - - let target = args.package.to_lowercase(); - - // Fix #2: Verify the target package is known - let target_known = packages.iter().any(|p| p.name.to_lowercase() == target); - if !target_known { - anyhow::bail!( - "Could not find package \"{}\" in your project", - args.package - ); - } - - // Parse the version constraint the user is asking about - let version_constraint = mozart_semver::VersionConstraint::parse(&args.version) - .map_err(|e| anyhow::anyhow!("Invalid version constraint '{}': {}", args.version, e))?; - - let recursive = args.tree || args.recursive; - let needles = vec![target]; - - let results = super::dependency::get_dependents( - &packages, - &needles, - Some(&version_constraint), - true, // inverted = prohibits mode - recursive, - )?; - - if results.is_empty() { - console.write_stdout( - &console_format!( - "<info>{} {} can be installed.</info>", - args.package, - args.version - ), - mozart_core::console::Verbosity::Normal, - ); - return Ok(()); - } - - if args.tree { - super::dependency::print_tree(&results, 0, console); - } else { - super::dependency::print_table(&results, console); - } - - // Fix #5: Print resolution hint message - // Determine the appropriate composer command based on whether the needle - // is in root's require or require-dev. - let needle_lower = args.package.to_lowercase(); - let composer_command = packages - .iter() - .find(|p| p.is_root) - .map(|root| { - if root - .require - .keys() - .any(|k| k.to_lowercase() == needle_lower) - { - "require" - } else if root - .require_dev - .keys() - .any(|k| k.to_lowercase() == needle_lower) - { - "require --dev" - } else { - "update" - } - }) - .unwrap_or("update"); - - console.info(&format!( - "Not finding what you were looking for? Try calling `composer {} \"{}:{}\" --dry-run` to get another view on the problem.", - composer_command, args.package, args.version - )); - - // Fix #3: Return exit code 1 when prohibitors are found - Err(mozart_core::exit_code::bail_silent( - mozart_core::exit_code::GENERAL_ERROR, - )) + super::dependency::do_execute( + cli, + console, + super::dependency::DoExecuteArgs { + package: &args.package, + version: Some(&args.version), + recursive: args.recursive, + tree: args.tree, + locked: args.locked, + inverted: true, + }, + ) } |
