use crate::dependency_resolver::DependencyResolver;
use crate::resolution::ResolutionResult;
use rez_next_common::RezCoreError;
use rez_next_package::{Package, PackageRequirement, Requirement};
use rez_next_repository::simple_repository::RepositoryManager;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::Arc;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SolverConfig {
pub max_attempts: usize,
pub max_time_seconds: u64,
pub enable_parallel: bool,
pub max_workers: usize,
pub enable_caching: bool,
pub cache_ttl_seconds: u64,
pub prefer_latest: bool,
pub allow_prerelease: bool,
pub conflict_strategy: ConflictStrategy,
pub strict_mode: bool,
}
impl Default for SolverConfig {
fn default() -> Self {
Self {
max_attempts: 1000,
max_time_seconds: 300, enable_parallel: true,
max_workers: 4,
enable_caching: true,
cache_ttl_seconds: 3600, prefer_latest: true,
allow_prerelease: false,
conflict_strategy: ConflictStrategy::LatestWins,
strict_mode: false,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum ConflictStrategy {
LatestWins,
EarliestWins,
FailOnConflict,
FindCompatible,
}
#[derive(Debug, Clone)]
pub struct SolverRequest {
pub requirements: Vec<PackageRequirement>,
pub constraints: Vec<PackageRequirement>,
pub excludes: Vec<String>,
pub platform: Option<String>,
pub arch: Option<String>,
pub metadata: HashMap<String, String>,
}
impl SolverRequest {
pub fn new(requirements: Vec<PackageRequirement>) -> Self {
Self {
requirements,
constraints: Vec::new(),
excludes: Vec::new(),
platform: None,
arch: None,
metadata: HashMap::new(),
}
}
pub fn with_constraint(mut self, constraint: PackageRequirement) -> Self {
self.constraints.push(constraint);
self
}
pub fn with_exclude(mut self, package_name: String) -> Self {
self.excludes.push(package_name);
self
}
pub fn with_platform(mut self, platform: String) -> Self {
self.platform = Some(platform);
self
}
pub fn with_arch(mut self, arch: String) -> Self {
self.arch = Some(arch);
self
}
}
pub struct DependencySolver {
config: SolverConfig,
repository_manager: Option<Arc<RepositoryManager>>,
}
impl std::fmt::Debug for DependencySolver {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("DependencySolver")
.field("config", &self.config)
.field("has_repository", &self.repository_manager.is_some())
.finish()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SolverStats {
pub total_resolutions: u64,
pub successful_resolutions: u64,
pub failed_resolutions: u64,
pub cache_hits: u64,
pub cache_misses: u64,
pub avg_resolution_time_ms: f64,
pub total_resolution_time_ms: u64,
}
impl Default for SolverStats {
fn default() -> Self {
Self {
total_resolutions: 0,
successful_resolutions: 0,
failed_resolutions: 0,
cache_hits: 0,
cache_misses: 0,
avg_resolution_time_ms: 0.0,
total_resolution_time_ms: 0,
}
}
}
impl DependencySolver {
pub fn new() -> Self {
let config = SolverConfig::default();
Self {
config,
repository_manager: None,
}
}
pub fn with_config(config: SolverConfig) -> Self {
Self {
config,
repository_manager: None,
}
}
pub fn with_repository_manager(mut self, manager: Arc<RepositoryManager>) -> Self {
self.repository_manager = Some(manager);
self
}
pub fn set_repository_manager(&mut self, manager: Arc<RepositoryManager>) {
self.repository_manager = Some(manager);
}
pub fn resolve(&self, request: SolverRequest) -> Result<ResolutionResult, RezCoreError> {
if let Some(ref repo_manager) = self.repository_manager {
let rt = tokio::runtime::Runtime::new()
.map_err(|e| RezCoreError::Solver(format!("Failed to create runtime: {}", e)))?;
let requirements: Vec<Requirement> = request
.requirements
.into_iter()
.map(|pr| {
let req_str = pr.to_string();
req_str
.parse::<Requirement>()
.unwrap_or_else(|_| Requirement::new(pr.name.clone()))
})
.collect();
let mut resolver =
DependencyResolver::new(Arc::clone(repo_manager), self.config.clone());
let result = rt.block_on(resolver.resolve(requirements))?;
let packages: Vec<Package> = result
.resolved_packages
.into_iter()
.map(|info| (*info.package).clone())
.collect();
Ok(ResolutionResult {
packages,
conflicts_resolved: !result.conflicts.is_empty(),
resolution_time_ms: result.stats.resolution_time_ms,
metadata: HashMap::new(),
})
} else {
Ok(ResolutionResult {
packages: Vec::new(),
conflicts_resolved: false,
resolution_time_ms: 0,
metadata: HashMap::new(),
})
}
}
}
impl Default for DependencySolver {
fn default() -> Self {
Self::new()
}
}