Skip to content

Commit c72099a

Browse files
committed
feat: support SourceKind::Patched in SourceId
One thing left out here is a consistent/stable hash for patches, The are absolute local paths that might introduces unnecessary changes in lockfile. To mitigate this, patches under the current workspace root will be relative.
1 parent c15a379 commit c72099a

File tree

1 file changed

+42
-1
lines changed

1 file changed

+42
-1
lines changed

Diff for: src/cargo/core/source_id.rs

+42-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::sources::{GitSource, PathSource, RegistrySource};
88
use crate::util::interning::InternedString;
99
use crate::util::{context, CanonicalUrl, CargoResult, GlobalContext, IntoUrl};
1010
use anyhow::Context as _;
11+
use cargo_util_schemas::core::PatchInfo;
1112
use serde::de;
1213
use serde::ser;
1314
use std::cmp::{self, Ordering};
@@ -176,6 +177,14 @@ impl SourceId {
176177
let url = url.into_url()?;
177178
SourceId::new(SourceKind::Path, url, None)
178179
}
180+
"patched" => {
181+
let mut url = url.into_url()?;
182+
let patch_info = PatchInfo::from_query(url.query_pairs())
183+
.with_context(|| format!("parse `{url}`"))?;
184+
url.set_fragment(None);
185+
url.set_query(None);
186+
SourceId::for_patches(SourceId::from_url(url.as_str())?, patch_info)
187+
}
179188
kind => Err(anyhow::format_err!("unsupported source protocol: {}", kind)),
180189
}
181190
}
@@ -245,6 +254,16 @@ impl SourceId {
245254
SourceId::new(SourceKind::Directory, url, None)
246255
}
247256

257+
pub fn for_patches(orig_source_id: SourceId, patch_info: PatchInfo) -> CargoResult<SourceId> {
258+
let url = orig_source_id.as_encoded_url();
259+
// `Url::set_scheme` disallow conversions between non-special and speicial schemes,
260+
// so parse the url from string again.
261+
let url = format!("patched+{url}")
262+
.parse()
263+
.with_context(|| format!("cannot set patched scheme on `{url}`"))?;
264+
SourceId::new(SourceKind::Patched(patch_info), url, None)
265+
}
266+
248267
/// Returns the `SourceId` corresponding to the main repository.
249268
///
250269
/// This is the main cargo registry by default, but it can be overridden in
@@ -666,7 +685,13 @@ impl fmt::Display for SourceId {
666685
}
667686
SourceKind::LocalRegistry => write!(f, "registry `{}`", url_display(&self.inner.url)),
668687
SourceKind::Directory => write!(f, "dir {}", url_display(&self.inner.url)),
669-
SourceKind::Patched(_) => todo!(),
688+
SourceKind::Patched(ref patch_info) => {
689+
let n = patch_info.patches().len();
690+
let plural = if n == 1 { "" } else { "s" };
691+
let name = patch_info.name();
692+
let version = patch_info.version();
693+
write!(f, "{name}@{version} with {n} patch file{plural}")
694+
}
670695
}
671696
}
672697
}
@@ -732,6 +757,14 @@ impl<'a> fmt::Display for SourceIdAsUrl<'a> {
732757
write!(f, "#{}", precise)?;
733758
}
734759
}
760+
761+
if let SourceIdInner {
762+
kind: SourceKind::Patched(patch_info),
763+
..
764+
} = &self.inner
765+
{
766+
write!(f, "?{}", patch_info.as_query())?;
767+
}
735768
Ok(())
736769
}
737770
}
@@ -808,6 +841,8 @@ mod tests {
808841
use std::hash::Hasher;
809842
use std::path::Path;
810843

844+
use cargo_util_schemas::core::PatchInfo;
845+
811846
let gen_hash = |source_id: SourceId| {
812847
let mut hasher = std::collections::hash_map::DefaultHasher::new();
813848
source_id.stable_hash(Path::new("/tmp/ws"), &mut hasher);
@@ -852,6 +887,12 @@ mod tests {
852887
let source_id = SourceId::for_directory(path).unwrap();
853888
assert_eq!(gen_hash(source_id), 17459999773908528552);
854889
assert_eq!(crate::util::hex::short_hash(&source_id), "6568fe2c2fab5bfe");
890+
891+
let patch_info = PatchInfo::new("foo".into(), "1.0.0".into(), vec![path.into()]);
892+
let registry_source_id = SourceId::for_registry(&url).unwrap();
893+
let source_id = SourceId::for_patches(registry_source_id, patch_info).unwrap();
894+
assert_eq!(gen_hash(source_id), 10476212805277277232);
895+
assert_eq!(crate::util::hex::short_hash(&source_id), "45f3b913ab447282");
855896
}
856897

857898
#[test]

0 commit comments

Comments
 (0)