From 0a4cfa630fd516433b17a5eaf3a86f6cf9c9e1f9 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 5 Jan 2019 10:56:49 -0800 Subject: [PATCH] publish: rework the crates.io detection logic. The old code used an unreliable method to detect if `cargo publish` was publishing to crates.io. This should work even if the `--index` flag is used. Also includes a very minor rewording of an error message mentioning crates.io, even for alternative registries. --- src/cargo/core/source/source_id.rs | 7 ------- src/cargo/ops/registry.rs | 27 +++++++++++++++++-------- tests/testsuite/alt_registry.rs | 32 +++++++++++++++++++++++++++++- tests/testsuite/publish.rs | 6 +++--- 4 files changed, 53 insertions(+), 19 deletions(-) diff --git a/src/cargo/core/source/source_id.rs b/src/cargo/core/source/source_id.rs index 19e27de51d5..5189d7ec542 100644 --- a/src/cargo/core/source/source_id.rs +++ b/src/cargo/core/source/source_id.rs @@ -248,13 +248,6 @@ impl SourceId { } } - /// 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 { - self.is_registry() && self.inner.name.is_some() - } - /// Is this source from a git repository pub fn is_git(self) -> bool { match self.inner.kind { diff --git a/src/cargo/ops/registry.rs b/src/cargo/ops/registry.rs index 04e482fe96d..33699872469 100644 --- a/src/cargo/ops/registry.rs +++ b/src/cargo/ops/registry.rs @@ -68,7 +68,7 @@ pub fn publish(ws: &Workspace<'_>, opts: &PublishOpts<'_>) -> CargoResult<()> { opts.registry.clone(), true, )?; - verify_dependencies(pkg, reg_id)?; + verify_dependencies(pkg, ®istry, reg_id)?; // Prepare a tarball, with a non-surpressable warning if metadata // is missing since this is being put online. @@ -102,7 +102,11 @@ pub fn publish(ws: &Workspace<'_>, opts: &PublishOpts<'_>) -> CargoResult<()> { Ok(()) } -fn verify_dependencies(pkg: &Package, registry_src: SourceId) -> CargoResult<()> { +fn verify_dependencies( + pkg: &Package, + registry: &Registry, + registry_src: SourceId, +) -> CargoResult<()> { for dep in pkg.dependencies().iter() { if dep.source_id().is_path() { if !dep.specified_req() { @@ -115,9 +119,16 @@ fn verify_dependencies(pkg: &Package, registry_src: SourceId) -> CargoResult<()> } } else if dep.source_id() != registry_src { if dep.source_id().is_registry() { - // Block requests to send to a registry if it is not an alternative - // registry - if !registry_src.is_alt_registry() { + // Block requests to send to crates.io with alt-registry deps. + // This extra hostname check is mostly to assist with testing, + // but also prevents someone using `--index` to specify + // something that points to crates.io. + let is_crates_io = registry + .host() + .to_url() + .map(|u| u.host_str() == Some("crates.io")) + .unwrap_or(false); + if registry_src.is_default_registry() || is_crates_io { failure::bail!("crates cannot be published to crates.io with dependencies sourced from other\n\ registries either publish `{}` on crates.io or pull it into this repository\n\ and specify it with a path and version\n\ @@ -128,9 +139,9 @@ fn verify_dependencies(pkg: &Package, registry_src: SourceId) -> CargoResult<()> } } else { failure::bail!( - "crates cannot be published to crates.io with dependencies sourced from \ - a repository\neither publish `{}` as its own crate on crates.io and \ - specify a crates.io version as a dependency or pull it into this \ + "crates cannot be published with dependencies sourced from \ + a repository\neither publish `{}` as its own crate and \ + specify a version as a dependency or pull it into this \ repository and specify it with a path and version\n(crate `{}` has \ repository path `{}`)", dep.package_name(), diff --git a/tests/testsuite/alt_registry.rs b/tests/testsuite/alt_registry.rs index f99ab93adc6..3377bb8f05d 100644 --- a/tests/testsuite/alt_registry.rs +++ b/tests/testsuite/alt_registry.rs @@ -1,6 +1,7 @@ use crate::support::publish::validate_alt_upload; use crate::support::registry::{self, Package}; use crate::support::{basic_manifest, git, paths, project}; +use cargo::util::ToUrl; use std::fs::{self, File}; use std::io::Write; @@ -288,6 +289,8 @@ fn registry_incompatible_with_git() { #[test] fn cannot_publish_to_crates_io_with_registry_dependency() { + let fakeio_path = paths::root().join("fake.io"); + let fakeio_url = fakeio_path.to_url().unwrap(); let p = project() .file( "Cargo.toml", @@ -303,12 +306,39 @@ fn cannot_publish_to_crates_io_with_registry_dependency() { "#, ) .file("src/main.rs", "fn main() {}") + .file( + ".cargo/config", + &format!( + r#" + [registries.fakeio] + index = "{}" + "#, + fakeio_url + ), + ) .build(); Package::new("bar", "0.0.1").alternative(true).publish(); + // Since this can't really call plain `publish` without fetching the real + // crates.io index, create a fake one that points to the real crates.io. + git::repo(&fakeio_path) + .file( + "config.json", + r#" + {"dl": "https://crates.io/api/v1/crates", "api": "https://crates.io"} + "#, + ) + .build(); + + p.cargo("publish --registry fakeio -Z unstable-options") + .masquerade_as_nightly_cargo() + .with_status(101) + .with_stderr_contains("[ERROR] crates cannot be published to crates.io[..]") + .run(); + p.cargo("publish --index") - .arg(registry::registry().to_string()) + .arg(fakeio_url.to_string()) .masquerade_as_nightly_cargo() .with_status(101) .with_stderr_contains("[ERROR] crates cannot be published to crates.io[..]") diff --git a/tests/testsuite/publish.rs b/tests/testsuite/publish.rs index 0ce1434a709..ee6a6db73d5 100644 --- a/tests/testsuite/publish.rs +++ b/tests/testsuite/publish.rs @@ -273,9 +273,9 @@ fn git_deps() { .with_stderr( "\ [UPDATING] [..] index -[ERROR] crates cannot be published to crates.io with dependencies sourced from \ -a repository\neither publish `foo` as its own crate on crates.io and \ -specify a crates.io version as a dependency or pull it into this \ +[ERROR] crates cannot be published with dependencies sourced from \ +a repository\neither publish `foo` as its own crate and \ +specify a version as a dependency or pull it into this \ repository and specify it with a path and version\n\ (crate `foo` has repository path `git://path/to/nowhere`)\ ",