Skip to content

Commit 3fc27b2

Browse files
committed
Introduce dl key to allow per-crate download links
This change allows the registry to override its own global `dl` key defined in the root config.json for each package version.
1 parent b1636fc commit 3fc27b2

File tree

13 files changed

+198
-44
lines changed

13 files changed

+198
-44
lines changed

crates/cargo-test-support/src/registry.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ pub struct Package {
324324
rust_version: Option<String>,
325325
cargo_features: Vec<String>,
326326
v: Option<u32>,
327+
dl: Option<String>,
327328
}
328329

329330
type FeatureMap = BTreeMap<String, Vec<String>>;
@@ -561,6 +562,7 @@ impl Package {
561562
rust_version: None,
562563
cargo_features: Vec::new(),
563564
v: None,
565+
dl: None,
564566
}
565567
}
566568

@@ -709,6 +711,12 @@ impl Package {
709711
self
710712
}
711713

714+
/// Specifies a different download URI for the package.
715+
pub fn dl(&mut self, dl: &str) -> &mut Package {
716+
self.dl = Some(dl.to_string());
717+
self
718+
}
719+
712720
pub fn cargo_feature(&mut self, feature: &str) -> &mut Package {
713721
self.cargo_features.push(feature.to_owned());
714722
self
@@ -788,6 +796,9 @@ impl Package {
788796
if let Some(v) = self.v {
789797
json["v"] = serde_json::json!(v);
790798
}
799+
if let Some(dl) = &self.dl {
800+
json["dl"] = serde_json::json!(dl);
801+
}
791802
let line = json.to_string();
792803

793804
let file = make_dep_path(&self.name, false);

crates/resolver-tests/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ pub fn resolve_with_config_raw(
180180
deps,
181181
&BTreeMap::new(),
182182
None::<&String>,
183+
None,
183184
)
184185
.unwrap();
185186
let opts = ResolveOpts::everything();
@@ -581,6 +582,7 @@ pub fn pkg_dep<T: ToPkgId>(name: T, dep: Vec<Dependency>) -> Summary {
581582
dep,
582583
&BTreeMap::new(),
583584
link,
585+
None,
584586
)
585587
.unwrap()
586588
}
@@ -609,6 +611,7 @@ pub fn pkg_loc(name: &str, loc: &str) -> Summary {
609611
Vec::new(),
610612
&BTreeMap::new(),
611613
link,
614+
None,
612615
)
613616
.unwrap()
614617
}
@@ -623,6 +626,7 @@ pub fn remove_dep(sum: &Summary, ind: usize) -> Summary {
623626
deps,
624627
&BTreeMap::new(),
625628
sum.links().map(|a| a.as_str()),
629+
None,
626630
)
627631
.unwrap()
628632
}

src/cargo/core/resolver/version_prefs.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,15 @@ mod test {
9292
let pkg_id = pkgid(name, version);
9393
let config = Config::default().unwrap();
9494
let features = BTreeMap::new();
95-
Summary::new(&config, pkg_id, Vec::new(), &features, None::<&String>).unwrap()
95+
Summary::new(
96+
&config,
97+
pkg_id,
98+
Vec::new(),
99+
&features,
100+
None::<&String>,
101+
None,
102+
)
103+
.unwrap()
96104
}
97105

98106
fn describe(summaries: &Vec<Summary>) -> String {

src/cargo/core/summary.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ struct Inner {
2525
features: Rc<FeatureMap>,
2626
checksum: Option<String>,
2727
links: Option<InternedString>,
28+
dl: Option<InternedString>,
2829
}
2930

3031
impl Summary {
@@ -34,6 +35,7 @@ impl Summary {
3435
dependencies: Vec<Dependency>,
3536
features: &BTreeMap<InternedString, Vec<InternedString>>,
3637
links: Option<impl Into<InternedString>>,
38+
dl: Option<InternedString>,
3739
) -> CargoResult<Summary> {
3840
// ****CAUTION**** If you change anything here that may raise a new
3941
// error, be sure to coordinate that change with either the index
@@ -55,6 +57,7 @@ impl Summary {
5557
features: Rc::new(feature_map),
5658
checksum: None,
5759
links: links.map(|l| l.into()),
60+
dl,
5861
}),
5962
})
6063
}
@@ -84,6 +87,9 @@ impl Summary {
8487
pub fn links(&self) -> Option<InternedString> {
8588
self.inner.links
8689
}
90+
pub fn dl(&self) -> Option<InternedString> {
91+
self.inner.dl
92+
}
8793

8894
pub fn override_id(mut self, id: PackageId) -> Summary {
8995
Rc::make_mut(&mut self.inner).package_id = id;

src/cargo/sources/registry/download.rs

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ pub(super) fn download(
2424
cache_path: &Filesystem,
2525
config: &Config,
2626
pkg: PackageId,
27+
override_dl: Option<&str>,
2728
checksum: &str,
2829
registry_config: RegistryConfig,
2930
) -> CargoResult<MaybeLock> {
@@ -44,30 +45,36 @@ pub(super) fn download(
4445
}
4546
}
4647

47-
let mut url = registry_config.dl;
48-
if !url.contains(CRATE_TEMPLATE)
49-
&& !url.contains(VERSION_TEMPLATE)
50-
&& !url.contains(PREFIX_TEMPLATE)
51-
&& !url.contains(LOWER_PREFIX_TEMPLATE)
52-
&& !url.contains(CHECKSUM_TEMPLATE)
53-
{
54-
// Original format before customizing the download URL was supported.
55-
write!(
56-
url,
57-
"/{}/{}/download",
58-
pkg.name(),
59-
pkg.version().to_string()
60-
)
61-
.unwrap();
62-
} else {
63-
let prefix = make_dep_prefix(&*pkg.name());
64-
url = url
65-
.replace(CRATE_TEMPLATE, &*pkg.name())
66-
.replace(VERSION_TEMPLATE, &pkg.version().to_string())
67-
.replace(PREFIX_TEMPLATE, &prefix)
68-
.replace(LOWER_PREFIX_TEMPLATE, &prefix.to_lowercase())
69-
.replace(CHECKSUM_TEMPLATE, checksum);
70-
}
48+
let url = override_dl.map_or_else(
49+
|| {
50+
let mut url = registry_config.dl;
51+
if !url.contains(CRATE_TEMPLATE)
52+
&& !url.contains(VERSION_TEMPLATE)
53+
&& !url.contains(PREFIX_TEMPLATE)
54+
&& !url.contains(LOWER_PREFIX_TEMPLATE)
55+
&& !url.contains(CHECKSUM_TEMPLATE)
56+
{
57+
// Original format before customizing the download URL was supported.
58+
write!(
59+
url,
60+
"/{}/{}/download",
61+
pkg.name(),
62+
pkg.version().to_string()
63+
)
64+
.unwrap();
65+
} else {
66+
let prefix = make_dep_prefix(&*pkg.name());
67+
url = url
68+
.replace(CRATE_TEMPLATE, &*pkg.name())
69+
.replace(VERSION_TEMPLATE, &pkg.version().to_string())
70+
.replace(PREFIX_TEMPLATE, &prefix)
71+
.replace(LOWER_PREFIX_TEMPLATE, &prefix.to_lowercase())
72+
.replace(CHECKSUM_TEMPLATE, checksum);
73+
}
74+
url
75+
},
76+
ToString::to_string,
77+
);
7178

7279
Ok(MaybeLock::Download {
7380
url,

src/cargo/sources/registry/http_remote.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,12 @@ impl<'cfg> RegistryData for HttpRegistry<'cfg> {
548548
self.requested_update = true;
549549
}
550550

551-
fn download(&mut self, pkg: PackageId, checksum: &str) -> CargoResult<MaybeLock> {
551+
fn download(
552+
&mut self,
553+
pkg: PackageId,
554+
override_dl: Option<&str>,
555+
checksum: &str,
556+
) -> CargoResult<MaybeLock> {
552557
let registry_config = loop {
553558
match self.config()? {
554559
Poll::Pending => self.block_until_ready()?,
@@ -559,6 +564,7 @@ impl<'cfg> RegistryData for HttpRegistry<'cfg> {
559564
&self.cache_path,
560565
&self.config,
561566
pkg,
567+
override_dl,
562568
checksum,
563569
registry_config,
564570
)

src/cargo/sources/registry/index.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -265,19 +265,21 @@ impl<'cfg> RegistryIndex<'cfg> {
265265
}
266266
}
267267

268-
/// Returns the hash listed for a specified `PackageId`.
269-
pub fn hash(&mut self, pkg: PackageId, load: &mut dyn RegistryData) -> Poll<CargoResult<&str>> {
268+
/// Returns the package summary for a specified `PackageId`.
269+
pub fn summary(
270+
&mut self,
271+
pkg: PackageId,
272+
load: &mut dyn RegistryData,
273+
) -> Poll<CargoResult<&IndexSummary>> {
270274
let req = OptVersionReq::exact(pkg.version());
271275
let summary = self.summaries(pkg.name(), &req, load)?;
272276
let summary = match summary {
273277
Poll::Ready(mut summary) => summary.next(),
274278
Poll::Pending => return Poll::Pending,
275279
};
276-
Poll::Ready(Ok(summary
277-
.ok_or_else(|| internal(format!("no hash listed for {}", pkg)))?
278-
.summary
279-
.checksum()
280-
.ok_or_else(|| internal(format!("no hash listed for {}", pkg)))?))
280+
Poll::Ready(Ok(
281+
summary.ok_or_else(|| internal(format!("no summary for {}", pkg)))?
282+
))
281283
}
282284

283285
/// Load a list of summaries for `name` package in this registry which
@@ -854,6 +856,7 @@ impl IndexSummary {
854856
yanked,
855857
links,
856858
v,
859+
dl,
857860
} = serde_json::from_slice(line)?;
858861
let v = v.unwrap_or(1);
859862
log::trace!("json parsed registry {}/{}", name, vers);
@@ -867,7 +870,7 @@ impl IndexSummary {
867870
features.entry(name).or_default().extend(values);
868871
}
869872
}
870-
let mut summary = Summary::new(config, pkgid, deps, &features, links)?;
873+
let mut summary = Summary::new(config, pkgid, deps, &features, links, dl)?;
871874
summary.set_checksum(cksum);
872875
Ok(IndexSummary {
873876
summary,

src/cargo/sources/registry/local.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,12 @@ impl<'cfg> RegistryData for LocalRegistry<'cfg> {
9999
self.updated
100100
}
101101

102-
fn download(&mut self, pkg: PackageId, checksum: &str) -> CargoResult<MaybeLock> {
102+
fn download(
103+
&mut self,
104+
pkg: PackageId,
105+
_override_dl: Option<&str>,
106+
checksum: &str,
107+
) -> CargoResult<MaybeLock> {
103108
let crate_file = format!("{}-{}.crate", pkg.name(), pkg.version());
104109

105110
// Note that the usage of `into_path_unlocked` here is because the local

src/cargo/sources/registry/mod.rs

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,10 @@ use tar::Archive;
176176
use crate::core::dependency::{DepKind, Dependency};
177177
use crate::core::source::MaybePackage;
178178
use crate::core::{Package, PackageId, Source, SourceId, Summary};
179+
use crate::sources::registry::index::IndexSummary;
179180
use crate::sources::PathSource;
180181
use crate::util::hex;
182+
use crate::util::internal;
181183
use crate::util::interning::InternedString;
182184
use crate::util::into_url::IntoUrl;
183185
use crate::util::network::PollExt;
@@ -277,6 +279,8 @@ pub struct RegistryPackage<'a> {
277279
/// Added early 2018 (see <https://github.com/rust-lang/cargo/pull/4978>),
278280
/// can be `None` if published before then.
279281
links: Option<InternedString>,
282+
/// Allows overriding the registry's global `dl` link for this package only.
283+
dl: Option<InternedString>,
280284
/// The schema version for this entry.
281285
///
282286
/// If this is None, it defaults to version 1. Entries with unknown
@@ -481,7 +485,12 @@ pub trait RegistryData {
481485
/// `finish_download`. For already downloaded `.crate` files, it does not
482486
/// validate the checksum, assuming the filesystem does not suffer from
483487
/// corruption or manipulation.
484-
fn download(&mut self, pkg: PackageId, checksum: &str) -> CargoResult<MaybeLock>;
488+
fn download(
489+
&mut self,
490+
pkg: PackageId,
491+
override_dl: Option<&str>,
492+
checksum: &str,
493+
) -> CargoResult<MaybeLock>;
485494

486495
/// Finish a download by saving a `.crate` file to disk.
487496
///
@@ -764,13 +773,20 @@ impl<'cfg> Source for RegistrySource<'cfg> {
764773
}
765774

766775
fn download(&mut self, package: PackageId) -> CargoResult<MaybePackage> {
767-
let hash = loop {
768-
match self.index.hash(package, &mut *self.ops)? {
776+
let (hash, override_dl) = loop {
777+
match self.index.summary(package, &mut *self.ops)? {
769778
Poll::Pending => self.block_until_ready()?,
770-
Poll::Ready(hash) => break hash,
779+
Poll::Ready(IndexSummary { ref summary, .. }) => {
780+
break (
781+
summary
782+
.checksum()
783+
.ok_or_else(|| internal(format!("no hash listed for {}", package)))?,
784+
summary.dl(),
785+
)
786+
}
771787
}
772788
};
773-
match self.ops.download(package, hash)? {
789+
match self.ops.download(package, override_dl.as_deref(), hash)? {
774790
MaybeLock::Ready(file) => self.get_pkg(package, &file).map(MaybePackage::Ready),
775791
MaybeLock::Download { url, descriptor } => {
776792
Ok(MaybePackage::Download { url, descriptor })
@@ -780,9 +796,13 @@ impl<'cfg> Source for RegistrySource<'cfg> {
780796

781797
fn finish_download(&mut self, package: PackageId, data: Vec<u8>) -> CargoResult<Package> {
782798
let hash = loop {
783-
match self.index.hash(package, &mut *self.ops)? {
799+
match self.index.summary(package, &mut *self.ops)? {
784800
Poll::Pending => self.block_until_ready()?,
785-
Poll::Ready(hash) => break hash,
801+
Poll::Ready(IndexSummary { ref summary, .. }) => {
802+
break summary
803+
.checksum()
804+
.ok_or_else(|| internal(format!("no hash listed for {}", package)))?
805+
}
786806
}
787807
};
788808
let file = self.ops.finish_download(package, hash, &data)?;

src/cargo/sources/registry/remote.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,12 @@ impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
296296
self.updated
297297
}
298298

299-
fn download(&mut self, pkg: PackageId, checksum: &str) -> CargoResult<MaybeLock> {
299+
fn download(
300+
&mut self,
301+
pkg: PackageId,
302+
override_dl: Option<&str>,
303+
checksum: &str,
304+
) -> CargoResult<MaybeLock> {
300305
let registry_config = loop {
301306
match self.config()? {
302307
Poll::Pending => self.block_until_ready()?,
@@ -308,6 +313,7 @@ impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
308313
&self.cache_path,
309314
&self.config,
310315
pkg,
316+
override_dl,
311317
checksum,
312318
registry_config,
313319
)

src/cargo/util/toml/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1627,6 +1627,7 @@ impl TomlManifest {
16271627
deps,
16281628
me.features.as_ref().unwrap_or(&empty_features),
16291629
project.links.as_deref(),
1630+
None,
16301631
)?;
16311632

16321633
let metadata = ManifestMetadata {

src/doc/src/reference/registries.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,11 @@ explaining the format of the entry.
264264
// The `links` string value from the package's manifest, or null if not
265265
// specified. This field is optional and defaults to null.
266266
"links": null,
267+
// This optional field specifies the download link for this package
268+
// only, overriding the global `dl` link declared in the registry's
269+
// `config.toml`. The `{crate}` markers et al. are not interpolated
270+
// in this context.
271+
"dl": "https://crates.io/api/v1/crates/foo/0.1.0/download"
267272
// An unsigned 32-bit integer value indicating the schema version of this
268273
// entry.
269274
//

0 commit comments

Comments
 (0)