1use crate::dependency_resolver::DependencyResolver;
4use crate::resolution::ResolutionResult;
5use rez_next_common::RezCoreError;
6use rez_next_package::{Package, PackageRequirement, Requirement};
7use rez_next_repository::simple_repository::RepositoryManager;
8use serde::{Deserialize, Serialize};
9use std::collections::HashMap;
10use std::sync::Arc;
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct SolverConfig {
15 pub max_attempts: usize,
17 pub max_time_seconds: u64,
19 pub enable_parallel: bool,
21 pub max_workers: usize,
23 pub enable_caching: bool,
25 pub cache_ttl_seconds: u64,
27 pub prefer_latest: bool,
29 pub allow_prerelease: bool,
31 pub conflict_strategy: ConflictStrategy,
33 pub strict_mode: bool,
37}
38
39impl Default for SolverConfig {
40 fn default() -> Self {
41 Self {
42 max_attempts: 1000,
43 max_time_seconds: 300, enable_parallel: true,
45 max_workers: 4,
46 enable_caching: true,
47 cache_ttl_seconds: 3600, prefer_latest: true,
49 allow_prerelease: false,
50 conflict_strategy: ConflictStrategy::LatestWins,
51 strict_mode: false,
52 }
53 }
54}
55
56#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
58pub enum ConflictStrategy {
59 LatestWins,
61 EarliestWins,
63 FailOnConflict,
65 FindCompatible,
67}
68
69#[derive(Debug, Clone)]
71pub struct SolverRequest {
72 pub requirements: Vec<PackageRequirement>,
74 pub constraints: Vec<PackageRequirement>,
76 pub excludes: Vec<String>,
78 pub platform: Option<String>,
80 pub arch: Option<String>,
82 pub metadata: HashMap<String, String>,
84}
85
86impl SolverRequest {
87 pub fn new(requirements: Vec<PackageRequirement>) -> Self {
89 Self {
90 requirements,
91 constraints: Vec::new(),
92 excludes: Vec::new(),
93 platform: None,
94 arch: None,
95 metadata: HashMap::new(),
96 }
97 }
98
99 pub fn with_constraint(mut self, constraint: PackageRequirement) -> Self {
101 self.constraints.push(constraint);
102 self
103 }
104
105 pub fn with_exclude(mut self, package_name: String) -> Self {
107 self.excludes.push(package_name);
108 self
109 }
110
111 pub fn with_platform(mut self, platform: String) -> Self {
113 self.platform = Some(platform);
114 self
115 }
116
117 pub fn with_arch(mut self, arch: String) -> Self {
119 self.arch = Some(arch);
120 self
121 }
122}
123
124pub struct DependencySolver {
126 config: SolverConfig,
128 repository_manager: Option<Arc<RepositoryManager>>,
130}
131
132impl std::fmt::Debug for DependencySolver {
133 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
134 f.debug_struct("DependencySolver")
135 .field("config", &self.config)
136 .field("has_repository", &self.repository_manager.is_some())
137 .finish()
138 }
139}
140
141#[derive(Debug, Clone, Serialize, Deserialize)]
143pub struct SolverStats {
144 pub total_resolutions: u64,
146 pub successful_resolutions: u64,
148 pub failed_resolutions: u64,
150 pub cache_hits: u64,
152 pub cache_misses: u64,
154 pub avg_resolution_time_ms: f64,
156 pub total_resolution_time_ms: u64,
158}
159
160impl Default for SolverStats {
161 fn default() -> Self {
162 Self {
163 total_resolutions: 0,
164 successful_resolutions: 0,
165 failed_resolutions: 0,
166 cache_hits: 0,
167 cache_misses: 0,
168 avg_resolution_time_ms: 0.0,
169 total_resolution_time_ms: 0,
170 }
171 }
172}
173
174impl DependencySolver {
175 pub fn new() -> Self {
177 let config = SolverConfig::default();
178 Self {
179 config,
180 repository_manager: None,
181 }
182 }
183
184 pub fn with_config(config: SolverConfig) -> Self {
186 Self {
187 config,
188 repository_manager: None,
189 }
190 }
191
192 pub fn with_repository_manager(mut self, manager: Arc<RepositoryManager>) -> Self {
194 self.repository_manager = Some(manager);
195 self
196 }
197
198 pub fn set_repository_manager(&mut self, manager: Arc<RepositoryManager>) {
200 self.repository_manager = Some(manager);
201 }
202
203 pub fn resolve(&self, request: SolverRequest) -> Result<ResolutionResult, RezCoreError> {
205 if let Some(ref repo_manager) = self.repository_manager {
206 let rt = tokio::runtime::Runtime::new()
208 .map_err(|e| RezCoreError::Solver(format!("Failed to create runtime: {}", e)))?;
209
210 let requirements: Vec<Requirement> = request
212 .requirements
213 .into_iter()
214 .map(|pr| {
215 let req_str = pr.to_string();
216 req_str
217 .parse::<Requirement>()
218 .unwrap_or_else(|_| Requirement::new(pr.name.clone()))
219 })
220 .collect();
221
222 let mut resolver =
223 DependencyResolver::new(Arc::clone(repo_manager), self.config.clone());
224
225 let result = rt.block_on(resolver.resolve(requirements))?;
226
227 let packages: Vec<Package> = result
228 .resolved_packages
229 .into_iter()
230 .map(|info| (*info.package).clone())
231 .collect();
232
233 Ok(ResolutionResult {
234 packages,
235 conflicts_resolved: !result.conflicts.is_empty(),
236 resolution_time_ms: result.stats.resolution_time_ms,
237 metadata: HashMap::new(),
238 })
239 } else {
240 Ok(ResolutionResult {
242 packages: Vec::new(),
243 conflicts_resolved: false,
244 resolution_time_ms: 0,
245 metadata: HashMap::new(),
246 })
247 }
248 }
249}
250
251impl Default for DependencySolver {
252 fn default() -> Self {
253 Self::new()
254 }
255}