mirror of
https://github.com/rust-lang/cargo.git
synced 2025-10-01 11:30:39 +00:00
Add dependency registry
to cargo metadata
.
This adds the `registry` field for dependencies for alternate registries in `cargo metadata`.
This commit is contained in:
parent
15e3b5a3c8
commit
3d84d0ad77
@ -19,6 +19,7 @@ path = "src/cargo/lib.rs"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
atty = "0.2"
|
atty = "0.2"
|
||||||
|
byteorder = "1.2"
|
||||||
bytesize = "1.0"
|
bytesize = "1.0"
|
||||||
crates-io = { path = "src/crates-io", version = "0.22" }
|
crates-io = { path = "src/crates-io", version = "0.22" }
|
||||||
crossbeam-utils = "0.6"
|
crossbeam-utils = "0.6"
|
||||||
@ -57,6 +58,7 @@ tempfile = "3.0"
|
|||||||
termcolor = "1.0"
|
termcolor = "1.0"
|
||||||
toml = "0.4.2"
|
toml = "0.4.2"
|
||||||
url = "1.1"
|
url = "1.1"
|
||||||
|
url_serde = "0.2.0"
|
||||||
clap = "2.31.2"
|
clap = "2.31.2"
|
||||||
unicode-width = "0.1.5"
|
unicode-width = "0.1.5"
|
||||||
openssl = { version = '0.10.11', optional = true }
|
openssl = { version = '0.10.11', optional = true }
|
||||||
|
@ -7,6 +7,7 @@ use semver::ReqParseError;
|
|||||||
use semver::VersionReq;
|
use semver::VersionReq;
|
||||||
use serde::ser;
|
use serde::ser;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
use crate::core::interning::InternedString;
|
use crate::core::interning::InternedString;
|
||||||
use crate::core::{PackageId, SourceId, Summary};
|
use crate::core::{PackageId, SourceId, Summary};
|
||||||
@ -25,6 +26,12 @@ pub struct Dependency {
|
|||||||
struct Inner {
|
struct Inner {
|
||||||
name: InternedString,
|
name: InternedString,
|
||||||
source_id: SourceId,
|
source_id: SourceId,
|
||||||
|
/// Source ID for the registry as specified in the manifest.
|
||||||
|
///
|
||||||
|
/// This will be None if it is not specified (crates.io dependency).
|
||||||
|
/// This is different from `source_id` for example when both a `path` and
|
||||||
|
/// `registry` is specified. Or in the case of a crates.io dependency,
|
||||||
|
/// `source_id` will be crates.io and this will be None.
|
||||||
registry_id: Option<SourceId>,
|
registry_id: Option<SourceId>,
|
||||||
req: VersionReq,
|
req: VersionReq,
|
||||||
specified_req: bool,
|
specified_req: bool,
|
||||||
@ -59,6 +66,10 @@ struct SerializedDependency<'a> {
|
|||||||
uses_default_features: bool,
|
uses_default_features: bool,
|
||||||
features: &'a [InternedString],
|
features: &'a [InternedString],
|
||||||
target: Option<&'a Platform>,
|
target: Option<&'a Platform>,
|
||||||
|
/// The registry URL this dependency is from.
|
||||||
|
/// If None, then it comes from the default registry (crates.io).
|
||||||
|
#[serde(with = "url_serde")]
|
||||||
|
registry: Option<Url>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ser::Serialize for Dependency {
|
impl ser::Serialize for Dependency {
|
||||||
@ -76,6 +87,7 @@ impl ser::Serialize for Dependency {
|
|||||||
features: self.features(),
|
features: self.features(),
|
||||||
target: self.platform(),
|
target: self.platform(),
|
||||||
rename: self.explicit_name_in_toml().map(|s| s.as_str()),
|
rename: self.explicit_name_in_toml().map(|s| s.as_str()),
|
||||||
|
registry: self.registry_id().map(|sid| sid.url().clone()),
|
||||||
}
|
}
|
||||||
.serialize(s)
|
.serialize(s)
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,8 @@ struct SourceIdInner {
|
|||||||
// e.g. the exact git revision of the specified branch for a Git Source
|
// e.g. the exact git revision of the specified branch for a Git Source
|
||||||
precise: Option<String>,
|
precise: Option<String>,
|
||||||
/// Name of the registry source for alternative registries
|
/// Name of the registry source for alternative registries
|
||||||
|
/// WARNING: This is not always set for alt-registries when the name is
|
||||||
|
/// not known.
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,6 +249,8 @@ impl SourceId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Is this source from an alternative registry
|
/// Is this source from an alternative registry
|
||||||
|
/// DEPRECATED: This is not correct if the registry name is not known
|
||||||
|
/// (for example when loaded from an index).
|
||||||
pub fn is_alt_registry(self) -> bool {
|
pub fn is_alt_registry(self) -> bool {
|
||||||
self.is_registry() && self.inner.name.is_some()
|
self.is_registry() && self.inner.name.is_some()
|
||||||
}
|
}
|
||||||
|
@ -159,8 +159,10 @@ fn transmit(
|
|||||||
// registry in the dependency.
|
// registry in the dependency.
|
||||||
let dep_registry_id = match dep.registry_id() {
|
let dep_registry_id = match dep.registry_id() {
|
||||||
Some(id) => id,
|
Some(id) => id,
|
||||||
None => failure::bail!("dependency missing registry ID"),
|
None => SourceId::crates_io(config)?,
|
||||||
};
|
};
|
||||||
|
// In the index and Web API, None means "from the same registry"
|
||||||
|
// whereas in Cargo.toml, it means "from crates.io".
|
||||||
let dep_registry = if dep_registry_id != registry_id {
|
let dep_registry = if dep_registry_id != registry_id {
|
||||||
Some(dep_registry_id.url().to_string())
|
Some(dep_registry_id.url().to_string())
|
||||||
} else {
|
} else {
|
||||||
|
@ -299,7 +299,7 @@ impl<'a> RegistryDependency<'a> {
|
|||||||
package,
|
package,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let id = if let Some(registry) = registry {
|
let id = if let Some(registry) = ®istry {
|
||||||
SourceId::for_registry(®istry.to_url()?)?
|
SourceId::for_registry(®istry.to_url()?)?
|
||||||
} else {
|
} else {
|
||||||
default
|
default
|
||||||
@ -328,6 +328,12 @@ impl<'a> RegistryDependency<'a> {
|
|||||||
// out here.
|
// out here.
|
||||||
features.retain(|s| !s.is_empty());
|
features.retain(|s| !s.is_empty());
|
||||||
|
|
||||||
|
// In index, "registry" is null if it is from the same index.
|
||||||
|
// In Cargo.toml, "registry" is None if it is from the default
|
||||||
|
if !id.is_default_registry() {
|
||||||
|
dep.set_registry_id(id);
|
||||||
|
}
|
||||||
|
|
||||||
dep.set_optional(optional)
|
dep.set_optional(optional)
|
||||||
.set_default_features(default_features)
|
.set_default_features(default_features)
|
||||||
.set_features(features)
|
.set_features(features)
|
||||||
@ -486,22 +492,7 @@ impl<'cfg> RegistrySource<'cfg> {
|
|||||||
MaybePackage::Ready(pkg) => pkg,
|
MaybePackage::Ready(pkg) => pkg,
|
||||||
MaybePackage::Download { .. } => unreachable!(),
|
MaybePackage::Download { .. } => unreachable!(),
|
||||||
};
|
};
|
||||||
|
Ok(pkg)
|
||||||
// Unfortunately the index and the actual Cargo.toml in the index can
|
|
||||||
// differ due to historical Cargo bugs. To paper over these we trash the
|
|
||||||
// *summary* loaded from the Cargo.toml we just downloaded with the one
|
|
||||||
// we loaded from the index.
|
|
||||||
let summaries = self
|
|
||||||
.index
|
|
||||||
.summaries(package.name().as_str(), &mut *self.ops)?;
|
|
||||||
let summary = summaries
|
|
||||||
.iter()
|
|
||||||
.map(|s| &s.0)
|
|
||||||
.find(|s| s.package_id() == package)
|
|
||||||
.expect("summary not found");
|
|
||||||
let mut manifest = pkg.manifest().clone();
|
|
||||||
manifest.set_summary(summary.clone());
|
|
||||||
Ok(Package::new(manifest, pkg.manifest_path()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1307,14 +1307,6 @@ impl DetailedTomlDependency {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let registry_id = match self.registry {
|
|
||||||
Some(ref registry) => {
|
|
||||||
cx.features.require(Feature::alternative_registries())?;
|
|
||||||
SourceId::alt_registry(cx.config, registry)?
|
|
||||||
}
|
|
||||||
None => SourceId::crates_io(cx.config)?,
|
|
||||||
};
|
|
||||||
|
|
||||||
let new_source_id = match (
|
let new_source_id = match (
|
||||||
self.git.as_ref(),
|
self.git.as_ref(),
|
||||||
self.path.as_ref(),
|
self.path.as_ref(),
|
||||||
@ -1410,8 +1402,13 @@ impl DetailedTomlDependency {
|
|||||||
.unwrap_or(true),
|
.unwrap_or(true),
|
||||||
)
|
)
|
||||||
.set_optional(self.optional.unwrap_or(false))
|
.set_optional(self.optional.unwrap_or(false))
|
||||||
.set_platform(cx.platform.clone())
|
.set_platform(cx.platform.clone());
|
||||||
.set_registry_id(registry_id);
|
if let Some(registry) = &self.registry {
|
||||||
|
cx.features.require(Feature::alternative_registries())?;
|
||||||
|
let registry_id = SourceId::alt_registry(cx.config, registry)?;
|
||||||
|
dep.set_registry_id(registry_id);
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(kind) = kind {
|
if let Some(kind) = kind {
|
||||||
dep.set_kind(kind);
|
dep.set_kind(kind);
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,9 @@ The output has the following format:
|
|||||||
{
|
{
|
||||||
/* The name of the dependency. */
|
/* The name of the dependency. */
|
||||||
"name": "bitflags",
|
"name": "bitflags",
|
||||||
/* The source ID of the dependency. */
|
/* The source ID of the dependency. May be null, see
|
||||||
|
description for the package source.
|
||||||
|
*/
|
||||||
"source": "registry+https://github.com/rust-lang/crates.io-index",
|
"source": "registry+https://github.com/rust-lang/crates.io-index",
|
||||||
/* The version requirement for the dependency.
|
/* The version requirement for the dependency.
|
||||||
Dependencies without a version requirement have a value of "*".
|
Dependencies without a version requirement have a value of "*".
|
||||||
@ -84,7 +86,12 @@ The output has the following format:
|
|||||||
/* The target platform for the dependency.
|
/* The target platform for the dependency.
|
||||||
null if not a target dependency.
|
null if not a target dependency.
|
||||||
*/
|
*/
|
||||||
"target": "cfg(windows)"
|
"target": "cfg(windows)",
|
||||||
|
/* A string of the URL of the registry this dependency is from.
|
||||||
|
If not specified or null, the dependency is from the default
|
||||||
|
registry (crates.io).
|
||||||
|
*/
|
||||||
|
"registry": null
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
/* Array of Cargo targets. */
|
/* Array of Cargo targets. */
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::support::registry::{self, alt_api_path, Package};
|
use crate::support::publish::validate_alt_upload;
|
||||||
|
use crate::support::registry::{self, Package};
|
||||||
use crate::support::{basic_manifest, git, paths, project};
|
use crate::support::{basic_manifest, git, paths, project};
|
||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
@ -107,7 +108,7 @@ fn depend_on_alt_registry_depends_on_same_registry_no_index() {
|
|||||||
|
|
||||||
Package::new("baz", "0.0.1").alternative(true).publish();
|
Package::new("baz", "0.0.1").alternative(true).publish();
|
||||||
Package::new("bar", "0.0.1")
|
Package::new("bar", "0.0.1")
|
||||||
.dep("baz", "0.0.1")
|
.registry_dep("baz", "0.0.1")
|
||||||
.alternative(true)
|
.alternative(true)
|
||||||
.publish();
|
.publish();
|
||||||
|
|
||||||
@ -152,7 +153,7 @@ fn depend_on_alt_registry_depends_on_same_registry() {
|
|||||||
|
|
||||||
Package::new("baz", "0.0.1").alternative(true).publish();
|
Package::new("baz", "0.0.1").alternative(true).publish();
|
||||||
Package::new("bar", "0.0.1")
|
Package::new("bar", "0.0.1")
|
||||||
.registry_dep("baz", "0.0.1", registry::alt_registry().as_str())
|
.registry_dep("baz", "0.0.1")
|
||||||
.alternative(true)
|
.alternative(true)
|
||||||
.publish();
|
.publish();
|
||||||
|
|
||||||
@ -197,7 +198,7 @@ fn depend_on_alt_registry_depends_on_crates_io() {
|
|||||||
|
|
||||||
Package::new("baz", "0.0.1").publish();
|
Package::new("baz", "0.0.1").publish();
|
||||||
Package::new("bar", "0.0.1")
|
Package::new("bar", "0.0.1")
|
||||||
.registry_dep("baz", "0.0.1", registry::registry().as_str())
|
.dep("baz", "0.0.1")
|
||||||
.alternative(true)
|
.alternative(true)
|
||||||
.publish();
|
.publish();
|
||||||
|
|
||||||
@ -210,7 +211,7 @@ fn depend_on_alt_registry_depends_on_crates_io() {
|
|||||||
[DOWNLOADING] crates ...
|
[DOWNLOADING] crates ...
|
||||||
[DOWNLOADED] baz v0.0.1 (registry `[ROOT][..]`)
|
[DOWNLOADED] baz v0.0.1 (registry `[ROOT][..]`)
|
||||||
[DOWNLOADED] bar v0.0.1 (registry `[ROOT][..]`)
|
[DOWNLOADED] bar v0.0.1 (registry `[ROOT][..]`)
|
||||||
[COMPILING] baz v0.0.1 (registry `[ROOT][..]`)
|
[COMPILING] baz v0.0.1
|
||||||
[COMPILING] bar v0.0.1 (registry `[ROOT][..]`)
|
[COMPILING] bar v0.0.1 (registry `[ROOT][..]`)
|
||||||
[COMPILING] foo v0.0.1 ([CWD])
|
[COMPILING] foo v0.0.1 ([CWD])
|
||||||
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
|
||||||
@ -345,6 +346,40 @@ fn publish_with_registry_dependency() {
|
|||||||
p.cargo("publish --registry alternative -Zunstable-options")
|
p.cargo("publish --registry alternative -Zunstable-options")
|
||||||
.masquerade_as_nightly_cargo()
|
.masquerade_as_nightly_cargo()
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
|
validate_alt_upload(
|
||||||
|
r#"{
|
||||||
|
"authors": [],
|
||||||
|
"badges": {},
|
||||||
|
"categories": [],
|
||||||
|
"deps": [
|
||||||
|
{
|
||||||
|
"default_features": true,
|
||||||
|
"features": [],
|
||||||
|
"kind": "normal",
|
||||||
|
"name": "bar",
|
||||||
|
"optional": false,
|
||||||
|
"target": null,
|
||||||
|
"version_req": "^0.0.1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": null,
|
||||||
|
"documentation": null,
|
||||||
|
"features": {},
|
||||||
|
"homepage": null,
|
||||||
|
"keywords": [],
|
||||||
|
"license": null,
|
||||||
|
"license_file": null,
|
||||||
|
"links": null,
|
||||||
|
"name": "foo",
|
||||||
|
"readme": null,
|
||||||
|
"readme_file": null,
|
||||||
|
"repository": null,
|
||||||
|
"vers": "0.0.1"
|
||||||
|
}"#,
|
||||||
|
"foo-0.0.1.crate",
|
||||||
|
&["Cargo.toml", "Cargo.toml.orig", "src/main.rs"],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -440,8 +475,29 @@ fn publish_to_alt_registry() {
|
|||||||
.masquerade_as_nightly_cargo()
|
.masquerade_as_nightly_cargo()
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
// Ensure that the crate is uploaded
|
validate_alt_upload(
|
||||||
assert!(alt_api_path().join("api/v1/crates/new").exists());
|
r#"{
|
||||||
|
"authors": [],
|
||||||
|
"badges": {},
|
||||||
|
"categories": [],
|
||||||
|
"deps": [],
|
||||||
|
"description": null,
|
||||||
|
"documentation": null,
|
||||||
|
"features": {},
|
||||||
|
"homepage": null,
|
||||||
|
"keywords": [],
|
||||||
|
"license": null,
|
||||||
|
"license_file": null,
|
||||||
|
"links": null,
|
||||||
|
"name": "foo",
|
||||||
|
"readme": null,
|
||||||
|
"readme_file": null,
|
||||||
|
"repository": null,
|
||||||
|
"vers": "0.0.1"
|
||||||
|
}"#,
|
||||||
|
"foo-0.0.1.crate",
|
||||||
|
&["Cargo.toml", "Cargo.toml.orig", "src/main.rs"],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -476,6 +532,41 @@ fn publish_with_crates_io_dep() {
|
|||||||
p.cargo("publish --registry alternative -Zunstable-options")
|
p.cargo("publish --registry alternative -Zunstable-options")
|
||||||
.masquerade_as_nightly_cargo()
|
.masquerade_as_nightly_cargo()
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
|
validate_alt_upload(
|
||||||
|
r#"{
|
||||||
|
"authors": ["me"],
|
||||||
|
"badges": {},
|
||||||
|
"categories": [],
|
||||||
|
"deps": [
|
||||||
|
{
|
||||||
|
"default_features": true,
|
||||||
|
"features": [],
|
||||||
|
"kind": "normal",
|
||||||
|
"name": "bar",
|
||||||
|
"optional": false,
|
||||||
|
"registry": "https://github.com/rust-lang/crates.io-index",
|
||||||
|
"target": null,
|
||||||
|
"version_req": "^0.0.1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "foo",
|
||||||
|
"documentation": null,
|
||||||
|
"features": {},
|
||||||
|
"homepage": null,
|
||||||
|
"keywords": [],
|
||||||
|
"license": "MIT",
|
||||||
|
"license_file": null,
|
||||||
|
"links": null,
|
||||||
|
"name": "foo",
|
||||||
|
"readme": null,
|
||||||
|
"readme_file": null,
|
||||||
|
"repository": null,
|
||||||
|
"vers": "0.0.1"
|
||||||
|
}"#,
|
||||||
|
"foo-0.0.1.crate",
|
||||||
|
&["Cargo.toml", "Cargo.toml.orig", "src/main.rs"],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -696,3 +787,279 @@ fn no_api() {
|
|||||||
.with_status(101)
|
.with_status(101)
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn alt_reg_metadata() {
|
||||||
|
// Check for "registry" entries in `cargo metadata` with alternative registries.
|
||||||
|
let p = project()
|
||||||
|
.file(
|
||||||
|
"Cargo.toml",
|
||||||
|
r#"
|
||||||
|
cargo-features = ["alternative-registries"]
|
||||||
|
[package]
|
||||||
|
name = "foo"
|
||||||
|
version = "0.0.1"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
altdep = { version = "0.0.1", registry = "alternative" }
|
||||||
|
iodep = { version = "0.0.1" }
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file("src/lib.rs", "")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Package::new("bar", "0.0.1").publish();
|
||||||
|
Package::new("altdep", "0.0.1")
|
||||||
|
.dep("bar", "0.0.1")
|
||||||
|
.alternative(true)
|
||||||
|
.publish();
|
||||||
|
Package::new("altdep2", "0.0.1").alternative(true).publish();
|
||||||
|
Package::new("iodep", "0.0.1")
|
||||||
|
.registry_dep("altdep2", "0.0.1")
|
||||||
|
.publish();
|
||||||
|
|
||||||
|
// The important thing to check here is the "registry" value in `deps`.
|
||||||
|
// They should be:
|
||||||
|
// foo -> altdep: alternative-registry
|
||||||
|
// foo -> iodep: null (because it is in crates.io)
|
||||||
|
// altdep -> bar: null (because it is in crates.io)
|
||||||
|
// iodep -> altdep2: alternative-registry
|
||||||
|
p.cargo("metadata --format-version=1 --no-deps")
|
||||||
|
.masquerade_as_nightly_cargo()
|
||||||
|
.with_json(
|
||||||
|
r#"
|
||||||
|
{
|
||||||
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "foo",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"id": "foo 0.0.1 (path+file:[..]/foo)",
|
||||||
|
"license": null,
|
||||||
|
"license_file": null,
|
||||||
|
"description": null,
|
||||||
|
"source": null,
|
||||||
|
"dependencies": [
|
||||||
|
{
|
||||||
|
"name": "altdep",
|
||||||
|
"source": "registry+file:[..]/alternative-registry",
|
||||||
|
"req": "^0.0.1",
|
||||||
|
"kind": null,
|
||||||
|
"rename": null,
|
||||||
|
"optional": false,
|
||||||
|
"uses_default_features": true,
|
||||||
|
"features": [],
|
||||||
|
"target": null,
|
||||||
|
"registry": "file:[..]/alternative-registry"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "iodep",
|
||||||
|
"source": "registry+https://github.com/rust-lang/crates.io-index",
|
||||||
|
"req": "^0.0.1",
|
||||||
|
"kind": null,
|
||||||
|
"rename": null,
|
||||||
|
"optional": false,
|
||||||
|
"uses_default_features": true,
|
||||||
|
"features": [],
|
||||||
|
"target": null,
|
||||||
|
"registry": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"targets": "{...}",
|
||||||
|
"features": {},
|
||||||
|
"manifest_path": "[..]/foo/Cargo.toml",
|
||||||
|
"metadata": null,
|
||||||
|
"authors": [],
|
||||||
|
"categories": [],
|
||||||
|
"keywords": [],
|
||||||
|
"readme": null,
|
||||||
|
"repository": null,
|
||||||
|
"edition": "2015",
|
||||||
|
"links": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"workspace_members": [
|
||||||
|
"foo 0.0.1 (path+file:[..]/foo)"
|
||||||
|
],
|
||||||
|
"resolve": null,
|
||||||
|
"target_directory": "[..]/foo/target",
|
||||||
|
"version": 1,
|
||||||
|
"workspace_root": "[..]/foo"
|
||||||
|
}"#,
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
|
||||||
|
// --no-deps uses a different code path, make sure both work.
|
||||||
|
p.cargo("metadata --format-version=1")
|
||||||
|
.masquerade_as_nightly_cargo()
|
||||||
|
.with_json(
|
||||||
|
r#"
|
||||||
|
{
|
||||||
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "altdep2",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"id": "altdep2 0.0.1 (registry+file:[..]/alternative-registry)",
|
||||||
|
"license": null,
|
||||||
|
"license_file": null,
|
||||||
|
"description": null,
|
||||||
|
"source": "registry+file:[..]/alternative-registry",
|
||||||
|
"dependencies": [],
|
||||||
|
"targets": "{...}",
|
||||||
|
"features": {},
|
||||||
|
"manifest_path": "[..]/altdep2-0.0.1/Cargo.toml",
|
||||||
|
"metadata": null,
|
||||||
|
"authors": [],
|
||||||
|
"categories": [],
|
||||||
|
"keywords": [],
|
||||||
|
"readme": null,
|
||||||
|
"repository": null,
|
||||||
|
"edition": "2015",
|
||||||
|
"links": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "altdep",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"id": "altdep 0.0.1 (registry+file:[..]/alternative-registry)",
|
||||||
|
"license": null,
|
||||||
|
"license_file": null,
|
||||||
|
"description": null,
|
||||||
|
"source": "registry+file:[..]/alternative-registry",
|
||||||
|
"dependencies": [
|
||||||
|
{
|
||||||
|
"name": "bar",
|
||||||
|
"source": "registry+https://github.com/rust-lang/crates.io-index",
|
||||||
|
"req": "^0.0.1",
|
||||||
|
"kind": null,
|
||||||
|
"rename": null,
|
||||||
|
"optional": false,
|
||||||
|
"uses_default_features": true,
|
||||||
|
"features": [],
|
||||||
|
"target": null,
|
||||||
|
"registry": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"targets": "{...}",
|
||||||
|
"features": {},
|
||||||
|
"manifest_path": "[..]/altdep-0.0.1/Cargo.toml",
|
||||||
|
"metadata": null,
|
||||||
|
"authors": [],
|
||||||
|
"categories": [],
|
||||||
|
"keywords": [],
|
||||||
|
"readme": null,
|
||||||
|
"repository": null,
|
||||||
|
"edition": "2015",
|
||||||
|
"links": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "foo",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"id": "foo 0.0.1 (path+file:[..]/foo)",
|
||||||
|
"license": null,
|
||||||
|
"license_file": null,
|
||||||
|
"description": null,
|
||||||
|
"source": null,
|
||||||
|
"dependencies": [
|
||||||
|
{
|
||||||
|
"name": "altdep",
|
||||||
|
"source": "registry+file:[..]/alternative-registry",
|
||||||
|
"req": "^0.0.1",
|
||||||
|
"kind": null,
|
||||||
|
"rename": null,
|
||||||
|
"optional": false,
|
||||||
|
"uses_default_features": true,
|
||||||
|
"features": [],
|
||||||
|
"target": null,
|
||||||
|
"registry": "file:[..]/alternative-registry"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "iodep",
|
||||||
|
"source": "registry+https://github.com/rust-lang/crates.io-index",
|
||||||
|
"req": "^0.0.1",
|
||||||
|
"kind": null,
|
||||||
|
"rename": null,
|
||||||
|
"optional": false,
|
||||||
|
"uses_default_features": true,
|
||||||
|
"features": [],
|
||||||
|
"target": null,
|
||||||
|
"registry": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"targets": "{...}",
|
||||||
|
"features": {},
|
||||||
|
"manifest_path": "[..]/foo/Cargo.toml",
|
||||||
|
"metadata": null,
|
||||||
|
"authors": [],
|
||||||
|
"categories": [],
|
||||||
|
"keywords": [],
|
||||||
|
"readme": null,
|
||||||
|
"repository": null,
|
||||||
|
"edition": "2015",
|
||||||
|
"links": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "iodep",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"id": "iodep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"license": null,
|
||||||
|
"license_file": null,
|
||||||
|
"description": null,
|
||||||
|
"source": "registry+https://github.com/rust-lang/crates.io-index",
|
||||||
|
"dependencies": [
|
||||||
|
{
|
||||||
|
"name": "altdep2",
|
||||||
|
"source": "registry+file:[..]/alternative-registry",
|
||||||
|
"req": "^0.0.1",
|
||||||
|
"kind": null,
|
||||||
|
"rename": null,
|
||||||
|
"optional": false,
|
||||||
|
"uses_default_features": true,
|
||||||
|
"features": [],
|
||||||
|
"target": null,
|
||||||
|
"registry": "file:[..]/alternative-registry"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"targets": "{...}",
|
||||||
|
"features": {},
|
||||||
|
"manifest_path": "[..]/iodep-0.0.1/Cargo.toml",
|
||||||
|
"metadata": null,
|
||||||
|
"authors": [],
|
||||||
|
"categories": [],
|
||||||
|
"keywords": [],
|
||||||
|
"readme": null,
|
||||||
|
"repository": null,
|
||||||
|
"edition": "2015",
|
||||||
|
"links": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "bar",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"id": "bar 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"license": null,
|
||||||
|
"license_file": null,
|
||||||
|
"description": null,
|
||||||
|
"source": "registry+https://github.com/rust-lang/crates.io-index",
|
||||||
|
"dependencies": [],
|
||||||
|
"targets": "{...}",
|
||||||
|
"features": {},
|
||||||
|
"manifest_path": "[..]/bar-0.0.1/Cargo.toml",
|
||||||
|
"metadata": null,
|
||||||
|
"authors": [],
|
||||||
|
"categories": [],
|
||||||
|
"keywords": [],
|
||||||
|
"readme": null,
|
||||||
|
"repository": null,
|
||||||
|
"edition": "2015",
|
||||||
|
"links": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"workspace_members": [
|
||||||
|
"foo 0.0.1 (path+file:[..]/foo)"
|
||||||
|
],
|
||||||
|
"resolve": "{...}",
|
||||||
|
"target_directory": "[..]/foo/target",
|
||||||
|
"version": 1,
|
||||||
|
"workspace_root": "[..]/foo"
|
||||||
|
}"#,
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::prelude::*;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use crate::support::{cross_compile, project, publish};
|
use crate::support::{cross_compile, project, publish};
|
||||||
use flate2::read::GzDecoder;
|
|
||||||
use tar::Archive;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn simple_cross_package() {
|
fn simple_cross_package() {
|
||||||
@ -54,17 +50,12 @@ fn simple_cross_package() {
|
|||||||
|
|
||||||
// Check that the tarball contains the files
|
// Check that the tarball contains the files
|
||||||
let f = File::open(&p.root().join("target/package/foo-0.0.0.crate")).unwrap();
|
let f = File::open(&p.root().join("target/package/foo-0.0.0.crate")).unwrap();
|
||||||
let mut rdr = GzDecoder::new(f);
|
publish::validate_crate_contents(
|
||||||
let mut contents = Vec::new();
|
f,
|
||||||
rdr.read_to_end(&mut contents).unwrap();
|
"foo-0.0.0.crate",
|
||||||
let mut ar = Archive::new(&contents[..]);
|
&["Cargo.toml", "Cargo.toml.orig", "src/main.rs"],
|
||||||
let entries = ar.entries().unwrap();
|
&[],
|
||||||
let entry_paths = entries
|
);
|
||||||
.map(|entry| entry.unwrap().path().unwrap().into_owned())
|
|
||||||
.collect::<Vec<PathBuf>>();
|
|
||||||
assert!(entry_paths.contains(&PathBuf::from("foo-0.0.0/Cargo.toml")));
|
|
||||||
assert!(entry_paths.contains(&PathBuf::from("foo-0.0.0/Cargo.toml.orig")));
|
|
||||||
assert!(entry_paths.contains(&PathBuf::from("foo-0.0.0/src/main.rs")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -321,6 +321,7 @@ fn cargo_metadata_with_deps_and_version() {
|
|||||||
"kind": null,
|
"kind": null,
|
||||||
"name": "bar",
|
"name": "bar",
|
||||||
"optional": false,
|
"optional": false,
|
||||||
|
"registry": null,
|
||||||
"rename": null,
|
"rename": null,
|
||||||
"req": "*",
|
"req": "*",
|
||||||
"source": "registry+https://github.com/rust-lang/crates.io-index",
|
"source": "registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@ -332,6 +333,7 @@ fn cargo_metadata_with_deps_and_version() {
|
|||||||
"kind": "dev",
|
"kind": "dev",
|
||||||
"name": "foobar",
|
"name": "foobar",
|
||||||
"optional": false,
|
"optional": false,
|
||||||
|
"registry": null,
|
||||||
"rename": null,
|
"rename": null,
|
||||||
"req": "*",
|
"req": "*",
|
||||||
"source": "registry+https://github.com/rust-lang/crates.io-index",
|
"source": "registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@ -410,6 +412,7 @@ fn cargo_metadata_with_deps_and_version() {
|
|||||||
"kind": null,
|
"kind": null,
|
||||||
"name": "baz",
|
"name": "baz",
|
||||||
"optional": false,
|
"optional": false,
|
||||||
|
"registry": null,
|
||||||
"rename": null,
|
"rename": null,
|
||||||
"req": "^0.0.1",
|
"req": "^0.0.1",
|
||||||
"source": "registry+https://github.com/rust-lang/crates.io-index",
|
"source": "registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@ -1417,6 +1420,7 @@ fn rename_dependency() {
|
|||||||
"name": "bar",
|
"name": "bar",
|
||||||
"optional": false,
|
"optional": false,
|
||||||
"rename": null,
|
"rename": null,
|
||||||
|
"registry": null,
|
||||||
"req": "^0.1.0",
|
"req": "^0.1.0",
|
||||||
"source": "registry+https://github.com/rust-lang/crates.io-index",
|
"source": "registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"target": null,
|
"target": null,
|
||||||
@ -1428,6 +1432,7 @@ fn rename_dependency() {
|
|||||||
"name": "bar",
|
"name": "bar",
|
||||||
"optional": false,
|
"optional": false,
|
||||||
"rename": "baz",
|
"rename": "baz",
|
||||||
|
"registry": null,
|
||||||
"req": "^0.2.0",
|
"req": "^0.2.0",
|
||||||
"source": "registry+https://github.com/rust-lang/crates.io-index",
|
"source": "registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"target": null,
|
"target": null,
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
use std;
|
use std;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::Path;
|
||||||
|
|
||||||
use crate::support::registry::Package;
|
use crate::support::registry::Package;
|
||||||
use crate::support::{basic_manifest, git, is_nightly, path2url, paths, project, registry};
|
use crate::support::{
|
||||||
|
basic_manifest, git, is_nightly, path2url, paths, project, publish::validate_crate_contents,
|
||||||
|
registry,
|
||||||
|
};
|
||||||
use crate::support::{cargo_process, sleep_ms};
|
use crate::support::{cargo_process, sleep_ms};
|
||||||
use flate2::read::GzDecoder;
|
|
||||||
use git2;
|
use git2;
|
||||||
use tar::Archive;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn simple() {
|
fn simple() {
|
||||||
@ -53,22 +54,12 @@ src/main.rs
|
|||||||
p.cargo("package").with_stdout("").run();
|
p.cargo("package").with_stdout("").run();
|
||||||
|
|
||||||
let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap();
|
let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap();
|
||||||
let mut rdr = GzDecoder::new(f);
|
validate_crate_contents(
|
||||||
let mut contents = Vec::new();
|
f,
|
||||||
rdr.read_to_end(&mut contents).unwrap();
|
"foo-0.0.1.crate",
|
||||||
let mut ar = Archive::new(&contents[..]);
|
&["Cargo.toml", "Cargo.toml.orig", "src/main.rs"],
|
||||||
for f in ar.entries().unwrap() {
|
&[],
|
||||||
let f = f.unwrap();
|
);
|
||||||
let fname = f.header().path_bytes();
|
|
||||||
let fname = &*fname;
|
|
||||||
assert!(
|
|
||||||
fname == b"foo-0.0.1/Cargo.toml"
|
|
||||||
|| fname == b"foo-0.0.1/Cargo.toml.orig"
|
|
||||||
|| fname == b"foo-0.0.1/src/main.rs",
|
|
||||||
"unexpected filename: {:?}",
|
|
||||||
f.header().path()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -168,29 +159,25 @@ See http://doc.crates.io/manifest.html#package-metadata for more info.
|
|||||||
.run();
|
.run();
|
||||||
|
|
||||||
let f = File::open(&repo.root().join("target/package/foo-0.0.1.crate")).unwrap();
|
let f = File::open(&repo.root().join("target/package/foo-0.0.1.crate")).unwrap();
|
||||||
let mut rdr = GzDecoder::new(f);
|
let vcs_contents = format!(
|
||||||
let mut contents = Vec::new();
|
r#"{{
|
||||||
rdr.read_to_end(&mut contents).unwrap();
|
|
||||||
let mut ar = Archive::new(&contents[..]);
|
|
||||||
let mut entry = ar
|
|
||||||
.entries()
|
|
||||||
.unwrap()
|
|
||||||
.map(|f| f.unwrap())
|
|
||||||
.find(|e| e.path().unwrap().ends_with(".cargo_vcs_info.json"))
|
|
||||||
.unwrap();
|
|
||||||
let mut contents = String::new();
|
|
||||||
entry.read_to_string(&mut contents).unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
&contents[..],
|
|
||||||
&*format!(
|
|
||||||
r#"{{
|
|
||||||
"git": {{
|
"git": {{
|
||||||
"sha1": "{}"
|
"sha1": "{}"
|
||||||
}}
|
}}
|
||||||
}}
|
}}
|
||||||
"#,
|
"#,
|
||||||
repo.revparse_head()
|
repo.revparse_head()
|
||||||
)
|
);
|
||||||
|
validate_crate_contents(
|
||||||
|
f,
|
||||||
|
"foo-0.0.1.crate",
|
||||||
|
&[
|
||||||
|
"Cargo.toml",
|
||||||
|
"Cargo.toml.orig",
|
||||||
|
"src/main.rs",
|
||||||
|
".cargo_vcs_info.json",
|
||||||
|
],
|
||||||
|
&[(".cargo_vcs_info.json", &vcs_contents)],
|
||||||
);
|
);
|
||||||
|
|
||||||
println!("package sub-repo");
|
println!("package sub-repo");
|
||||||
@ -602,22 +589,12 @@ src[..]main.rs
|
|||||||
p.cargo("package").with_stdout("").run();
|
p.cargo("package").with_stdout("").run();
|
||||||
|
|
||||||
let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap();
|
let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap();
|
||||||
let mut rdr = GzDecoder::new(f);
|
validate_crate_contents(
|
||||||
let mut contents = Vec::new();
|
f,
|
||||||
rdr.read_to_end(&mut contents).unwrap();
|
"foo-0.0.1.crate",
|
||||||
let mut ar = Archive::new(&contents[..]);
|
&["Cargo.toml", "Cargo.toml.orig", "src/main.rs"],
|
||||||
for f in ar.entries().unwrap() {
|
&[],
|
||||||
let f = f.unwrap();
|
);
|
||||||
let fname = f.header().path_bytes();
|
|
||||||
let fname = &*fname;
|
|
||||||
assert!(
|
|
||||||
fname == b"foo-0.0.1/Cargo.toml"
|
|
||||||
|| fname == b"foo-0.0.1/Cargo.toml.orig"
|
|
||||||
|| fname == b"foo-0.0.1/src/main.rs",
|
|
||||||
"unexpected filename: {:?}",
|
|
||||||
f.header().path()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)] // windows doesn't allow these characters in filenames
|
#[cfg(unix)] // windows doesn't allow these characters in filenames
|
||||||
@ -681,15 +658,12 @@ See [..]
|
|||||||
|
|
||||||
// Check that the tarball contains the added file
|
// Check that the tarball contains the added file
|
||||||
let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap();
|
let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap();
|
||||||
let mut rdr = GzDecoder::new(f);
|
validate_crate_contents(
|
||||||
let mut contents = Vec::new();
|
f,
|
||||||
rdr.read_to_end(&mut contents).unwrap();
|
"foo-0.0.1.crate",
|
||||||
let mut ar = Archive::new(&contents[..]);
|
&["Cargo.toml", "Cargo.toml.orig", "src/main.rs", "src/foo.rs"],
|
||||||
let entries = ar.entries().unwrap();
|
&[],
|
||||||
let entry_paths = entries
|
);
|
||||||
.map(|entry| entry.unwrap().path().unwrap().into_owned())
|
|
||||||
.collect::<Vec<PathBuf>>();
|
|
||||||
assert!(entry_paths.contains(&PathBuf::from("foo-0.0.1/src/foo.rs")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -827,24 +801,8 @@ fn generated_manifest() {
|
|||||||
.run();
|
.run();
|
||||||
|
|
||||||
let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap();
|
let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap();
|
||||||
let mut rdr = GzDecoder::new(f);
|
let rewritten_toml = format!(
|
||||||
let mut contents = Vec::new();
|
r#"# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||||
rdr.read_to_end(&mut contents).unwrap();
|
|
||||||
let mut ar = Archive::new(&contents[..]);
|
|
||||||
let mut entry = ar
|
|
||||||
.entries()
|
|
||||||
.unwrap()
|
|
||||||
.map(|f| f.unwrap())
|
|
||||||
.find(|e| e.path().unwrap().ends_with("Cargo.toml"))
|
|
||||||
.unwrap();
|
|
||||||
let mut contents = String::new();
|
|
||||||
entry.read_to_string(&mut contents).unwrap();
|
|
||||||
// BTreeMap makes the order of dependencies in the generated file deterministic
|
|
||||||
// by sorting alphabetically
|
|
||||||
assert_eq!(
|
|
||||||
&contents[..],
|
|
||||||
&*format!(
|
|
||||||
r#"# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
|
||||||
#
|
#
|
||||||
# When uploading crates to the registry Cargo will automatically
|
# When uploading crates to the registry Cargo will automatically
|
||||||
# "normalize" Cargo.toml files for maximal compatibility
|
# "normalize" Cargo.toml files for maximal compatibility
|
||||||
@ -881,8 +839,14 @@ registry-index = "{}"
|
|||||||
[dependencies.ghi]
|
[dependencies.ghi]
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
"#,
|
"#,
|
||||||
registry::alt_registry()
|
registry::alt_registry()
|
||||||
)
|
);
|
||||||
|
|
||||||
|
validate_crate_contents(
|
||||||
|
f,
|
||||||
|
"foo-0.0.1.crate",
|
||||||
|
&["Cargo.toml", "Cargo.toml.orig", "src/main.rs"],
|
||||||
|
&[("Cargo.toml", &rewritten_toml)],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -923,21 +887,7 @@ fn ignore_workspace_specifier() {
|
|||||||
.run();
|
.run();
|
||||||
|
|
||||||
let f = File::open(&p.root().join("target/package/bar-0.1.0.crate")).unwrap();
|
let f = File::open(&p.root().join("target/package/bar-0.1.0.crate")).unwrap();
|
||||||
let mut rdr = GzDecoder::new(f);
|
let rewritten_toml = r#"# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||||
let mut contents = Vec::new();
|
|
||||||
rdr.read_to_end(&mut contents).unwrap();
|
|
||||||
let mut ar = Archive::new(&contents[..]);
|
|
||||||
let mut entry = ar
|
|
||||||
.entries()
|
|
||||||
.unwrap()
|
|
||||||
.map(|f| f.unwrap())
|
|
||||||
.find(|e| e.path().unwrap().ends_with("Cargo.toml"))
|
|
||||||
.unwrap();
|
|
||||||
let mut contents = String::new();
|
|
||||||
entry.read_to_string(&mut contents).unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
&contents[..],
|
|
||||||
r#"# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
|
||||||
#
|
#
|
||||||
# When uploading crates to the registry Cargo will automatically
|
# When uploading crates to the registry Cargo will automatically
|
||||||
# "normalize" Cargo.toml files for maximal compatibility
|
# "normalize" Cargo.toml files for maximal compatibility
|
||||||
@ -953,7 +903,12 @@ fn ignore_workspace_specifier() {
|
|||||||
name = "bar"
|
name = "bar"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = []
|
authors = []
|
||||||
"#
|
"#;
|
||||||
|
validate_crate_contents(
|
||||||
|
f,
|
||||||
|
"bar-0.1.0.crate",
|
||||||
|
&["Cargo.toml", "Cargo.toml.orig", "src/lib.rs"],
|
||||||
|
&[("Cargo.toml", &rewritten_toml)],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1123,23 +1078,12 @@ src/main.rs
|
|||||||
.run();
|
.run();
|
||||||
|
|
||||||
let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap();
|
let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap();
|
||||||
let mut rdr = GzDecoder::new(f);
|
validate_crate_contents(
|
||||||
let mut contents = Vec::new();
|
f,
|
||||||
rdr.read_to_end(&mut contents).unwrap();
|
"foo-0.0.1.crate",
|
||||||
let mut ar = Archive::new(&contents[..]);
|
&["Cargo.toml", "Cargo.toml.orig", "Cargo.lock", "src/main.rs"],
|
||||||
for f in ar.entries().unwrap() {
|
&[],
|
||||||
let f = f.unwrap();
|
);
|
||||||
let fname = f.header().path_bytes();
|
|
||||||
let fname = &*fname;
|
|
||||||
assert!(
|
|
||||||
fname == b"foo-0.0.1/Cargo.toml"
|
|
||||||
|| fname == b"foo-0.0.1/Cargo.toml.orig"
|
|
||||||
|| fname == b"foo-0.0.1/Cargo.lock"
|
|
||||||
|| fname == b"foo-0.0.1/src/main.rs",
|
|
||||||
"unexpected filename: {:?}",
|
|
||||||
f.header().path()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1202,15 +1146,12 @@ fn no_lock_file_with_library() {
|
|||||||
p.cargo("package").masquerade_as_nightly_cargo().run();
|
p.cargo("package").masquerade_as_nightly_cargo().run();
|
||||||
|
|
||||||
let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap();
|
let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap();
|
||||||
let mut rdr = GzDecoder::new(f);
|
validate_crate_contents(
|
||||||
let mut contents = Vec::new();
|
f,
|
||||||
rdr.read_to_end(&mut contents).unwrap();
|
"foo-0.0.1.crate",
|
||||||
let mut ar = Archive::new(&contents[..]);
|
&["Cargo.toml", "Cargo.toml.orig", "src/lib.rs"],
|
||||||
for f in ar.entries().unwrap() {
|
&[],
|
||||||
let f = f.unwrap();
|
);
|
||||||
let fname = f.header().path().unwrap();
|
|
||||||
assert!(!fname.ends_with("Cargo.lock"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1246,15 +1187,12 @@ fn lock_file_and_workspace() {
|
|||||||
.run();
|
.run();
|
||||||
|
|
||||||
let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap();
|
let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap();
|
||||||
let mut rdr = GzDecoder::new(f);
|
validate_crate_contents(
|
||||||
let mut contents = Vec::new();
|
f,
|
||||||
rdr.read_to_end(&mut contents).unwrap();
|
"foo-0.0.1.crate",
|
||||||
let mut ar = Archive::new(&contents[..]);
|
&["Cargo.toml", "Cargo.toml.orig", "src/main.rs", "Cargo.lock"],
|
||||||
assert!(ar.entries().unwrap().into_iter().any(|f| {
|
&[],
|
||||||
let f = f.unwrap();
|
);
|
||||||
let fname = f.header().path().unwrap();
|
|
||||||
fname.ends_with("Cargo.lock")
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1,12 +1,72 @@
|
|||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::io::SeekFrom;
|
|
||||||
|
|
||||||
use crate::support::git::repo;
|
use crate::support::git::repo;
|
||||||
use crate::support::paths;
|
use crate::support::paths;
|
||||||
use crate::support::{basic_manifest, project, publish};
|
use crate::support::{basic_manifest, project, publish};
|
||||||
use flate2::read::GzDecoder;
|
|
||||||
use tar::Archive;
|
const CLEAN_FOO_JSON: &str = r#"
|
||||||
|
{
|
||||||
|
"authors": [],
|
||||||
|
"badges": {},
|
||||||
|
"categories": [],
|
||||||
|
"deps": [],
|
||||||
|
"description": "foo",
|
||||||
|
"documentation": "foo",
|
||||||
|
"features": {},
|
||||||
|
"homepage": "foo",
|
||||||
|
"keywords": [],
|
||||||
|
"license": "MIT",
|
||||||
|
"license_file": null,
|
||||||
|
"links": null,
|
||||||
|
"name": "foo",
|
||||||
|
"readme": null,
|
||||||
|
"readme_file": null,
|
||||||
|
"repository": "foo",
|
||||||
|
"vers": "0.0.1"
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
fn validate_upload_foo() {
|
||||||
|
publish::validate_upload(
|
||||||
|
r#"
|
||||||
|
{
|
||||||
|
"authors": [],
|
||||||
|
"badges": {},
|
||||||
|
"categories": [],
|
||||||
|
"deps": [],
|
||||||
|
"description": "foo",
|
||||||
|
"documentation": null,
|
||||||
|
"features": {},
|
||||||
|
"homepage": null,
|
||||||
|
"keywords": [],
|
||||||
|
"license": "MIT",
|
||||||
|
"license_file": null,
|
||||||
|
"links": null,
|
||||||
|
"name": "foo",
|
||||||
|
"readme": null,
|
||||||
|
"readme_file": null,
|
||||||
|
"repository": null,
|
||||||
|
"vers": "0.0.1"
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
"foo-0.0.1.crate",
|
||||||
|
&["Cargo.toml", "Cargo.toml.orig", "src/main.rs"],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_upload_foo_clean() {
|
||||||
|
publish::validate_upload(
|
||||||
|
CLEAN_FOO_JSON,
|
||||||
|
"foo-0.0.1.crate",
|
||||||
|
&[
|
||||||
|
"Cargo.toml",
|
||||||
|
"Cargo.toml.orig",
|
||||||
|
"src/main.rs",
|
||||||
|
".cargo_vcs_info.json",
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn simple() {
|
fn simple() {
|
||||||
@ -41,37 +101,7 @@ See [..]
|
|||||||
))
|
))
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
let mut f = File::open(&publish::upload_path().join("api/v1/crates/new")).unwrap();
|
validate_upload_foo();
|
||||||
// Skip the metadata payload and the size of the tarball
|
|
||||||
let mut sz = [0; 4];
|
|
||||||
assert_eq!(f.read(&mut sz).unwrap(), 4);
|
|
||||||
let sz = (u32::from(sz[0]) << 0)
|
|
||||||
| (u32::from(sz[1]) << 8)
|
|
||||||
| (u32::from(sz[2]) << 16)
|
|
||||||
| (u32::from(sz[3]) << 24);
|
|
||||||
f.seek(SeekFrom::Current(i64::from(sz) + 4)).unwrap();
|
|
||||||
|
|
||||||
// Verify the tarball
|
|
||||||
let mut rdr = GzDecoder::new(f);
|
|
||||||
assert_eq!(
|
|
||||||
rdr.header().unwrap().filename().unwrap(),
|
|
||||||
b"foo-0.0.1.crate"
|
|
||||||
);
|
|
||||||
let mut contents = Vec::new();
|
|
||||||
rdr.read_to_end(&mut contents).unwrap();
|
|
||||||
let mut ar = Archive::new(&contents[..]);
|
|
||||||
for file in ar.entries().unwrap() {
|
|
||||||
let file = file.unwrap();
|
|
||||||
let fname = file.header().path_bytes();
|
|
||||||
let fname = &*fname;
|
|
||||||
assert!(
|
|
||||||
fname == b"foo-0.0.1/Cargo.toml"
|
|
||||||
|| fname == b"foo-0.0.1/Cargo.toml.orig"
|
|
||||||
|| fname == b"foo-0.0.1/src/main.rs",
|
|
||||||
"unexpected filename: {:?}",
|
|
||||||
file.header().path()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -116,37 +146,7 @@ See [..]
|
|||||||
))
|
))
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
let mut f = File::open(&publish::upload_path().join("api/v1/crates/new")).unwrap();
|
validate_upload_foo();
|
||||||
// Skip the metadata payload and the size of the tarball
|
|
||||||
let mut sz = [0; 4];
|
|
||||||
assert_eq!(f.read(&mut sz).unwrap(), 4);
|
|
||||||
let sz = (u32::from(sz[0]) << 0)
|
|
||||||
| (u32::from(sz[1]) << 8)
|
|
||||||
| (u32::from(sz[2]) << 16)
|
|
||||||
| (u32::from(sz[3]) << 24);
|
|
||||||
f.seek(SeekFrom::Current(i64::from(sz) + 4)).unwrap();
|
|
||||||
|
|
||||||
// Verify the tarball
|
|
||||||
let mut rdr = GzDecoder::new(f);
|
|
||||||
assert_eq!(
|
|
||||||
rdr.header().unwrap().filename().unwrap(),
|
|
||||||
b"foo-0.0.1.crate"
|
|
||||||
);
|
|
||||||
let mut contents = Vec::new();
|
|
||||||
rdr.read_to_end(&mut contents).unwrap();
|
|
||||||
let mut ar = Archive::new(&contents[..]);
|
|
||||||
for file in ar.entries().unwrap() {
|
|
||||||
let file = file.unwrap();
|
|
||||||
let fname = file.header().path_bytes();
|
|
||||||
let fname = &*fname;
|
|
||||||
assert!(
|
|
||||||
fname == b"foo-0.0.1/Cargo.toml"
|
|
||||||
|| fname == b"foo-0.0.1/Cargo.toml.orig"
|
|
||||||
|| fname == b"foo-0.0.1/src/main.rs",
|
|
||||||
"unexpected filename: {:?}",
|
|
||||||
file.header().path()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Deprecated
|
// TODO: Deprecated
|
||||||
@ -193,37 +193,7 @@ See [..]
|
|||||||
))
|
))
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
let mut f = File::open(&publish::upload_path().join("api/v1/crates/new")).unwrap();
|
validate_upload_foo();
|
||||||
// Skip the metadata payload and the size of the tarball
|
|
||||||
let mut sz = [0; 4];
|
|
||||||
assert_eq!(f.read(&mut sz).unwrap(), 4);
|
|
||||||
let sz = (u32::from(sz[0]) << 0)
|
|
||||||
| (u32::from(sz[1]) << 8)
|
|
||||||
| (u32::from(sz[2]) << 16)
|
|
||||||
| (u32::from(sz[3]) << 24);
|
|
||||||
f.seek(SeekFrom::Current(i64::from(sz) + 4)).unwrap();
|
|
||||||
|
|
||||||
// Verify the tarball
|
|
||||||
let mut rdr = GzDecoder::new(f);
|
|
||||||
assert_eq!(
|
|
||||||
rdr.header().unwrap().filename().unwrap(),
|
|
||||||
b"foo-0.0.1.crate"
|
|
||||||
);
|
|
||||||
let mut contents = Vec::new();
|
|
||||||
rdr.read_to_end(&mut contents).unwrap();
|
|
||||||
let mut ar = Archive::new(&contents[..]);
|
|
||||||
for file in ar.entries().unwrap() {
|
|
||||||
let file = file.unwrap();
|
|
||||||
let fname = file.header().path_bytes();
|
|
||||||
let fname = &*fname;
|
|
||||||
assert!(
|
|
||||||
fname == b"foo-0.0.1/Cargo.toml"
|
|
||||||
|| fname == b"foo-0.0.1/Cargo.toml.orig"
|
|
||||||
|| fname == b"foo-0.0.1/src/main.rs",
|
|
||||||
"unexpected filename: {:?}",
|
|
||||||
file.header().path()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Deprecated
|
// TODO: Deprecated
|
||||||
@ -272,37 +242,7 @@ See [..]
|
|||||||
))
|
))
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
let mut f = File::open(&publish::upload_path().join("api/v1/crates/new")).unwrap();
|
validate_upload_foo();
|
||||||
// Skip the metadata payload and the size of the tarball
|
|
||||||
let mut sz = [0; 4];
|
|
||||||
assert_eq!(f.read(&mut sz).unwrap(), 4);
|
|
||||||
let sz = (u32::from(sz[0]) << 0)
|
|
||||||
| (u32::from(sz[1]) << 8)
|
|
||||||
| (u32::from(sz[2]) << 16)
|
|
||||||
| (u32::from(sz[3]) << 24);
|
|
||||||
f.seek(SeekFrom::Current(i64::from(sz) + 4)).unwrap();
|
|
||||||
|
|
||||||
// Verify the tarball
|
|
||||||
let mut rdr = GzDecoder::new(f);
|
|
||||||
assert_eq!(
|
|
||||||
rdr.header().unwrap().filename().unwrap(),
|
|
||||||
b"foo-0.0.1.crate"
|
|
||||||
);
|
|
||||||
let mut contents = Vec::new();
|
|
||||||
rdr.read_to_end(&mut contents).unwrap();
|
|
||||||
let mut ar = Archive::new(&contents[..]);
|
|
||||||
for file in ar.entries().unwrap() {
|
|
||||||
let file = file.unwrap();
|
|
||||||
let fname = file.header().path_bytes();
|
|
||||||
let fname = &*fname;
|
|
||||||
assert!(
|
|
||||||
fname == b"foo-0.0.1/Cargo.toml"
|
|
||||||
|| fname == b"foo-0.0.1/Cargo.toml.orig"
|
|
||||||
|| fname == b"foo-0.0.1/src/main.rs",
|
|
||||||
"unexpected filename: {:?}",
|
|
||||||
file.header().path()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -479,6 +419,8 @@ fn publish_clean() {
|
|||||||
p.cargo("publish --index")
|
p.cargo("publish --index")
|
||||||
.arg(publish::registry().to_string())
|
.arg(publish::registry().to_string())
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
|
validate_upload_foo_clean();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -510,6 +452,8 @@ fn publish_in_sub_repo() {
|
|||||||
.arg("--index")
|
.arg("--index")
|
||||||
.arg(publish::registry().to_string())
|
.arg(publish::registry().to_string())
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
|
validate_upload_foo_clean();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -540,6 +484,18 @@ fn publish_when_ignored() {
|
|||||||
p.cargo("publish --index")
|
p.cargo("publish --index")
|
||||||
.arg(publish::registry().to_string())
|
.arg(publish::registry().to_string())
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
|
publish::validate_upload(
|
||||||
|
CLEAN_FOO_JSON,
|
||||||
|
"foo-0.0.1.crate",
|
||||||
|
&[
|
||||||
|
"Cargo.toml",
|
||||||
|
"Cargo.toml.orig",
|
||||||
|
"src/main.rs",
|
||||||
|
".gitignore",
|
||||||
|
".cargo_vcs_info.json",
|
||||||
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -570,6 +526,12 @@ fn ignore_when_crate_ignored() {
|
|||||||
.arg("--index")
|
.arg("--index")
|
||||||
.arg(publish::registry().to_string())
|
.arg(publish::registry().to_string())
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
|
publish::validate_upload(
|
||||||
|
CLEAN_FOO_JSON,
|
||||||
|
"foo-0.0.1.crate",
|
||||||
|
&["Cargo.toml", "Cargo.toml.orig", "src/main.rs", "baz"],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -778,6 +740,7 @@ fn publish_allowed_registry() {
|
|||||||
description = "foo"
|
description = "foo"
|
||||||
documentation = "foo"
|
documentation = "foo"
|
||||||
homepage = "foo"
|
homepage = "foo"
|
||||||
|
repository = "foo"
|
||||||
publish = ["alternative"]
|
publish = ["alternative"]
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
@ -787,6 +750,8 @@ fn publish_allowed_registry() {
|
|||||||
p.cargo("publish --registry alternative -Zunstable-options")
|
p.cargo("publish --registry alternative -Zunstable-options")
|
||||||
.masquerade_as_nightly_cargo()
|
.masquerade_as_nightly_cargo()
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
|
validate_upload_foo_clean();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1192,16 +1192,7 @@ impl Execs {
|
|||||||
Ok(actual) => actual,
|
Ok(actual) => actual,
|
||||||
};
|
};
|
||||||
|
|
||||||
match find_mismatch(expected, &actual) {
|
find_json_mismatch(expected, &actual)
|
||||||
Some((expected_part, actual_part)) => Err(format!(
|
|
||||||
"JSON mismatch\nExpected:\n{}\nWas:\n{}\nExpected part:\n{}\nActual part:\n{}\n",
|
|
||||||
serde_json::to_string_pretty(expected).unwrap(),
|
|
||||||
serde_json::to_string_pretty(&actual).unwrap(),
|
|
||||||
serde_json::to_string_pretty(expected_part).unwrap(),
|
|
||||||
serde_json::to_string_pretty(actual_part).unwrap(),
|
|
||||||
)),
|
|
||||||
None => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn diff_lines<'a>(
|
fn diff_lines<'a>(
|
||||||
@ -1292,12 +1283,28 @@ fn lines_match_works() {
|
|||||||
assert!(!lines_match("b", "cb"));
|
assert!(!lines_match("b", "cb"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compares JSON object for approximate equality.
|
/// Compares JSON object for approximate equality.
|
||||||
// You can use `[..]` wildcard in strings (useful for OS dependent things such
|
/// You can use `[..]` wildcard in strings (useful for OS dependent things such
|
||||||
// as paths). You can use a `"{...}"` string literal as a wildcard for
|
/// as paths). You can use a `"{...}"` string literal as a wildcard for
|
||||||
// arbitrary nested JSON (useful for parts of object emitted by other programs
|
/// arbitrary nested JSON (useful for parts of object emitted by other programs
|
||||||
// (e.g. rustc) rather than Cargo itself). Arrays are sorted before comparison.
|
/// (e.g. rustc) rather than Cargo itself). Arrays are sorted before comparison.
|
||||||
fn find_mismatch<'a>(expected: &'a Value, actual: &'a Value) -> Option<(&'a Value, &'a Value)> {
|
pub fn find_json_mismatch(expected: &Value, actual: &Value) -> Result<(), String> {
|
||||||
|
match find_json_mismatch_r(expected, &actual) {
|
||||||
|
Some((expected_part, actual_part)) => Err(format!(
|
||||||
|
"JSON mismatch\nExpected:\n{}\nWas:\n{}\nExpected part:\n{}\nActual part:\n{}\n",
|
||||||
|
serde_json::to_string_pretty(expected).unwrap(),
|
||||||
|
serde_json::to_string_pretty(&actual).unwrap(),
|
||||||
|
serde_json::to_string_pretty(expected_part).unwrap(),
|
||||||
|
serde_json::to_string_pretty(actual_part).unwrap(),
|
||||||
|
)),
|
||||||
|
None => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_json_mismatch_r<'a>(
|
||||||
|
expected: &'a Value,
|
||||||
|
actual: &'a Value,
|
||||||
|
) -> Option<(&'a Value, &'a Value)> {
|
||||||
use serde_json::Value::*;
|
use serde_json::Value::*;
|
||||||
match (expected, actual) {
|
match (expected, actual) {
|
||||||
(&Number(ref l), &Number(ref r)) if l == r => None,
|
(&Number(ref l), &Number(ref r)) if l == r => None,
|
||||||
@ -1312,7 +1319,7 @@ fn find_mismatch<'a>(expected: &'a Value, actual: &'a Value) -> Option<(&'a Valu
|
|||||||
let mut r = r.iter().collect::<Vec<_>>();
|
let mut r = r.iter().collect::<Vec<_>>();
|
||||||
|
|
||||||
l.retain(
|
l.retain(
|
||||||
|l| match r.iter().position(|r| find_mismatch(l, r).is_none()) {
|
|l| match r.iter().position(|r| find_json_mismatch_r(l, r).is_none()) {
|
||||||
Some(i) => {
|
Some(i) => {
|
||||||
r.remove(i);
|
r.remove(i);
|
||||||
false
|
false
|
||||||
@ -1337,7 +1344,7 @@ fn find_mismatch<'a>(expected: &'a Value, actual: &'a Value) -> Option<(&'a Valu
|
|||||||
|
|
||||||
l.values()
|
l.values()
|
||||||
.zip(r.values())
|
.zip(r.values())
|
||||||
.filter_map(|(l, r)| find_mismatch(l, r))
|
.filter_map(|(l, r)| find_json_mismatch_r(l, r))
|
||||||
.nth(0)
|
.nth(0)
|
||||||
}
|
}
|
||||||
(&Null, &Null) => None,
|
(&Null, &Null) => None,
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
use std::io::prelude::*;
|
use std::io::{prelude::*, SeekFrom};
|
||||||
use std::path::PathBuf;
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use crate::support::git::{repo, Repository};
|
use crate::support::git::{repo, Repository};
|
||||||
use crate::support::paths;
|
use crate::support::registry::alt_api_path;
|
||||||
|
use crate::support::{find_json_mismatch, paths};
|
||||||
|
|
||||||
|
use byteorder::{LittleEndian, ReadBytesExt};
|
||||||
|
use flate2::read::GzDecoder;
|
||||||
|
use tar::Archive;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
pub fn setup() -> Repository {
|
pub fn setup() -> Repository {
|
||||||
@ -61,3 +66,116 @@ pub fn upload_path() -> PathBuf {
|
|||||||
fn upload() -> Url {
|
fn upload() -> Url {
|
||||||
Url::from_file_path(&*upload_path()).ok().unwrap()
|
Url::from_file_path(&*upload_path()).ok().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check the result of a crate publish.
|
||||||
|
pub fn validate_upload(expected_json: &str, expected_crate_name: &str, expected_files: &[&str]) {
|
||||||
|
let new_path = upload_path().join("api/v1/crates/new");
|
||||||
|
_validate_upload(
|
||||||
|
&new_path,
|
||||||
|
expected_json,
|
||||||
|
expected_crate_name,
|
||||||
|
expected_files,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check the result of a crate publish to an alternative registry.
|
||||||
|
pub fn validate_alt_upload(
|
||||||
|
expected_json: &str,
|
||||||
|
expected_crate_name: &str,
|
||||||
|
expected_files: &[&str],
|
||||||
|
) {
|
||||||
|
let new_path = alt_api_path().join("api/v1/crates/new");
|
||||||
|
_validate_upload(
|
||||||
|
&new_path,
|
||||||
|
expected_json,
|
||||||
|
expected_crate_name,
|
||||||
|
expected_files,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _validate_upload(
|
||||||
|
new_path: &Path,
|
||||||
|
expected_json: &str,
|
||||||
|
expected_crate_name: &str,
|
||||||
|
expected_files: &[&str],
|
||||||
|
) {
|
||||||
|
let mut f = File::open(new_path).unwrap();
|
||||||
|
// 32-bit little-endian integer of length of JSON data.
|
||||||
|
let json_sz = f.read_u32::<LittleEndian>().expect("read json length");
|
||||||
|
let mut json_bytes = vec![0; json_sz as usize];
|
||||||
|
f.read_exact(&mut json_bytes).expect("read JSON data");
|
||||||
|
let actual_json = serde_json::from_slice(&json_bytes).expect("uploaded JSON should be valid");
|
||||||
|
let expected_json = serde_json::from_str(expected_json).expect("expected JSON does not parse");
|
||||||
|
find_json_mismatch(&expected_json, &actual_json)
|
||||||
|
.expect("uploaded JSON did not match expected JSON");
|
||||||
|
|
||||||
|
// 32-bit little-endian integer of length of crate file.
|
||||||
|
let crate_sz = f.read_u32::<LittleEndian>().expect("read crate length");
|
||||||
|
let mut krate_bytes = vec![0; crate_sz as usize];
|
||||||
|
f.read_exact(&mut krate_bytes).expect("read crate data");
|
||||||
|
// Check at end.
|
||||||
|
let current = f.seek(SeekFrom::Current(0)).unwrap();
|
||||||
|
assert_eq!(f.seek(SeekFrom::End(0)).unwrap(), current);
|
||||||
|
|
||||||
|
// Verify the tarball
|
||||||
|
validate_crate_contents(&krate_bytes[..], expected_crate_name, expected_files, &[]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check the contents of a `.crate` file.
|
||||||
|
///
|
||||||
|
/// - `expected_crate_name` should be something like `foo-0.0.1.crate`.
|
||||||
|
/// - `expected_files` should be a complete list of files in the crate
|
||||||
|
/// (relative to expected_crate_name).
|
||||||
|
/// - `expected_contents` should be a list of `(file_name, contents)` tuples
|
||||||
|
/// to validate the contents of the given file. Only the listed files will
|
||||||
|
/// be checked (others will be ignored).
|
||||||
|
pub fn validate_crate_contents(
|
||||||
|
reader: impl Read,
|
||||||
|
expected_crate_name: &str,
|
||||||
|
expected_files: &[&str],
|
||||||
|
expected_contents: &[(&str, &str)],
|
||||||
|
) {
|
||||||
|
let mut rdr = GzDecoder::new(reader);
|
||||||
|
assert_eq!(
|
||||||
|
rdr.header().unwrap().filename().unwrap(),
|
||||||
|
expected_crate_name.as_bytes()
|
||||||
|
);
|
||||||
|
let mut contents = Vec::new();
|
||||||
|
rdr.read_to_end(&mut contents).unwrap();
|
||||||
|
let mut ar = Archive::new(&contents[..]);
|
||||||
|
let files: HashMap<PathBuf, String> = ar
|
||||||
|
.entries()
|
||||||
|
.unwrap()
|
||||||
|
.map(|entry| {
|
||||||
|
let mut entry = entry.unwrap();
|
||||||
|
let name = entry.path().unwrap().into_owned();
|
||||||
|
let mut contents = String::new();
|
||||||
|
entry.read_to_string(&mut contents).unwrap();
|
||||||
|
(name, contents)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
assert!(expected_crate_name.ends_with(".crate"));
|
||||||
|
let base_crate_name = Path::new(&expected_crate_name[..expected_crate_name.len() - 6]);
|
||||||
|
let actual_files: HashSet<PathBuf> = files.keys().cloned().collect();
|
||||||
|
let expected_files: HashSet<PathBuf> = expected_files
|
||||||
|
.iter()
|
||||||
|
.map(|name| base_crate_name.join(name))
|
||||||
|
.collect();
|
||||||
|
let missing: Vec<&PathBuf> = expected_files.difference(&actual_files).collect();
|
||||||
|
let extra: Vec<&PathBuf> = actual_files.difference(&expected_files).collect();
|
||||||
|
if !missing.is_empty() || !extra.is_empty() {
|
||||||
|
panic!(
|
||||||
|
"uploaded archive does not match.\nMissing: {:?}\nExtra: {:?}\n",
|
||||||
|
missing, extra
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if !expected_contents.is_empty() {
|
||||||
|
for (e_file_name, e_file_contents) in expected_contents {
|
||||||
|
let full_e_name = base_crate_name.join(e_file_name);
|
||||||
|
let actual_contents = files
|
||||||
|
.get(&full_e_name)
|
||||||
|
.unwrap_or_else(|| panic!("file `{}` missing in archive", e_file_name));
|
||||||
|
assert_eq!(actual_contents, e_file_contents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@ use std::fs::{self, File};
|
|||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use cargo::sources::CRATES_IO_INDEX;
|
||||||
use cargo::util::Sha256;
|
use cargo::util::Sha256;
|
||||||
use flate2::write::GzEncoder;
|
use flate2::write::GzEncoder;
|
||||||
use flate2::Compression;
|
use flate2::Compression;
|
||||||
@ -277,10 +278,9 @@ impl Package {
|
|||||||
self.add_dep(Dependency::new(name, vers).target(target))
|
self.add_dep(Dependency::new(name, vers).target(target))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a dependency to an alternative registry.
|
/// Add a dependency to the alternative registry.
|
||||||
/// The given registry should be a URI to the alternative registry.
|
pub fn registry_dep(&mut self, name: &str, vers: &str) -> &mut Package {
|
||||||
pub fn registry_dep(&mut self, name: &str, vers: &str, registry: &str) -> &mut Package {
|
self.add_dep(Dependency::new(name, vers).registry("alternative"))
|
||||||
self.add_dep(Dependency::new(name, vers).registry(registry))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a dev-dependency. Example:
|
/// Add a dev-dependency. Example:
|
||||||
@ -333,6 +333,16 @@ impl Package {
|
|||||||
.deps
|
.deps
|
||||||
.iter()
|
.iter()
|
||||||
.map(|dep| {
|
.map(|dep| {
|
||||||
|
// In the index, the `registry` is null if it is from the same registry.
|
||||||
|
// In Cargo.toml, it is None if it is from crates.io.
|
||||||
|
let registry_url =
|
||||||
|
match (self.alternative, dep.registry.as_ref().map(|s| s.as_ref())) {
|
||||||
|
(false, None) => None,
|
||||||
|
(false, Some("alternative")) => Some(alt_registry().to_string()),
|
||||||
|
(true, None) => Some(CRATES_IO_INDEX.to_string()),
|
||||||
|
(true, Some("alternative")) => None,
|
||||||
|
_ => panic!("registry_dep currently only supports `alternative`"),
|
||||||
|
};
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"name": dep.name,
|
"name": dep.name,
|
||||||
"req": dep.vers,
|
"req": dep.vers,
|
||||||
@ -341,7 +351,7 @@ impl Package {
|
|||||||
"target": dep.target,
|
"target": dep.target,
|
||||||
"optional": dep.optional,
|
"optional": dep.optional,
|
||||||
"kind": dep.kind,
|
"kind": dep.kind,
|
||||||
"registry": dep.registry,
|
"registry": registry_url,
|
||||||
"package": dep.package,
|
"package": dep.package,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -412,14 +422,19 @@ impl Package {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn make_archive(&self) {
|
fn make_archive(&self) {
|
||||||
|
let features = if self.deps.iter().any(|dep| dep.registry.is_some()) {
|
||||||
|
"cargo-features = [\"alternative-registries\"]\n"
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
let mut manifest = format!(
|
let mut manifest = format!(
|
||||||
r#"
|
r#"
|
||||||
[package]
|
{}[package]
|
||||||
name = "{}"
|
name = "{}"
|
||||||
version = "{}"
|
version = "{}"
|
||||||
authors = []
|
authors = []
|
||||||
"#,
|
"#,
|
||||||
self.name, self.vers
|
features, self.name, self.vers
|
||||||
);
|
);
|
||||||
for dep in self.deps.iter() {
|
for dep in self.deps.iter() {
|
||||||
let target = match dep.target {
|
let target = match dep.target {
|
||||||
@ -438,6 +453,9 @@ impl Package {
|
|||||||
"#,
|
"#,
|
||||||
target, kind, dep.name, dep.vers
|
target, kind, dep.name, dep.vers
|
||||||
));
|
));
|
||||||
|
if let Some(registry) = &dep.registry {
|
||||||
|
manifest.push_str(&format!("registry = \"{}\"", registry));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let dst = self.archive_dst();
|
let dst = self.archive_dst();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user