Path,
/// represents a remote registry
Registry,
+ /// represents a remote alternative registry
+ AltRegistry,
/// represents a local filesystem-based registry
LocalRegistry,
/// represents a directory-based registry
SourceId::new(Kind::Registry, url.clone())
}
+ /// Create a SourceId from an alternative registry url
+ pub fn for_alt_registry(url: &Url) -> CargoResult<SourceId> {
+ SourceId::new(Kind::AltRegistry, url.clone())
+ }
+
/// Create a SourceId from a local registry path
pub fn for_local_registry(path: &Path) -> CargoResult<SourceId> {
let url = path.to_url()?;
let url = config.get_registry_index(key)?;
Ok(SourceId {
inner: Arc::new(SourceIdInner {
- kind: Kind::Registry,
+ kind: Kind::AltRegistry,
canonical_url: git::canonicalize_url(&url)?,
url: url,
precise: None,
/// Is this source from a registry (either local or not)
pub fn is_registry(&self) -> bool {
match self.inner.kind {
- Kind::Registry | Kind::LocalRegistry => true,
- _ => false,
+ Kind::Registry | Kind::AltRegistry | Kind::LocalRegistry => true,
+ _ => false,
}
}
+ /// Is this source from an alternative registry
+ pub fn is_alt_registry(&self) -> bool {
+ self.inner.kind == Kind::AltRegistry
+ }
+
/// Is this source from a git repository
pub fn is_git(&self) -> bool {
match self.inner.kind {
};
Ok(Box::new(PathSource::new(&path, self, config)))
}
- Kind::Registry => Ok(Box::new(RegistrySource::remote(self, config))),
+ Kind::Registry | Kind::AltRegistry => Ok(Box::new(RegistrySource::remote(self, config))),
Kind::LocalRegistry => {
let path = match self.inner.url.to_file_path() {
Ok(p) => p,
Ok(())
}
SourceIdInner { kind: Kind::Registry, ref url, .. } |
+ SourceIdInner { kind: Kind::AltRegistry, ref url, .. } |
SourceIdInner { kind: Kind::LocalRegistry, ref url, .. } => {
write!(f, "registry `{}`", url)
}
}
Ok(())
}
- SourceIdInner { kind: Kind::Registry, ref url, .. } => {
+ SourceIdInner { kind: Kind::Registry, ref url, .. } |
+ SourceIdInner { kind: Kind::AltRegistry, ref url, .. } => {
write!(f, "registry+{}", url)
}
SourceIdInner { kind: Kind::LocalRegistry, ref url, .. } => {
// Upload said tarball to the specified destination
opts.config.shell().status("Uploading", pkg.package_id().to_string())?;
- transmit(opts.config, pkg, tarball.file(), &mut registry, opts.dry_run)?;
+ transmit(opts.config, pkg, tarball.file(), &mut registry, ®_id, opts.dry_run)?;
Ok(())
}
}
} else if dep.source_id() != registry_src {
if dep.source_id().is_registry() {
- 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\
- (crate `{}` is pulled from {}", dep.name(), dep.name(), dep.source_id());
+ // Block requests to send to a registry if it is not an alternative
+ // registry
+ if !registry_src.is_alt_registry() {
+ 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\
+ (crate `{}` is pulled from {}", dep.name(), dep.name(), dep.source_id());
+ }
} else {
bail!("crates cannot be published to crates.io with dependencies sourced from \
a repository\neither publish `{}` as its own crate on crates.io and \
pkg: &Package,
tarball: &File,
registry: &mut Registry,
+ registry_id: &SourceId,
dry_run: bool) -> CargoResult<()> {
+
let deps = pkg.dependencies().iter().map(|dep| {
+
+ // If the dependency is from a different registry, then include the
+ // registry in the dependency.
+ let dep_registry = if dep.source_id() != registry_id {
+ Some(dep.source_id().url().to_string())
+ } else {
+ None
+ };
+
NewCrateDependency {
optional: dep.is_optional(),
default_features: dep.uses_default_features(),
Kind::Build => "build",
Kind::Development => "dev",
}.to_string(),
+ registry: dep_registry,
}
}).collect::<Vec<NewCrateDependency>>();
let manifest = pkg.manifest();
index: index_config,
} = registry_configuration(config, registry.clone())?;
let token = token.or(token_config);
- let sid = match (index_config, index) {
- (Some(index), _) | (None, Some(index)) => SourceId::for_registry(&index.to_url()?)?,
- (None, None) => SourceId::crates_io(config)?,
+ let sid = match (index_config, index, registry) {
+ (Some(index), _, Some(_registry)) => SourceId::for_alt_registry(&index.to_url()?)?,
+ (Some(index), _, _) | (None, Some(index), _) => SourceId::for_registry(&index.to_url()?)?,
+ (None, None, _) => SourceId::crates_io(config)?,
};
let api_host = {
let mut src = RegistrySource::remote(&sid, config);
pub version_req: String,
pub target: Option<String>,
pub kind: String,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub registry: Option<String>,
}
#[derive(Deserialize)]
// Don't download a second time
assert_that(p.cargo("build").masquerade_as_nightly_cargo(),
execs().with_status(0).with_stderr(&format!("\
+[UPDATING] registry `{reg}`
[COMPILING] bar v0.0.1 (registry `file://[..]`)
[COMPILING] foo v0.0.1 ({dir})
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] secs
",
- dir = p.url())));
+ dir = p.url(),
+ reg = registry::alt_registry())));
}
#[test]
.build();
Package::new("baz", "0.0.1").alternative(true).publish();
- Package::new("bar", "0.0.1").registry_dep("baz", "0.0.1", registry::alt_registry().as_str()).alternative(true).publish();
+ Package::new("bar", "0.0.1").dep("baz", "0.0.1").alternative(true).publish();
assert_that(p.cargo("build").masquerade_as_nightly_cargo(),
execs().with_status(0).with_stderr(&format!("\
reg = registry::alt_registry())));
}
-
#[test]
fn depend_on_alt_registry_depends_on_crates_io() {
let p = project("foo")
}
#[test]
-fn cannot_publish_with_registry_dependency() {
+fn publish_with_registry_dependency() {
let p = project("foo")
.file("Cargo.toml", r#"
cargo-features = ["alternative-registries"]
Package::new("bar", "0.0.1").alternative(true).publish();
+ // Login so that we have the token available
+ assert_that(p.cargo("login").masquerade_as_nightly_cargo()
+ .arg("--registry").arg("alternative").arg("TOKEN").arg("-Zunstable-options"),
+ execs().with_status(0));
+
assert_that(p.cargo("publish").masquerade_as_nightly_cargo()
- .arg("--index").arg(registry::alt_registry().to_string()),
- execs().with_status(101));
+ .arg("--registry").arg("alternative").arg("-Zunstable-options"),
+ execs().with_status(0));
}
#[test]
fn publish_to_alt_registry() {
let p = project("foo")
.file("Cargo.toml", r#"
+ cargo-features = ["alternative-registries"]
+
[project]
name = "foo"
version = "0.0.1"
// Login so that we have the token available
assert_that(p.cargo("login").masquerade_as_nightly_cargo()
- .arg("--registry").arg("alternative").arg("TOKEN").arg("-Zunstable-options"),
+ .arg("--registry").arg("alternative").arg("TOKEN").arg("-Zunstable-options"),
execs().with_status(0));
// Now perform the actual publish
// Ensure that the crate is uploaded
assert!(alt_dl_path().join("api/v1/crates/new").exists());
}
+
+#[test]
+fn publish_with_crates_io_dep() {
+ let p = project("foo")
+ .file("Cargo.toml", r#"
+ cargo-features = ["alternative-registries"]
+
+ [project]
+ name = "foo"
+ version = "0.0.1"
+ authors = ["me"]
+ license = "MIT"
+ description = "foo"
+
+ [dependencies.bar]
+ version = "0.0.1"
+ "#)
+ .file("src/main.rs", "fn main() {}")
+ .build();
+
+ Package::new("bar", "0.0.1").publish();
+
+ // Login so that we have the token available
+ assert_that(p.cargo("login").masquerade_as_nightly_cargo()
+ .arg("--registry").arg("alternative").arg("TOKEN").arg("-Zunstable-options"),
+ execs().with_status(0));
+
+ assert_that(p.cargo("publish").masquerade_as_nightly_cargo()
+ .arg("--registry").arg("alternative").arg("-Zunstable-options"),
+ execs().with_status(0));
+}