]> git.proxmox.com Git - cargo.git/blob - src/cargo/core/package.rs
More lint cleaning
[cargo.git] / src / cargo / core / package.rs
1 use std::cell::{Ref, RefCell};
2 use std::collections::HashMap;
3 use std::fmt;
4 use std::hash;
5 use std::path::{Path, PathBuf};
6
7 use semver::Version;
8 use serde::ser;
9 use toml;
10
11 use core::{Dependency, Manifest, PackageId, SourceId, Target};
12 use core::{Summary, SourceMap};
13 use ops;
14 use util::{Config, LazyCell, internal, lev_distance};
15 use util::errors::{CargoResult, CargoResultExt};
16
17 /// Information about a package that is available somewhere in the file system.
18 ///
19 /// A package is a `Cargo.toml` file plus all the files that are part of it.
20 // TODO: Is manifest_path a relic?
21 #[derive(Clone, Debug)]
22 pub struct Package {
23 // The package's manifest
24 manifest: Manifest,
25 // The root of the package
26 manifest_path: PathBuf,
27 }
28
29 #[derive(Serialize)]
30 struct SerializedPackage<'a> {
31 name: &'a str,
32 version: &'a str,
33 id: &'a PackageId,
34 license: Option<&'a str>,
35 license_file: Option<&'a str>,
36 description: Option<&'a str>,
37 source: &'a SourceId,
38 dependencies: &'a [Dependency],
39 targets: &'a [Target],
40 features: &'a HashMap<String, Vec<String>>,
41 manifest_path: &'a str,
42 }
43
44 impl ser::Serialize for Package {
45 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
46 where S: ser::Serializer,
47 {
48 let summary = self.manifest.summary();
49 let package_id = summary.package_id();
50 let manmeta = self.manifest.metadata();
51 let license = manmeta.license.as_ref().map(String::as_ref);
52 let license_file = manmeta.license_file.as_ref().map(String::as_ref);
53 let description = manmeta.description.as_ref().map(String::as_ref);
54
55 SerializedPackage {
56 name: package_id.name(),
57 version: &package_id.version().to_string(),
58 id: package_id,
59 license: license,
60 license_file: license_file,
61 description: description,
62 source: summary.source_id(),
63 dependencies: summary.dependencies(),
64 targets: self.manifest.targets(),
65 features: summary.features(),
66 manifest_path: &self.manifest_path.display().to_string(),
67 }.serialize(s)
68 }
69 }
70
71 impl Package {
72 pub fn new(manifest: Manifest,
73 manifest_path: &Path) -> Package {
74 Package {
75 manifest: manifest,
76 manifest_path: manifest_path.to_path_buf(),
77 }
78 }
79
80 pub fn for_path(manifest_path: &Path, config: &Config) -> CargoResult<Package> {
81 let path = manifest_path.parent().unwrap();
82 let source_id = SourceId::for_path(path)?;
83 let (pkg, _) = ops::read_package(manifest_path, &source_id, config)?;
84 Ok(pkg)
85 }
86
87 pub fn dependencies(&self) -> &[Dependency] { self.manifest.dependencies() }
88 pub fn manifest(&self) -> &Manifest { &self.manifest }
89 pub fn manifest_path(&self) -> &Path { &self.manifest_path }
90 pub fn name(&self) -> &str { self.package_id().name() }
91 pub fn package_id(&self) -> &PackageId { self.manifest.package_id() }
92 pub fn root(&self) -> &Path { self.manifest_path.parent().unwrap() }
93 pub fn summary(&self) -> &Summary { self.manifest.summary() }
94 pub fn targets(&self) -> &[Target] { self.manifest.targets() }
95 pub fn version(&self) -> &Version { self.package_id().version() }
96 pub fn authors(&self) -> &Vec<String> { &self.manifest.metadata().authors }
97 pub fn publish(&self) -> bool { self.manifest.publish() }
98
99 pub fn has_custom_build(&self) -> bool {
100 self.targets().iter().any(|t| t.is_custom_build())
101 }
102
103 pub fn find_closest_target(&self,
104 target: &str,
105 is_expected_kind: fn(&Target)-> bool) -> Option<&Target> {
106 let targets = self.targets();
107
108 let matches = targets.iter().filter(|t| is_expected_kind(t))
109 .map(|t| (lev_distance(target, t.name()), t))
110 .filter(|&(d, _)| d < 4);
111 matches.min_by_key(|t| t.0).map(|t| t.1)
112 }
113
114 pub fn map_source(self, to_replace: &SourceId, replace_with: &SourceId)
115 -> Package {
116 Package {
117 manifest: self.manifest.map_source(to_replace, replace_with),
118 manifest_path: self.manifest_path,
119 }
120 }
121
122 pub fn to_registry_toml(&self) -> String {
123 let manifest = self.manifest().original().prepare_for_publish();
124 let toml = toml::to_string(&manifest).unwrap();
125 format!("\
126 # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO\n\
127 #\n\
128 # When uploading crates to the registry Cargo will automatically\n\
129 # \"normalize\" Cargo.toml files for maximal compatibility\n\
130 # with all versions of Cargo and also rewrite `path` dependencies\n\
131 # to registry (e.g. crates.io) dependencies\n\
132 #\n\
133 # If you believe there's an error in this file please file an\n\
134 # issue against the rust-lang/cargo repository. If you're\n\
135 # editing this file be aware that the upstream Cargo.toml\n\
136 # will likely look very different (and much more reasonable)\n\
137 \n\
138 {}\
139 ", toml)
140 }
141 }
142
143 impl fmt::Display for Package {
144 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
145 write!(f, "{}", self.summary().package_id())
146 }
147 }
148
149 impl PartialEq for Package {
150 fn eq(&self, other: &Package) -> bool {
151 self.package_id() == other.package_id()
152 }
153 }
154
155 impl Eq for Package {}
156
157 impl hash::Hash for Package {
158 fn hash<H: hash::Hasher>(&self, into: &mut H) {
159 self.package_id().hash(into)
160 }
161 }
162
163 pub struct PackageSet<'cfg> {
164 packages: HashMap<PackageId, LazyCell<Package>>,
165 sources: RefCell<SourceMap<'cfg>>,
166 }
167
168 impl<'cfg> PackageSet<'cfg> {
169 pub fn new(package_ids: &[PackageId],
170 sources: SourceMap<'cfg>) -> PackageSet<'cfg> {
171 PackageSet {
172 packages: package_ids.iter().map(|id| {
173 (id.clone(), LazyCell::new())
174 }).collect(),
175 sources: RefCell::new(sources),
176 }
177 }
178
179 pub fn package_ids<'a>(&'a self) -> Box<Iterator<Item=&'a PackageId> + 'a> {
180 Box::new(self.packages.keys())
181 }
182
183 pub fn get(&self, id: &PackageId) -> CargoResult<&Package> {
184 let slot = self.packages.get(id).ok_or_else(|| {
185 internal(format!("couldn't find `{}` in package set", id))
186 })?;
187 if let Some(pkg) = slot.borrow() {
188 return Ok(pkg)
189 }
190 let mut sources = self.sources.borrow_mut();
191 let source = sources.get_mut(id.source_id()).ok_or_else(|| {
192 internal(format!("couldn't find source for `{}`", id))
193 })?;
194 let pkg = source.download(id).chain_err(|| {
195 "unable to get packages from source"
196 })?;
197 assert!(slot.fill(pkg).is_ok());
198 Ok(slot.borrow().unwrap())
199 }
200
201 pub fn sources(&self) -> Ref<SourceMap<'cfg>> {
202 self.sources.borrow()
203 }
204 }