Skip to content

Commit 19dadf1

Browse files
authored
Support reading relative paths from Cargo config (#91)
### Checklist * [x] I have read the [Contributor Guide](../blob/main/CONTRIBUTING.md) * [x] I have read and agree to the [Code of Conduct](../blob/main/CODE_OF_CONDUCT.md) * [x] I have added a description of my changes and why I'd like them included in the section below ### Description of Changes Improved handling of source replacement configuration to closer match what Cargo does.
1 parent 411b11c commit 19dadf1

File tree

2 files changed

+96
-33
lines changed

2 files changed

+96
-33
lines changed

src/index/location.rs

Lines changed: 47 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,12 @@ impl<'iu> IndexUrl<'iu> {
5757
) -> Result<Self, Error> {
5858
// If the crates.io registry has been replaced it doesn't matter what
5959
// the protocol for it has been changed to
60-
if let Some(replacement) =
61-
get_source_replacement(config_root.clone(), cargo_home, "crates-io")?
62-
{
60+
if let Some(replacement) = get_source_replacement(
61+
config_root.clone(),
62+
cargo_home,
63+
crate::CRATES_IO_INDEX,
64+
"crates-io",
65+
)? {
6366
return Ok(replacement);
6467
}
6568

@@ -70,17 +73,16 @@ impl<'iu> IndexUrl<'iu> {
7073
Some("sparse") => true,
7174
Some("git") => false,
7275
_ => {
73-
let sparse_index =
74-
read_cargo_config(config_root, cargo_home, |config| {
75-
match config
76-
.pointer("/registries/crates-io/protocol")
77-
.and_then(|p| p.as_str())?
78-
{
79-
"sparse" => Some(true),
80-
"git" => Some(false),
81-
_ => None,
82-
}
83-
})?;
76+
let sparse_index = read_cargo_config(config_root, cargo_home, |_, config| {
77+
match config
78+
.pointer("/registries/crates-io/protocol")
79+
.and_then(|p| p.as_str())?
80+
{
81+
"sparse" => Some(true),
82+
"git" => Some(false),
83+
_ => None,
84+
}
85+
})?;
8486

8587
if let Some(si) = sparse_index {
8688
si
@@ -144,20 +146,22 @@ impl<'iu> IndexUrl<'iu> {
144146
}
145147
}
146148

147-
if let Some(replacement) =
148-
get_source_replacement(config_root.clone(), cargo_home, registry_name)?
149-
{
149+
let registry_url = read_cargo_config(config_root.clone(), cargo_home, |_, config| {
150+
let path = format!("/registries/{registry_name}/index");
151+
config.pointer(&path)?.as_str().map(String::from)
152+
})?
153+
.ok_or_else(|| Error::UnknownRegistry(registry_name.into()))?;
154+
155+
if let Some(replacement) = get_source_replacement(
156+
config_root.clone(),
157+
cargo_home,
158+
&registry_url,
159+
registry_name,
160+
)? {
150161
return Ok(replacement);
151162
}
152163

153-
read_cargo_config(config_root, cargo_home, |config| {
154-
let path = format!("/registries/{registry_name}/index");
155-
config
156-
.pointer(&path)?
157-
.as_str()
158-
.map(|si| Self::NonCratesIo(si.to_owned().into()))
159-
})?
160-
.ok_or_else(|| Error::UnknownRegistry(registry_name.into()))
164+
Ok(Self::NonCratesIo(registry_url.into()))
161165
}
162166
}
163167

@@ -268,7 +272,7 @@ impl<'il> IndexLocation<'il> {
268272
pub(crate) fn read_cargo_config<T>(
269273
root: Option<PathBuf>,
270274
cargo_home: Option<&Path>,
271-
callback: impl Fn(&toml_span::value::Value<'_>) -> Option<T>,
275+
callback: impl Fn(&Path, &toml_span::value::Value<'_>) -> Option<T>,
272276
) -> Result<Option<T>, Error> {
273277
if let Some(mut path) = root.or_else(|| {
274278
std::env::current_dir()
@@ -284,7 +288,7 @@ pub(crate) fn read_cargo_config<T>(
284288
};
285289

286290
let toml = toml_span::parse(&contents).map_err(Box::new)?;
287-
if let Some(value) = callback(&toml) {
291+
if let Some(value) = callback(&path, &toml) {
288292
return Ok(Some(value));
289293
}
290294
}
@@ -306,7 +310,7 @@ pub(crate) fn read_cargo_config<T>(
306310
if path.exists() {
307311
let fc = std::fs::read_to_string(&path)?;
308312
let toml = toml_span::parse(&fc).map_err(Box::new)?;
309-
if let Some(value) = callback(&toml) {
313+
if let Some(value) = callback(&path, &toml) {
310314
return Ok(Some(value));
311315
}
312316
}
@@ -322,20 +326,30 @@ pub(crate) fn read_cargo_config<T>(
322326
pub(crate) fn get_source_replacement<'iu>(
323327
root: Option<PathBuf>,
324328
cargo_home: Option<&Path>,
329+
registry_url: &str,
325330
registry_name: &str,
326331
) -> Result<Option<IndexUrl<'iu>>, Error> {
327-
read_cargo_config(root, cargo_home, |config| {
328-
let path = format!("/source/{registry_name}/replace-with");
329-
let repw = config.pointer(&path)?.as_str()?;
332+
read_cargo_config(root, cargo_home, |config_path, config| {
333+
let sources = config.as_table()?.get("source")?.as_table()?;
334+
let repw = sources.iter().find_map(|(source_name, source)| {
335+
let source = source.as_table()?;
336+
337+
let matches = registry_name == source_name.name
338+
|| registry_url == source.get("registry")?.as_str()?;
339+
matches.then_some(source.get("replace-with")?.as_str()?)
340+
})?;
341+
330342
let sources = config.pointer("/source")?.as_table()?;
331343
let replace_src = sources.get(repw)?.as_table()?;
332344

333345
if let Some(rr) = replace_src.get("registry") {
334346
rr.as_str()
335347
.map(|r| IndexUrl::NonCratesIo(r.to_owned().into()))
336348
} else if let Some(rlr) = replace_src.get("local-registry") {
337-
rlr.as_str()
338-
.map(|l| IndexUrl::Local(PathBuf::from(l).into()))
349+
let rel_path = rlr.as_str()?;
350+
Some(IndexUrl::Local(
351+
config_path.parent()?.parent()?.join(rel_path).into(),
352+
))
339353
} else {
340354
None
341355
}

tests/local.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,52 @@ fn downloads_and_verifies() {
156156
.unwrap()
157157
);
158158
}
159+
160+
#[test]
161+
fn finds_source_replacement() {
162+
let td = tempfile::tempdir().unwrap();
163+
let cfg_toml = td.path().join(".cargo/config.toml");
164+
std::fs::create_dir_all(cfg_toml.parent().unwrap()).unwrap();
165+
std::fs::write(
166+
&cfg_toml,
167+
r#"
168+
[registries.imaginary-registry]
169+
credential-provider = ["cargo:token"]
170+
index = "sparse+https://imaginary-registry.example.net/index/"
171+
172+
[source._real_cargo_ignores_this_]
173+
registry = "sparse+https://imaginary-registry.example.net/index/"
174+
replace-with = "actual-registry-on-disk"
175+
176+
[source.actual-registry-on-disk]
177+
local-registry = "test-local-registry"
178+
"#,
179+
)
180+
.unwrap();
181+
182+
let meta_path = td
183+
.path()
184+
.join("test-local-registry/index/ex/am/example-dependency");
185+
std::fs::create_dir_all(meta_path.parent().unwrap()).unwrap();
186+
std::fs::write(&meta_path, r#"{"name":"example-dependency","vers":"2.0.0","deps":[],"cksum":"a89f6827d6042043aa77282b091280d2ebb47365e3ff097d07f45b5a797dff63","features":{},"yanked":false}"#).unwrap();
187+
188+
let subdir = td.path().join("test-subdirectory");
189+
std::fs::create_dir_all(&subdir).unwrap();
190+
191+
let url = tame_index::IndexUrl::for_registry_name(
192+
Some(subdir.try_into().unwrap()),
193+
None,
194+
"imaginary-registry",
195+
)
196+
.unwrap();
197+
198+
assert!(matches!(url, tame_index::IndexUrl::Local(_)));
199+
let index =
200+
tame_index::index::ComboIndexCache::new(tame_index::IndexLocation::new(url)).unwrap();
201+
let lock = tame_index::utils::flock::FileLock::unlocked();
202+
let krate = index
203+
.cached_krate("example-dependency".try_into().unwrap(), &lock)
204+
.unwrap()
205+
.unwrap();
206+
assert_eq!("2.0.0", krate.versions[0].version);
207+
}

0 commit comments

Comments
 (0)