diff --git a/src/bin/cargo/commands/add.rs b/src/bin/cargo/commands/add.rs index 1ff2aad1944..0c5c0231125 100644 --- a/src/bin/cargo/commands/add.rs +++ b/src/bin/cargo/commands/add.rs @@ -6,10 +6,10 @@ use cargo::core::FeatureValue; use cargo::ops::cargo_add::add; use cargo::ops::cargo_add::AddOptions; use cargo::ops::cargo_add::DepOp; -use cargo::ops::cargo_add::DepTable; use cargo::ops::resolve_ws; use cargo::util::command_prelude::*; use cargo::util::interning::InternedString; +use cargo::util::toml_mut::manifest::DepTable; use cargo::CargoResult; pub fn cli() -> clap::Command<'static> { diff --git a/src/cargo/ops/cargo_add/crate_spec.rs b/src/cargo/ops/cargo_add/crate_spec.rs index 33b4957f758..f07e2fae59b 100644 --- a/src/cargo/ops/cargo_add/crate_spec.rs +++ b/src/cargo/ops/cargo_add/crate_spec.rs @@ -3,7 +3,7 @@ use anyhow::Context as _; use super::Dependency; -use super::RegistrySource; +use crate::util::toml_mut::dependency::RegistrySource; use crate::util::validate_package_name; use crate::CargoResult; diff --git a/src/cargo/ops/cargo_add/mod.rs b/src/cargo/ops/cargo_add/mod.rs index 48963284e0e..31d3a97fe2a 100644 --- a/src/cargo/ops/cargo_add/mod.rs +++ b/src/cargo/ops/cargo_add/mod.rs @@ -1,8 +1,6 @@ //! Core of cargo-add command mod crate_spec; -mod dependency; -mod manifest; use std::collections::BTreeMap; use std::collections::BTreeSet; @@ -26,18 +24,17 @@ use crate::core::Registry; use crate::core::Shell; use crate::core::Summary; use crate::core::Workspace; +use crate::util::toml_mut::dependency::Dependency; +use crate::util::toml_mut::dependency::GitSource; +use crate::util::toml_mut::dependency::MaybeWorkspace; +use crate::util::toml_mut::dependency::PathSource; +use crate::util::toml_mut::dependency::Source; +use crate::util::toml_mut::dependency::WorkspaceSource; +use crate::util::toml_mut::manifest::DepTable; +use crate::util::toml_mut::manifest::LocalManifest; use crate::CargoResult; use crate::Config; use crate_spec::CrateSpec; -use dependency::Dependency; -use dependency::GitSource; -use dependency::PathSource; -use dependency::RegistrySource; -use dependency::Source; -use manifest::LocalManifest; - -use crate::ops::cargo_add::dependency::{MaybeWorkspace, WorkspaceSource}; -pub use manifest::DepTable; /// Information on what dependencies should be added #[derive(Clone, Debug)] diff --git a/src/cargo/util/mod.rs b/src/cargo/util/mod.rs index 2cfea54d2ea..28f685c209a 100644 --- a/src/cargo/util/mod.rs +++ b/src/cargo/util/mod.rs @@ -57,6 +57,7 @@ pub mod rustc; mod semver_ext; pub mod to_semver; pub mod toml; +pub mod toml_mut; mod vcs; mod workspace; diff --git a/src/cargo/ops/cargo_add/dependency.rs b/src/cargo/util/toml_mut/dependency.rs similarity index 93% rename from src/cargo/ops/cargo_add/dependency.rs rename to src/cargo/util/toml_mut/dependency.rs index d105d9d9728..d8a2f2750aa 100644 --- a/src/cargo/ops/cargo_add/dependency.rs +++ b/src/cargo/util/toml_mut/dependency.rs @@ -1,3 +1,5 @@ +//! Information about dependencies in a manifest. + use std::fmt::{Display, Formatter}; use std::path::{Path, PathBuf}; @@ -11,27 +13,28 @@ use crate::core::Summary; use crate::CargoResult; use crate::Config; -/// A dependency handled by Cargo +/// A dependency handled by Cargo. /// -/// `None` means the field will be blank in TOML +/// `None` means the field will be blank in TOML. #[derive(Debug, PartialEq, Eq, Clone)] #[non_exhaustive] pub struct Dependency { - /// The name of the dependency (as it is set in its `Cargo.toml` and known to crates.io) + /// The name of the dependency (as it is set in its `Cargo.toml` and known + /// to crates.io). pub name: String, - /// Whether the dependency is opted-in with a feature flag + /// Whether the dependency is opted-in with a feature flag. pub optional: Option, /// List of features to add (or None to keep features unchanged). pub features: Option>, - /// Whether default features are enabled + /// Whether default features are enabled. pub default_features: Option, - /// List of features inherited from a workspace dependency + /// List of features inherited from a workspace dependency. pub inherited_features: Option>, - /// Where the dependency comes from + /// Where the dependency comes from. pub source: Option, - /// Non-default registry + /// Non-default registry. pub registry: Option, /// If the dependency is renamed, this is the new name for the dependency @@ -40,7 +43,7 @@ pub struct Dependency { } impl Dependency { - /// Create a new dependency with a name + /// Create a new dependency with a name. pub fn new(name: &str) -> Self { Self { name: name.into(), @@ -54,13 +57,13 @@ impl Dependency { } } - /// Set dependency to a given version + /// Set dependency to a given version. pub fn set_source(mut self, source: impl Into) -> Self { self.source = Some(source.into()); self } - /// Remove the existing version requirement + /// Remove the existing version requirement. pub fn clear_version(mut self) -> Self { match &mut self.source { Some(Source::Registry(_)) => { @@ -78,20 +81,21 @@ impl Dependency { self } - /// Set whether the dependency is optional + /// Set whether the dependency is optional. #[allow(dead_code)] pub fn set_optional(mut self, opt: bool) -> Self { self.optional = Some(opt); self } - /// Set features as an array of string (does some basic parsing) + /// Set features as an array of string (does some basic parsing). #[allow(dead_code)] pub fn set_features(mut self, features: IndexSet) -> Self { self.features = Some(features); self } - /// Set features as an array of string (does some basic parsing) + + /// Set features as an array of string (does some basic parsing). pub fn extend_features(mut self, features: impl IntoIterator) -> Self { self.features .get_or_insert_with(Default::default) @@ -99,37 +103,37 @@ impl Dependency { self } - /// Set the value of default-features for the dependency + /// Set the value of default-features for the dependency. #[allow(dead_code)] pub fn set_default_features(mut self, default_features: bool) -> Self { self.default_features = Some(default_features); self } - /// Set the alias for the dependency + /// Set the alias for the dependency. pub fn set_rename(mut self, rename: &str) -> Self { self.rename = Some(rename.into()); self } - /// Set the value of registry for the dependency + /// Set the value of registry for the dependency. pub fn set_registry(mut self, registry: impl Into) -> Self { self.registry = Some(registry.into()); self } - /// Set features as an array of string (does some basic parsing) + /// Set features as an array of string (does some basic parsing). pub fn set_inherited_features(mut self, features: IndexSet) -> Self { self.inherited_features = Some(features); self } - /// Get the dependency source + /// Get the dependency source. pub fn source(&self) -> Option<&Source> { self.source.as_ref() } - /// Get version of dependency + /// Get version of dependency. pub fn version(&self) -> Option<&str> { match self.source()? { Source::Registry(src) => Some(src.version.as_str()), @@ -139,27 +143,27 @@ impl Dependency { } } - /// Get registry of the dependency + /// Get registry of the dependency. pub fn registry(&self) -> Option<&str> { self.registry.as_deref() } - /// Get the alias for the dependency (if any) + /// Get the alias for the dependency (if any). pub fn rename(&self) -> Option<&str> { self.rename.as_deref() } - /// Whether default features are activated + /// Whether default features are activated. pub fn default_features(&self) -> Option { self.default_features } - /// Get whether the dep is optional + /// Get whether the dep is optional. pub fn optional(&self) -> Option { self.optional } - /// Get the SourceID for this dependency + /// Get the SourceID for this dependency. pub fn source_id(&self, config: &Config) -> CargoResult> { match &self.source.as_ref() { Some(Source::Registry(_)) | None => { @@ -177,7 +181,7 @@ impl Dependency { } } - /// Query to find this dependency + /// Query to find this dependency. pub fn query( &self, config: &Config, @@ -196,13 +200,14 @@ impl Dependency { } } +/// Either a workspace or another type. pub enum MaybeWorkspace { Workspace(WorkspaceSource), Other(T), } impl Dependency { - /// Create a dependency from a TOML table entry + /// Create a dependency from a TOML table entry. pub fn from_toml(crate_root: &Path, key: &str, item: &toml_edit::Item) -> CargoResult { if let Some(version) = item.as_str() { let dep = Self::new(key).set_source(RegistrySource::new(version)); @@ -334,12 +339,12 @@ impl Dependency { self.rename().unwrap_or(&self.name) } - /// Convert dependency to TOML + /// Convert dependency to TOML. /// - /// Returns a tuple with the dependency's name and either the version as a `String` - /// or the path/git repository as an `InlineTable`. - /// (If the dependency is set as `optional` or `default-features` is set to `false`, - /// an `InlineTable` is returned in any case.) + /// Returns a tuple with the dependency's name and either the version as a + /// `String` or the path/git repository as an `InlineTable`. + /// (If the dependency is set as `optional` or `default-features` is set to + /// `false`, an `InlineTable` is returned in any case.) /// /// # Panic /// @@ -435,7 +440,7 @@ impl Dependency { table } - /// Modify existing entry to match this dependency + /// Modify existing entry to match this dependency. pub fn update_toml<'k>( &self, crate_root: &Path, @@ -621,21 +626,21 @@ fn path_field(crate_root: &Path, abs_path: &Path) -> String { relpath } -/// Primary location of a dependency +/// Primary location of a dependency. #[derive(Debug, Hash, PartialEq, Eq, Clone)] pub enum Source { - /// Dependency from a registry + /// Dependency from a registry. Registry(RegistrySource), - /// Dependency from a local path + /// Dependency from a local path. Path(PathSource), - /// Dependency from a git repo + /// Dependency from a git repo. Git(GitSource), - /// Dependency from a workspace + /// Dependency from a workspace. Workspace(WorkspaceSource), } impl Source { - /// Access the registry source, if present + /// Access the registry source, if present. pub fn as_registry(&self) -> Option<&RegistrySource> { match self { Self::Registry(src) => Some(src), @@ -643,7 +648,7 @@ impl Source { } } - /// Access the path source, if present + /// Access the path source, if present. #[allow(dead_code)] pub fn as_path(&self) -> Option<&PathSource> { match self { @@ -652,7 +657,7 @@ impl Source { } } - /// Access the git source, if present + /// Access the git source, if present. #[allow(dead_code)] pub fn as_git(&self) -> Option<&GitSource> { match self { @@ -661,7 +666,7 @@ impl Source { } } - /// Access the workspace source, if present + /// Access the workspace source, if present. #[allow(dead_code)] pub fn as_workspace(&self) -> Option<&WorkspaceSource> { match self { @@ -712,16 +717,16 @@ impl From for Source { } } -/// Dependency from a registry +/// Dependency from a registry. #[derive(Debug, Hash, PartialEq, Eq, Clone)] #[non_exhaustive] pub struct RegistrySource { - /// Version requirement + /// Version requirement. pub version: String, } impl RegistrySource { - /// Specify dependency by version requirement + /// Specify dependency by version requirement. pub fn new(version: impl AsRef) -> Self { // versions might have semver metadata appended which we do not want to // store in the cargo toml files. This would cause a warning upon compilation @@ -739,18 +744,18 @@ impl std::fmt::Display for RegistrySource { } } -/// Dependency from a local path +/// Dependency from a local path. #[derive(Debug, Hash, PartialEq, Eq, Clone)] #[non_exhaustive] pub struct PathSource { - /// Local, absolute path + /// Local, absolute path. pub path: PathBuf, - /// Version requirement for when published + /// Version requirement for when published. pub version: Option, } impl PathSource { - /// Specify dependency from a path + /// Specify dependency from a path. pub fn new(path: impl Into) -> Self { Self { path: path.into(), @@ -758,7 +763,7 @@ impl PathSource { } } - /// Set an optional version requirement + /// Set an optional version requirement. pub fn set_version(mut self, version: impl AsRef) -> Self { // versions might have semver metadata appended which we do not want to // store in the cargo toml files. This would cause a warning upon compilation @@ -768,7 +773,7 @@ impl PathSource { self } - /// Get the SourceID for this dependency + /// Get the SourceID for this dependency. pub fn source_id(&self) -> CargoResult { SourceId::for_path(&self.path) } @@ -780,24 +785,24 @@ impl std::fmt::Display for PathSource { } } -/// Dependency from a git repo +/// Dependency from a git repo. #[derive(Debug, Hash, PartialEq, Eq, Clone)] #[non_exhaustive] pub struct GitSource { - /// Repo URL + /// Repository URL. pub git: String, - /// Select specific branch + /// Select specific branch. pub branch: Option, - /// Select specific tag + /// Select specific tag. pub tag: Option, - /// Select specific rev + /// Select specific rev. pub rev: Option, - /// Version requirement for when published + /// Version requirement for when published. pub version: Option, } impl GitSource { - /// Specify dependency from a git repo + /// Specify dependency from a git repo. pub fn new(git: impl Into) -> Self { Self { git: git.into(), @@ -808,7 +813,7 @@ impl GitSource { } } - /// Specify an optional branch + /// Specify an optional branch. pub fn set_branch(mut self, branch: impl Into) -> Self { self.branch = Some(branch.into()); self.tag = None; @@ -816,7 +821,7 @@ impl GitSource { self } - /// Specify an optional tag + /// Specify an optional tag. pub fn set_tag(mut self, tag: impl Into) -> Self { self.branch = None; self.tag = Some(tag.into()); @@ -824,7 +829,7 @@ impl GitSource { self } - /// Specify an optional rev + /// Specify an optional rev. pub fn set_rev(mut self, rev: impl Into) -> Self { self.branch = None; self.tag = None; @@ -832,7 +837,7 @@ impl GitSource { self } - /// Get the SourceID for this dependency + /// Get the SourceID for this dependency. pub fn source_id(&self) -> CargoResult { let git_url = self.git.parse::()?; let git_ref = self.git_ref(); @@ -852,7 +857,7 @@ impl GitSource { } } - /// Set an optional version requirement + /// Set an optional version requirement. pub fn set_version(mut self, version: impl AsRef) -> Self { // versions might have semver metadata appended which we do not want to // store in the cargo toml files. This would cause a warning upon compilation @@ -874,7 +879,7 @@ impl std::fmt::Display for GitSource { } } -/// Dependency from a workspace +/// Dependency from a workspace. #[derive(Debug, Hash, PartialEq, Eq, Clone)] #[non_exhaustive] pub struct WorkspaceSource; @@ -895,7 +900,7 @@ impl Display for WorkspaceSource { mod tests { use std::path::Path; - use crate::ops::cargo_add::manifest::LocalManifest; + use crate::util::toml_mut::manifest::LocalManifest; use cargo_util::paths; use super::*; diff --git a/src/cargo/ops/cargo_add/manifest.rs b/src/cargo/util/toml_mut/manifest.rs similarity index 95% rename from src/cargo/ops/cargo_add/manifest.rs rename to src/cargo/util/toml_mut/manifest.rs index 1c96b477062..c9a5f5d2cfa 100644 --- a/src/cargo/ops/cargo_add/manifest.rs +++ b/src/cargo/util/toml_mut/manifest.rs @@ -1,3 +1,5 @@ +//! Parsing and editing of manifest files. + use std::ops::{Deref, DerefMut}; use std::path::{Path, PathBuf}; use std::str; @@ -10,7 +12,7 @@ use crate::core::FeatureValue; use crate::util::interning::InternedString; use crate::CargoResult; -/// Dependency table to add dep to +/// Dependency table to add deps to. #[derive(Clone, Debug, PartialEq, Eq)] pub struct DepTable { kind: DepKind, @@ -24,7 +26,7 @@ impl DepTable { Self::new().set_kind(DepKind::Build), ]; - /// Reference to a Dependency Table + /// Reference to a Dependency Table. pub const fn new() -> Self { Self { kind: DepKind::Normal, @@ -32,29 +34,29 @@ impl DepTable { } } - /// Choose the type of dependency + /// Choose the type of dependency. pub const fn set_kind(mut self, kind: DepKind) -> Self { self.kind = kind; self } - /// Choose the platform for the dependency + /// Choose the platform for the dependency. pub fn set_target(mut self, target: impl Into) -> Self { self.target = Some(target.into()); self } - /// Type of dependency + /// Type of dependency. pub fn kind(&self) -> DepKind { self.kind } - /// Platform for the dependency + /// Platform for the dependency. pub fn target(&self) -> Option<&str> { self.target.as_deref() } - /// Keys to the table + /// Keys to the table. pub fn to_table(&self) -> Vec<&str> { if let Some(target) = &self.target { vec!["target", target, self.kind_table()] @@ -84,15 +86,15 @@ impl From for DepTable { } } -/// A Cargo manifest +/// An editable Cargo manifest. #[derive(Debug, Clone)] pub struct Manifest { - /// Manifest contents as TOML data + /// Manifest contents as TOML data. pub data: toml_edit::Document, } impl Manifest { - /// Get the manifest's package name + /// Get the manifest's package name. pub fn package_name(&self) -> CargoResult<&str> { self.data .as_table() @@ -155,8 +157,9 @@ impl Manifest { descend(self.data.as_item_mut(), table_path) } - /// Get all sections in the manifest that exist and might contain dependencies. - /// The returned items are always `Table` or `InlineTable`. + /// Get all sections in the manifest that exist and might contain + /// dependencies. The returned items are always `Table` or + /// `InlineTable`. pub fn get_sections(&self) -> Vec<(DepTable, toml_edit::Item)> { let mut sections = Vec::new(); @@ -242,12 +245,12 @@ impl std::fmt::Display for Manifest { } } -/// A Cargo manifest that is available locally. +/// An editable Cargo manifest that is available locally. #[derive(Debug)] pub struct LocalManifest { - /// Path to the manifest + /// Path to the manifest. pub path: PathBuf, - /// Manifest contents + /// Manifest contents. pub manifest: Manifest, } @@ -266,7 +269,7 @@ impl DerefMut for LocalManifest { } impl LocalManifest { - /// Construct the `LocalManifest` corresponding to the `Path` provided. + /// Construct the `LocalManifest` corresponding to the `Path` provided.. pub fn try_new(path: &Path) -> CargoResult { if !path.is_absolute() { anyhow::bail!("can only edit absolute paths, got {}", path.display()); @@ -279,7 +282,7 @@ impl LocalManifest { }) } - /// Write changes back to the file + /// Write changes back to the file. pub fn write(&self) -> CargoResult<()> { if !self.manifest.data.contains_key("package") && !self.manifest.data.contains_key("project") @@ -304,7 +307,7 @@ impl LocalManifest { cargo_util::paths::write(&self.path, new_contents_bytes) } - /// Lookup a dependency + /// Lookup a dependency. pub fn get_dependency_versions<'s>( &'s self, dep_key: &'s str, @@ -365,7 +368,7 @@ impl LocalManifest { Ok(()) } - /// Remove references to `dep_key` if its no longer present + /// Remove references to `dep_key` if its no longer present. pub fn gc_dep(&mut self, dep_key: &str) { let explicit_dep_activation = self.is_explicit_dep_activation(dep_key); let status = self.dep_status(dep_key); diff --git a/src/cargo/util/toml_mut/mod.rs b/src/cargo/util/toml_mut/mod.rs new file mode 100644 index 00000000000..bdd70e8e6f8 --- /dev/null +++ b/src/cargo/util/toml_mut/mod.rs @@ -0,0 +1,13 @@ +//! Utilities for in-place editing of Cargo.toml manifests. +//! +//! These utilities operate only on the level of a TOML document, and generally +//! do not perform any processing of information beyond what is required for +//! editing. For more comprehensive usage of manifests, see +//! [`Manifest`](crate::core::manifest::Manifest). +//! +//! In most cases, the entrypoint for editing is +//! [`LocalManifest`](crate::util::toml_mut::manifest::LocalManifest), +//! which contains editing functionality for a given manifest's dependencies. + +pub mod dependency; +pub mod manifest;