cargo/sources/
replaced.rs

1use crate::core::{Dependency, Package, PackageId, SourceId};
2use crate::sources::source::MaybePackage;
3use crate::sources::source::QueryKind;
4use crate::sources::source::Source;
5use crate::sources::IndexSummary;
6use crate::util::errors::CargoResult;
7use std::task::Poll;
8
9/// A source that replaces one source with the other. This manages the [source
10/// replacement] feature.
11///
12/// The implementation is merely redirecting from the original to the replacement.
13///
14/// [source replacement]: https://doc.rust-lang.org/nightly/cargo/reference/source-replacement.html
15pub struct ReplacedSource<'gctx> {
16    /// The identifier of the original source.
17    to_replace: SourceId,
18    /// The identifier of the new replacement source.
19    replace_with: SourceId,
20    inner: Box<dyn Source + 'gctx>,
21}
22
23impl<'gctx> ReplacedSource<'gctx> {
24    /// Creates a replaced source.
25    ///
26    /// The `src` argument is the new replacement source.
27    pub fn new(
28        to_replace: SourceId,
29        replace_with: SourceId,
30        src: Box<dyn Source + 'gctx>,
31    ) -> ReplacedSource<'gctx> {
32        ReplacedSource {
33            to_replace,
34            replace_with,
35            inner: src,
36        }
37    }
38
39    /// Is this source a built-in replacement of crates.io?
40    ///
41    /// Built-in source replacement of crates.io for sparse registry or tests
42    /// should not show messages indicating source replacement.
43    fn is_builtin_replacement(&self) -> bool {
44        self.replace_with.is_crates_io() && self.to_replace.is_crates_io()
45    }
46}
47
48impl<'gctx> Source for ReplacedSource<'gctx> {
49    fn source_id(&self) -> SourceId {
50        self.to_replace
51    }
52
53    fn replaced_source_id(&self) -> SourceId {
54        self.replace_with
55    }
56
57    fn supports_checksums(&self) -> bool {
58        self.inner.supports_checksums()
59    }
60
61    fn requires_precise(&self) -> bool {
62        self.inner.requires_precise()
63    }
64
65    fn query(
66        &mut self,
67        dep: &Dependency,
68        kind: QueryKind,
69        f: &mut dyn FnMut(IndexSummary),
70    ) -> Poll<CargoResult<()>> {
71        let (replace_with, to_replace) = (self.replace_with, self.to_replace);
72        let dep = dep.clone().map_source(to_replace, replace_with);
73
74        self.inner
75            .query(&dep, kind, &mut |summary| {
76                f(summary.map_summary(|s| s.map_source(replace_with, to_replace)))
77            })
78            .map_err(|e| {
79                if self.is_builtin_replacement() {
80                    e
81                } else {
82                    e.context(format!(
83                        "failed to query replaced source {}",
84                        self.to_replace
85                    ))
86                }
87            })
88    }
89
90    fn invalidate_cache(&mut self) {
91        self.inner.invalidate_cache()
92    }
93
94    fn set_quiet(&mut self, quiet: bool) {
95        self.inner.set_quiet(quiet);
96    }
97
98    fn download(&mut self, id: PackageId) -> CargoResult<MaybePackage> {
99        let id = id.with_source_id(self.replace_with);
100        let pkg = self.inner.download(id).map_err(|e| {
101            if self.is_builtin_replacement() {
102                e
103            } else {
104                e.context(format!(
105                    "failed to download replaced source {}",
106                    self.to_replace
107                ))
108            }
109        })?;
110        Ok(match pkg {
111            MaybePackage::Ready(pkg) => {
112                MaybePackage::Ready(pkg.map_source(self.replace_with, self.to_replace))
113            }
114            other @ MaybePackage::Download { .. } => other,
115        })
116    }
117
118    fn finish_download(&mut self, id: PackageId, data: Vec<u8>) -> CargoResult<Package> {
119        let id = id.with_source_id(self.replace_with);
120        let pkg = self.inner.finish_download(id, data).map_err(|e| {
121            if self.is_builtin_replacement() {
122                e
123            } else {
124                e.context(format!(
125                    "failed to download replaced source {}",
126                    self.to_replace
127                ))
128            }
129        })?;
130        Ok(pkg.map_source(self.replace_with, self.to_replace))
131    }
132
133    fn fingerprint(&self, id: &Package) -> CargoResult<String> {
134        self.inner.fingerprint(id)
135    }
136
137    fn verify(&self, id: PackageId) -> CargoResult<()> {
138        let id = id.with_source_id(self.replace_with);
139        self.inner.verify(id)
140    }
141
142    fn describe(&self) -> String {
143        if self.is_builtin_replacement() {
144            self.inner.describe()
145        } else {
146            format!(
147                "{} (which is replacing {})",
148                self.inner.describe(),
149                self.to_replace
150            )
151        }
152    }
153
154    fn is_replaced(&self) -> bool {
155        !self.is_builtin_replacement()
156    }
157
158    fn add_to_yanked_whitelist(&mut self, pkgs: &[PackageId]) {
159        let pkgs = pkgs
160            .iter()
161            .map(|id| id.with_source_id(self.replace_with))
162            .collect::<Vec<_>>();
163        self.inner.add_to_yanked_whitelist(&pkgs);
164    }
165
166    fn is_yanked(&mut self, pkg: PackageId) -> Poll<CargoResult<bool>> {
167        self.inner.is_yanked(pkg)
168    }
169
170    fn block_until_ready(&mut self) -> CargoResult<()> {
171        self.inner.block_until_ready().map_err(|e| {
172            if self.is_builtin_replacement() {
173                e
174            } else {
175                e.context(format!(
176                    "failed to update replaced source {}",
177                    self.to_replace
178                ))
179            }
180        })
181    }
182}