aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/mozart/src/commands/install.rs
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-02-21 23:38:32 +0900
committernsfisis <nsfisis@gmail.com>2026-02-21 23:38:32 +0900
commit52310761f67220c9c075cd847205825a720035ee (patch)
tree0528fc94aea7853e41313e19964d74a958dae9c9 /crates/mozart/src/commands/install.rs
parent92da9e37c68beb180e45e550fba5acd7d28dca27 (diff)
downloadphp-mozart-52310761f67220c9c075cd847205825a720035ee.tar.gz
php-mozart-52310761f67220c9c075cd847205825a720035ee.tar.zst
php-mozart-52310761f67220c9c075cd847205825a720035ee.zip
feat(console): add structured error handling, verbosity, and suggestions
Implement Phase 7.2 error handling & UX infrastructure: - Add exit_code module with MozartError, bail()/bail_silent() helpers, and Composer-compatible exit code constants (0-5, 100) - Redesign Console struct with Verbosity enum (Quiet/Normal/Verbose/ VeryVerbose/Debug), ANSI auto-detection via IsTerminal, and verbosity-gated output methods (info/verbose/debug/error) - Thread Console through all 33 command execute() signatures - Replace all std::process::exit() calls with structured MozartError returns handled in main() - Migrate eprintln\! status messages to console.info() for quiet-mode suppression - Add suggest module with Levenshtein distance and "Did you mean?" formatting for future package name suggestions Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'crates/mozart/src/commands/install.rs')
-rw-r--r--crates/mozart/src/commands/install.rs73
1 files changed, 30 insertions, 43 deletions
diff --git a/crates/mozart/src/commands/install.rs b/crates/mozart/src/commands/install.rs
index b5f9142..fb7335b 100644
--- a/crates/mozart/src/commands/install.rs
+++ b/crates/mozart/src/commands/install.rs
@@ -496,58 +496,51 @@ pub fn install_from_lock(
Ok(())
}
-pub fn execute(args: &InstallArgs, cli: &super::Cli) -> anyhow::Result<()> {
+pub fn execute(
+ args: &InstallArgs,
+ cli: &super::Cli,
+ console: &crate::console::Console,
+) -> anyhow::Result<()> {
// Step 1: Resolve the working directory
let working_dir = resolve_working_dir(cli);
// Step 2: Validate arguments
if !args.packages.is_empty() {
let pkgs = args.packages.join(" ");
- eprintln!(
- "{}",
- console::error(&format!(
+ return Err(crate::exit_code::bail(
+ crate::exit_code::GENERAL_ERROR,
+ format!(
"Invalid argument {pkgs}. Use \"mozart require {pkgs}\" instead to add packages to your composer.json."
- ))
- );
- std::process::exit(1);
+ ),
+ ));
}
if args.no_install {
- eprintln!(
- "{}",
- console::error(
- "Invalid option \"--no-install\". Use \"mozart update --no-install\" instead if you are trying to update the composer.lock file."
- )
- );
- std::process::exit(1);
+ return Err(crate::exit_code::bail(
+ crate::exit_code::GENERAL_ERROR,
+ "Invalid option \"--no-install\". Use \"mozart update --no-install\" instead if you are trying to update the composer.lock file.",
+ ));
}
if args.dev {
- eprintln!(
- "{}",
- console::warning(
- "The --dev option is deprecated. Dev packages are installed by default."
- )
- );
+ console.info(&console::warning(
+ "The --dev option is deprecated. Dev packages are installed by default.",
+ ));
}
if args.no_suggest {
- eprintln!(
- "{}",
- console::warning("The --no-suggest option is deprecated and has no effect.")
- );
+ console.info(&console::warning(
+ "The --no-suggest option is deprecated and has no effect.",
+ ));
}
// Step 3: Read composer.lock
let lock_path = working_dir.join("composer.lock");
if !lock_path.exists() {
- eprintln!(
- "{}",
- console::warning(
- "No composer.lock file present. Run \"mozart update\" to generate one."
- )
- );
- std::process::exit(1);
+ return Err(crate::exit_code::bail(
+ crate::exit_code::LOCK_FILE_INVALID,
+ "No composer.lock file present. Run \"mozart update\" to generate one.",
+ ));
}
let lock = lockfile::LockFile::read_from_file(&lock_path)?;
@@ -556,12 +549,9 @@ pub fn execute(args: &InstallArgs, cli: &super::Cli) -> anyhow::Result<()> {
if composer_json_path.exists() {
let content = std::fs::read_to_string(&composer_json_path)?;
if !lock.is_fresh(&content) {
- eprintln!(
- "{}",
- console::warning(
- "Warning: The lock file is not up to date with the latest changes in composer.json. You may be getting outdated dependencies. It is recommended that you run `mozart update`."
- )
- );
+ console.info(&console::warning(
+ "Warning: The lock file is not up to date with the latest changes in composer.json. You may be getting outdated dependencies. It is recommended that you run `mozart update`."
+ ));
}
}
@@ -573,12 +563,9 @@ pub fn execute(args: &InstallArgs, cli: &super::Cli) -> anyhow::Result<()> {
.map(|s| s.eq_ignore_ascii_case("source"))
.unwrap_or(false);
if prefer_source {
- eprintln!(
- "{}",
- console::warning(
- "Warning: Source installs are not yet supported. Falling back to dist."
- )
- );
+ console.info(&console::warning(
+ "Warning: Source installs are not yet supported. Falling back to dist.",
+ ));
}
// Step 6: Determine dev mode and vendor directory