Skip to content

Commit 4f1c6db

Browse files
committed
Auto merge of #4953 - alexcrichton:rename-via-as, r=matklad
Implement renaming dependencies in the manifest This commit implements a new unstable feature for manifests which allows renaming a crate when depending on it. For example you can do: ```toml cargo-features = ["dependencies-as"] ... [dependencies] foo = "0.1" bar = { version = "0.1", registry = "custom", package = "foo" } baz = { git = "https://github.com/foo/bar", package = "foo" } ``` Here three crates will be imported but they'll be made available to the Rust source code via the names `foo` (crates.io), `bar` (the custom registry), and `baz` (the git dependency). The *package* name, however, will be `foo` for all of them. In other words the git repository here would be searched for a crate called `foo`. For example: ```rust extern crate foo; // crates.io extern crate bar; // registry `custom` extern crate baz; // git repository ``` The intention here is to enable a few use cases: * Enable depending on the same named crate from different registries * Allow depending on multiple versions of a crate from one registry * Removing the need for `extern crate foo as bar` syntactically in Rust source Currently I don't think we're ready to stabilize this so it's just a nightly feature, but I'm hoping we can continue to iterate on it! cc #1311
2 parents 0a37d76 + 79942fe commit 4f1c6db

File tree

6 files changed

+216
-40
lines changed

6 files changed

+216
-40
lines changed

src/cargo/core/dependency.rs

+13
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ struct Inner {
2727
specified_req: bool,
2828
kind: Kind,
2929
only_match_name: bool,
30+
rename: Option<String>,
3031

3132
optional: bool,
3233
default_features: bool,
@@ -49,6 +50,7 @@ struct SerializedDependency<'a> {
4950
source: &'a SourceId,
5051
req: String,
5152
kind: Kind,
53+
rename: Option<&'a str>,
5254

5355
optional: bool,
5456
uses_default_features: bool,
@@ -69,6 +71,7 @@ impl ser::Serialize for Dependency {
6971
uses_default_features: self.uses_default_features(),
7072
features: self.features(),
7173
target: self.platform(),
74+
rename: self.rename(),
7275
}.serialize(s)
7376
}
7477
}
@@ -182,6 +185,7 @@ impl Dependency {
182185
default_features: true,
183186
specified_req: false,
184187
platform: None,
188+
rename: None,
185189
}),
186190
}
187191
}
@@ -221,6 +225,10 @@ impl Dependency {
221225
self.inner.platform.as_ref()
222226
}
223227

228+
pub fn rename(&self) -> Option<&str> {
229+
self.inner.rename.as_ref().map(|s| &**s)
230+
}
231+
224232
pub fn set_kind(&mut self, kind: Kind) -> &mut Dependency {
225233
Rc::make_mut(&mut self.inner).kind = kind;
226234
self
@@ -261,6 +269,11 @@ impl Dependency {
261269
self
262270
}
263271

272+
pub fn set_rename(&mut self, rename: &str) -> &mut Dependency {
273+
Rc::make_mut(&mut self.inner).rename = Some(rename.to_string());
274+
self
275+
}
276+
264277
/// Lock this dependency to depending on the specified package id
265278
pub fn lock_to(&mut self, id: &PackageId) -> &mut Dependency {
266279
assert_eq!(self.inner.source_id, *id.source_id());

src/cargo/core/features.rs

+3
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,9 @@ features! {
159159

160160
// Using epochs
161161
[unstable] epoch: bool,
162+
163+
// Renaming a package in the manifest via the `package` key
164+
[unstable] rename_dependency: bool,
162165
}
163166
}
164167

src/cargo/ops/cargo_rustc/mod.rs

+25-9
Original file line numberDiff line numberDiff line change
@@ -947,28 +947,44 @@ Cargo.toml. This warning might turn into a hard error in the future.",
947947
}
948948
}
949949

950-
for unit in dep_targets {
951-
if unit.profile.run_custom_build {
952-
cmd.env("OUT_DIR", &cx.build_script_out_dir(&unit));
950+
for dep in dep_targets {
951+
if dep.profile.run_custom_build {
952+
cmd.env("OUT_DIR", &cx.build_script_out_dir(&dep));
953953
}
954-
if unit.target.linkable() && !unit.profile.doc {
955-
link_to(cmd, cx, &unit)?;
954+
if dep.target.linkable() && !dep.profile.doc {
955+
link_to(cmd, cx, &unit, &dep)?;
956956
}
957957
}
958958

959959
return Ok(());
960960

961961
fn link_to<'a, 'cfg>(cmd: &mut ProcessBuilder,
962962
cx: &mut Context<'a, 'cfg>,
963-
unit: &Unit<'a>) -> CargoResult<()> {
964-
for &(ref dst, _, file_type) in cx.target_filenames(unit)?.iter() {
963+
current: &Unit<'a>,
964+
dep: &Unit<'a>) -> CargoResult<()> {
965+
for &(ref dst, _, file_type) in cx.target_filenames(dep)?.iter() {
965966
if file_type != TargetFileType::Linkable {
966967
continue
967968
}
968969
let mut v = OsString::new();
969-
v.push(&unit.target.crate_name());
970+
971+
// Unfortunately right now Cargo doesn't have a great way to get a
972+
// 1:1 mapping of entries in `dependencies()` to the actual crate
973+
// we're depending on. Instead we're left to do some guesswork here
974+
// to figure out what `Dependency` the `dep` unit corresponds to in
975+
// `current` to see if we're renaming it.
976+
//
977+
// This I believe mostly works out for now, but we'll likely want
978+
// to tighten up this in the future.
979+
let name = current.pkg.dependencies()
980+
.iter()
981+
.filter(|d| d.matches_ignoring_source(dep.pkg.summary()))
982+
.filter_map(|d| d.rename())
983+
.next();
984+
985+
v.push(name.unwrap_or(&dep.target.crate_name()));
970986
v.push("=");
971-
v.push(cx.out_dir(unit));
987+
v.push(cx.out_dir(dep));
972988
v.push(&path::MAIN_SEPARATOR.to_string());
973989
v.push(&dst.file_name().unwrap());
974990
cmd.arg("--extern").arg(&v);

src/cargo/util/toml/mod.rs

+51-29
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ type TomlBenchTarget = TomlTarget;
142142
#[serde(untagged)]
143143
pub enum TomlDependency {
144144
Simple(String),
145-
Detailed(DetailedTomlDependency)
145+
Detailed(DetailedTomlDependency),
146146
}
147147

148148
impl<'de> de::Deserialize<'de> for TomlDependency {
@@ -193,6 +193,7 @@ pub struct DetailedTomlDependency {
193193
default_features: Option<bool>,
194194
#[serde(rename = "default_features")]
195195
default_features2: Option<bool>,
196+
package: Option<String>,
196197
}
197198

198199
#[derive(Debug, Deserialize, Serialize)]
@@ -917,28 +918,40 @@ impl TomlDependency {
917918
cx: &mut Context,
918919
kind: Option<Kind>)
919920
-> CargoResult<Dependency> {
920-
let details = match *self {
921-
TomlDependency::Simple(ref version) => DetailedTomlDependency {
922-
version: Some(version.clone()),
923-
.. Default::default()
924-
},
925-
TomlDependency::Detailed(ref details) => details.clone(),
926-
};
921+
match *self {
922+
TomlDependency::Simple(ref version) => {
923+
DetailedTomlDependency {
924+
version: Some(version.clone()),
925+
..Default::default()
926+
}.to_dependency(name, cx, kind)
927+
}
928+
TomlDependency::Detailed(ref details) => {
929+
details.to_dependency(name, cx, kind)
930+
}
931+
}
932+
}
933+
}
927934

928-
if details.version.is_none() && details.path.is_none() &&
929-
details.git.is_none() {
935+
impl DetailedTomlDependency {
936+
fn to_dependency(&self,
937+
name: &str,
938+
cx: &mut Context,
939+
kind: Option<Kind>)
940+
-> CargoResult<Dependency> {
941+
if self.version.is_none() && self.path.is_none() &&
942+
self.git.is_none() {
930943
let msg = format!("dependency ({}) specified without \
931944
providing a local path, Git repository, or \
932945
version to use. This will be considered an \
933946
error in future versions", name);
934947
cx.warnings.push(msg);
935948
}
936949

937-
if details.git.is_none() {
950+
if self.git.is_none() {
938951
let git_only_keys = [
939-
(&details.branch, "branch"),
940-
(&details.tag, "tag"),
941-
(&details.rev, "rev")
952+
(&self.branch, "branch"),
953+
(&self.tag, "tag"),
954+
(&self.rev, "rev")
942955
];
943956

944957
for &(key, key_name) in &git_only_keys {
@@ -951,7 +964,7 @@ impl TomlDependency {
951964
}
952965
}
953966

954-
let registry_id = match details.registry {
967+
let registry_id = match self.registry {
955968
Some(ref registry) => {
956969
cx.features.require(Feature::alternative_registries())?;
957970
SourceId::alt_registry(cx.config, registry)?
@@ -960,10 +973,10 @@ impl TomlDependency {
960973
};
961974

962975
let new_source_id = match (
963-
details.git.as_ref(),
964-
details.path.as_ref(),
965-
details.registry.as_ref(),
966-
details.registry_index.as_ref(),
976+
self.git.as_ref(),
977+
self.path.as_ref(),
978+
self.registry.as_ref(),
979+
self.registry_index.as_ref(),
967980
) {
968981
(Some(_), _, Some(_), _) |
969982
(Some(_), _, _, Some(_))=> bail!("dependency ({}) specification is ambiguous. \
@@ -978,7 +991,7 @@ impl TomlDependency {
978991
cx.warnings.push(msg)
979992
}
980993

981-
let n_details = [&details.branch, &details.tag, &details.rev]
994+
let n_details = [&self.branch, &self.tag, &self.rev]
982995
.iter()
983996
.filter(|d| d.is_some())
984997
.count();
@@ -990,9 +1003,9 @@ impl TomlDependency {
9901003
cx.warnings.push(msg)
9911004
}
9921005

993-
let reference = details.branch.clone().map(GitReference::Branch)
994-
.or_else(|| details.tag.clone().map(GitReference::Tag))
995-
.or_else(|| details.rev.clone().map(GitReference::Rev))
1006+
let reference = self.branch.clone().map(GitReference::Branch)
1007+
.or_else(|| self.tag.clone().map(GitReference::Tag))
1008+
.or_else(|| self.rev.clone().map(GitReference::Rev))
9961009
.unwrap_or_else(|| GitReference::Branch("master".to_string()));
9971010
let loc = git.to_url()?;
9981011
SourceId::for_git(&loc, reference)?
@@ -1023,24 +1036,33 @@ impl TomlDependency {
10231036
(None, None, None, None) => SourceId::crates_io(cx.config)?,
10241037
};
10251038

1026-
let version = details.version.as_ref().map(|v| &v[..]);
1039+
let (pkg_name, rename) = match self.package {
1040+
Some(ref s) => (&s[..], Some(name)),
1041+
None => (name, None),
1042+
};
1043+
1044+
let version = self.version.as_ref().map(|v| &v[..]);
10271045
let mut dep = match cx.pkgid {
10281046
Some(id) => {
1029-
Dependency::parse(name, version, &new_source_id,
1047+
Dependency::parse(pkg_name, version, &new_source_id,
10301048
id, cx.config)?
10311049
}
10321050
None => Dependency::parse_no_deprecated(name, version, &new_source_id)?,
10331051
};
1034-
dep.set_features(details.features.unwrap_or_default())
1035-
.set_default_features(details.default_features
1036-
.or(details.default_features2)
1052+
dep.set_features(self.features.clone().unwrap_or_default())
1053+
.set_default_features(self.default_features
1054+
.or(self.default_features2)
10371055
.unwrap_or(true))
1038-
.set_optional(details.optional.unwrap_or(false))
1056+
.set_optional(self.optional.unwrap_or(false))
10391057
.set_platform(cx.platform.clone())
10401058
.set_registry_id(&registry_id);
10411059
if let Some(kind) = kind {
10421060
dep.set_kind(kind);
10431061
}
1062+
if let Some(rename) = rename {
1063+
cx.features.require(Feature::rename_dependency())?;
1064+
dep.set_rename(rename);
1065+
}
10441066
Ok(dep)
10451067
}
10461068
}

tests/metadata.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,8 @@ fn cargo_metadata_with_deps_and_version() {
193193
"req": "^0.0.1",
194194
"source": "registry+[..]",
195195
"target": null,
196-
"uses_default_features": true
196+
"uses_default_features": true,
197+
"rename": null
197198
}
198199
],
199200
"features": {},
@@ -228,7 +229,8 @@ fn cargo_metadata_with_deps_and_version() {
228229
"req": "*",
229230
"source": "registry+[..]",
230231
"target": null,
231-
"uses_default_features": true
232+
"uses_default_features": true,
233+
"rename": null
232234
}
233235
],
234236
"features": {},

0 commit comments

Comments
 (0)