From 294bd3dd425a374eda13a52b925a2cd0c4db7f0a Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sat, 21 Feb 2026 14:11:18 +0900 Subject: feat(depends): implement depends and prohibits commands with shared dependency logic Add the `depends` (why) and `prohibits` (why-not) commands that query the dependency graph to answer "which packages require X?" and "which packages prevent version Y of X from being installed?" respectively. Introduces the shared `dependency` module with package loading from lock file or installed.json, forward/inverted dependency graph walking, recursive traversal with cycle detection, and table/tree output formatters. Adds `conflict` field to LockedPackage for conflict-based prohibition detection, updating all struct literals across install, remove, require, and update test helpers. Co-Authored-By: Claude Opus 4.6 --- crates/mozart/src/commands/depends.rs | 41 +++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) (limited to 'crates/mozart/src/commands/depends.rs') diff --git a/crates/mozart/src/commands/depends.rs b/crates/mozart/src/commands/depends.rs index ecdbb24..fa84f7d 100644 --- a/crates/mozart/src/commands/depends.rs +++ b/crates/mozart/src/commands/depends.rs @@ -1,4 +1,5 @@ use clap::Args; +use std::path::PathBuf; #[derive(Args)] pub struct DependsArgs { @@ -18,6 +19,42 @@ pub struct DependsArgs { pub locked: bool, } -pub fn execute(_args: &DependsArgs, _cli: &super::Cli) -> anyhow::Result<()> { - todo!() +pub fn execute(args: &DependsArgs, cli: &super::Cli) -> 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() { + println!( + "{}", + crate::console::info("No packages found. Run `mozart install` first.") + ); + return Ok(()); + } + + 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 { + anyhow::bail!( + "Package '{}' not found in the dependency graph.", + args.package + ); + } + + let recursive = args.tree || args.recursive; + let needles = vec![target]; + let results = super::dependency::get_dependents(&packages, &needles, None, false, recursive)?; + + if args.tree { + super::dependency::print_tree(&results, 0); + } else { + super::dependency::print_table(&results); + } + + Ok(()) } -- cgit v1.3.1