diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs index e0b8d36016d..14087106492 100644 --- a/src/cargo/core/manifest.rs +++ b/src/cargo/core/manifest.rs @@ -1,12 +1,14 @@ use std::collections::HashMap; use std::fmt; use std::path::{PathBuf, Path}; +use std::rc::Rc; use semver::Version; use serde::ser; use core::{Dependency, PackageId, Summary, SourceId, PackageIdSpec}; use core::WorkspaceConfig; +use util::toml::TomlManifest; pub enum EitherManifest { Real(Manifest), @@ -14,7 +16,7 @@ pub enum EitherManifest { } /// Contains all the information about a package, as loaded from a Cargo.toml. -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct Manifest { summary: Summary, targets: Vec, @@ -27,6 +29,7 @@ pub struct Manifest { publish: bool, replace: Vec<(PackageIdSpec, Dependency)>, workspace: WorkspaceConfig, + original: Rc, } #[derive(Clone, Debug)] @@ -222,7 +225,8 @@ impl Manifest { profiles: Profiles, publish: bool, replace: Vec<(PackageIdSpec, Dependency)>, - workspace: WorkspaceConfig) -> Manifest { + workspace: WorkspaceConfig, + original: Rc) -> Manifest { Manifest { summary: summary, targets: targets, @@ -235,6 +239,7 @@ impl Manifest { publish: publish, replace: replace, workspace: workspace, + original: original, } } @@ -251,6 +256,7 @@ impl Manifest { pub fn profiles(&self) -> &Profiles { &self.profiles } pub fn publish(&self) -> bool { self.publish } pub fn replace(&self) -> &[(PackageIdSpec, Dependency)] { &self.replace } + pub fn original(&self) -> &TomlManifest { &self.original } pub fn links(&self) -> Option<&str> { self.links.as_ref().map(|s| &s[..]) } diff --git a/src/cargo/core/package.rs b/src/cargo/core/package.rs index 898745460f9..943f570d335 100644 --- a/src/cargo/core/package.rs +++ b/src/cargo/core/package.rs @@ -6,6 +6,7 @@ use std::path::{Path, PathBuf}; use semver::Version; use serde::ser; +use toml; use core::{Dependency, Manifest, PackageId, SourceId, Target}; use core::{Summary, SourceMap}; @@ -16,7 +17,7 @@ use util::{CargoResult, Config, LazyCell, ChainError, internal, human, lev_dista /// /// A package is a `Cargo.toml` file plus all the files that are part of it. // TODO: Is manifest_path a relic? -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct Package { // The package's manifest manifest: Manifest, @@ -117,6 +118,26 @@ impl Package { manifest_path: self.manifest_path, } } + + pub fn to_registry_toml(&self) -> String { + let manifest = self.manifest().original().prepare_for_publish(); + let toml = toml::to_string(&manifest).unwrap(); + format!("\ + # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO\n\ + #\n\ + # When uploading crates to the registry Cargo will automatically\n\ + # \"normalize\" Cargo.toml files for maximal compatibility\n\ + # with all versions of Cargo and also rewrite `path` dependencies\n\ + # to registry (e.g. crates.io) dependencies\n\ + #\n\ + # If you believe there's an error in this file please file an\n\ + # issue against the rust-lang/cargo repository. If you're\n\ + # editing this file be aware that the upstream Cargo.toml\n\ + # will likely look very different (and much more reasonable)\n\ + \n\ + {}\ + ", toml) + } } impl fmt::Display for Package { diff --git a/src/cargo/core/workspace.rs b/src/cargo/core/workspace.rs index 5015448a569..0607e828bcd 100644 --- a/src/cargo/core/workspace.rs +++ b/src/cargo/core/workspace.rs @@ -124,7 +124,9 @@ impl<'cfg> Workspace<'cfg> { /// /// This is currently only used in niche situations like `cargo install` or /// `cargo package`. - pub fn ephemeral(package: Package, config: &'cfg Config, target_dir: Option, + pub fn ephemeral(package: Package, + config: &'cfg Config, + target_dir: Option, require_optional_deps: bool) -> CargoResult> { let mut ws = Workspace { config: config, diff --git a/src/cargo/ops/cargo_package.rs b/src/cargo/ops/cargo_package.rs index 107a4f2a554..de788bab5b6 100644 --- a/src/cargo/ops/cargo_package.rs +++ b/src/cargo/ops/cargo_package.rs @@ -7,9 +7,9 @@ use std::sync::Arc; use flate2::read::GzDecoder; use flate2::{GzBuilder, Compression}; use git2; -use tar::{Archive, Builder, Header}; +use tar::{Archive, Builder, Header, EntryType}; -use core::{SourceId, Package, PackageId, Workspace, Source}; +use core::{Package, Workspace, Source, SourceId}; use sources::PathSource; use util::{self, CargoResult, human, internal, ChainError, Config, FileLock}; use ops::{self, DefaultExecutor}; @@ -202,9 +202,6 @@ fn tar(ws: &Workspace, human(format!("non-utf8 path in source directory: {}", relative.display())) })?; - let mut file = File::open(file).chain_error(|| { - human(format!("failed to open for archiving: `{}`", file.display())) - })?; config.shell().verbose(|shell| { shell.status("Archiving", &relative) })?; @@ -230,18 +227,41 @@ fn tar(ws: &Workspace, // unpack the selectors 0.4.0 crate on crates.io. Either that or take a // look at rust-lang/cargo#2326 let mut header = Header::new_ustar(); - let metadata = file.metadata().chain_error(|| { - human(format!("could not learn metadata for: `{}`", relative)) - })?; header.set_path(&path).chain_error(|| { human(format!("failed to add to archive: `{}`", relative)) })?; + let mut file = File::open(file).chain_error(|| { + human(format!("failed to open for archiving: `{}`", file.display())) + })?; + let metadata = file.metadata().chain_error(|| { + human(format!("could not learn metadata for: `{}`", relative)) + })?; header.set_metadata(&metadata); - header.set_cksum(); - ar.append(&header, &mut file).chain_error(|| { - internal(format!("could not archive source file `{}`", relative)) - })?; + if relative == "Cargo.toml" { + let orig = Path::new(&path).with_file_name("Cargo.toml.orig"); + header.set_path(&orig)?; + header.set_cksum(); + ar.append(&header, &mut file).chain_error(|| { + internal(format!("could not archive source file `{}`", relative)) + })?; + + let mut header = Header::new_ustar(); + let toml = pkg.to_registry_toml(); + header.set_path(&path)?; + header.set_entry_type(EntryType::file()); + header.set_mode(0o644); + header.set_size(toml.len() as u64); + header.set_cksum(); + ar.append(&header, toml.as_bytes()).chain_error(|| { + internal(format!("could not archive source file `{}`", relative)) + })?; + } else { + header.set_cksum(); + ar.append(&header, &mut file).chain_error(|| { + internal(format!("could not archive source file `{}`", relative)) + })?; + } } let encoder = ar.into_inner()?; encoder.finish()?; @@ -262,30 +282,14 @@ fn run_verify(ws: &Workspace, tar: &File, opts: &PackageOpts) -> CargoResult<()> } let mut archive = Archive::new(f); archive.unpack(dst.parent().unwrap())?; - let manifest_path = dst.join("Cargo.toml"); - // When packages are uploaded to a registry, all path dependencies are - // implicitly converted to registry dependencies, so we rewrite those - // dependencies here. - // - // We also make sure to point all paths at `dst` instead of the previous - // location that the package was originally read from. In locking the - // `SourceId` we're telling it that the corresponding `PathSource` will be - // considered updated and we won't actually read any packages. - let cratesio = SourceId::crates_io(config)?; - let precise = Some("locked".to_string()); - let new_src = SourceId::for_path(&dst)?.with_precise(precise); - let new_pkgid = PackageId::new(pkg.name(), pkg.version(), &new_src)?; - let new_summary = pkg.summary().clone().map_dependencies(|d| { - if !d.source_id().is_path() { return d } - d.clone_inner().set_source_id(cratesio.clone()).into_dependency() - }); - let mut new_manifest = pkg.manifest().clone(); - new_manifest.set_summary(new_summary.override_id(new_pkgid)); - let new_pkg = Package::new(new_manifest, &manifest_path); - - // Now that we've rewritten all our path dependencies, compile it! + // Manufacture an ephemeral workspace to ensure that even if the top-level + // package has a workspace we can still build our new crate. + let id = SourceId::for_path(&dst)?; + let mut src = PathSource::new(&dst, &id, ws.config()); + let new_pkg = src.root_package()?; let ws = Workspace::ephemeral(new_pkg, config, None, true)?; + ops::compile_ws(&ws, None, &ops::CompileOptions { config: config, jobs: opts.jobs, diff --git a/src/cargo/ops/cargo_rustc/context.rs b/src/cargo/ops/cargo_rustc/context.rs index e17a0823b6c..34d9c8cc9b6 100644 --- a/src/cargo/ops/cargo_rustc/context.rs +++ b/src/cargo/ops/cargo_rustc/context.rs @@ -20,7 +20,7 @@ use super::layout::Layout; use super::links::Links; use super::{Kind, Compilation, BuildConfig}; -#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] +#[derive(Clone, Copy, Eq, PartialEq, Hash)] pub struct Unit<'a> { pub pkg: &'a Package, pub target: &'a Target, diff --git a/src/cargo/util/toml.rs b/src/cargo/util/toml.rs index 771f48ddfda..254d0328017 100644 --- a/src/cargo/util/toml.rs +++ b/src/cargo/util/toml.rs @@ -1,12 +1,13 @@ use std::collections::{HashMap, HashSet, BTreeSet}; -use std::default::Default; use std::fmt; use std::fs; use std::path::{Path, PathBuf}; +use std::rc::Rc; use std::str; use toml; use semver::{self, VersionReq}; +use serde::ser; use serde::de::{self, Deserialize}; use serde_ignored; @@ -112,7 +113,11 @@ pub fn to_manifest(contents: &str, } })?; - return match manifest.to_real_manifest(source_id, &layout, config) { + let manifest = Rc::new(manifest); + return match TomlManifest::to_real_manifest(&manifest, + source_id, + &layout, + config) { Ok((mut manifest, paths)) => { for key in unused { manifest.add_warning(format!("unused manifest key: {}", key)); @@ -125,7 +130,10 @@ pub fn to_manifest(contents: &str, Ok((EitherManifest::Real(manifest), paths)) } Err(e) => { - match manifest.to_virtual_manifest(source_id, &layout, config) { + match TomlManifest::to_virtual_manifest(&manifest, + source_id, + &layout, + config) { Ok((m, paths)) => Ok((EitherManifest::Virtual(m), paths)), Err(..) => Err(e), } @@ -192,6 +200,8 @@ type TomlExampleTarget = TomlTarget; type TomlTestTarget = TomlTarget; type TomlBenchTarget = TomlTarget; +#[derive(Serialize)] +#[serde(untagged)] pub enum TomlDependency { Simple(String), Detailed(DetailedTomlDependency) @@ -229,7 +239,7 @@ impl<'de> de::Deserialize<'de> for TomlDependency { } } -#[derive(Deserialize, Clone, Default)] +#[derive(Deserialize, Serialize, Clone, Default)] pub struct DetailedTomlDependency { version: Option, path: Option, @@ -245,7 +255,7 @@ pub struct DetailedTomlDependency { default_features2: Option, } -#[derive(Deserialize)] +#[derive(Deserialize, Serialize)] pub struct TomlManifest { package: Option>, project: Option>, @@ -271,7 +281,7 @@ pub struct TomlManifest { badges: Option>>, } -#[derive(Deserialize, Clone, Default)] +#[derive(Deserialize, Serialize, Clone, Default)] pub struct TomlProfiles { test: Option, doc: Option, @@ -318,7 +328,19 @@ impl<'de> de::Deserialize<'de> for TomlOptLevel { } } -#[derive(Clone)] +impl ser::Serialize for TomlOptLevel { + fn serialize(&self, serializer: S) -> Result + where S: ser::Serializer, + { + match self.0.parse::() { + Ok(n) => n.serialize(serializer), + Err(_) => self.0.serialize(serializer), + } + } +} + +#[derive(Clone, Serialize)] +#[serde(untagged)] pub enum U32OrBool { U32(u32), Bool(bool), @@ -360,7 +382,7 @@ impl<'de> de::Deserialize<'de> for U32OrBool { } } -#[derive(Deserialize, Clone, Default)] +#[derive(Deserialize, Serialize, Clone, Default)] pub struct TomlProfile { #[serde(rename = "opt-level")] opt_level: Option, @@ -376,7 +398,8 @@ pub struct TomlProfile { overflow_checks: Option, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize)] +#[serde(untagged)] pub enum StringOrBool { String(String), Bool(bool), @@ -412,7 +435,7 @@ impl<'de> de::Deserialize<'de> for StringOrBool { } } -#[derive(Deserialize)] +#[derive(Deserialize, Serialize, Clone)] pub struct TomlProject { name: String, version: TomlVersion, @@ -437,12 +460,13 @@ pub struct TomlProject { repository: Option, } -#[derive(Deserialize)] +#[derive(Deserialize, Serialize)] pub struct TomlWorkspace { members: Option>, exclude: Option>, } +#[derive(Clone)] pub struct TomlVersion { version: semver::Version, } @@ -474,6 +498,15 @@ impl<'de> de::Deserialize<'de> for TomlVersion { } } +impl ser::Serialize for TomlVersion { + fn serialize(&self, s: S) -> Result + where S: ser::Serializer, + { + self.version.to_string().serialize(s) + } +} + + impl TomlProject { pub fn to_package_id(&self, source_id: &SourceId) -> CargoResult { PackageId::new(&self.name, self.version.version.clone(), @@ -564,7 +597,72 @@ fn inferred_bench_targets(layout: &Layout) -> Vec { } impl TomlManifest { - fn to_real_manifest(&self, + pub fn prepare_for_publish(&self) -> TomlManifest { + let mut package = self.package.as_ref() + .or(self.project.as_ref()) + .unwrap() + .clone(); + package.workspace = None; + return TomlManifest { + package: Some(package), + project: None, + profile: self.profile.clone(), + lib: self.lib.clone(), + bin: self.bin.clone(), + example: self.example.clone(), + test: self.test.clone(), + bench: self.bench.clone(), + dependencies: map_deps(self.dependencies.as_ref()), + dev_dependencies: map_deps(self.dev_dependencies.as_ref() + .or(self.dev_dependencies2.as_ref())), + dev_dependencies2: None, + build_dependencies: map_deps(self.build_dependencies.as_ref() + .or(self.build_dependencies2.as_ref())), + build_dependencies2: None, + features: self.features.clone(), + target: self.target.as_ref().map(|target_map| { + target_map.iter().map(|(k, v)| { + (k.clone(), TomlPlatform { + dependencies: map_deps(v.dependencies.as_ref()), + dev_dependencies: map_deps(v.dev_dependencies.as_ref() + .or(v.dev_dependencies2.as_ref())), + dev_dependencies2: None, + build_dependencies: map_deps(v.build_dependencies.as_ref() + .or(v.build_dependencies2.as_ref())), + build_dependencies2: None, + }) + }).collect() + }), + replace: None, + workspace: None, + badges: self.badges.clone(), + }; + + fn map_deps(deps: Option<&HashMap>) + -> Option> + { + let deps = match deps { + Some(deps) => deps, + None => return None + }; + Some(deps.iter().map(|(k, v)| (k.clone(), map_dependency(v))).collect()) + } + + fn map_dependency(dep: &TomlDependency) -> TomlDependency { + match *dep { + TomlDependency::Detailed(ref d) => { + let mut d = d.clone(); + d.path.take(); // path dependencies become crates.io deps + TomlDependency::Detailed(d) + } + TomlDependency::Simple(ref s) => { + TomlDependency::Simple(s.clone()) + } + } + } + } + + fn to_real_manifest(me: &Rc, source_id: &SourceId, layout: &Layout, config: &Config) @@ -572,7 +670,7 @@ impl TomlManifest { let mut nested_paths = vec![]; let mut warnings = vec![]; - let project = self.project.as_ref().or_else(|| self.package.as_ref()); + let project = me.project.as_ref().or_else(|| me.package.as_ref()); let project = project.chain_error(|| { human("no `package` or `project` section found.") })?; @@ -587,7 +685,7 @@ impl TomlManifest { // If we have a lib with a path, we're done // If we have a lib with no path, use the inferred lib or_else package name - let lib = match self.lib { + let lib = match me.lib { Some(ref lib) => { lib.validate_library_name()?; lib.validate_crate_type()?; @@ -604,7 +702,7 @@ impl TomlManifest { None => inferred_lib_target(&project.name, layout), }; - let bins = match self.bin { + let bins = match me.bin { Some(ref bins) => { for target in bins { target.validate_binary_name()?; @@ -621,7 +719,7 @@ impl TomlManifest { } } - let examples = match self.example { + let examples = match me.example { Some(ref examples) => { for target in examples { target.validate_example_name()?; @@ -631,7 +729,7 @@ impl TomlManifest { None => inferred_example_targets(layout) }; - let tests = match self.test { + let tests = match me.test { Some(ref tests) => { for target in tests { target.validate_test_name()?; @@ -641,7 +739,7 @@ impl TomlManifest { None => inferred_test_targets(layout) }; - let benches = match self.bench { + let benches = match me.bench { Some(ref benches) => { for target in benches { target.validate_bench_name()?; @@ -672,7 +770,7 @@ impl TomlManifest { } // processing the custom build script - let new_build = self.maybe_custom_build(&project.build, &layout.root); + let new_build = me.maybe_custom_build(&project.build, &layout.root); // Get targets let targets = normalize(&layout.root, @@ -727,16 +825,16 @@ impl TomlManifest { } // Collect the deps - process_dependencies(&mut cx, self.dependencies.as_ref(), + process_dependencies(&mut cx, me.dependencies.as_ref(), None)?; - let dev_deps = self.dev_dependencies.as_ref() - .or(self.dev_dependencies2.as_ref()); + let dev_deps = me.dev_dependencies.as_ref() + .or(me.dev_dependencies2.as_ref()); process_dependencies(&mut cx, dev_deps, Some(Kind::Development))?; - let build_deps = self.build_dependencies.as_ref() - .or(self.build_dependencies2.as_ref()); + let build_deps = me.build_dependencies.as_ref() + .or(me.build_dependencies2.as_ref()); process_dependencies(&mut cx, build_deps, Some(Kind::Build))?; - for (name, platform) in self.target.iter().flat_map(|t| t) { + for (name, platform) in me.target.iter().flat_map(|t| t) { cx.platform = Some(name.parse()?); process_dependencies(&mut cx, platform.dependencies.as_ref(), None)?; @@ -748,7 +846,7 @@ impl TomlManifest { process_dependencies(&mut cx, dev_deps, Some(Kind::Development))?; } - replace = self.replace(&mut cx)?; + replace = me.replace(&mut cx)?; } { @@ -767,7 +865,7 @@ impl TomlManifest { let exclude = project.exclude.clone().unwrap_or(Vec::new()); let include = project.include.clone().unwrap_or(Vec::new()); - let summary = Summary::new(pkgid, deps, self.features.clone() + let summary = Summary::new(pkgid, deps, me.features.clone() .unwrap_or_else(HashMap::new))?; let metadata = ManifestMetadata { description: project.description.clone(), @@ -780,10 +878,10 @@ impl TomlManifest { repository: project.repository.clone(), keywords: project.keywords.clone().unwrap_or(Vec::new()), categories: project.categories.clone().unwrap_or(Vec::new()), - badges: self.badges.clone().unwrap_or_else(HashMap::new), + badges: me.badges.clone().unwrap_or_else(HashMap::new), }; - let workspace_config = match (self.workspace.as_ref(), + let workspace_config = match (me.workspace.as_ref(), project.workspace.as_ref()) { (Some(config), None) => { WorkspaceConfig::Root { @@ -799,7 +897,7 @@ impl TomlManifest { `[workspace]`, only one can be specified") } }; - let profiles = build_profiles(&self.profile); + let profiles = build_profiles(&me.profile); let publish = project.publish.unwrap_or(true); let mut manifest = Manifest::new(summary, targets, @@ -810,7 +908,8 @@ impl TomlManifest { profiles, publish, replace, - workspace_config); + workspace_config, + me.clone()); if project.license_file.is_some() && project.license.is_some() { manifest.add_warning("only one of `license` or \ `license-file` is necessary".to_string()); @@ -822,37 +921,37 @@ impl TomlManifest { Ok((manifest, nested_paths)) } - fn to_virtual_manifest(&self, + fn to_virtual_manifest(me: &Rc, source_id: &SourceId, layout: &Layout, config: &Config) -> CargoResult<(VirtualManifest, Vec)> { - if self.project.is_some() { + if me.project.is_some() { bail!("virtual manifests do not define [project]"); } - if self.package.is_some() { + if me.package.is_some() { bail!("virtual manifests do not define [package]"); } - if self.lib.is_some() { + if me.lib.is_some() { bail!("virtual manifests do not specifiy [lib]"); } - if self.bin.is_some() { + if me.bin.is_some() { bail!("virtual manifests do not specifiy [[bin]]"); } - if self.example.is_some() { + if me.example.is_some() { bail!("virtual manifests do not specifiy [[example]]"); } - if self.test.is_some() { + if me.test.is_some() { bail!("virtual manifests do not specifiy [[test]]"); } - if self.bench.is_some() { + if me.bench.is_some() { bail!("virtual manifests do not specifiy [[bench]]"); } let mut nested_paths = Vec::new(); let mut warnings = Vec::new(); let mut deps = Vec::new(); - let replace = self.replace(&mut Context { + let replace = me.replace(&mut Context { pkgid: None, deps: &mut deps, source_id: source_id, @@ -862,8 +961,8 @@ impl TomlManifest { platform: None, layout: layout, })?; - let profiles = build_profiles(&self.profile); - let workspace_config = match self.workspace { + let profiles = build_profiles(&me.profile); + let workspace_config = match me.workspace { Some(ref config) => { WorkspaceConfig::Root { members: config.members.clone(), @@ -1070,7 +1169,7 @@ impl TomlDependency { } } -#[derive(Default, Deserialize, Debug, Clone)] +#[derive(Default, Serialize, Deserialize, Debug, Clone)] struct TomlTarget { name: Option, @@ -1107,8 +1206,16 @@ impl<'de> de::Deserialize<'de> for PathValue { } } +impl ser::Serialize for PathValue { + fn serialize(&self, serializer: S) -> Result + where S: ser::Serializer, + { + self.0.serialize(serializer) + } +} + /// Corresponds to a `target` entry, but `TomlTarget` is already used. -#[derive(Deserialize)] +#[derive(Serialize, Deserialize)] struct TomlPlatform { dependencies: Option>, #[serde(rename = "build-dependencies")] diff --git a/tests/package.rs b/tests/package.rs index cbcf1468385..540c66c57d0 100644 --- a/tests/package.rs +++ b/tests/package.rs @@ -13,7 +13,7 @@ use std::path::{Path, PathBuf}; use cargotest::{cargo_process, process}; use cargotest::support::{project, execs, paths, git, path2url, cargo_exe}; use flate2::read::GzDecoder; -use hamcrest::{assert_that, existing_file, contains}; +use hamcrest::{assert_that, existing_file, contains, equal_to}; use tar::Archive; #[test] @@ -62,6 +62,7 @@ src[/]main.rs 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()) } @@ -423,6 +424,7 @@ src[..]main.rs let fname = f.header().path_bytes(); let fname = &*fname; assert!(fname == b"nested-0.0.1/Cargo.toml" || + fname == b"nested-0.0.1/Cargo.toml.orig" || fname == b"nested-0.0.1/src/main.rs", "unexpected filename: {:?}", f.header().path()) } @@ -588,3 +590,127 @@ Cargo.toml to proceed despite this, pass the `--allow-dirty` flag ")); } + +#[test] +fn generated_manifest() { + let p = project("foo") + .file("Cargo.toml", r#" + [project] + name = "foo" + version = "0.0.1" + authors = [] + exclude = ["*.txt"] + license = "MIT" + description = "foo" + + [workspace] + + [dependencies] + bar = { path = "bar", version = "0.1" } + "#) + .file("src/main.rs", "") + .file("bar/Cargo.toml", r#" + [package] + name = "bar" + version = "0.1.0" + authors = [] + "#) + .file("bar/src/lib.rs", ""); + + assert_that(p.cargo_process("package").arg("--no-verify"), + execs().with_status(0)); + + let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); + let mut rdr = GzDecoder::new(f).unwrap(); + 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_that(&contents[..], equal_to( +r#"# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "foo" +version = "0.0.1" +authors = [] +exclude = ["*.txt"] +description = "foo" +license = "MIT" +[dependencies.bar] +version = "0.1" +"#)); +} + +#[test] +fn ignore_workspace_specifier() { + let p = project("foo") + .file("Cargo.toml", r#" + [project] + name = "foo" + version = "0.0.1" + authors = [] + + [workspace] + + [dependencies] + bar = { path = "bar", version = "0.1" } + "#) + .file("src/main.rs", "") + .file("bar/Cargo.toml", r#" + [package] + name = "bar" + version = "0.1.0" + authors = [] + workspace = ".." + "#) + .file("bar/src/lib.rs", ""); + p.build(); + + assert_that(p.cargo("package").arg("--no-verify").cwd(p.root().join("bar")), + execs().with_status(0)); + + let f = File::open(&p.root().join("target/package/bar-0.1.0.crate")).unwrap(); + let mut rdr = GzDecoder::new(f).unwrap(); + 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_that(&contents[..], equal_to( +r#"# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "bar" +version = "0.1.0" +authors = [] +"#)); +} diff --git a/tests/publish.rs b/tests/publish.rs index 1e4d71400aa..968281f6219 100644 --- a/tests/publish.rs +++ b/tests/publish.rs @@ -88,6 +88,7 @@ See [..] 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()); }