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

Support [patch] in .cargo/config files #9204

Merged
merged 7 commits into from
Mar 15, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/cargo/core/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,7 @@ pub struct CliUnstable {
pub extra_link_arg: bool,
pub credential_process: bool,
pub configurable_env: bool,
pub patch_in_config: bool,
}

const STABILIZED_COMPILE_PROGRESS: &str = "The progress bar is now always \
Expand Down Expand Up @@ -718,6 +719,7 @@ impl CliUnstable {
"panic-abort-tests" => self.panic_abort_tests = parse_empty(k, v)?,
"jobserver-per-rustc" => self.jobserver_per_rustc = parse_empty(k, v)?,
"configurable-env" => self.configurable_env = parse_empty(k, v)?,
"patch-in-config" => self.patch_in_config = parse_empty(k, v)?,
"features" => {
// For now this is still allowed (there are still some
// unstable options like "compare"). This should be removed at
Expand Down
40 changes: 38 additions & 2 deletions src/cargo/core/workspace.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::borrow::Cow;
use std::cell::RefCell;
use std::collections::hash_map::{Entry, HashMap};
use std::collections::{BTreeMap, BTreeSet, HashSet};
Expand Down Expand Up @@ -365,11 +366,46 @@ impl<'cfg> Workspace<'cfg> {
/// Returns the root `[patch]` section of this workspace.
///
/// This may be from a virtual crate or an actual crate.
pub fn root_patch(&self) -> &HashMap<Url, Vec<Dependency>> {
match self.root_maybe() {
pub fn root_patch(&self) -> Cow<'_, HashMap<Url, Vec<Dependency>>> {
jonhoo marked this conversation as resolved.
Show resolved Hide resolved
let from_manifest = match self.root_maybe() {
MaybePackage::Package(p) => p.manifest().patch(),
MaybePackage::Virtual(vm) => vm.patch(),
};

let from_config = self
.config
.patch()
.expect("config [patch] was never parsed");
if from_config.is_empty() {
return Cow::Borrowed(from_manifest);
}
if from_manifest.is_empty() {
return Cow::Borrowed(from_config);
}

// We could just chain from_manifest and from_config,
// but that's not quite right as it won't deal with overlaps.
let mut combined = from_manifest.clone();
for (url, cdeps) in from_config {
if let Some(deps) = combined.get_mut(url) {
// We want from_manifest to take precedence for each patched name.
// NOTE: This is inefficient if the number of patches is large!
let mut left = cdeps.clone();
for dep in &mut *deps {
if let Some(i) = left.iter().position(|cdep| {
// XXX: should this also take into account version numbers?
dep.name_in_toml() == cdep.name_in_toml()
}) {
left.swap_remove(i);
}
}
// Whatever is left does not exist in manifest dependencies.
deps.extend(left);
} else {
combined.insert(url.clone(), cdeps.clone());
}
}
Cow::Owned(combined)
}

/// Returns an iterator over all packages in this workspace
Expand Down
2 changes: 1 addition & 1 deletion src/cargo/ops/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ pub fn resolve_with_previous<'cfg>(
// locked.
let mut avoid_patch_ids = HashSet::new();
if register_patches {
for (url, patches) in ws.root_patch() {
for (url, patches) in ws.root_patch().iter() {
let previous = match previous {
Some(r) => r,
None => {
Expand Down
16 changes: 15 additions & 1 deletion src/cargo/util/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ use url::Url;
use self::ConfigValue as CV;
use crate::core::compiler::rustdoc::RustdocExternMap;
use crate::core::shell::Verbosity;
use crate::core::{features, CliUnstable, Shell, SourceId, Workspace};
use crate::core::{features, CliUnstable, Dependency, Shell, SourceId, Workspace};
use crate::ops;
use crate::util::errors::{CargoResult, CargoResultExt};
use crate::util::toml as cargo_toml;
Expand Down Expand Up @@ -176,6 +176,8 @@ pub struct Config {
/// Lock, if held, of the global package cache along with the number of
/// acquisitions so far.
package_cache_lock: RefCell<Option<(Option<FileLock>, usize)>>,
/// `[patch]` section parsed from configuration.
patch: LazyCell<HashMap<Url, Vec<Dependency>>>,
/// Cached configuration parsed by Cargo
http_config: LazyCell<CargoHttpConfig>,
net_config: LazyCell<CargoNetConfig>,
Expand Down Expand Up @@ -277,6 +279,7 @@ impl Config {
upper_case_env,
updated_sources: LazyCell::new(),
package_cache_lock: RefCell::new(None),
patch: LazyCell::new(),
http_config: LazyCell::new(),
net_config: LazyCell::new(),
build_config: LazyCell::new(),
Expand Down Expand Up @@ -1324,6 +1327,17 @@ impl Config {
Ok(*(self.crates_io_source_id.try_borrow_with(f)?))
}

pub fn maybe_init_patch<F>(&self, f: F) -> CargoResult<&HashMap<Url, Vec<Dependency>>>
where
F: FnMut() -> CargoResult<HashMap<Url, Vec<Dependency>>>,
{
self.patch.try_borrow_with(f)
}

pub fn patch(&self) -> Option<&HashMap<Url, Vec<Dependency>>> {
self.patch.borrow()
}

pub fn creation_time(&self) -> Instant {
self.creation_time
}
Expand Down
26 changes: 23 additions & 3 deletions src/cargo/util/toml/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::str;

use anyhow::{anyhow, bail};
use anyhow::{anyhow, bail, Context as _};
use cargo_platform::Platform;
use log::{debug, trace};
use semver::{self, VersionReq};
Expand Down Expand Up @@ -1530,9 +1530,12 @@ impl TomlManifest {
Ok(replace)
}

fn patch(&self, cx: &mut Context<'_, '_>) -> CargoResult<HashMap<Url, Vec<Dependency>>> {
fn patch_(
table: Option<&BTreeMap<String, BTreeMap<String, TomlDependency>>>,
cx: &mut Context<'_, '_>,
) -> CargoResult<HashMap<Url, Vec<Dependency>>> {
let mut patch = HashMap::new();
for (url, deps) in self.patch.iter().flatten() {
for (url, deps) in table.into_iter().flatten() {
let url = match &url[..] {
CRATES_IO_REGISTRY => CRATES_IO_INDEX.parse().unwrap(),
_ => cx
Expand All @@ -1553,6 +1556,23 @@ impl TomlManifest {
Ok(patch)
}

fn patch(&self, cx: &mut Context<'_, '_>) -> CargoResult<HashMap<Url, Vec<Dependency>>> {
let _ = cx.config.maybe_init_patch(|| {
jonhoo marked this conversation as resolved.
Show resolved Hide resolved
// Parse out the patches from .config while we're at it.
let config_patch: Option<BTreeMap<String, BTreeMap<String, TomlDependency>>> =
cx.config.get("patch")?;

if config_patch.is_some() && !cx.config.cli_unstable().patch_in_config {
cx.warnings.push("`[patch]` in .cargo/config.toml ignored, the -Zpatch-in-config command-line flag is required".to_owned());
return Ok(HashMap::new());
}

Self::patch_(config_patch.as_ref(), cx)
}).context("parse `[patch]` from .cargo/config.toml")?;

Self::patch_(self.patch.as_ref(), cx)
}

/// Returns the path to the build script if one exists for this crate.
fn maybe_custom_build(
&self,
Expand Down
Loading