Skip to content

Commit

Permalink
Allow running cargo add foo when a foo.workspace = true already e…
Browse files Browse the repository at this point in the history
…xists
  • Loading branch information
Muscraft committed Apr 22, 2022
1 parent c85a71e commit d0bf960
Show file tree
Hide file tree
Showing 33 changed files with 387 additions and 61 deletions.
112 changes: 102 additions & 10 deletions src/cargo/ops/cargo_add/dependency.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::collections::BTreeMap;
use std::fmt::{Display, Formatter};
use std::path::{Path, PathBuf};

use indexmap::IndexSet;
Expand Down Expand Up @@ -74,6 +75,7 @@ impl Dependency {
Some(Source::Git(git)) => {
git.version = None;
}
Some(Source::Workspace(_workspace)) => {}
None => {}
}
self
Expand Down Expand Up @@ -161,6 +163,7 @@ impl Dependency {
Source::Registry(src) => Some(src.version.as_str()),
Source::Path(src) => src.version.as_deref(),
Source::Git(src) => src.version.as_deref(),
Source::Workspace(_) => None,
}
}

Expand All @@ -185,29 +188,47 @@ impl Dependency {
}

/// Get the SourceID for this dependency
pub fn source_id(&self, config: &Config) -> CargoResult<SourceId> {
pub fn source_id(&self, config: &Config) -> CargoResult<MaybeWorkspace<SourceId>> {
match &self.source.as_ref() {
Some(Source::Registry(_)) | None => {
if let Some(r) = self.registry() {
let source_id = SourceId::alt_registry(config, r)?;
Ok(source_id)
Ok(MaybeWorkspace::Other(source_id))
} else {
let source_id = SourceId::crates_io(config)?;
Ok(source_id)
Ok(MaybeWorkspace::Other(source_id))
}
}
Some(Source::Path(source)) => source.source_id(),
Some(Source::Git(source)) => source.source_id(),
Some(Source::Path(source)) => Ok(MaybeWorkspace::Other(source.source_id()?)),
Some(Source::Git(source)) => Ok(MaybeWorkspace::Other(source.source_id()?)),
Some(Source::Workspace(workspace)) => Ok(MaybeWorkspace::Workspace(workspace.clone())),
}
}

/// Query to find this dependency
pub fn query(&self, config: &Config) -> CargoResult<crate::core::dependency::Dependency> {
pub fn query(
&self,
config: &Config,
) -> CargoResult<MaybeWorkspace<crate::core::dependency::Dependency>> {
let source_id = self.source_id(config)?;
crate::core::dependency::Dependency::parse(self.name.as_str(), self.version(), source_id)
match source_id {
MaybeWorkspace::Workspace(workspace) => Ok(MaybeWorkspace::Workspace(workspace)),
MaybeWorkspace::Other(source_id) => Ok(MaybeWorkspace::Other(
crate::core::dependency::Dependency::parse(
self.name.as_str(),
self.version(),
source_id,
)?,
)),
}
}
}

pub enum MaybeWorkspace<T> {
Workspace(WorkspaceSource),
Other(T),
}

impl Dependency {
/// Create a dependency from a TOML table entry
pub fn from_toml(crate_root: &Path, key: &str, item: &toml_edit::Item) -> CargoResult<Self> {
Expand Down Expand Up @@ -271,6 +292,15 @@ impl Dependency {
invalid_type(key, "version", version.type_name(), "string")
})?);
src.into()
} else if let Some(workspace) = table.get("workspace") {
let workspace_bool = workspace.as_bool().ok_or_else(|| {
invalid_type(key, "workspace", workspace.type_name(), "bool")
})?;
if !workspace_bool {
anyhow::bail!("`{key}.workspace = false` is unsupported")
}
let src = WorkspaceSource::new();
src.into()
} else {
anyhow::bail!("Unrecognized dependency source for `{key}`");
};
Expand Down Expand Up @@ -367,6 +397,12 @@ impl Dependency {
None,
None,
) => toml_edit::value(v),
(false, None, true, Some(Source::Workspace(WorkspaceSource {})), None, None) => {
let mut table = toml_edit::InlineTable::default();
table.set_dotted(true);
table.insert("workspace", true.into());
toml_edit::value(toml_edit::Value::InlineTable(table))
}
// Other cases are represented as an inline table
(_, _, _, _, _, _) => {
let mut table = toml_edit::InlineTable::default();
Expand Down Expand Up @@ -397,6 +433,9 @@ impl Dependency {
table.insert("version", r.into());
}
}
Some(Source::Workspace(_)) => {
table.insert("workspace", true.into());
}
None => {}
}
if table.contains_key("version") {
Expand Down Expand Up @@ -436,7 +475,7 @@ impl Dependency {
Some(Source::Registry(src)) => {
table.insert("version", toml_edit::value(src.version.as_str()));

for key in ["path", "git", "branch", "tag", "rev"] {
for key in ["path", "git", "branch", "tag", "rev", "workspace"] {
table.remove(key);
}
}
Expand All @@ -449,7 +488,7 @@ impl Dependency {
table.remove("version");
}

for key in ["git", "branch", "tag", "rev"] {
for key in ["git", "branch", "tag", "rev", "workspace"] {
table.remove(key);
}
}
Expand All @@ -476,7 +515,23 @@ impl Dependency {
table.remove("version");
}

for key in ["path"] {
for key in ["path", "workspace"] {
table.remove(key);
}
}
Some(Source::Workspace(_)) => {
table.set_dotted(true);
for key in [
"version",
"registry",
"registry-index",
"path",
"git",
"branch",
"tag",
"rev",
"package",
] {
table.remove(key);
}
}
Expand Down Expand Up @@ -516,12 +571,14 @@ impl Dependency {
.unwrap_or_default();
features.extend(new_features.iter().map(|s| s.as_str()));
let features = toml_edit::value(features.into_iter().collect::<toml_edit::Value>());
table.set_dotted(false);
table.insert("features", features);
} else {
table.remove("features");
}
match self.optional {
Some(v) => {
table.set_dotted(false);
table.insert("optional", toml_edit::value(v));
}
None => {
Expand Down Expand Up @@ -596,6 +653,8 @@ pub enum Source {
Path(PathSource),
/// Dependency from a git repo
Git(GitSource),
/// Dependency from a workspace
Workspace(WorkspaceSource),
}

impl Source {
Expand Down Expand Up @@ -624,6 +683,15 @@ impl Source {
_ => None,
}
}

/// Access the workspace source, if present
#[allow(dead_code)]
pub fn as_workspace(&self) -> Option<&WorkspaceSource> {
match self {
Self::Workspace(src) => Some(src),
_ => None,
}
}
}

impl std::fmt::Display for Source {
Expand All @@ -632,6 +700,7 @@ impl std::fmt::Display for Source {
Self::Registry(src) => src.fmt(f),
Self::Path(src) => src.fmt(f),
Self::Git(src) => src.fmt(f),
Self::Workspace(src) => src.fmt(f),
}
}
}
Expand Down Expand Up @@ -660,6 +729,12 @@ impl From<GitSource> for Source {
}
}

impl From<WorkspaceSource> for Source {
fn from(inner: WorkspaceSource) -> Self {
Self::Workspace(inner)
}
}

/// Dependency from a registry
#[derive(Debug, Hash, PartialEq, Eq, Clone)]
#[non_exhaustive]
Expand Down Expand Up @@ -822,6 +897,23 @@ impl std::fmt::Display for GitSource {
}
}

/// Dependency from a workspace
#[derive(Debug, Hash, PartialEq, Eq, Clone)]
#[non_exhaustive]
pub struct WorkspaceSource;

impl WorkspaceSource {
pub fn new() -> Self {
Self
}
}

impl Display for WorkspaceSource {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
"workspace".fmt(f)
}
}

#[cfg(test)]
mod tests {
use std::path::Path;
Expand Down
Loading

0 comments on commit d0bf960

Please sign in to comment.