Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add workspace initial support #1358

Merged
merged 14 commits into from
Nov 6, 2023
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add warning message when using incompatible contract's ink! version - [#1334](https://github.com/paritytech/cargo-contract/pull/1334)
- Bump `subxt` to `0.32.0` - [#1352](https://github.com/paritytech/cargo-contract/pull/1352)
- Remove check for compatible `scale` and `scale-info` versions - [#1370](https://github.com/paritytech/cargo-contract/pull/1370)
- Add workspace support -[#1358](https://github.com/paritytech/cargo-contract/pull/1358)

## [4.0.0-alpha]

Expand Down
1 change: 1 addition & 0 deletions crates/build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ fn exec_cargo_for_onchain_target(
manifest
.with_replaced_lib_to_bin()?
.with_profile_release_defaults(Profile::default_contract_release())?
.with_merged_workspace_dependencies(crate_metadata)?
.with_empty_workspace();
Ok(())
})?
Expand Down
1 change: 1 addition & 0 deletions crates/build/src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ pub fn execute(
lto: Some(Lto::Thin),
..Profile::default()
})?
.with_merged_workspace_dependencies(crate_metadata)?
.with_empty_workspace();
Ok(())
})?
Expand Down
127 changes: 126 additions & 1 deletion crates/build/src/workspace/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ use super::{
metadata,
Profile,
};
use crate::OptimizationPasses;
use crate::{
CrateMetadata,
OptimizationPasses,
};

use std::{
convert::TryFrom,
Expand Down Expand Up @@ -341,6 +344,57 @@ impl Manifest {
Ok(self)
}

/// Merge the workspace dependencies with the crate dependencies.
pub fn with_merged_workspace_dependencies(
&mut self,
crate_metadata: &CrateMetadata,
) -> Result<&mut Self> {
let workspace_manifest_path =
crate_metadata.cargo_meta.workspace_root.join("Cargo.toml");

// If the workspace manifest is the same as the crate manifest, there's not
// workspace to fix
if workspace_manifest_path == self.path.path {
return Ok(self)
ascjones marked this conversation as resolved.
Show resolved Hide resolved
}

let workspace_toml =
fs::read_to_string(&workspace_manifest_path).context("Loading Cargo.toml")?;
let workspace_toml: value::Table = toml::from_str(&workspace_toml)?;

let workspace_dependencies = workspace_toml
.get("workspace")
.ok_or_else(|| {
anyhow::anyhow!("[workspace] should exist in workspace manifest")
})?
.as_table()
.ok_or_else(|| anyhow::anyhow!("[workspace] should be a table"))?
.get("dependencies");

// If no workspace dependencies are defined, return
let Some(workspace_dependencies) = workspace_dependencies else {
return Ok(self)
};

let workspace_dependencies =
workspace_dependencies.as_table().ok_or_else(|| {
anyhow::anyhow!("[workspace.dependencies] should be a table")
})?;

merge_workspace_with_crate_dependencies(
"dependencies",
&mut self.toml,
workspace_dependencies,
)?;
merge_workspace_with_crate_dependencies(
"dev-dependencies",
&mut self.toml,
workspace_dependencies,
)?;

Ok(self)
}

/// Replace relative paths with absolute paths with the working directory.
///
/// Enables the use of a temporary amended copy of the manifest.
Expand Down Expand Up @@ -548,6 +602,77 @@ fn crate_type_exists(crate_type: &str, crate_types: &[value::Value]) -> bool {
.any(|v| v.as_str().map_or(false, |s| s == crate_type))
}

fn merge_workspace_with_crate_dependencies(
section_name: &str,
crate_toml: &mut value::Table,
workspace_dependencies: &value::Table,
) -> Result<()> {
let Some(dependencies) = crate_toml.get_mut(section_name) else {
return Ok(())
};

let table = dependencies
.as_table_mut()
.ok_or_else(|| anyhow::anyhow!("dependencies should be a table"))?;

for (name, value) in table {
let Some(dependency) = value.as_table_mut() else {
continue
};

let is_workspace_dependency = dependency
.get_mut("workspace")
.unwrap_or(&mut toml::Value::Boolean(false))
.as_bool()
.unwrap_or(false);
if !is_workspace_dependency {
continue
}

let workspace_dependency = workspace_dependencies.get(name).ok_or_else(|| {
anyhow::anyhow!("'{}' is not a key in workspace_dependencies", name)
})?;
let workspace_dependency = match workspace_dependency {
toml::Value::Table(table) => table.to_owned(),
// If the workspace dependency is just a version string, we create a table
toml::Value::String(version) => {
let mut table = toml::value::Table::new();
table.insert("version".to_string(), toml::Value::String(version.clone()));
table
}
// If the workspace dependency is invalid, we throw an error
_ => {
anyhow::bail!("Invalid workspace dependency for {}", name);
}
};

dependency.remove("workspace");
for (key, value) in workspace_dependency {
if let Some(config) = dependency.get_mut(&key) {
// If it's an array we merge the values,
// otherwise we keep the crate value.
if let toml::Value::Array(value) = value {
if let toml::Value::Array(config) = config {
config.extend(value.clone());
ascjones marked this conversation as resolved.
Show resolved Hide resolved

let mut new_config = Vec::new();
for v in config.iter() {
if !new_config.contains(v) {
new_config.push(v.clone());
}
}
*config = new_config;
}
}
} else {
dependency.insert(key.clone(), value.clone());
}
}
}

Ok(())
}

#[cfg(test)]
mod test {
use super::ManifestPath;
Expand Down
Loading