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

feat: workspace level patch table added #4086

Merged
merged 12 commits into from
Apr 19, 2023
20 changes: 20 additions & 0 deletions docs/book/src/forc/workspaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ The key points for workspaces are:
Workspace manifests are declared within `Forc.toml` files and support the following fields:

* [`members`](#the-members-field) - Packages to include in the workspace.
* [`[patch]`](#the-patch-section) - Defines the patches.

An empty workspace can be created with `forc new --workspace` or `forc init --workspace`.

Expand All @@ -25,6 +26,25 @@ members = ["member1", "path/to/member2"]
The `members` field accepts entries to be given in relative path with respect to the workspace root.
Packages that are located within a workspace directory but are *not* contained within the `members` set are ignored.

## The `[patch]` section

The `[patch]` section can be used to override any dependency in the workspace dependency graph. The usage is the same with package level `[patch]` section and details can be seen [here](./manifest_reference.md#the-patch-section).
kayagokalp marked this conversation as resolved.
Show resolved Hide resolved

It is not allowed to declare patch table in member of a workspace if the workspace manifest file contains a patch table.
kayagokalp marked this conversation as resolved.
Show resolved Hide resolved

Example:

```toml
[workspace]
members = ["member1", "path/to/member2"]


[patch.'https://github.com/fuellabs/sway']
std = { git = "https://github.com/fuellabs/sway", branch = "test" }
```

In the above example each occurance of `std` as a dependency in the workspace will be changed with `std` from `test` branch of sway repo.

## Some `forc` commands that support workspaces

* `forc build` - Builds an entire workspace.
Expand Down
53 changes: 46 additions & 7 deletions forc-pkg/src/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,36 @@ impl PackageManifestFile {
Ok(Self { manifest, path })
}

/// Apply patch declarations from the workspace (which declares this package manifest as a
/// member) to this package manifest.
///
/// If there are conflicting patch declarations from `PackageManifestFile` and
/// `WorkspaceManifestFile`, returns an error.
///
/// This checks whether there is such workspace present before attempting to apply patches so
/// it is safe to use with standalone package manifests as well.
pub fn with_workspace_patches(&self) -> Result<Self> {
let workspace_patches = self
.workspace()
.ok()
.flatten()
.and_then(|workspace| workspace.patch.clone());
let package_patches = self.patch.clone();
let patch = match (workspace_patches, package_patches) {
(Some(_), Some(_)) => bail!("Found [patch] table both in workspace and member package's manifest file. Consider removing [patch] table from package's manifest file."),
(Some(workspace_patches), None) => Some(workspace_patches),
(None, Some(pkg_patches)) => Some(pkg_patches),
(None, None) => None,
};
Ok(Self {
manifest: PackageManifest {
patch,
..self.manifest.clone()
},
..self.clone()
})
}
kayagokalp marked this conversation as resolved.
Show resolved Hide resolved

/// Read the manifest from the `Forc.toml` in the directory specified by the given `path` or
/// any of its parent directories.
///
Expand Down Expand Up @@ -486,6 +516,13 @@ impl PackageManifest {
.flat_map(|patches| patches.iter())
}

/// Retrieve the listed patches for the given name.
pub fn patch(&self, patch_name: &str) -> Option<&PatchMap> {
self.patch
.as_ref()
.and_then(|patches| patches.get(patch_name))
}

/// Check for the `core` and `std` packages under `[dependencies]`. If both are missing, add
/// `std` implicitly.
///
Expand Down Expand Up @@ -545,13 +582,6 @@ impl PackageManifest {
})
}

/// Retrieve the listed patches for the given name.
pub fn patch(&self, patch_name: &str) -> Option<&PatchMap> {
self.patch
.as_ref()
.and_then(|patches| patches.get(patch_name))
}

/// Retrieve a reference to the contract dependency with the given name.
pub fn contract_dep(&self, contract_dep_name: &str) -> Option<&ContractDependency> {
self.contract_dependencies
Expand Down Expand Up @@ -694,6 +724,7 @@ pub struct WorkspaceManifestFile {
#[serde(rename_all = "kebab-case")]
pub struct WorkspaceManifest {
workspace: Workspace,
patch: Option<BTreeMap<String, PatchMap>>,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
Expand Down Expand Up @@ -798,6 +829,14 @@ impl WorkspaceManifestFile {
pub fn lock_path(&self) -> PathBuf {
self.dir().to_path_buf().join(constants::LOCK_FILE_NAME)
}

/// Produce an iterator yielding all listed patches.
pub fn patches(&self) -> impl Iterator<Item = (&String, &PatchMap)> {
self.patch
.as_ref()
.into_iter()
.flat_map(|patches| patches.iter())
}
}

impl WorkspaceManifest {
Expand Down
3 changes: 2 additions & 1 deletion forc-pkg/src/source/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,8 @@ impl Source {
manifest: &PackageManifestFile,
members: &MemberManifestFiles,
) -> Result<Self> {
match self.dep_patch(dep_name, manifest) {
let manifest = PackageManifestFile::with_workspace_patches(manifest)?;
match self.dep_patch(dep_name, &manifest) {
Some(patch) => Self::from_manifest_dep(manifest.dir(), patch, members),
None => Ok(self.clone()),
}
Expand Down