diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-02-23 11:38:42 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-02-23 11:38:42 +0900 |
| commit | 0080efea9386d46f65d1862fcb90eb44999d9761 (patch) | |
| tree | e9f7e17b3f12ff9b09b3df0848fd55e91003cd23 /crates/mozart/src/commands/install.rs | |
| parent | eb1e21c059d83f0af9786e4d3cace80afe8456a2 (diff) | |
| download | php-mozart-0080efea9386d46f65d1862fcb90eb44999d9761.tar.gz php-mozart-0080efea9386d46f65d1862fcb90eb44999d9761.tar.zst php-mozart-0080efea9386d46f65d1862fcb90eb44999d9761.zip | |
feat(vcs): add mozart-vcs crate for VCS repository support
Implement VCS driver/downloader infrastructure mirroring Composer's VCS
subsystem. Includes drivers for GitHub, GitLab, Bitbucket, Forgejo, Git,
Hg, and SVN with API-based metadata resolution, plus source downloaders
for Git/Hg/SVN. Integrates into mozart-registry via vcs_bridge module to
scan VCS repositories and feed discovered packages into the SAT resolver.
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.rs | 99 |
1 files changed, 75 insertions, 24 deletions
diff --git a/crates/mozart/src/commands/install.rs b/crates/mozart/src/commands/install.rs index 24c79b3..bf35788 100644 --- a/crates/mozart/src/commands/install.rs +++ b/crates/mozart/src/commands/install.rs @@ -117,6 +117,8 @@ pub struct InstallConfig { pub apcu_autoloader_prefix: Option<String>, /// Only download packages, skip autoloader generation and installed.json write. pub download_only: bool, + /// Prefer installing from VCS source rather than dist archives. + pub prefer_source: bool, } impl Default for InstallConfig { @@ -133,6 +135,7 @@ impl Default for InstallConfig { apcu_autoloader: false, apcu_autoloader_prefix: None, download_only: false, + prefer_source: false, } } } @@ -300,20 +303,51 @@ fn make_progress(show: bool, pkg_name: &str, version: &str) -> downloader::Downl downloader::DownloadProgress::new(show, format!("{pkg_name} ({version})")) } -/// Install packages from a lock file into vendor/. -/// -/// Used by both the `install` and `update` commands. -/// -/// This function: -/// 1. Determines which packages to install (prod + optionally dev) -/// 2. Warns about platform requirements (unless ignored) -/// 3. Reads currently installed packages -/// 4. Computes install/update/skip/removal operations -/// 5. Prints a summary -/// 6. Executes downloads with optional progress bars (unless dry_run) -/// 7. Writes vendor/composer/installed.json -/// 8. Cleans up empty vendor directories -/// 9. Generates the autoloader (unless no_autoloader) +/// Install a package from VCS source (git/svn/hg). +fn install_from_source( + source_type: &str, + url: &str, + reference: &str, + vendor_dir: &Path, + package_name: &str, +) -> anyhow::Result<()> { + let target = vendor_dir.join(package_name); + if target.exists() { + std::fs::remove_dir_all(&target)?; + } + + match source_type { + "git" => { + let process = mozart_vcs::process::ProcessExecutor::new(); + let git_util = + mozart_vcs::util::git::GitUtil::new(process, vendor_dir.join(".cache").join("git")); + let downloader = mozart_vcs::downloader::git::GitDownloader::new(git_util); + use mozart_vcs::downloader::VcsDownloader; + downloader.download(url, reference, &target)?; + downloader.install(url, reference, &target)?; + } + "svn" => { + let process = mozart_vcs::process::ProcessExecutor::new(); + let svn_util = mozart_vcs::util::svn::SvnUtil::new(process); + let downloader = mozart_vcs::downloader::svn::SvnDownloader::new(svn_util); + use mozart_vcs::downloader::VcsDownloader; + downloader.install(url, reference, &target)?; + } + "hg" => { + let process = mozart_vcs::process::ProcessExecutor::new(); + let hg_util = mozart_vcs::util::hg::HgUtil::new(process); + let downloader = mozart_vcs::downloader::hg::HgDownloader::new(hg_util); + use mozart_vcs::downloader::VcsDownloader; + downloader.install(url, reference, &target)?; + } + _ => { + anyhow::bail!("Unsupported source type for VCS install: {}", source_type); + } + } + + Ok(()) +} + pub async fn install_from_lock( lock: &lockfile::LockFile, working_dir: &Path, @@ -405,11 +439,32 @@ pub async fn install_from_lock( } } + // Try source install if --prefer-source and source info is available + if config.prefer_source + && let Some(source) = &pkg.source + { + install_from_source( + &source.source_type, + &source.url, + source.reference.as_deref().unwrap_or("HEAD"), + vendor_dir, + &pkg.name, + )?; + continue; + } + let dist = pkg.dist.as_ref().ok_or_else(|| { - anyhow::anyhow!( - "Package {} has no dist information — source installs are not yet supported", - pkg.name - ) + if pkg.source.is_some() { + anyhow::anyhow!( + "Package {} has no dist information. Use --prefer-source to install from VCS.", + pkg.name, + ) + } else { + anyhow::anyhow!( + "Package {} has no dist or source information", + pkg.name, + ) + } })?; let mut progress = make_progress(!config.no_progress, &pkg.name, &pkg.version); @@ -604,18 +659,13 @@ pub async fn execute( } } - // Step 5: Warn about prefer-source (not yet supported) + // Step 5: Determine if prefer-source is enabled let prefer_source = args.prefer_source || args .prefer_install .as_deref() .map(|s| s.eq_ignore_ascii_case("source")) .unwrap_or(false); - if prefer_source { - console.info(&console_format!( - "<warning>Warning: Source installs are not yet supported. Falling back to dist.</warning>" - )); - } // Step 6: Determine dev mode and vendor directory let dev_mode = !args.no_dev; @@ -638,6 +688,7 @@ pub async fn execute( apcu_autoloader: args.apcu_autoloader || args.apcu_autoloader_prefix.is_some(), apcu_autoloader_prefix: args.apcu_autoloader_prefix.clone(), download_only: args.download_only, + prefer_source, }, ) .await |
