mod layout;
pub mod scripts;
pub use layout::BundleLayout;
pub use scripts::{generate_bundle_scripts, save_bundle_scripts, BundleScripts};
use crate::downloader::{download_msvc, download_sdk, DownloadOptions};
use crate::error::{MsvcKitError, Result};
use crate::installer::InstallInfo;
use crate::version::Architecture;
use std::path::{Path, PathBuf};
#[derive(Debug, Clone)]
pub struct BundleOptions {
pub output_dir: PathBuf,
pub arch: Architecture,
pub host_arch: Architecture,
pub msvc_version: Option<String>,
pub sdk_version: Option<String>,
pub parallel_downloads: usize,
}
impl Default for BundleOptions {
fn default() -> Self {
Self {
output_dir: PathBuf::from("./msvc-bundle"),
arch: Architecture::X64,
host_arch: Architecture::host(),
msvc_version: None,
sdk_version: None,
parallel_downloads: 8,
}
}
}
#[derive(Debug, Clone)]
pub struct BundleResult {
pub layout: BundleLayout,
pub msvc_info: InstallInfo,
pub sdk_info: InstallInfo,
pub scripts: BundleScripts,
}
pub async fn create_bundle(options: BundleOptions) -> Result<BundleResult> {
tokio::fs::create_dir_all(&options.output_dir)
.await
.map_err(MsvcKitError::Io)?;
let download_opts = DownloadOptions {
msvc_version: options.msvc_version.clone(),
sdk_version: options.sdk_version.clone(),
target_dir: options.output_dir.clone(),
arch: options.arch,
host_arch: Some(options.host_arch),
verify_hashes: true,
parallel_downloads: options.parallel_downloads,
http_client: None,
progress_handler: None,
cache_manager: None,
dry_run: false,
include_components: Default::default(),
exclude_patterns: Default::default(),
};
let mut msvc_info = download_msvc(&download_opts).await?;
crate::installer::extract_and_finalize_msvc(&mut msvc_info).await?;
let sdk_info = download_sdk(&download_opts).await?;
crate::installer::extract_and_finalize_sdk(&sdk_info).await?;
let layout = BundleLayout::from_root_with_versions(
&options.output_dir,
&msvc_info.version,
&sdk_info.version,
options.arch,
options.host_arch,
)?;
let scripts = generate_bundle_scripts(&layout)?;
Ok(BundleResult {
layout,
msvc_info,
sdk_info,
scripts,
})
}
pub fn discover_bundle<P: AsRef<Path>>(root: P) -> Result<BundleLayout> {
BundleLayout::from_root(root)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bundle_options_default() {
let opts = BundleOptions::default();
assert_eq!(opts.arch, Architecture::X64);
assert_eq!(opts.parallel_downloads, 8);
}
#[test]
fn test_bundle_download_options_has_no_cache_manager() {
let opts = BundleOptions::default();
let download_opts = DownloadOptions {
msvc_version: opts.msvc_version.clone(),
sdk_version: opts.sdk_version.clone(),
target_dir: opts.output_dir.clone(),
arch: opts.arch,
host_arch: Some(opts.host_arch),
verify_hashes: true,
parallel_downloads: opts.parallel_downloads,
http_client: None,
progress_handler: None,
cache_manager: None,
dry_run: false,
include_components: Default::default(),
exclude_patterns: Default::default(),
};
assert!(download_opts.cache_manager.is_none());
assert!(!download_opts.dry_run);
}
}