1use cargo_platform::Platform;
2use semver::VersionReq;
3use serde::Serialize;
4use serde::ser;
5use std::borrow::Cow;
6use std::fmt;
7use std::fmt::{Display, Formatter};
8use std::path::{Path, PathBuf};
9use std::sync::Arc;
10use tracing::trace;
11
12use crate::compiler::{CompileKind, CompileTarget};
13use crate::context::Definition;
14use crate::util::OptVersionReq;
15use crate::util::VersionReqMatchMode;
16use crate::util::errors::CargoResult;
17use crate::util::interning::InternedString;
18use crate::workspace::{CliUnstable, Feature, Features, PackageId, SourceId, Summary};
19
20#[derive(PartialEq, Eq, Hash, Clone, Debug)]
23pub struct Dependency {
24 inner: Arc<Inner>,
25}
26
27#[derive(PartialEq, Eq, Hash, Clone, Debug)]
29struct Inner {
30 name: InternedString,
31 source_id: SourceId,
32 registry_id: Option<SourceId>,
39 req: OptVersionReq,
40 specified_req: bool,
41 kind: DepKind,
42 only_match_name: bool,
43 explicit_name_in_toml: Option<InternedString>,
44
45 optional: bool,
46 public: bool,
47 default_features: bool,
48 features: Vec<InternedString>,
49 artifact: Option<Artifact>,
51
52 platform: Option<Platform>,
55}
56
57#[derive(Serialize)]
58pub struct SerializedDependency {
59 name: InternedString,
60 source: SourceId,
61 req: String,
62 kind: DepKind,
63 rename: Option<InternedString>,
64
65 optional: bool,
66 uses_default_features: bool,
67 features: Vec<InternedString>,
68 #[serde(skip_serializing_if = "Option::is_none")]
69 artifact: Option<Artifact>,
70 target: Option<Platform>,
71 registry: Option<String>,
74
75 #[serde(skip_serializing_if = "Option::is_none")]
77 path: Option<PathBuf>,
78
79 #[serde(skip_serializing_if = "Option::is_none")]
83 public: Option<bool>,
84}
85
86#[derive(PartialEq, Eq, Hash, Ord, PartialOrd, Clone, Debug, Copy)]
87pub enum DepKind {
88 Normal,
89 Development,
90 Build,
91}
92
93impl DepKind {
94 pub fn kind_table(&self) -> &'static str {
95 match self {
96 DepKind::Normal => "dependencies",
97 DepKind::Development => "dev-dependencies",
98 DepKind::Build => "build-dependencies",
99 }
100 }
101}
102
103impl ser::Serialize for DepKind {
104 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
105 where
106 S: ser::Serializer,
107 {
108 match *self {
109 DepKind::Normal => None,
110 DepKind::Development => Some("dev"),
111 DepKind::Build => Some("build"),
112 }
113 .serialize(s)
114 }
115}
116
117impl Dependency {
118 pub fn parse(
120 name: impl Into<InternedString>,
121 version: Option<&str>,
122 source_id: SourceId,
123 ) -> CargoResult<Dependency> {
124 let name = name.into();
125 let (specified_req, version_req) = match version {
126 Some(v) => match VersionReq::parse(v) {
127 Ok(req) => (true, OptVersionReq::Req(req)),
128 Err(err) => {
129 return Err(anyhow::Error::new(err).context(format!(
130 "failed to parse the version requirement `{}` for dependency `{}`",
131 v, name,
132 )));
133 }
134 },
135 None => (false, OptVersionReq::Any),
136 };
137
138 let mut ret = Dependency::new_override(name, source_id);
139 {
140 let ptr = Arc::make_mut(&mut ret.inner);
141 ptr.only_match_name = false;
142 ptr.req = version_req;
143 ptr.specified_req = specified_req;
144 }
145 Ok(ret)
146 }
147
148 pub fn new_override(name: InternedString, source_id: SourceId) -> Dependency {
149 assert!(!name.is_empty());
150 Dependency {
151 inner: Arc::new(Inner {
152 name,
153 source_id,
154 registry_id: None,
155 req: OptVersionReq::Any,
156 kind: DepKind::Normal,
157 only_match_name: true,
158 optional: false,
159 public: false,
160 features: Vec::new(),
161 default_features: true,
162 specified_req: false,
163 platform: None,
164 explicit_name_in_toml: None,
165 artifact: None,
166 }),
167 }
168 }
169
170 pub fn serialized(
171 &self,
172 unstable_flags: &CliUnstable,
173 features: &Features,
174 ) -> SerializedDependency {
175 SerializedDependency {
176 name: self.package_name(),
177 source: self.source_id(),
178 req: self.version_req().to_string(),
179 kind: self.kind(),
180 optional: self.is_optional(),
181 uses_default_features: self.uses_default_features(),
182 features: self.features().to_vec(),
183 target: self.inner.platform.clone(),
184 rename: self.explicit_name_in_toml(),
185 registry: self.registry_id().as_ref().map(|sid| sid.url().to_string()),
186 path: self.source_id().local_path(),
187 artifact: self.inner.artifact.clone(),
188 public: if unstable_flags.public_dependency
189 || features.is_enabled(Feature::public_dependency())
190 {
191 Some(self.inner.public)
192 } else {
193 None
194 },
195 }
196 }
197
198 pub fn version_req(&self) -> &OptVersionReq {
199 &self.inner.req
200 }
201
202 pub fn name_in_toml(&self) -> InternedString {
223 self.explicit_name_in_toml().unwrap_or(self.inner.name)
224 }
225
226 pub fn package_name(&self) -> InternedString {
245 self.inner.name
246 }
247
248 pub fn source_id(&self) -> SourceId {
249 self.inner.source_id
250 }
251
252 pub fn registry_id(&self) -> Option<SourceId> {
253 self.inner.registry_id
254 }
255
256 pub fn set_registry_id(&mut self, registry_id: SourceId) -> &mut Dependency {
257 Arc::make_mut(&mut self.inner).registry_id = Some(registry_id);
258 self
259 }
260
261 pub fn kind(&self) -> DepKind {
262 self.inner.kind
263 }
264
265 pub fn is_public(&self) -> bool {
266 self.inner.public
267 }
268
269 pub fn set_public(&mut self, public: bool) -> &mut Dependency {
271 if public {
272 assert_eq!(self.kind(), DepKind::Normal);
274 }
275 Arc::make_mut(&mut self.inner).public = public;
276 self
277 }
278
279 pub fn specified_req(&self) -> bool {
280 self.inner.specified_req
281 }
282
283 pub fn platform(&self) -> Option<&Platform> {
286 self.inner.platform.as_ref()
287 }
288
289 pub fn explicit_name_in_toml(&self) -> Option<InternedString> {
294 self.inner.explicit_name_in_toml
295 }
296
297 pub fn toml_path(&self) -> Vec<String> {
299 let mut path = Vec::new();
300 if let Some(platform) = self.platform() {
301 path.push("target".to_owned());
302 path.push(platform.to_string());
303 }
304 path.push(self.kind().kind_table().to_owned());
305 path.push((&*self.name_in_toml()).to_owned());
306 path
307 }
308
309 pub fn set_kind(&mut self, kind: DepKind) -> &mut Dependency {
310 if self.is_public() {
311 assert_eq!(kind, DepKind::Normal);
313 }
314 Arc::make_mut(&mut self.inner).kind = kind;
315 self
316 }
317
318 pub fn set_features(
320 &mut self,
321 features: impl IntoIterator<Item = impl Into<InternedString>>,
322 ) -> &mut Dependency {
323 Arc::make_mut(&mut self.inner).features = features.into_iter().map(|s| s.into()).collect();
324 self
325 }
326
327 pub fn set_default_features(&mut self, default_features: bool) -> &mut Dependency {
329 Arc::make_mut(&mut self.inner).default_features = default_features;
330 self
331 }
332
333 pub fn set_optional(&mut self, optional: bool) -> &mut Dependency {
335 Arc::make_mut(&mut self.inner).optional = optional;
336 self
337 }
338
339 pub fn set_source_id(&mut self, id: SourceId) -> &mut Dependency {
341 Arc::make_mut(&mut self.inner).source_id = id;
342 self
343 }
344
345 pub fn set_version_req(&mut self, req: OptVersionReq) -> &mut Dependency {
347 Arc::make_mut(&mut self.inner).req = req;
348 self
349 }
350
351 pub fn set_platform(&mut self, platform: Option<Platform>) -> &mut Dependency {
352 Arc::make_mut(&mut self.inner).platform = platform;
353 self
354 }
355
356 pub fn set_explicit_name_in_toml(
357 &mut self,
358 name: impl Into<InternedString>,
359 ) -> &mut Dependency {
360 Arc::make_mut(&mut self.inner).explicit_name_in_toml = Some(name.into());
361 self
362 }
363
364 pub fn lock_to(&mut self, id: PackageId, mode: VersionReqMatchMode) -> &mut Dependency {
366 assert_eq!(self.inner.source_id, id.source_id());
367 trace!(
368 "locking dep from `{}` with `{}` at {} to {}",
369 self.package_name(),
370 self.version_req(),
371 self.source_id(),
372 id
373 );
374 let me = Arc::make_mut(&mut self.inner);
375 me.req.lock_to(id.version(), mode);
376
377 me.source_id = me.source_id.with_precise_from(id.source_id());
381 self
382 }
383
384 pub fn lock_version(
389 &mut self,
390 version: &semver::Version,
391 mode: VersionReqMatchMode,
392 ) -> &mut Dependency {
393 let me = Arc::make_mut(&mut self.inner);
394 me.req.lock_to(version, mode);
395 self
396 }
397
398 pub fn is_locked(&self) -> bool {
401 self.inner.req.is_locked()
402 }
403
404 pub fn is_transitive(&self) -> bool {
406 match self.inner.kind {
407 DepKind::Normal | DepKind::Build => true,
408 DepKind::Development => false,
409 }
410 }
411
412 pub fn is_build(&self) -> bool {
413 matches!(self.inner.kind, DepKind::Build)
414 }
415
416 pub fn is_optional(&self) -> bool {
417 self.inner.optional
418 }
419
420 pub fn uses_default_features(&self) -> bool {
422 self.inner.default_features
423 }
424 pub fn features(&self) -> &[InternedString] {
426 &self.inner.features
427 }
428
429 pub fn matches(&self, sum: &Summary, mode: VersionReqMatchMode) -> bool {
431 self.matches_id(sum.package_id(), mode)
432 }
433
434 pub fn matches_ignoring_source(&self, id: PackageId, mode: VersionReqMatchMode) -> bool {
436 self.package_name() == id.name() && self.version_req().matches(id.version(), mode)
437 }
438
439 pub fn matches_id(&self, id: PackageId, mode: VersionReqMatchMode) -> bool {
441 self.inner.name == id.name()
442 && (self.inner.only_match_name
443 || (self.inner.req.matches(id.version(), mode)
444 && self.inner.source_id == id.source_id()))
445 }
446
447 pub fn map_source(mut self, to_replace: SourceId, replace_with: SourceId) -> Dependency {
448 if self.source_id() == to_replace {
449 self.set_source_id(replace_with);
450 }
451 self
452 }
453
454 pub(crate) fn set_artifact(&mut self, artifact: Artifact) {
455 Arc::make_mut(&mut self.inner).artifact = Some(artifact);
456 }
457
458 pub fn artifact(&self) -> Option<&Artifact> {
459 self.inner.artifact.as_ref()
460 }
461
462 pub(crate) fn maybe_lib(&self) -> bool {
466 self.artifact().map(|a| a.is_lib).unwrap_or(true)
467 }
468}
469
470#[derive(PartialEq, Eq, Hash, Clone, Debug)]
477pub struct Artifact {
478 inner: Arc<Vec<ArtifactKind>>,
479 is_lib: bool,
480 target: Option<ArtifactTarget>,
481}
482
483#[derive(Serialize)]
484pub struct SerializedArtifact<'a> {
485 kinds: &'a [ArtifactKind],
486 lib: bool,
487 target: Option<&'a str>,
488}
489
490impl ser::Serialize for Artifact {
491 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
492 where
493 S: ser::Serializer,
494 {
495 SerializedArtifact {
496 kinds: self.kinds(),
497 lib: self.is_lib,
498 target: self.target.as_ref().map(ArtifactTarget::as_str),
499 }
500 .serialize(s)
501 }
502}
503
504impl Artifact {
505 pub(crate) fn parse(
506 artifacts: &[impl AsRef<str>],
507 is_lib: bool,
508 target: Option<&str>,
509 unstable_json: bool,
510 ) -> CargoResult<Self> {
511 let kinds = ArtifactKind::validate(
512 artifacts
513 .iter()
514 .map(|s| ArtifactKind::parse(s.as_ref()))
515 .collect::<Result<Vec<_>, _>>()?,
516 )?;
517 Ok(Artifact {
518 inner: Arc::new(kinds),
519 is_lib,
520 target: target
521 .map(|name| ArtifactTarget::parse(name, unstable_json))
522 .transpose()?,
523 })
524 }
525
526 pub fn kinds(&self) -> &[ArtifactKind] {
527 &self.inner
528 }
529
530 pub fn is_lib(&self) -> bool {
531 self.is_lib
532 }
533
534 pub fn target(&self) -> Option<ArtifactTarget> {
535 self.target
536 }
537}
538
539#[derive(PartialEq, Eq, Hash, Copy, Clone, Ord, PartialOrd, Debug)]
540pub enum ArtifactTarget {
541 BuildDependencyAssumeTarget,
545 Force(CompileTarget),
549}
550
551impl ArtifactTarget {
552 pub fn parse(target: &str, unstable_json: bool) -> CargoResult<ArtifactTarget> {
553 Ok(match target {
554 "target" => ArtifactTarget::BuildDependencyAssumeTarget,
555 name => ArtifactTarget::Force(CompileTarget::new(name, unstable_json)?),
556 })
557 }
558
559 pub fn as_str(&self) -> &str {
560 match self {
561 ArtifactTarget::BuildDependencyAssumeTarget => "target",
562 ArtifactTarget::Force(target) => target.rustc_target().as_str(),
563 }
564 }
565
566 pub fn to_compile_kind(&self) -> Option<CompileKind> {
567 self.to_compile_target().map(CompileKind::Target)
568 }
569
570 pub fn to_compile_target(&self) -> Option<CompileTarget> {
571 match self {
572 ArtifactTarget::BuildDependencyAssumeTarget => None,
573 ArtifactTarget::Force(target) => Some(*target),
574 }
575 }
576
577 pub(crate) fn to_resolved_compile_kind(
578 &self,
579 root_unit_compile_kind: CompileKind,
580 ) -> CompileKind {
581 match self {
582 ArtifactTarget::Force(target) => CompileKind::Target(*target),
583 ArtifactTarget::BuildDependencyAssumeTarget => root_unit_compile_kind,
584 }
585 }
586
587 pub(crate) fn to_resolved_compile_target(
588 &self,
589 root_unit_compile_kind: CompileKind,
590 ) -> Option<CompileTarget> {
591 match self.to_resolved_compile_kind(root_unit_compile_kind) {
592 CompileKind::Host => None,
593 CompileKind::Target(target) => Some(target),
594 }
595 }
596}
597
598#[derive(PartialEq, Eq, Hash, Copy, Clone, Ord, PartialOrd, Debug)]
599pub enum ArtifactKind {
600 AllBinaries,
602 SelectedBinary(InternedString),
604 Cdylib,
605 Staticlib,
606}
607
608impl ser::Serialize for ArtifactKind {
609 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
610 where
611 S: ser::Serializer,
612 {
613 self.as_str().serialize(s)
614 }
615}
616
617impl fmt::Display for ArtifactKind {
618 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
619 f.write_str(&self.as_str())
620 }
621}
622
623impl ArtifactKind {
624 pub fn crate_type(&self) -> &'static str {
628 match self {
629 ArtifactKind::AllBinaries | ArtifactKind::SelectedBinary(_) => "bin",
630 ArtifactKind::Cdylib => "cdylib",
631 ArtifactKind::Staticlib => "staticlib",
632 }
633 }
634
635 pub fn as_str(&self) -> Cow<'static, str> {
636 match *self {
637 ArtifactKind::SelectedBinary(name) => format!("bin:{}", name.as_str()).into(),
638 _ => self.crate_type().into(),
639 }
640 }
641
642 pub fn parse(kind: &str) -> CargoResult<Self> {
643 Ok(match kind {
644 "bin" => ArtifactKind::AllBinaries,
645 "cdylib" => ArtifactKind::Cdylib,
646 "staticlib" => ArtifactKind::Staticlib,
647 _ => {
648 return kind
649 .strip_prefix("bin:")
650 .map(|bin_name| ArtifactKind::SelectedBinary(bin_name.into()))
651 .ok_or_else(|| {
652 anyhow::anyhow!("'{}' is not a valid artifact specifier", kind)
653 });
654 }
655 })
656 }
657
658 fn validate(kinds: Vec<ArtifactKind>) -> CargoResult<Vec<ArtifactKind>> {
659 if kinds.iter().any(|k| matches!(k, ArtifactKind::AllBinaries))
660 && kinds
661 .iter()
662 .any(|k| matches!(k, ArtifactKind::SelectedBinary(_)))
663 {
664 anyhow::bail!(
665 "Cannot specify both 'bin' and 'bin:<name>' binary artifacts, as 'bin' selects all available binaries."
666 );
667 }
668 let mut kinds_without_dupes = kinds.clone();
669 kinds_without_dupes.sort();
670 kinds_without_dupes.dedup();
671 let num_dupes = kinds.len() - kinds_without_dupes.len();
672 if num_dupes != 0 {
673 anyhow::bail!(
674 "Found {} duplicate binary artifact{}",
675 num_dupes,
676 (num_dupes > 1).then(|| "s").unwrap_or("")
677 );
678 }
679 Ok(kinds)
680 }
681}
682
683#[derive(Clone, Debug)]
686pub struct Patch {
687 pub dep: Dependency,
688 pub loc: PatchLocation,
689}
690
691#[derive(Clone, Debug)]
693pub enum PatchLocation {
694 Manifest(PathBuf),
696 Config(Definition),
698}
699
700impl Display for PatchLocation {
701 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
702 match self {
703 PatchLocation::Manifest(p) => Path::display(p).fmt(f),
704 PatchLocation::Config(def) => def.fmt(f),
705 }
706 }
707}