cargo/sources/
overlay.rs
1use std::task::ready;
2
3use tracing::debug;
4
5use crate::sources::IndexSummary;
6
7use super::source::{MaybePackage, Source};
8
9pub struct DependencyConfusionThreatOverlaySource<'gctx> {
17 local: Box<dyn Source + 'gctx>,
20 remote: Box<dyn Source + 'gctx>,
22}
23
24impl<'gctx> DependencyConfusionThreatOverlaySource<'gctx> {
25 pub fn new(local: Box<dyn Source + 'gctx>, remote: Box<dyn Source + 'gctx>) -> Self {
26 debug!(
27 "overlaying {} on {}",
28 local.source_id().as_url(),
29 remote.source_id().as_url()
30 );
31 Self { local, remote }
32 }
33}
34
35impl<'gctx> Source for DependencyConfusionThreatOverlaySource<'gctx> {
36 fn source_id(&self) -> crate::core::SourceId {
37 self.remote.source_id()
38 }
39
40 fn supports_checksums(&self) -> bool {
41 self.local.supports_checksums() && self.remote.supports_checksums()
42 }
43
44 fn requires_precise(&self) -> bool {
45 self.local.requires_precise() || self.remote.requires_precise()
46 }
47
48 fn query(
49 &mut self,
50 dep: &crate::core::Dependency,
51 kind: super::source::QueryKind,
52 f: &mut dyn FnMut(super::IndexSummary),
53 ) -> std::task::Poll<crate::CargoResult<()>> {
54 let local_source = self.local.source_id();
55 let remote_source = self.remote.source_id();
56
57 let local_dep = dep.clone().map_source(remote_source, local_source);
58 let mut local_packages = std::collections::HashSet::new();
59 let mut local_callback = |index: IndexSummary| {
60 let index = index.map_summary(|s| s.map_source(local_source, remote_source));
61 local_packages.insert(index.as_summary().clone());
62 f(index)
63 };
64 ready!(self.local.query(&local_dep, kind, &mut local_callback))?;
65
66 let mut remote_callback = |index: IndexSummary| {
67 if local_packages.contains(index.as_summary()) {
68 tracing::debug!(?local_source, ?remote_source, ?index, "package collision");
69 } else {
70 f(index)
71 }
72 };
73 ready!(self.remote.query(dep, kind, &mut remote_callback))?;
74
75 std::task::Poll::Ready(Ok(()))
76 }
77
78 fn invalidate_cache(&mut self) {
79 self.local.invalidate_cache();
80 self.remote.invalidate_cache();
81 }
82
83 fn set_quiet(&mut self, quiet: bool) {
84 self.local.set_quiet(quiet);
85 self.remote.set_quiet(quiet);
86 }
87
88 fn download(
89 &mut self,
90 package: crate::core::PackageId,
91 ) -> crate::CargoResult<super::source::MaybePackage> {
92 let local_source = self.local.source_id();
93 let remote_source = self.remote.source_id();
94
95 self.local
96 .download(package.map_source(remote_source, local_source))
97 .map(|maybe_pkg| match maybe_pkg {
98 MaybePackage::Ready(pkg) => {
99 MaybePackage::Ready(pkg.map_source(local_source, remote_source))
100 }
101 x => x,
102 })
103 .or_else(|_| self.remote.download(package))
104 }
105
106 fn finish_download(
107 &mut self,
108 pkg_id: crate::core::PackageId,
109 contents: Vec<u8>,
110 ) -> crate::CargoResult<crate::core::Package> {
111 self.remote.finish_download(pkg_id, contents)
114 }
115
116 fn fingerprint(&self, pkg: &crate::core::Package) -> crate::CargoResult<String> {
117 Ok(pkg.package_id().version().to_string())
118 }
119
120 fn describe(&self) -> String {
121 self.remote.describe()
122 }
123
124 fn add_to_yanked_whitelist(&mut self, pkgs: &[crate::core::PackageId]) {
125 self.local.add_to_yanked_whitelist(pkgs);
126 self.remote.add_to_yanked_whitelist(pkgs);
127 }
128
129 fn is_yanked(
130 &mut self,
131 pkg: crate::core::PackageId,
132 ) -> std::task::Poll<crate::CargoResult<bool>> {
133 self.remote.is_yanked(pkg)
134 }
135
136 fn block_until_ready(&mut self) -> crate::CargoResult<()> {
137 self.local.block_until_ready()?;
138 self.remote.block_until_ready()
139 }
140}