Skip to content

Commit 6f39916

Browse files
committedApr 29, 2019
Auto merge of #6873 - fluffysquirrels:rel-registry-url, r=ehuss
Support relative paths for registries Closes #2252 I haven't finished the tests for this yet as I wasn't sure what was necessary. Is it OK to just test through `registry_configuration()` in `src/cargo/ops/registry.rs` or are integration tests required? If integration tests then I'm not sure what cargo sub-command I can run without a real remote registry to play with; any thoughts?
2 parents db40f1b + 987f19d commit 6f39916

File tree

6 files changed

+249
-12
lines changed

6 files changed

+249
-12
lines changed
 

‎src/cargo/ops/registry.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -324,9 +324,9 @@ pub fn registry_configuration(
324324
)
325325
}
326326
None => {
327-
// Checking out for default index and token
327+
// Checking for default index and token
328328
(
329-
config.get_string("registry.index")?.map(|p| p.val),
329+
config.get_default_registry_index()?.map(|url| url.to_string()),
330330
config.get_string("registry.token")?.map(|p| p.val),
331331
)
332332
}

‎src/cargo/util/config.rs

+24-8
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use crate::util::errors::{self, internal, CargoResult, CargoResultExt};
2929
use crate::util::toml as cargo_toml;
3030
use crate::util::Filesystem;
3131
use crate::util::Rustc;
32-
use crate::util::ToUrl;
32+
use crate::util::{ToUrl, ToUrlWithBase};
3333
use crate::util::{paths, validate_package_name};
3434

3535
/// Configuration information for cargo. This is not specific to a build, it is information
@@ -667,18 +667,33 @@ impl Config {
667667
validate_package_name(registry, "registry name", "")?;
668668
Ok(
669669
match self.get_string(&format!("registries.{}.index", registry))? {
670-
Some(index) => {
671-
let url = index.val.to_url()?;
672-
if url.password().is_some() {
673-
failure::bail!("Registry URLs may not contain passwords");
674-
}
675-
url
676-
}
670+
Some(index) => self.resolve_registry_index(index)?,
677671
None => failure::bail!("No index found for registry: `{}`", registry),
678672
},
679673
)
680674
}
681675

676+
/// Gets the index for the default registry.
677+
pub fn get_default_registry_index(&self) -> CargoResult<Option<Url>> {
678+
Ok(
679+
match self.get_string("registry.index")? {
680+
Some(index) => Some(self.resolve_registry_index(index)?),
681+
None => None,
682+
},
683+
)
684+
}
685+
686+
fn resolve_registry_index(&self, index: Value<String>) -> CargoResult<Url> {
687+
let base = index.definition.root(&self).join("truncated-by-url_with_base");
688+
// Parse val to check it is a URL, not a relative path without a protocol.
689+
let _parsed = index.val.to_url()?;
690+
let url = index.val.to_url_with_base(Some(&*base))?;
691+
if url.password().is_some() {
692+
failure::bail!("Registry URLs may not contain passwords");
693+
}
694+
Ok(url)
695+
}
696+
682697
/// Loads credentials config from the credentials file into the `ConfigValue` object, if
683698
/// present.
684699
fn load_credentials(&self, cfg: &mut ConfigValue) -> CargoResult<()> {
@@ -1648,3 +1663,4 @@ pub fn save_credentials(cfg: &Config, token: String, registry: Option<String>) -
16481663
Ok(())
16491664
}
16501665
}
1666+

‎src/cargo/util/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pub use self::rustc::Rustc;
2121
pub use self::sha256::Sha256;
2222
pub use self::to_semver::ToSemver;
2323
pub use self::to_url::ToUrl;
24+
pub use self::to_url_with_base::ToUrlWithBase;
2425
pub use self::vcs::{existing_vcs_repo, FossilRepo, GitRepo, HgRepo, PijulRepo};
2526
pub use self::workspace::{
2627
print_available_benches, print_available_binaries, print_available_examples,
@@ -51,6 +52,7 @@ pub mod rustc;
5152
mod sha256;
5253
pub mod to_semver;
5354
pub mod to_url;
55+
mod to_url_with_base;
5456
pub mod toml;
5557
mod vcs;
5658
mod workspace;

‎src/cargo/util/to_url.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::path::Path;
1+
use std::path::{Path, PathBuf};
22

33
use url::Url;
44

@@ -22,3 +22,9 @@ impl<'a> ToUrl for &'a Path {
2222
.map_err(|()| failure::format_err!("invalid path url `{}`", self.display()))
2323
}
2424
}
25+
26+
impl<'a> ToUrl for &'a PathBuf {
27+
fn to_url(self) -> CargoResult<Url> {
28+
self.as_path().to_url()
29+
}
30+
}

‎src/cargo/util/to_url_with_base.rs

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
use crate::util::{CargoResult, ToUrl};
2+
3+
use url::Url;
4+
5+
/// A type that can be interpreted as a relative Url and converted to
6+
/// a Url.
7+
pub trait ToUrlWithBase {
8+
/// Performs the conversion
9+
fn to_url_with_base<U: ToUrl>(self, base: Option<U>) -> CargoResult<Url>;
10+
}
11+
12+
impl<'a> ToUrlWithBase for &'a str {
13+
fn to_url_with_base<U: ToUrl>(self, base: Option<U>) -> CargoResult<Url> {
14+
let base_url = match base {
15+
Some(base) =>
16+
Some(base.to_url().map_err(|s| {
17+
failure::format_err!("invalid url `{}`: {}", self, s)
18+
})?),
19+
None => None
20+
};
21+
22+
Url::options()
23+
.base_url(base_url.as_ref())
24+
.parse(self).map_err(|s| {
25+
failure::format_err!("invalid url `{}`: {}", self, s)
26+
})
27+
}
28+
}
29+
30+
#[cfg(test)]
31+
mod tests {
32+
use crate::util::ToUrlWithBase;
33+
34+
#[test]
35+
fn to_url_with_base() {
36+
assert_eq!("rel/path".to_url_with_base(Some("file:///abs/path/"))
37+
.unwrap()
38+
.to_string(),
39+
"file:///abs/path/rel/path");
40+
assert_eq!("rel/path".to_url_with_base(Some("file:///abs/path/popped-file"))
41+
.unwrap()
42+
.to_string(),
43+
"file:///abs/path/rel/path");
44+
}
45+
}

‎tests/testsuite/alt_registry.rs

+169-1
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,31 @@ fn publish_with_crates_io_dep() {
528528
}
529529

530530
#[test]
531-
fn passwords_in_url_forbidden() {
531+
fn passwords_in_registry_index_url_forbidden() {
532+
registry::init();
533+
534+
let config = paths::home().join(".cargo/config");
535+
536+
File::create(config)
537+
.unwrap()
538+
.write_all(
539+
br#"
540+
[registry]
541+
index = "ssh://git:secret@foobar.com"
542+
"#,
543+
)
544+
.unwrap();
545+
546+
let p = project().file("src/main.rs", "fn main() {}").build();
547+
548+
p.cargo("publish")
549+
.with_status(101)
550+
.with_stderr_contains("error: Registry URLs may not contain passwords")
551+
.run();
552+
}
553+
554+
#[test]
555+
fn passwords_in_registries_index_url_forbidden() {
532556
registry::init();
533557

534558
let config = paths::home().join(".cargo/config");
@@ -1141,3 +1165,147 @@ fn unknown_registry() {
11411165
)
11421166
.run();
11431167
}
1168+
1169+
#[test]
1170+
fn registries_index_relative_url() {
1171+
let config = paths::root().join(".cargo/config");
1172+
fs::create_dir_all(config.parent().unwrap()).unwrap();
1173+
File::create(&config).unwrap()
1174+
.write_all(br#"
1175+
[registries.relative]
1176+
index = "file:alternative-registry"
1177+
"#).unwrap();
1178+
1179+
registry::init();
1180+
1181+
let p = project()
1182+
.file(
1183+
"Cargo.toml",
1184+
r#"
1185+
[project]
1186+
name = "foo"
1187+
version = "0.0.1"
1188+
authors = []
1189+
1190+
[dependencies.bar]
1191+
version = "0.0.1"
1192+
registry = "relative"
1193+
"#,
1194+
)
1195+
.file("src/main.rs", "fn main() {}")
1196+
.build();
1197+
1198+
Package::new("bar", "0.0.1")
1199+
.alternative(true)
1200+
.publish();
1201+
1202+
p.cargo("build")
1203+
.with_stderr(&format!(
1204+
"\
1205+
[UPDATING] `{reg}` index
1206+
[DOWNLOADING] crates ...
1207+
[DOWNLOADED] bar v0.0.1 (registry `[ROOT][..]`)
1208+
[COMPILING] bar v0.0.1 (registry `[ROOT][..]`)
1209+
[COMPILING] foo v0.0.1 ([CWD])
1210+
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
1211+
",
1212+
reg = registry::alt_registry_path().to_str().unwrap()
1213+
))
1214+
.run();
1215+
}
1216+
1217+
#[test]
1218+
fn registry_index_relative_url() {
1219+
let config = paths::root().join(".cargo/config");
1220+
fs::create_dir_all(config.parent().unwrap()).unwrap();
1221+
File::create(&config).unwrap()
1222+
.write_all(br#"
1223+
[registry]
1224+
index = "file:alternative-registry"
1225+
"#).unwrap();
1226+
1227+
registry::init();
1228+
1229+
let p = project()
1230+
.file(
1231+
"Cargo.toml",
1232+
r#"
1233+
[project]
1234+
name = "foo"
1235+
version = "0.0.1"
1236+
authors = []
1237+
1238+
[dependencies.bar]
1239+
version = "0.0.1"
1240+
"#,
1241+
)
1242+
.file("src/main.rs", "fn main() {}")
1243+
.build();
1244+
1245+
Package::new("bar", "0.0.1")
1246+
.alternative(true)
1247+
.publish();
1248+
1249+
fs::remove_file(paths::home().join(".cargo/config")).unwrap();
1250+
1251+
p.cargo("build")
1252+
.with_stderr(&format!(
1253+
"\
1254+
warning: custom registry support via the `registry.index` configuration is being removed, this functionality will not work in the future
1255+
[UPDATING] `{reg}` index
1256+
[DOWNLOADING] crates ...
1257+
[DOWNLOADED] bar v0.0.1 (registry `[ROOT][..]`)
1258+
[COMPILING] bar v0.0.1 (registry `[ROOT][..]`)
1259+
[COMPILING] foo v0.0.1 ([CWD])
1260+
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
1261+
",
1262+
reg = registry::alt_registry_path().to_str().unwrap()
1263+
))
1264+
.run();
1265+
}
1266+
1267+
#[test]
1268+
fn registries_index_relative_path_not_allowed() {
1269+
let config = paths::root().join(".cargo/config");
1270+
fs::create_dir_all(config.parent().unwrap()).unwrap();
1271+
File::create(&config).unwrap()
1272+
.write_all(br#"
1273+
[registries.relative]
1274+
index = "alternative-registry"
1275+
"#).unwrap();
1276+
1277+
registry::init();
1278+
1279+
let p = project()
1280+
.file(
1281+
"Cargo.toml",
1282+
r#"
1283+
[project]
1284+
name = "foo"
1285+
version = "0.0.1"
1286+
authors = []
1287+
1288+
[dependencies.bar]
1289+
version = "0.0.1"
1290+
registry = "relative"
1291+
"#,
1292+
)
1293+
.file("src/main.rs", "fn main() {}")
1294+
.build();
1295+
1296+
Package::new("bar", "0.0.1")
1297+
.alternative(true)
1298+
.publish();
1299+
1300+
p.cargo("build")
1301+
.with_stderr(&format!(
1302+
"\
1303+
error: failed to parse manifest at `{root}/foo/Cargo.toml`
1304+
1305+
Caused by:
1306+
invalid url `alternative-registry`: relative URL without a base
1307+
"
1308+
, root = paths::root().to_str().unwrap()))
1309+
.with_status(101)
1310+
.run();
1311+
}

0 commit comments

Comments
 (0)