]>
Commit | Line | Data |
---|---|---|
f38c53f5 | 1 | use std::collections::BTreeMap; |
798b620c | 2 | use std::mem; |
0d17d6c4 | 3 | use std::rc::Rc; |
2b46d039 | 4 | |
540bd458 DO |
5 | use serde::{Serialize, Serializer}; |
6 | ||
9b731821 | 7 | use core::interning::InternedString; |
5c9d34be E |
8 | use core::{Dependency, PackageId, SourceId}; |
9 | use semver::Version; | |
2b46d039 | 10 | |
7ab18e3a | 11 | use util::CargoResult; |
1ce76415 | 12 | |
670a3df4 | 13 | /// Subset of a `Manifest`. Contains only the most important information about |
798b620c | 14 | /// a package. |
c7641c24 | 15 | /// |
64ff29ff | 16 | /// Summaries are cloned, and should not be mutated after creation |
0d17d6c4 | 17 | #[derive(Debug, Clone)] |
1ce76415 | 18 | pub struct Summary { |
0d17d6c4 AC |
19 | inner: Rc<Inner>, |
20 | } | |
21 | ||
22 | #[derive(Debug, Clone)] | |
23 | struct Inner { | |
61c95b75 | 24 | package_id: PackageId, |
2b46d039 | 25 | dependencies: Vec<Dependency>, |
116a3cd2 | 26 | features: FeatureMap, |
5430db61 | 27 | checksum: Option<String>, |
9b731821 | 28 | links: Option<InternedString>, |
1ce76415 CL |
29 | } |
30 | ||
31 | impl Summary { | |
1e682848 AC |
32 | pub fn new( |
33 | pkg_id: PackageId, | |
34 | dependencies: Vec<Dependency>, | |
35 | features: BTreeMap<String, Vec<String>>, | |
36 | links: Option<String>, | |
37 | ) -> CargoResult<Summary> { | |
2b46d039 | 38 | for dep in dependencies.iter() { |
85f96a99 | 39 | if features.get(&*dep.name()).is_some() { |
1e682848 AC |
40 | bail!( |
41 | "Features and dependencies cannot have the \ | |
42 | same name: `{}`", | |
43 | dep.name() | |
44 | ) | |
2b46d039 AC |
45 | } |
46 | if dep.is_optional() && !dep.is_transitive() { | |
1e682848 AC |
47 | bail!( |
48 | "Dev-dependencies are not allowed to be optional: `{}`", | |
49 | dep.name() | |
50 | ) | |
2b46d039 AC |
51 | } |
52 | } | |
76211088 | 53 | let feature_map = build_feature_map(features, &dependencies)?; |
2b46d039 | 54 | Ok(Summary { |
0d17d6c4 AC |
55 | inner: Rc::new(Inner { |
56 | package_id: pkg_id, | |
78f35646 | 57 | dependencies, |
76211088 | 58 | features: feature_map, |
0d17d6c4 | 59 | checksum: None, |
9b731821 | 60 | links: links.map(|l| InternedString::new(&l)), |
0d17d6c4 | 61 | }), |
2b46d039 | 62 | }) |
1ce76415 CL |
63 | } |
64 | ||
1e682848 AC |
65 | pub fn package_id(&self) -> &PackageId { |
66 | &self.inner.package_id | |
67 | } | |
68 | pub fn name(&self) -> InternedString { | |
69 | self.package_id().name() | |
70 | } | |
71 | pub fn version(&self) -> &Version { | |
72 | self.package_id().version() | |
73 | } | |
74 | pub fn source_id(&self) -> &SourceId { | |
75 | self.package_id().source_id() | |
76 | } | |
77 | pub fn dependencies(&self) -> &[Dependency] { | |
78 | &self.inner.dependencies | |
79 | } | |
116a3cd2 | 80 | pub fn features(&self) -> &FeatureMap { |
1e682848 AC |
81 | &self.inner.features |
82 | } | |
5430db61 | 83 | pub fn checksum(&self) -> Option<&str> { |
0d17d6c4 | 84 | self.inner.checksum.as_ref().map(|s| &s[..]) |
5430db61 | 85 | } |
9b731821 E |
86 | pub fn links(&self) -> Option<InternedString> { |
87 | self.inner.links | |
78f35646 | 88 | } |
798b620c | 89 | |
816373d9 | 90 | pub fn override_id(mut self, id: PackageId) -> Summary { |
0d17d6c4 | 91 | Rc::make_mut(&mut self.inner).package_id = id; |
816373d9 AC |
92 | self |
93 | } | |
94 | ||
5430db61 | 95 | pub fn set_checksum(mut self, cksum: String) -> Summary { |
0d17d6c4 | 96 | Rc::make_mut(&mut self.inner).checksum = Some(cksum); |
5430db61 AC |
97 | self |
98 | } | |
99 | ||
157d639a | 100 | pub fn map_dependencies<F>(mut self, f: F) -> Summary |
1e682848 AC |
101 | where |
102 | F: FnMut(Dependency) -> Dependency, | |
103 | { | |
0d17d6c4 AC |
104 | { |
105 | let slot = &mut Rc::make_mut(&mut self.inner).dependencies; | |
106 | let deps = mem::replace(slot, Vec::new()); | |
107 | *slot = deps.into_iter().map(f).collect(); | |
108 | } | |
798b620c AC |
109 | self |
110 | } | |
99ec335f | 111 | |
1e682848 | 112 | pub fn map_source(self, to_replace: &SourceId, replace_with: &SourceId) -> Summary { |
99ec335f AC |
113 | let me = if self.package_id().source_id() == to_replace { |
114 | let new_id = self.package_id().with_source_id(replace_with); | |
115 | self.override_id(new_id) | |
116 | } else { | |
117 | self | |
118 | }; | |
1e682848 | 119 | me.map_dependencies(|dep| dep.map_source(to_replace, replace_with)) |
99ec335f | 120 | } |
1ce76415 | 121 | } |
da0ec9a3 | 122 | |
58518273 AC |
123 | impl PartialEq for Summary { |
124 | fn eq(&self, other: &Summary) -> bool { | |
0d17d6c4 | 125 | self.inner.package_id == other.inner.package_id |
58518273 AC |
126 | } |
127 | } | |
116a3cd2 | 128 | |
76211088 DO |
129 | // Checks features for errors, bailing out a CargoResult:Err if invalid, |
130 | // and creates FeatureValues for each feature. | |
131 | fn build_feature_map( | |
132 | features: BTreeMap<String, Vec<String>>, | |
51d19d01 | 133 | dependencies: &[Dependency], |
76211088 DO |
134 | ) -> CargoResult<FeatureMap> { |
135 | use self::FeatureValue::*; | |
136 | let mut map = BTreeMap::new(); | |
137 | for (feature, list) in features.iter() { | |
138 | let mut values = vec![]; | |
139 | for dep in list { | |
5c9d34be | 140 | let val = FeatureValue::build(InternedString::new(dep), |fs| features.contains_key(fs)); |
76211088 DO |
141 | if let &Feature(_) = &val { |
142 | values.push(val); | |
143 | continue; | |
144 | } | |
145 | ||
146 | // Find data for the referenced dependency... | |
147 | let dep_data = { | |
e357d174 DO |
148 | match val { |
149 | Feature(_) => None, | |
150 | Crate(ref dep_name) | CrateFeature(ref dep_name, _) => { | |
151 | dependencies.iter().find(|d| d.name() == *dep_name) | |
152 | } | |
153 | } | |
76211088 DO |
154 | }; |
155 | ||
156 | match (&val, dep_data) { | |
157 | (&Crate(ref dep), Some(d)) => { | |
158 | if !d.is_optional() { | |
159 | bail!( | |
160 | "Feature `{}` depends on `{}` which is not an \ | |
161 | optional dependency.\nConsider adding \ | |
162 | `optional = true` to the dependency", | |
163 | feature, | |
164 | dep | |
165 | ) | |
166 | } | |
167 | } | |
168 | (&CrateFeature(ref dep_name, _), None) => bail!( | |
169 | "Feature `{}` requires a feature of `{}` which is not a \ | |
170 | dependency", | |
171 | feature, | |
172 | dep_name | |
173 | ), | |
174 | (&Crate(ref dep), None) => bail!( | |
175 | "Feature `{}` includes `{}` which is neither \ | |
176 | a dependency nor another feature", | |
177 | feature, | |
178 | dep | |
179 | ), | |
180 | (&CrateFeature(_, _), Some(_)) | (&Feature(_), _) => {} | |
181 | } | |
182 | values.push(val); | |
183 | } | |
184 | map.insert(feature.clone(), values); | |
185 | } | |
186 | Ok(map) | |
187 | } | |
188 | ||
7b542268 DO |
189 | /// FeatureValue represents the types of dependencies a feature can have: |
190 | /// | |
191 | /// * Another feature | |
192 | /// * An optional dependency | |
193 | /// * A feature in a depedency | |
194 | /// | |
195 | /// The selection between these 3 things happens as part of the construction of the FeatureValue. | |
540bd458 | 196 | #[derive(Clone, Debug)] |
7b542268 DO |
197 | pub enum FeatureValue { |
198 | Feature(InternedString), | |
199 | Crate(InternedString), | |
200 | CrateFeature(InternedString, InternedString), | |
201 | } | |
202 | ||
203 | impl FeatureValue { | |
5c9d34be | 204 | fn build<T>(feature: InternedString, is_feature: T) -> FeatureValue |
7b542268 DO |
205 | where |
206 | T: Fn(&str) -> bool, | |
207 | { | |
208 | match feature.find('/') { | |
209 | Some(pos) => { | |
210 | let (dep, dep_feat) = feature.split_at(pos); | |
211 | let dep_feat = &dep_feat[1..]; | |
212 | FeatureValue::CrateFeature(InternedString::new(dep), InternedString::new(dep_feat)) | |
213 | } | |
5c9d34be E |
214 | None if is_feature(&feature) => FeatureValue::Feature(feature), |
215 | None => FeatureValue::Crate(feature), | |
7b542268 DO |
216 | } |
217 | } | |
218 | ||
5c9d34be E |
219 | pub fn new(feature: InternedString, s: &Summary) -> FeatureValue { |
220 | Self::build(feature, |fs| s.features().contains_key(fs)) | |
7b542268 DO |
221 | } |
222 | ||
223 | pub fn to_string(&self) -> String { | |
224 | use self::FeatureValue::*; | |
225 | match *self { | |
226 | Feature(ref f) => f.to_string(), | |
227 | Crate(ref c) => c.to_string(), | |
228 | CrateFeature(ref c, ref f) => [c.as_ref(), f.as_ref()].join("/"), | |
229 | } | |
230 | } | |
231 | } | |
232 | ||
540bd458 DO |
233 | impl Serialize for FeatureValue { |
234 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | |
235 | where | |
236 | S: Serializer, | |
237 | { | |
238 | use self::FeatureValue::*; | |
239 | match *self { | |
240 | Feature(ref f) => serializer.serialize_str(f), | |
241 | Crate(ref c) => serializer.serialize_str(c), | |
242 | CrateFeature(ref c, ref f) => { | |
243 | serializer.serialize_str(&[c.as_ref(), f.as_ref()].join("/")) | |
244 | } | |
245 | } | |
246 | } | |
247 | } | |
248 | ||
7b542268 | 249 | pub type FeatureMap = BTreeMap<String, Vec<FeatureValue>>; |