|
3 | 3 | // https://github.com/imageworks/spk |
4 | 4 |
|
5 | 5 | use std::collections::HashSet; |
| 6 | +use std::fmt::Write; |
6 | 7 |
|
7 | 8 | use serde::{Deserialize, Serialize}; |
8 | 9 | use spk_schema_foundation::version::Compatibility; |
@@ -81,16 +82,26 @@ impl RequirementsList { |
81 | 82 | pub fn contains_request(&self, theirs: &Request) -> Compatibility { |
82 | 83 | for ours in self.iter() { |
83 | 84 | match (ours, theirs) { |
84 | | - (Request::Pkg(ours), Request::Pkg(theirs)) => { |
| 85 | + (Request::Pkg(ours), Request::Pkg(theirs)) if ours.pkg.name == theirs.pkg.name => { |
85 | 86 | return ours.contains(theirs); |
86 | 87 | } |
87 | | - (Request::Var(ours), Request::Var(theirs)) => { |
| 88 | + (Request::Var(ours), Request::Var(theirs)) |
| 89 | + // a var request satisfy another if they have the same opt name or |
| 90 | + // if our request is package-less and has the same base name, eg: |
| 91 | + // name/value [contains] name/value |
| 92 | + // pkg.name/value [contains] pkg.name/value |
| 93 | + // name/value [contains] pkg.name/value |
| 94 | + if ours.var == theirs.var || ours.var.as_str() == theirs.var.base_name() => |
| 95 | + { |
88 | 96 | return ours.contains(theirs); |
89 | 97 | } |
90 | | - _ => continue, |
| 98 | + _ => { |
| 99 | + tracing::trace!("skip {ours}, not {theirs}"); |
| 100 | + continue; |
| 101 | + } |
91 | 102 | } |
92 | 103 | } |
93 | | - Compatibility::incompatible("No request exists for this") |
| 104 | + Compatibility::incompatible(format!("No request exists for {}", theirs.name())) |
94 | 105 | } |
95 | 106 |
|
96 | 107 | /// Render all requests with a package pin using the given resolved packages. |
@@ -136,7 +147,7 @@ impl RequirementsList { |
136 | 147 | )); |
137 | 148 | } |
138 | 149 | Some(opt) => { |
139 | | - let rendered = request.render_pin(opt)?; |
| 150 | + let rendered = request.render_pin(opt.as_str())?; |
140 | 151 | let _ = std::mem::replace(request, rendered); |
141 | 152 | } |
142 | 153 | } |
@@ -167,6 +178,20 @@ impl RequirementsList { |
167 | 178 | } |
168 | 179 | } |
169 | 180 |
|
| 181 | +impl std::fmt::Display for RequirementsList { |
| 182 | + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| 183 | + f.write_char('[')?; |
| 184 | + let mut entries = self.0.iter().peekable(); |
| 185 | + while let Some(i) = entries.next() { |
| 186 | + i.fmt(f)?; |
| 187 | + if entries.peek().is_some() { |
| 188 | + f.write_str(", ")?; |
| 189 | + } |
| 190 | + } |
| 191 | + f.write_char(']') |
| 192 | + } |
| 193 | +} |
| 194 | + |
170 | 195 | impl IntoIterator for RequirementsList { |
171 | 196 | type Item = Request; |
172 | 197 | type IntoIter = std::vec::IntoIter<Request>; |
@@ -199,12 +224,11 @@ impl<'de> Deserialize<'de> for RequirementsList { |
199 | 224 | let mut requirement_names = HashSet::with_capacity(size_hint); |
200 | 225 | while let Some(request) = seq.next_element::<Request>()? { |
201 | 226 | let name = request.name(); |
202 | | - if requirement_names.contains(name) { |
| 227 | + if !requirement_names.insert(name.to_owned()) { |
203 | 228 | return Err(serde::de::Error::custom(format!( |
204 | 229 | "found multiple install requirements for '{name}'" |
205 | 230 | ))); |
206 | 231 | } |
207 | | - requirement_names.insert(name.to_owned()); |
208 | 232 | requirements.push(request); |
209 | 233 | } |
210 | 234 | Ok(RequirementsList(requirements)) |
|
0 commit comments