1 use std
::cell
::{Ref, RefCell}
;
2 use std
::collections
::HashMap
;
5 use std
::path
::{Path, PathBuf}
;
11 use core
::{Dependency, Manifest, PackageId, SourceId, Target}
;
12 use core
::{Summary, SourceMap}
;
14 use util
::{Config, LazyCell, internal, lev_distance}
;
15 use util
::errors
::{CargoResult, CargoResultExt}
;
17 /// Information about a package that is available somewhere in the file system.
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)]
23 // The package's manifest
25 // The root of the package
26 manifest_path
: PathBuf
,
30 struct SerializedPackage
<'a
> {
34 license
: Option
<&'a
str>,
35 license_file
: Option
<&'a
str>,
36 description
: Option
<&'a
str>,
38 dependencies
: &'a
[Dependency
],
39 targets
: &'a
[Target
],
40 features
: &'a HashMap
<String
, Vec
<String
>>,
41 manifest_path
: &'a
str,
44 impl ser
::Serialize
for Package
{
45 fn serialize
<S
>(&self, s
: S
) -> Result
<S
::Ok
, S
::Error
>
46 where S
: ser
::Serializer
,
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
);
56 name
: package_id
.name(),
57 version
: &package_id
.version().to_string(),
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(),
72 pub fn new(manifest
: Manifest
,
73 manifest_path
: &Path
) -> Package
{
76 manifest_path
: manifest_path
.to_path_buf(),
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
)?
;
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() }
99 pub fn has_custom_build(&self) -> bool
{
100 self.targets().iter().any(|t
| t
.is_custom_build())
103 pub fn find_closest_target(&self,
105 is_expected_kind
: fn(&Target
)-> bool
) -> Option
<&Target
> {
106 let targets
= self.targets();
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)
114 pub fn map_source(self, to_replace
: &SourceId
, replace_with
: &SourceId
)
117 manifest
: self.manifest
.map_source(to_replace
, replace_with
),
118 manifest_path
: self.manifest_path
,
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();
126 # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO\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\
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\
143 impl fmt
::Display
for Package
{
144 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
145 write
!(f
, "{}", self.summary().package_id())
149 impl PartialEq
for Package
{
150 fn eq(&self, other
: &Package
) -> bool
{
151 self.package_id() == other
.package_id()
155 impl Eq
for Package {}
157 impl hash
::Hash
for Package
{
158 fn hash
<H
: hash
::Hasher
>(&self, into
: &mut H
) {
159 self.package_id().hash(into
)
163 pub struct PackageSet
<'cfg
> {
164 packages
: HashMap
<PackageId
, LazyCell
<Package
>>,
165 sources
: RefCell
<SourceMap
<'cfg
>>,
168 impl<'cfg
> PackageSet
<'cfg
> {
169 pub fn new(package_ids
: &[PackageId
],
170 sources
: SourceMap
<'cfg
>) -> PackageSet
<'cfg
> {
172 packages
: package_ids
.iter().map(|id
| {
173 (id
.clone(), LazyCell
::new())
175 sources
: RefCell
::new(sources
),
179 pub fn package_ids
<'a
>(&'a
self) -> Box
<Iterator
<Item
=&'a PackageId
> + 'a
> {
180 Box
::new(self.packages
.keys())
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
))
187 if let Some(pkg
) = slot
.borrow() {
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
))
194 let pkg
= source
.download(id
).chain_err(|| {
195 "unable to get packages from source"
197 assert
!(slot
.fill(pkg
).is_ok());
198 Ok(slot
.borrow().unwrap())
201 pub fn sources(&self) -> Ref
<SourceMap
<'cfg
>> {
202 self.sources
.borrow()