diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-02-22 16:37:49 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-02-22 16:37:49 +0900 |
| commit | b696eb7608d921ae0e14a4296e412c33340ceee8 (patch) | |
| tree | 9a6937bed42ee550553fdb118b9281d00cdce4d9 /crates | |
| parent | 6490fe43676919bc1dcc8659ec4e52da225f92e6 (diff) | |
| download | php-mozart-b696eb7608d921ae0e14a4296e412c33340ceee8.tar.gz php-mozart-b696eb7608d921ae0e14a4296e412c33340ceee8.tar.zst php-mozart-b696eb7608d921ae0e14a4296e412c33340ceee8.zip | |
refactor: reorganize crates to match Composer subpackage structure
Rename mozart-constraint to mozart-semver (mirrors composer/semver) and
extract mozart-class-map-generator from mozart-autoload (mirrors
composer/class-map-generator). No logic changes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'crates')
18 files changed, 294 insertions, 270 deletions
diff --git a/crates/mozart-autoload/Cargo.toml b/crates/mozart-autoload/Cargo.toml index 93037df..98c4f6f 100644 --- a/crates/mozart-autoload/Cargo.toml +++ b/crates/mozart-autoload/Cargo.toml @@ -4,10 +4,10 @@ version.workspace = true edition.workspace = true [dependencies] +mozart-class-map-generator.workspace = true mozart-registry.workspace = true anyhow.workspace = true md5.workspace = true -regex.workspace = true serde_json.workspace = true [dev-dependencies] diff --git a/crates/mozart-autoload/src/autoload.rs b/crates/mozart-autoload/src/autoload.rs index 2e4158c..27f75ff 100644 --- a/crates/mozart-autoload/src/autoload.rs +++ b/crates/mozart-autoload/src/autoload.rs @@ -1,3 +1,4 @@ +use mozart_class_map_generator::{scan_classmap_dirs, scan_psr_for_classmap}; use mozart_registry::installed::InstalledPackages; use mozart_registry::lockfile::LockedPackage; use std::collections::{BTreeMap, HashSet}; @@ -453,238 +454,6 @@ fn generate_autoload_static(static_data: &AutoloadData, suffix: &str) -> String out } -/// Recursively collect PHP files from a directory, skipping excluded paths. -fn collect_php_files( - dir: &Path, - excluded: &[String], - vendor_dir: &Path, - project_dir: &Path, -) -> Vec<PathBuf> { - let mut result = Vec::new(); - if !dir.is_dir() { - return result; - } - collect_php_files_inner(dir, excluded, vendor_dir, project_dir, &mut result); - result -} - -fn collect_php_files_inner( - dir: &Path, - excluded: &[String], - vendor_dir: &Path, - project_dir: &Path, - result: &mut Vec<PathBuf>, -) { - let entries = match std::fs::read_dir(dir) { - Ok(e) => e, - Err(_) => return, - }; - for entry in entries.flatten() { - let path = entry.path(); - - // Check if path matches any excluded pattern - if is_excluded(&path, excluded, vendor_dir, project_dir) { - continue; - } - - if path.is_dir() { - collect_php_files_inner(&path, excluded, vendor_dir, project_dir, result); - } else if crate::php_scanner::is_php_ext(&path) { - result.push(path); - } - } -} - -/// Check whether a path matches any of the excluded patterns. -fn is_excluded(path: &Path, excluded: &[String], vendor_dir: &Path, project_dir: &Path) -> bool { - for exc in excluded { - // Excluded patterns can be relative to project_dir or absolute - let exc_path = if Path::new(exc).is_absolute() { - PathBuf::from(exc) - } else { - project_dir.join(exc) - }; - if path.starts_with(&exc_path) || path == exc_path { - return true; - } - // Also check relative to vendor_dir - let exc_vendor = vendor_dir.join(exc); - if path.starts_with(&exc_vendor) || path == exc_vendor { - return true; - } - } - false -} - -/// Scan directories for PHP class declarations and return a classmap. -/// -/// `dirs` is a list of absolute directory paths to scan. -/// Returns a `BTreeMap<class_name, file_path_expression>` where the path expression -/// uses `$vendorDir` or `$baseDir` as appropriate. -fn scan_classmap_dirs( - dirs: &[PathBuf], - vendor_dir: &Path, - project_dir: &Path, - excluded: &[String], -) -> BTreeMap<String, String> { - let mut classmap = BTreeMap::new(); - - for dir in dirs { - let files = collect_php_files(dir, excluded, vendor_dir, project_dir); - for file in files { - match crate::php_scanner::find_classes(&file) { - Ok(classes) => { - for class in classes { - let path_expr = path_to_php_expr(&file, vendor_dir, project_dir); - classmap.entry(class).or_insert(path_expr); - } - } - Err(_) => continue, - } - } - } - - classmap -} - -/// Convert an absolute file path to a PHP path expression using `$vendorDir` or `$baseDir`. -fn path_to_php_expr(file: &Path, vendor_dir: &Path, project_dir: &Path) -> String { - if let Ok(rel) = file.strip_prefix(vendor_dir) { - let rel_str = rel.to_string_lossy().replace('\\', "/"); - format!("$vendorDir . '/{rel_str}'") - } else if let Ok(rel) = file.strip_prefix(project_dir) { - let rel_str = rel.to_string_lossy().replace('\\', "/"); - format!("$baseDir . '/{rel_str}'") - } else { - // Fall back to absolute path - let abs = file.to_string_lossy().replace('\\', "/"); - format!("'{abs}'") - } -} - -/// Convert an absolute file path to a static PHP path expression using `__DIR__ . '/..` form. -fn path_to_static_expr(file: &Path, vendor_dir: &Path, project_dir: &Path) -> String { - if let Ok(rel) = file.strip_prefix(vendor_dir) { - let rel_str = rel.to_string_lossy().replace('\\', "/"); - format!("__DIR__ . '/..' . '/{rel_str}'") - } else if let Ok(rel) = file.strip_prefix(project_dir) { - let rel_str = rel.to_string_lossy().replace('\\', "/"); - format!("__DIR__ . '/../..' . '/{rel_str}'") - } else { - let abs = file.to_string_lossy().replace('\\', "/"); - format!("'{abs}'") - } -} - -/// Scan PSR-4 and PSR-0 directories for class declarations (used in optimize mode). -/// -/// Returns `(dynamic_classmap, static_classmap, psr_violations)`. -fn scan_psr_for_classmap( - psr4: &BTreeMap<String, Vec<String>>, - psr0: &BTreeMap<String, Vec<String>>, - vendor_dir: &Path, - project_dir: &Path, - excluded: &[String], -) -> ( - BTreeMap<String, String>, - BTreeMap<String, String>, - Vec<String>, -) { - let mut dyn_map: BTreeMap<String, String> = BTreeMap::new(); - let mut static_map: BTreeMap<String, String> = BTreeMap::new(); - let mut violations: Vec<String> = Vec::new(); - - // Helper: resolve a PHP path expression to an absolute path. - let resolve = |expr: &str| -> Option<PathBuf> { - // Expressions look like: - // $vendorDir . '/psr/log/src' - // $baseDir . '/src' - // __DIR__ . '/..' . '/psr/log/src' - // __DIR__ . '/../..' . '/src' - if let Some(rest) = expr.strip_prefix("$vendorDir . '") { - let rel = rest.trim_end_matches('\''); - Some(vendor_dir.join(rel.trim_start_matches('/'))) - } else if let Some(rest) = expr.strip_prefix("$baseDir . '") { - let rel = rest.trim_end_matches('\''); - Some(project_dir.join(rel.trim_start_matches('/'))) - } else if expr == "$vendorDir" { - Some(vendor_dir.to_path_buf()) - } else if expr == "$baseDir" { - Some(project_dir.to_path_buf()) - } else { - None - } - }; - - // Scan PSR-4 dirs - for (ns, paths) in psr4 { - for path_expr in paths { - if let Some(abs_dir) = resolve(path_expr) { - let files = collect_php_files(&abs_dir, excluded, vendor_dir, project_dir); - for file in files { - match crate::php_scanner::find_classes(&file) { - Ok(classes) => { - for class in classes { - // PSR-4 validation - let file_str = file.to_string_lossy(); - let dir_str = abs_dir.to_string_lossy(); - let base_ns = ns.as_str(); - if !crate::php_scanner::validate_psr4_class( - &class, base_ns, &file_str, &dir_str, - ) { - violations.push(format!( - "Class {class} in {file_str} does not comply with PSR-4 (namespace prefix: {ns})" - )); - } - let dyn_expr = path_to_php_expr(&file, vendor_dir, project_dir); - let static_expr = - path_to_static_expr(&file, vendor_dir, project_dir); - dyn_map.entry(class.clone()).or_insert(dyn_expr); - static_map.entry(class).or_insert(static_expr); - } - } - Err(_) => continue, - } - } - } - } - } - - // Scan PSR-0 dirs - for (ns, paths) in psr0 { - for path_expr in paths { - if let Some(abs_dir) = resolve(path_expr) { - let files = collect_php_files(&abs_dir, excluded, vendor_dir, project_dir); - for file in files { - match crate::php_scanner::find_classes(&file) { - Ok(classes) => { - for class in classes { - let file_str = file.to_string_lossy(); - let dir_str = abs_dir.to_string_lossy(); - if !crate::php_scanner::validate_psr0_class( - &class, &file_str, &dir_str, - ) { - violations.push(format!( - "Class {class} in {file_str} does not comply with PSR-0 (namespace prefix: {ns})" - )); - } - let dyn_expr = path_to_php_expr(&file, vendor_dir, project_dir); - let static_expr = - path_to_static_expr(&file, vendor_dir, project_dir); - dyn_map.entry(class.clone()).or_insert(dyn_expr); - static_map.entry(class).or_insert(static_expr); - } - } - Err(_) => continue, - } - } - } - } - } - - (dyn_map, static_map, violations) -} - /// Generate `vendor/composer/platform_check.php`. /// /// Returns `None` if mode is `Disabled` or there are no relevant requirements. diff --git a/crates/mozart-autoload/src/lib.rs b/crates/mozart-autoload/src/lib.rs index 9d798c6..fc80aed 100644 --- a/crates/mozart-autoload/src/lib.rs +++ b/crates/mozart-autoload/src/lib.rs @@ -1,2 +1 @@ pub mod autoload; -pub mod php_scanner; diff --git a/crates/mozart-class-map-generator/Cargo.toml b/crates/mozart-class-map-generator/Cargo.toml new file mode 100644 index 0000000..15ae0cb --- /dev/null +++ b/crates/mozart-class-map-generator/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "mozart-class-map-generator" +version.workspace = true +edition.workspace = true + +[dependencies] +anyhow.workspace = true +regex.workspace = true + +[dev-dependencies] +tempfile.workspace = true diff --git a/crates/mozart-class-map-generator/src/classmap.rs b/crates/mozart-class-map-generator/src/classmap.rs new file mode 100644 index 0000000..e1631f4 --- /dev/null +++ b/crates/mozart-class-map-generator/src/classmap.rs @@ -0,0 +1,239 @@ +use std::collections::BTreeMap; +use std::path::{Path, PathBuf}; + +/// Recursively collect PHP files from a directory, skipping excluded paths. +pub fn collect_php_files( + dir: &Path, + excluded: &[String], + vendor_dir: &Path, + project_dir: &Path, +) -> Vec<PathBuf> { + let mut result = Vec::new(); + if !dir.is_dir() { + return result; + } + collect_php_files_inner(dir, excluded, vendor_dir, project_dir, &mut result); + result +} + +fn collect_php_files_inner( + dir: &Path, + excluded: &[String], + vendor_dir: &Path, + project_dir: &Path, + result: &mut Vec<PathBuf>, +) { + let entries = match std::fs::read_dir(dir) { + Ok(e) => e, + Err(_) => return, + }; + for entry in entries.flatten() { + let path = entry.path(); + + // Check if path matches any excluded pattern + if is_excluded(&path, excluded, vendor_dir, project_dir) { + continue; + } + + if path.is_dir() { + collect_php_files_inner(&path, excluded, vendor_dir, project_dir, result); + } else if crate::php_scanner::is_php_ext(&path) { + result.push(path); + } + } +} + +/// Check whether a path matches any of the excluded patterns. +pub fn is_excluded( + path: &Path, + excluded: &[String], + vendor_dir: &Path, + project_dir: &Path, +) -> bool { + for exc in excluded { + // Excluded patterns can be relative to project_dir or absolute + let exc_path = if Path::new(exc).is_absolute() { + PathBuf::from(exc) + } else { + project_dir.join(exc) + }; + if path.starts_with(&exc_path) || path == exc_path { + return true; + } + // Also check relative to vendor_dir + let exc_vendor = vendor_dir.join(exc); + if path.starts_with(&exc_vendor) || path == exc_vendor { + return true; + } + } + false +} + +/// Scan directories for PHP class declarations and return a classmap. +/// +/// `dirs` is a list of absolute directory paths to scan. +/// Returns a `BTreeMap<class_name, file_path_expression>` where the path expression +/// uses `$vendorDir` or `$baseDir` as appropriate. +pub fn scan_classmap_dirs( + dirs: &[PathBuf], + vendor_dir: &Path, + project_dir: &Path, + excluded: &[String], +) -> BTreeMap<String, String> { + let mut classmap = BTreeMap::new(); + + for dir in dirs { + let files = collect_php_files(dir, excluded, vendor_dir, project_dir); + for file in files { + match crate::php_scanner::find_classes(&file) { + Ok(classes) => { + for class in classes { + let path_expr = path_to_php_expr(&file, vendor_dir, project_dir); + classmap.entry(class).or_insert(path_expr); + } + } + Err(_) => continue, + } + } + } + + classmap +} + +/// Convert an absolute file path to a PHP path expression using `$vendorDir` or `$baseDir`. +pub fn path_to_php_expr(file: &Path, vendor_dir: &Path, project_dir: &Path) -> String { + if let Ok(rel) = file.strip_prefix(vendor_dir) { + let rel_str = rel.to_string_lossy().replace('\\', "/"); + format!("$vendorDir . '/{rel_str}'") + } else if let Ok(rel) = file.strip_prefix(project_dir) { + let rel_str = rel.to_string_lossy().replace('\\', "/"); + format!("$baseDir . '/{rel_str}'") + } else { + // Fall back to absolute path + let abs = file.to_string_lossy().replace('\\', "/"); + format!("'{abs}'") + } +} + +/// Convert an absolute file path to a static PHP path expression using `__DIR__ . '/..` form. +pub fn path_to_static_expr(file: &Path, vendor_dir: &Path, project_dir: &Path) -> String { + if let Ok(rel) = file.strip_prefix(vendor_dir) { + let rel_str = rel.to_string_lossy().replace('\\', "/"); + format!("__DIR__ . '/..' . '/{rel_str}'") + } else if let Ok(rel) = file.strip_prefix(project_dir) { + let rel_str = rel.to_string_lossy().replace('\\', "/"); + format!("__DIR__ . '/../..' . '/{rel_str}'") + } else { + let abs = file.to_string_lossy().replace('\\', "/"); + format!("'{abs}'") + } +} + +/// Scan PSR-4 and PSR-0 directories for class declarations (used in optimize mode). +/// +/// Returns `(dynamic_classmap, static_classmap, psr_violations)`. +pub fn scan_psr_for_classmap( + psr4: &BTreeMap<String, Vec<String>>, + psr0: &BTreeMap<String, Vec<String>>, + vendor_dir: &Path, + project_dir: &Path, + excluded: &[String], +) -> ( + BTreeMap<String, String>, + BTreeMap<String, String>, + Vec<String>, +) { + let mut dyn_map: BTreeMap<String, String> = BTreeMap::new(); + let mut static_map: BTreeMap<String, String> = BTreeMap::new(); + let mut violations: Vec<String> = Vec::new(); + + // Helper: resolve a PHP path expression to an absolute path. + let resolve = |expr: &str| -> Option<PathBuf> { + // Expressions look like: + // $vendorDir . '/psr/log/src' + // $baseDir . '/src' + // __DIR__ . '/..' . '/psr/log/src' + // __DIR__ . '/../..' . '/src' + if let Some(rest) = expr.strip_prefix("$vendorDir . '") { + let rel = rest.trim_end_matches('\''); + Some(vendor_dir.join(rel.trim_start_matches('/'))) + } else if let Some(rest) = expr.strip_prefix("$baseDir . '") { + let rel = rest.trim_end_matches('\''); + Some(project_dir.join(rel.trim_start_matches('/'))) + } else if expr == "$vendorDir" { + Some(vendor_dir.to_path_buf()) + } else if expr == "$baseDir" { + Some(project_dir.to_path_buf()) + } else { + None + } + }; + + // Scan PSR-4 dirs + for (ns, paths) in psr4 { + for path_expr in paths { + if let Some(abs_dir) = resolve(path_expr) { + let files = collect_php_files(&abs_dir, excluded, vendor_dir, project_dir); + for file in files { + match crate::php_scanner::find_classes(&file) { + Ok(classes) => { + for class in classes { + // PSR-4 validation + let file_str = file.to_string_lossy(); + let dir_str = abs_dir.to_string_lossy(); + let base_ns = ns.as_str(); + if !crate::php_scanner::validate_psr4_class( + &class, base_ns, &file_str, &dir_str, + ) { + violations.push(format!( + "Class {class} in {file_str} does not comply with PSR-4 (namespace prefix: {ns})" + )); + } + let dyn_expr = path_to_php_expr(&file, vendor_dir, project_dir); + let static_expr = + path_to_static_expr(&file, vendor_dir, project_dir); + dyn_map.entry(class.clone()).or_insert(dyn_expr); + static_map.entry(class).or_insert(static_expr); + } + } + Err(_) => continue, + } + } + } + } + } + + // Scan PSR-0 dirs + for (ns, paths) in psr0 { + for path_expr in paths { + if let Some(abs_dir) = resolve(path_expr) { + let files = collect_php_files(&abs_dir, excluded, vendor_dir, project_dir); + for file in files { + match crate::php_scanner::find_classes(&file) { + Ok(classes) => { + for class in classes { + let file_str = file.to_string_lossy(); + let dir_str = abs_dir.to_string_lossy(); + if !crate::php_scanner::validate_psr0_class( + &class, &file_str, &dir_str, + ) { + violations.push(format!( + "Class {class} in {file_str} does not comply with PSR-0 (namespace prefix: {ns})" + )); + } + let dyn_expr = path_to_php_expr(&file, vendor_dir, project_dir); + let static_expr = + path_to_static_expr(&file, vendor_dir, project_dir); + dyn_map.entry(class.clone()).or_insert(dyn_expr); + static_map.entry(class).or_insert(static_expr); + } + } + Err(_) => continue, + } + } + } + } + } + + (dyn_map, static_map, violations) +} diff --git a/crates/mozart-class-map-generator/src/lib.rs b/crates/mozart-class-map-generator/src/lib.rs new file mode 100644 index 0000000..a17405c --- /dev/null +++ b/crates/mozart-class-map-generator/src/lib.rs @@ -0,0 +1,8 @@ +pub mod classmap; +pub mod php_scanner; + +pub use classmap::{ + collect_php_files, is_excluded, path_to_php_expr, path_to_static_expr, scan_classmap_dirs, + scan_psr_for_classmap, +}; +pub use php_scanner::{find_classes, is_php_ext, validate_psr0_class, validate_psr4_class}; diff --git a/crates/mozart-autoload/src/php_scanner.rs b/crates/mozart-class-map-generator/src/php_scanner.rs index 3d0d51d..3d0d51d 100644 --- a/crates/mozart-autoload/src/php_scanner.rs +++ b/crates/mozart-class-map-generator/src/php_scanner.rs diff --git a/crates/mozart-core/Cargo.toml b/crates/mozart-core/Cargo.toml index 885fdf4..599dbb3 100644 --- a/crates/mozart-core/Cargo.toml +++ b/crates/mozart-core/Cargo.toml @@ -4,10 +4,10 @@ version.workspace = true edition.workspace = true [dependencies] +mozart-spdx-licenses.workspace = true anyhow.workspace = true colored.workspace = true dialoguer.workspace = true -mozart-spdx-licenses.workspace = true regex.workspace = true serde.workspace = true serde_json.workspace = true diff --git a/crates/mozart-registry/Cargo.toml b/crates/mozart-registry/Cargo.toml index 8672708..d0159b6 100644 --- a/crates/mozart-registry/Cargo.toml +++ b/crates/mozart-registry/Cargo.toml @@ -4,9 +4,9 @@ version.workspace = true edition.workspace = true [dependencies] -mozart-constraint.workspace = true mozart-core.workspace = true mozart-metadata-minifier.workspace = true +mozart-semver.workspace = true anyhow.workspace = true filetime.workspace = true flate2.workspace = true diff --git a/crates/mozart-registry/src/resolver.rs b/crates/mozart-registry/src/resolver.rs index 61895eb..e240dcd 100644 --- a/crates/mozart-registry/src/resolver.rs +++ b/crates/mozart-registry/src/resolver.rs @@ -15,8 +15,8 @@ use pubgrub::{ use crate::cache::Cache; use crate::packagist; -use mozart_constraint::{Constraint, VersionConstraint}; use mozart_core::package::Stability; +use mozart_semver::{Constraint, VersionConstraint}; // ───────────────────────────────────────────────────────────────────────────── // Stability constants @@ -372,7 +372,7 @@ fn single_constraint_to_ranges(c: &Constraint) -> Result<ComposerVS, String> { } /// Convert a `constraint::Version` to a `ComposerVersion`. -fn version_to_composer(v: &mozart_constraint::Version) -> Result<ComposerVersion, String> { +fn version_to_composer(v: &mozart_semver::Version) -> Result<ComposerVersion, String> { // Dev branches cannot be represented as ComposerVersion if v.is_dev_branch { return Err(format!( diff --git a/crates/mozart-constraint/Cargo.toml b/crates/mozart-semver/Cargo.toml index 49265d7..cee0804 100644 --- a/crates/mozart-constraint/Cargo.toml +++ b/crates/mozart-semver/Cargo.toml @@ -1,4 +1,4 @@ [package] -name = "mozart-constraint" +name = "mozart-semver" version.workspace = true edition.workspace = true diff --git a/crates/mozart-constraint/src/lib.rs b/crates/mozart-semver/src/lib.rs index 7c417ec..7c417ec 100644 --- a/crates/mozart-constraint/src/lib.rs +++ b/crates/mozart-semver/src/lib.rs diff --git a/crates/mozart/Cargo.toml b/crates/mozart/Cargo.toml index 18b34bf..443cd9e 100644 --- a/crates/mozart/Cargo.toml +++ b/crates/mozart/Cargo.toml @@ -4,11 +4,11 @@ version.workspace = true edition.workspace = true [dependencies] -mozart-constraint.workspace = true mozart-archiver.workspace = true mozart-autoload.workspace = true mozart-core.workspace = true mozart-registry.workspace = true +mozart-semver.workspace = true anyhow.workspace = true clap.workspace = true clap_complete.workspace = true @@ -21,8 +21,8 @@ serde_json.workspace = true sha1.workspace = true tempfile.workspace = true tokio.workspace = true -tracing.workspace = true tracing-subscriber.workspace = true +tracing.workspace = true [dev-dependencies] assert_cmd.workspace = true diff --git a/crates/mozart/src/commands/audit.rs b/crates/mozart/src/commands/audit.rs index 8f15ef0..2faec19 100644 --- a/crates/mozart/src/commands/audit.rs +++ b/crates/mozart/src/commands/audit.rs @@ -273,7 +273,7 @@ fn filter_advisories( .as_deref() .unwrap_or(pkg.version.as_str()); - let installed_ver = match mozart_constraint::Version::parse(version_str) { + let installed_ver = match mozart_semver::Version::parse(version_str) { Ok(v) => v, Err(_) => { eprintln!( @@ -298,9 +298,7 @@ fn filter_advisories( // Normalize single-pipe OR separators (`|`) to double-pipe (`||`) // since the Packagist API may use either form. let normalized_constraint = normalize_or_separator(&advisory.affected_versions); - let constraint = match mozart_constraint::VersionConstraint::parse( - &normalized_constraint, - ) { + let constraint = match mozart_semver::VersionConstraint::parse(&normalized_constraint) { Ok(c) => c, Err(_) => { eprintln!( diff --git a/crates/mozart/src/commands/check_platform_reqs.rs b/crates/mozart/src/commands/check_platform_reqs.rs index 295f9b7..79a1da7 100644 --- a/crates/mozart/src/commands/check_platform_reqs.rs +++ b/crates/mozart/src/commands/check_platform_reqs.rs @@ -279,21 +279,21 @@ fn check_requirements( } Some(detected) => { // Check all constraints - let detected_version = match mozart_constraint::Version::parse(&detected.version) { + let detected_version = match mozart_semver::Version::parse(&detected.version) { Ok(v) => v, Err(_) => { // Unparseable version → treat as 0.0.0 - mozart_constraint::Version::parse("0.0.0").unwrap() + mozart_semver::Version::parse("0.0.0").unwrap() } }; let mut failed_req: Option<(String, String)> = None; for req in reqs { - let constraint = - match mozart_constraint::VersionConstraint::parse(&req.constraint) { - Ok(c) => c, - Err(_) => continue, // skip unparseable constraints - }; + let constraint = match mozart_semver::VersionConstraint::parse(&req.constraint) + { + Ok(c) => c, + Err(_) => continue, // skip unparseable constraints + }; if !constraint.matches(&detected_version) { failed_req = Some((req.constraint.clone(), req.provider.clone())); break; diff --git a/crates/mozart/src/commands/dependency.rs b/crates/mozart/src/commands/dependency.rs index 4714de2..5073be0 100644 --- a/crates/mozart/src/commands/dependency.rs +++ b/crates/mozart/src/commands/dependency.rs @@ -192,7 +192,7 @@ fn load_from_installed(working_dir: &Path) -> Result<Vec<PackageInfo>> { pub fn get_dependents( packages: &[PackageInfo], needles: &[String], - constraint: Option<&mozart_constraint::VersionConstraint>, + constraint: Option<&mozart_semver::VersionConstraint>, inverted: bool, recursive: bool, ) -> Result<Vec<DependencyResult>> { @@ -317,7 +317,7 @@ fn recurse_dependents( fn get_prohibitors( packages: &[PackageInfo], needles: &[String], - constraint: Option<&mozart_constraint::VersionConstraint>, + constraint: Option<&mozart_semver::VersionConstraint>, _recursive: bool, ) -> Result<Vec<DependencyResult>> { let mut results: Vec<DependencyResult> = Vec::new(); @@ -333,7 +333,7 @@ fn get_prohibitors( .find(|(k, _)| k.to_lowercase() == needle_lower) && let Some(requested_version) = constraint && let Ok(pkg_constraint) = - mozart_constraint::VersionConstraint::parse(req_constraint_str) + mozart_semver::VersionConstraint::parse(req_constraint_str) { // The package requires `needle` but with a different // (incompatible) constraint — it blocks the requested version. @@ -359,7 +359,7 @@ fn get_prohibitors( .find(|(k, _)| k.to_lowercase() == needle_lower) && let Some(requested_version) = constraint && let Ok(pkg_constraint) = - mozart_constraint::VersionConstraint::parse(req_constraint_str) + mozart_semver::VersionConstraint::parse(req_constraint_str) && constraint_prohibits(requested_version, &pkg_constraint) { results.push(DependencyResult { @@ -380,7 +380,7 @@ fn get_prohibitors( .find(|(k, _)| k.to_lowercase() == needle_lower) && let Some(requested_version) = constraint && let Ok(conflict_constraint) = - mozart_constraint::VersionConstraint::parse(conflict_constraint_str) + mozart_semver::VersionConstraint::parse(conflict_constraint_str) { // If the conflict constraint overlaps with (matches) the // requested version range, this package conflicts with it. @@ -408,8 +408,8 @@ fn get_prohibitors( /// We sample a set of "representative versions" from the requested constraint /// and check whether none of them satisfy the package's constraint. fn constraint_prohibits( - requested: &mozart_constraint::VersionConstraint, - pkg_constraint: &mozart_constraint::VersionConstraint, + requested: &mozart_semver::VersionConstraint, + pkg_constraint: &mozart_semver::VersionConstraint, ) -> bool { // We try to determine if there is any version satisfying *requested* that // does NOT satisfy *pkg_constraint*. @@ -430,8 +430,8 @@ fn constraint_prohibits( /// That is, if the conflict constraint matches at least one version that the /// requested constraint also matches. fn constraint_overlaps( - requested: &mozart_constraint::VersionConstraint, - conflict_constraint: &mozart_constraint::VersionConstraint, + requested: &mozart_semver::VersionConstraint, + conflict_constraint: &mozart_semver::VersionConstraint, ) -> bool { let probes = sample_versions_from_constraint(requested); if probes.is_empty() { @@ -446,9 +446,9 @@ fn constraint_overlaps( /// constraint. These are used for the "does this constraint overlap/prohibit /// that constraint?" heuristic. fn sample_versions_from_constraint( - constraint: &mozart_constraint::VersionConstraint, -) -> Vec<mozart_constraint::Version> { - use mozart_constraint::Version; + constraint: &mozart_semver::VersionConstraint, +) -> Vec<mozart_semver::Version> { + use mozart_semver::Version; // Broad grid of versions to probe let candidates: &[&str] = &[ @@ -685,7 +685,7 @@ mod tests { make_pkg("root/project", "ROOT", &[("vendor/a", "^1.0")], &[], true), make_pkg("vendor/a", "1.0.0", &[], &[], false), ]; - let constraint = mozart_constraint::VersionConstraint::parse("2.0.0").unwrap(); + let constraint = mozart_semver::VersionConstraint::parse("2.0.0").unwrap(); let needles = vec!["vendor/a".to_string()]; let results = get_dependents(&packages, &needles, Some(&constraint), true, false).unwrap(); assert!(!results.is_empty(), "root should prohibit vendor/a 2.0"); @@ -713,7 +713,7 @@ mod tests { false, ), ]; - let constraint = mozart_constraint::VersionConstraint::parse("2.0.0").unwrap(); + let constraint = mozart_semver::VersionConstraint::parse("2.0.0").unwrap(); let needles = vec!["vendor/a".to_string()]; let results = get_dependents(&packages, &needles, Some(&constraint), true, false).unwrap(); // vendor/b conflicts with vendor/a ^2.0 which covers 2.0.0 @@ -733,7 +733,7 @@ mod tests { make_pkg("root/project", "ROOT", &[("vendor/a", "^2.0")], &[], true), make_pkg("vendor/a", "2.0.0", &[], &[], false), ]; - let constraint = mozart_constraint::VersionConstraint::parse("2.5.0").unwrap(); + let constraint = mozart_semver::VersionConstraint::parse("2.5.0").unwrap(); let needles = vec!["vendor/a".to_string()]; let results = get_dependents(&packages, &needles, Some(&constraint), true, false).unwrap(); assert!( diff --git a/crates/mozart/src/commands/outdated.rs b/crates/mozart/src/commands/outdated.rs index eba0d52..1807435 100644 --- a/crates/mozart/src/commands/outdated.rs +++ b/crates/mozart/src/commands/outdated.rs @@ -371,8 +371,8 @@ fn classify_update( // We have an update available — classify it if let Some(constraint_str) = root_constraint - && let Ok(constraint) = mozart_constraint::VersionConstraint::parse(constraint_str) - && let Ok(latest_ver) = mozart_constraint::Version::parse(latest_normalized) + && let Ok(constraint) = mozart_semver::VersionConstraint::parse(constraint_str) + && let Ok(latest_ver) = mozart_semver::Version::parse(latest_normalized) { if constraint.matches(&latest_ver) { return UpdateCategory::SemverCompatible; diff --git a/crates/mozart/src/commands/prohibits.rs b/crates/mozart/src/commands/prohibits.rs index 1f45b27..ca3bc35 100644 --- a/crates/mozart/src/commands/prohibits.rs +++ b/crates/mozart/src/commands/prohibits.rs @@ -43,7 +43,7 @@ pub async fn execute( } // Parse the version constraint the user is asking about - let version_constraint = mozart_constraint::VersionConstraint::parse(&args.version) + 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; |
