aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/mozart-autoload/src/autoload.rs28
-rw-r--r--crates/mozart/src/commands/dump_autoload.rs86
-rw-r--r--crates/mozart/src/commands/install.rs28
-rw-r--r--crates/mozart/src/commands/reinstall.rs28
4 files changed, 136 insertions, 34 deletions
diff --git a/crates/mozart-autoload/src/autoload.rs b/crates/mozart-autoload/src/autoload.rs
index 27f75ff..8d59db5 100644
--- a/crates/mozart-autoload/src/autoload.rs
+++ b/crates/mozart-autoload/src/autoload.rs
@@ -23,6 +23,13 @@ pub enum PlatformCheckMode {
Disabled,
}
+/// Result of autoload generation, reporting statistics and warnings.
+pub struct GenerateResult {
+ pub class_count: usize,
+ pub has_psr_violations: bool,
+ pub has_ambiguous_classes: bool,
+}
+
/// Configuration for autoload generation.
pub struct AutoloadConfig {
/// Absolute path to the project root (where composer.json lives).
@@ -44,6 +51,8 @@ pub struct AutoloadConfig {
pub apcu_prefix: Option<String>,
/// When true, return an error on PSR mapping violations detected during classmap scan.
pub strict_psr: bool,
+ /// When true, return exit code 2 if ambiguous class mappings are detected.
+ pub strict_ambiguous: bool,
/// How to handle platform requirement checks.
pub platform_check: PlatformCheckMode,
/// When true, skip all platform requirement checks.
@@ -760,7 +769,7 @@ pub fn determine_suffix(working_dir: &Path, vendor_dir: &Path) -> anyhow::Result
/// Generate all autoloader files for the given project.
///
/// This is the main entry point called by `install` and `dump-autoload`.
-pub fn generate(config: &AutoloadConfig) -> anyhow::Result<()> {
+pub fn generate(config: &AutoloadConfig) -> anyhow::Result<GenerateResult> {
// 1. Read installed.json
let installed = InstalledPackages::read(&config.vendor_dir)?;
@@ -838,6 +847,7 @@ pub fn generate(config: &AutoloadConfig) -> anyhow::Result<()> {
}
// Scan classmap dirs
+ let mut ambiguous_found = false;
if !classmap_dirs.is_empty() {
let scanned = scan_classmap_dirs(
&classmap_dirs,
@@ -846,6 +856,10 @@ pub fn generate(config: &AutoloadConfig) -> anyhow::Result<()> {
&excluded,
);
for (class, path_expr) in scanned {
+ if let Some(existing) = data.classmap.get(&class)
+ && existing != &path_expr {
+ ambiguous_found = true;
+ }
// Also generate the static expression
// We store the dynamic expression in data.classmap; static_data.classmap
// will be populated similarly. For now we insert into both.
@@ -869,6 +883,10 @@ pub fn generate(config: &AutoloadConfig) -> anyhow::Result<()> {
);
psr_violations = violations;
for (class, path_expr) in opt_dyn {
+ if let Some(existing) = data.classmap.get(&class)
+ && existing != &path_expr {
+ ambiguous_found = true;
+ }
data.classmap.entry(class).or_insert(path_expr);
}
for (class, path_expr) in opt_static {
@@ -1021,7 +1039,11 @@ pub fn generate(config: &AutoloadConfig) -> anyhow::Result<()> {
generate_installed_php(&root_name, &root_type, &installed, config.dev_mode),
)?;
- Ok(())
+ Ok(GenerateResult {
+ class_count: data.classmap.len(),
+ has_psr_violations: !psr_violations.is_empty(),
+ has_ambiguous_classes: ambiguous_found,
+ })
}
// ─────────────────────────────────────────────────────────────────────────────
@@ -1443,6 +1465,7 @@ mod tests {
apcu: false,
apcu_prefix: None,
strict_psr: false,
+ strict_ambiguous: false,
platform_check: PlatformCheckMode::Disabled,
ignore_platform_reqs: false,
};
@@ -1545,6 +1568,7 @@ mod tests {
apcu: false,
apcu_prefix: None,
strict_psr: false,
+ strict_ambiguous: false,
platform_check: PlatformCheckMode::Disabled,
ignore_platform_reqs: false,
};
diff --git a/crates/mozart/src/commands/dump_autoload.rs b/crates/mozart/src/commands/dump_autoload.rs
index 43108ab..0828288 100644
--- a/crates/mozart/src/commands/dump_autoload.rs
+++ b/crates/mozart/src/commands/dump_autoload.rs
@@ -53,6 +53,11 @@ pub async fn execute(
cli: &super::Cli,
console: &mozart_core::console::Console,
) -> anyhow::Result<()> {
+ // A: --dev / --no-dev conflict detection
+ if args.dev && args.no_dev {
+ anyhow::bail!("You can not use both --no-dev and --dev as they conflict with each other.");
+ }
+
let working_dir = match &cli.working_dir {
Some(dir) => PathBuf::from(dir),
None => std::env::current_dir()?,
@@ -61,6 +66,59 @@ pub async fn execute(
let vendor_dir = working_dir.join("vendor");
let dev_mode = !args.no_dev;
+ // B: Read config-driven defaults from composer.json
+ let composer_json_path = working_dir.join("composer.json");
+ let mut composer_config = super::config::ComposerConfig::defaults();
+ if composer_json_path.exists()
+ && let Ok(content) = std::fs::read_to_string(&composer_json_path)
+ && let Ok(value) = serde_json::from_str::<serde_json::Value>(&content)
+ && let Some(cfg_obj) = value.get("config").and_then(|v| v.as_object()) {
+ let overrides: std::collections::BTreeMap<String, serde_json::Value> = cfg_obj
+ .iter()
+ .map(|(k, v)| (k.clone(), v.clone()))
+ .collect();
+ composer_config.merge(&overrides);
+ }
+
+ let optimize = args.optimize
+ || composer_config
+ .get("optimize-autoloader")
+ .and_then(|v| v.as_bool())
+ .unwrap_or(false);
+ let classmap_authoritative = args.classmap_authoritative
+ || composer_config
+ .get("classmap-authoritative")
+ .and_then(|v| v.as_bool())
+ .unwrap_or(false);
+ let apcu = args.apcu
+ || args.apcu_prefix.is_some()
+ || composer_config
+ .get("apcu-autoloader")
+ .and_then(|v| v.as_bool())
+ .unwrap_or(false);
+
+ // C: Validate --strict-psr and --strict-ambiguous require optimize
+ let effective_optimize = optimize || classmap_authoritative;
+ if args.strict_psr && !effective_optimize {
+ anyhow::bail!(
+ "--strict-psr mode only works with optimized autoloader, use --optimize or --classmap-authoritative."
+ );
+ }
+ if args.strict_ambiguous && !effective_optimize {
+ anyhow::bail!(
+ "--strict-ambiguous mode only works with optimized autoloader, use --optimize or --classmap-authoritative."
+ );
+ }
+
+ // D: Pre-generation output message
+ if classmap_authoritative {
+ console.info("Generating optimized autoload files (authoritative)");
+ } else if optimize {
+ console.info("Generating optimized autoload files");
+ } else {
+ console.info("Generating autoload files");
+ }
+
// Determine suffix: read from existing autoload.php, or from lock file, or generate
let suffix = mozart_autoload::autoload::determine_suffix(&working_dir, &vendor_dir)?;
@@ -69,21 +127,37 @@ pub async fn execute(
return Ok(());
}
- mozart_autoload::autoload::generate(&mozart_autoload::autoload::AutoloadConfig {
+ // E: AutoloadConfig construction using config-merged values
+ let autoload_config = mozart_autoload::autoload::AutoloadConfig {
project_dir: working_dir,
vendor_dir,
dev_mode,
suffix,
- classmap_authoritative: args.classmap_authoritative,
- optimize: args.optimize,
- apcu: args.apcu,
+ classmap_authoritative,
+ optimize,
+ apcu,
apcu_prefix: args.apcu_prefix.clone(),
strict_psr: args.strict_psr,
+ strict_ambiguous: args.strict_ambiguous,
platform_check: mozart_autoload::autoload::PlatformCheckMode::Full,
ignore_platform_reqs: args.ignore_platform_reqs,
- })?;
+ };
+
+ // F: Handle GenerateResult and post-generation messages
+ let result = mozart_autoload::autoload::generate(&autoload_config)?;
- console.info("Generated autoload files");
+ if effective_optimize || classmap_authoritative {
+ console.info(&format!(
+ "Generated optimized autoload files containing {} classes",
+ result.class_count
+ ));
+ } else {
+ console.info("Generated autoload files");
+ }
+
+ if args.strict_ambiguous && result.has_ambiguous_classes {
+ std::process::exit(2);
+ }
Ok(())
}
diff --git a/crates/mozart/src/commands/install.rs b/crates/mozart/src/commands/install.rs
index 4105a7b..f29c992 100644
--- a/crates/mozart/src/commands/install.rs
+++ b/crates/mozart/src/commands/install.rs
@@ -476,19 +476,21 @@ pub async fn install_from_lock(
let suffix = lock.content_hash.clone();
- mozart_autoload::autoload::generate(&mozart_autoload::autoload::AutoloadConfig {
- project_dir: working_dir.to_path_buf(),
- vendor_dir: vendor_dir.to_path_buf(),
- dev_mode,
- suffix,
- classmap_authoritative: config.classmap_authoritative,
- optimize: config.optimize_autoloader,
- apcu: config.apcu_autoloader,
- apcu_prefix: config.apcu_autoloader_prefix.clone(),
- strict_psr: false,
- platform_check: mozart_autoload::autoload::PlatformCheckMode::Full,
- ignore_platform_reqs: config.ignore_platform_reqs,
- })?;
+ let _result =
+ mozart_autoload::autoload::generate(&mozart_autoload::autoload::AutoloadConfig {
+ project_dir: working_dir.to_path_buf(),
+ vendor_dir: vendor_dir.to_path_buf(),
+ dev_mode,
+ suffix,
+ classmap_authoritative: config.classmap_authoritative,
+ optimize: config.optimize_autoloader,
+ apcu: config.apcu_autoloader,
+ apcu_prefix: config.apcu_autoloader_prefix.clone(),
+ strict_psr: false,
+ strict_ambiguous: false,
+ platform_check: mozart_autoload::autoload::PlatformCheckMode::Full,
+ ignore_platform_reqs: config.ignore_platform_reqs,
+ })?;
eprintln!("Generated autoload files");
}
diff --git a/crates/mozart/src/commands/reinstall.rs b/crates/mozart/src/commands/reinstall.rs
index 313c70c..c6df20d 100644
--- a/crates/mozart/src/commands/reinstall.rs
+++ b/crates/mozart/src/commands/reinstall.rs
@@ -234,19 +234,21 @@ pub async fn execute(
let dev_mode = !args.no_dev && installed.dev;
let suffix = lock.content_hash.clone();
- mozart_autoload::autoload::generate(&mozart_autoload::autoload::AutoloadConfig {
- project_dir: working_dir.to_path_buf(),
- vendor_dir: vendor_dir.to_path_buf(),
- dev_mode,
- suffix,
- classmap_authoritative: args.classmap_authoritative,
- optimize: args.optimize_autoloader,
- apcu: args.apcu_autoloader,
- apcu_prefix: args.apcu_autoloader_prefix.clone(),
- strict_psr: false,
- platform_check: mozart_autoload::autoload::PlatformCheckMode::Full,
- ignore_platform_reqs: args.ignore_platform_reqs,
- })?;
+ let _result =
+ mozart_autoload::autoload::generate(&mozart_autoload::autoload::AutoloadConfig {
+ project_dir: working_dir.to_path_buf(),
+ vendor_dir: vendor_dir.to_path_buf(),
+ dev_mode,
+ suffix,
+ classmap_authoritative: args.classmap_authoritative,
+ optimize: args.optimize_autoloader,
+ apcu: args.apcu_autoloader,
+ apcu_prefix: args.apcu_autoloader_prefix.clone(),
+ strict_psr: false,
+ strict_ambiguous: false,
+ platform_check: mozart_autoload::autoload::PlatformCheckMode::Full,
+ ignore_platform_reqs: args.ignore_platform_reqs,
+ })?;
console.info("Generated autoload files");
}