mirror of
https://github.com/rust-lang/cargo
synced 2024-08-28 11:50:23 +00:00
Auto merge of #8028 - ehuss:new-proc-macro-decouple, r=alexcrichton
Re-implement proc-macro feature decoupling. This is essentially a rewrite of #8003. Instead of adding proc-macro to the index, it uses a strategy of downloading all packages before doing feature resolution. Then the package can be inspected for the proc-macro field. This is a fairly major change. A brief overview: - `PackageSet` now has a `download_accessible` method which tries to download a minimal set of every accessible package. This isn't very smart right now, and errs on downloading too much. In most cases it should be the same (or nearly the same) as before. It downloads extra in the following cases: - The check for `[target]` dependencies checks both host and target for every dependency. I could tighten that up a little so build dependencies only check for the host, but it would add some complexity and I wanted to get feedback first. - Optional dependencies disabled by the new feature resolver will get downloaded. - Removed the loop in computing unit dependencies where downloading used to reside. - When downloading starts, it should now show a more accurate count of how many crates are to be downloaded. Previously the count would fluctuate while the graph is being built.
This commit is contained in:
commit
8a0d4d9c9a
|
@ -22,7 +22,7 @@ path = "src/cargo/lib.rs"
|
|||
atty = "0.2"
|
||||
bytesize = "1.0"
|
||||
cargo-platform = { path = "crates/cargo-platform", version = "0.1.1" }
|
||||
crates-io = { path = "crates/crates-io", version = "0.32" }
|
||||
crates-io = { path = "crates/crates-io", version = "0.31" }
|
||||
crossbeam-utils = "0.7"
|
||||
crypto-hash = "0.3.1"
|
||||
curl = { version = "0.4.23", features = ["http2"] }
|
||||
|
|
|
@ -420,7 +420,6 @@ impl Package {
|
|||
"cksum": cksum,
|
||||
"features": self.features,
|
||||
"yanked": self.yanked,
|
||||
"pm": self.proc_macro,
|
||||
})
|
||||
.to_string();
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "crates-io"
|
||||
version = "0.32.0"
|
||||
version = "0.31.0"
|
||||
edition = "2018"
|
||||
authors = ["Alex Crichton <alex@alexcrichton.com>"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
|
|
@ -55,7 +55,6 @@ pub struct NewCrate {
|
|||
pub repository: Option<String>,
|
||||
pub badges: BTreeMap<String, BTreeMap<String, String>>,
|
||||
pub links: Option<String>,
|
||||
pub proc_macro: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
|
|
|
@ -176,7 +176,6 @@ pub fn resolve_with_config_raw(
|
|||
&BTreeMap::<String, Vec<String>>::new(),
|
||||
None::<&String>,
|
||||
false,
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
let opts = ResolveOpts::everything();
|
||||
|
@ -578,7 +577,6 @@ pub fn pkg_dep<T: ToPkgId>(name: T, dep: Vec<Dependency>) -> Summary {
|
|||
&BTreeMap::<String, Vec<String>>::new(),
|
||||
link,
|
||||
false,
|
||||
false,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
@ -607,7 +605,6 @@ pub fn pkg_loc(name: &str, loc: &str) -> Summary {
|
|||
&BTreeMap::<String, Vec<String>>::new(),
|
||||
link,
|
||||
false,
|
||||
false,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
@ -622,7 +619,6 @@ pub fn remove_dep(sum: &Summary, ind: usize) -> Summary {
|
|||
&BTreeMap::<String, Vec<String>>::new(),
|
||||
sum.links().map(|a| a.as_str()),
|
||||
sum.namespaced_features(),
|
||||
sum.proc_macro(),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ use crate::core::compiler::unit_graph::{UnitDep, UnitGraph};
|
|||
use crate::core::compiler::Unit;
|
||||
use crate::core::compiler::{BuildContext, CompileKind, CompileMode};
|
||||
use crate::core::dependency::DepKind;
|
||||
use crate::core::package::Downloads;
|
||||
use crate::core::profiles::{Profile, UnitFor};
|
||||
use crate::core::resolver::features::{FeaturesFor, ResolvedFeatures};
|
||||
use crate::core::resolver::Resolve;
|
||||
|
@ -31,10 +30,7 @@ use std::collections::{HashMap, HashSet};
|
|||
/// Collection of stuff used while creating the `UnitGraph`.
|
||||
struct State<'a, 'cfg> {
|
||||
bcx: &'a BuildContext<'a, 'cfg>,
|
||||
waiting_on_download: HashSet<PackageId>,
|
||||
downloads: Downloads<'a, 'cfg>,
|
||||
unit_dependencies: UnitGraph<'a>,
|
||||
package_cache: HashMap<PackageId, &'a Package>,
|
||||
usr_resolve: &'a Resolve,
|
||||
usr_features: &'a ResolvedFeatures,
|
||||
std_resolve: Option<&'a Resolve>,
|
||||
|
@ -58,10 +54,7 @@ pub fn build_unit_dependencies<'a, 'cfg>(
|
|||
};
|
||||
let mut state = State {
|
||||
bcx,
|
||||
downloads: bcx.packages.enable_download()?,
|
||||
waiting_on_download: HashSet::new(),
|
||||
unit_dependencies: HashMap::new(),
|
||||
package_cache: HashMap::new(),
|
||||
usr_resolve: resolve,
|
||||
usr_features: features,
|
||||
std_resolve,
|
||||
|
@ -141,44 +134,32 @@ fn attach_std_deps<'a, 'cfg>(
|
|||
/// Compute all the dependencies of the given root units.
|
||||
/// The result is stored in state.unit_dependencies.
|
||||
fn deps_of_roots<'a, 'cfg>(roots: &[Unit<'a>], mut state: &mut State<'a, 'cfg>) -> CargoResult<()> {
|
||||
// Loop because we are downloading while building the dependency graph.
|
||||
// The partially-built unit graph is discarded through each pass of the
|
||||
// loop because it is incomplete because not all required Packages have
|
||||
// been downloaded.
|
||||
loop {
|
||||
for unit in roots.iter() {
|
||||
state.get(unit.pkg.package_id())?;
|
||||
for unit in roots.iter() {
|
||||
state.get(unit.pkg.package_id());
|
||||
|
||||
// Dependencies of tests/benches should not have `panic` set.
|
||||
// We check the global test mode to see if we are running in `cargo
|
||||
// test` in which case we ensure all dependencies have `panic`
|
||||
// cleared, and avoid building the lib thrice (once with `panic`, once
|
||||
// without, once for `--test`). In particular, the lib included for
|
||||
// Doc tests and examples are `Build` mode here.
|
||||
let unit_for = if unit.mode.is_any_test() || state.bcx.build_config.test() {
|
||||
UnitFor::new_test(state.bcx.config)
|
||||
} else if unit.target.is_custom_build() {
|
||||
// This normally doesn't happen, except `clean` aggressively
|
||||
// generates all units.
|
||||
UnitFor::new_host(false)
|
||||
} else if unit.target.proc_macro() {
|
||||
UnitFor::new_host(true)
|
||||
} else if unit.target.for_host() {
|
||||
// Plugin should never have panic set.
|
||||
UnitFor::new_compiler()
|
||||
} else {
|
||||
UnitFor::new_normal()
|
||||
};
|
||||
deps_of(unit, &mut state, unit_for)?;
|
||||
}
|
||||
|
||||
if !state.waiting_on_download.is_empty() {
|
||||
state.finish_some_downloads()?;
|
||||
state.unit_dependencies.clear();
|
||||
// Dependencies of tests/benches should not have `panic` set.
|
||||
// We check the global test mode to see if we are running in `cargo
|
||||
// test` in which case we ensure all dependencies have `panic`
|
||||
// cleared, and avoid building the lib thrice (once with `panic`, once
|
||||
// without, once for `--test`). In particular, the lib included for
|
||||
// Doc tests and examples are `Build` mode here.
|
||||
let unit_for = if unit.mode.is_any_test() || state.bcx.build_config.test() {
|
||||
UnitFor::new_test(state.bcx.config)
|
||||
} else if unit.target.is_custom_build() {
|
||||
// This normally doesn't happen, except `clean` aggressively
|
||||
// generates all units.
|
||||
UnitFor::new_host(false)
|
||||
} else if unit.target.proc_macro() {
|
||||
UnitFor::new_host(true)
|
||||
} else if unit.target.for_host() {
|
||||
// Plugin should never have panic set.
|
||||
UnitFor::new_compiler()
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
UnitFor::new_normal()
|
||||
};
|
||||
deps_of(unit, &mut state, unit_for)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -269,10 +250,7 @@ fn compute_deps<'a, 'cfg>(
|
|||
|
||||
let mut ret = Vec::new();
|
||||
for (id, _) in filtered_deps {
|
||||
let pkg = match state.get(id)? {
|
||||
Some(pkg) => pkg,
|
||||
None => continue,
|
||||
};
|
||||
let pkg = state.get(id);
|
||||
let lib = match pkg.targets().iter().find(|t| t.is_lib()) {
|
||||
Some(t) => t,
|
||||
None => continue,
|
||||
|
@ -419,10 +397,7 @@ fn compute_deps_doc<'a, 'cfg>(
|
|||
// the documentation of the library being built.
|
||||
let mut ret = Vec::new();
|
||||
for (id, _deps) in deps {
|
||||
let dep = match state.get(id)? {
|
||||
Some(dep) => dep,
|
||||
None => continue,
|
||||
};
|
||||
let dep = state.get(id);
|
||||
let lib = match dep.targets().iter().find(|t| t.is_lib()) {
|
||||
Some(lib) => lib,
|
||||
None => continue,
|
||||
|
@ -730,44 +705,10 @@ impl<'a, 'cfg> State<'a, 'cfg> {
|
|||
features.activated_features(pkg_id, features_for)
|
||||
}
|
||||
|
||||
fn get(&mut self, id: PackageId) -> CargoResult<Option<&'a Package>> {
|
||||
if let Some(pkg) = self.package_cache.get(&id) {
|
||||
return Ok(Some(pkg));
|
||||
}
|
||||
if !self.waiting_on_download.insert(id) {
|
||||
return Ok(None);
|
||||
}
|
||||
if let Some(pkg) = self.downloads.start(id)? {
|
||||
self.package_cache.insert(id, pkg);
|
||||
self.waiting_on_download.remove(&id);
|
||||
return Ok(Some(pkg));
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
/// Completes at least one downloading, maybe waiting for more to complete.
|
||||
///
|
||||
/// This function will block the current thread waiting for at least one
|
||||
/// crate to finish downloading. The function may continue to download more
|
||||
/// crates if it looks like there's a long enough queue of crates to keep
|
||||
/// downloading. When only a handful of packages remain this function
|
||||
/// returns, and it's hoped that by returning we'll be able to push more
|
||||
/// packages to download into the queue.
|
||||
fn finish_some_downloads(&mut self) -> CargoResult<()> {
|
||||
assert!(self.downloads.remaining() > 0);
|
||||
loop {
|
||||
let pkg = self.downloads.wait()?;
|
||||
self.waiting_on_download.remove(&pkg.package_id());
|
||||
self.package_cache.insert(pkg.package_id(), pkg);
|
||||
|
||||
// Arbitrarily choose that 5 or more packages concurrently download
|
||||
// is a good enough number to "fill the network pipe". If we have
|
||||
// less than this let's recompute the whole unit dependency graph
|
||||
// again and try to find some more packages to download.
|
||||
if self.downloads.remaining() < 5 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
fn get(&self, id: PackageId) -> &'a Package {
|
||||
self.bcx
|
||||
.packages
|
||||
.get_one(id)
|
||||
.unwrap_or_else(|_| panic!("expected {} to be downloaded", id))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::cell::{Cell, Ref, RefCell, RefMut};
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::collections::{BTreeSet, HashMap, HashSet};
|
||||
use std::fmt;
|
||||
use std::hash;
|
||||
use std::mem;
|
||||
|
@ -17,7 +17,10 @@ use semver::Version;
|
|||
use serde::ser;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::core::compiler::{CompileKind, RustcTargetData};
|
||||
use crate::core::dependency::DepKind;
|
||||
use crate::core::interning::InternedString;
|
||||
use crate::core::resolver::{HasDevUnits, Resolve};
|
||||
use crate::core::source::MaybePackage;
|
||||
use crate::core::{Dependency, Manifest, PackageId, SourceId, Target};
|
||||
use crate::core::{FeatureMap, SourceMap, Summary};
|
||||
|
@ -189,6 +192,10 @@ impl Package {
|
|||
pub fn publish(&self) -> &Option<Vec<String>> {
|
||||
self.manifest.publish()
|
||||
}
|
||||
/// Returns `true` if this package is a proc-macro.
|
||||
pub fn proc_macro(&self) -> bool {
|
||||
self.targets().iter().any(|target| target.proc_macro())
|
||||
}
|
||||
|
||||
/// Returns `true` if the package uses a custom build script for any target.
|
||||
pub fn has_custom_build(&self) -> bool {
|
||||
|
@ -432,6 +439,9 @@ impl<'cfg> PackageSet<'cfg> {
|
|||
}
|
||||
|
||||
pub fn get_one(&self, id: PackageId) -> CargoResult<&Package> {
|
||||
if let Some(pkg) = self.packages.get(&id).and_then(|slot| slot.borrow()) {
|
||||
return Ok(pkg);
|
||||
}
|
||||
Ok(self.get_many(Some(id))?.remove(0))
|
||||
}
|
||||
|
||||
|
@ -448,6 +458,75 @@ impl<'cfg> PackageSet<'cfg> {
|
|||
Ok(pkgs)
|
||||
}
|
||||
|
||||
/// Downloads any packages accessible from the give root ids.
|
||||
pub fn download_accessible(
|
||||
&self,
|
||||
resolve: &Resolve,
|
||||
root_ids: &[PackageId],
|
||||
has_dev_units: HasDevUnits,
|
||||
requested_kind: CompileKind,
|
||||
target_data: &RustcTargetData,
|
||||
) -> CargoResult<()> {
|
||||
fn collect_used_deps(
|
||||
used: &mut BTreeSet<PackageId>,
|
||||
resolve: &Resolve,
|
||||
pkg_id: PackageId,
|
||||
has_dev_units: HasDevUnits,
|
||||
requested_kind: CompileKind,
|
||||
target_data: &RustcTargetData,
|
||||
) -> CargoResult<()> {
|
||||
if !used.insert(pkg_id) {
|
||||
return Ok(());
|
||||
}
|
||||
let filtered_deps = resolve.deps(pkg_id).filter(|&(_id, deps)| {
|
||||
deps.iter().any(|dep| {
|
||||
if dep.kind() == DepKind::Development && has_dev_units == HasDevUnits::No {
|
||||
return false;
|
||||
}
|
||||
// This is overly broad, since not all target-specific
|
||||
// dependencies are used both for target and host. To tighten this
|
||||
// up, this function would need to track "for_host" similar to how
|
||||
// unit dependencies handles it.
|
||||
if !target_data.dep_platform_activated(dep, requested_kind)
|
||||
&& !target_data.dep_platform_activated(dep, CompileKind::Host)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
true
|
||||
})
|
||||
});
|
||||
for (dep_id, _deps) in filtered_deps {
|
||||
collect_used_deps(
|
||||
used,
|
||||
resolve,
|
||||
dep_id,
|
||||
has_dev_units,
|
||||
requested_kind,
|
||||
target_data,
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// This is sorted by PackageId to get consistent behavior and error
|
||||
// messages for Cargo's testsuite. Perhaps there is a better ordering
|
||||
// that optimizes download time?
|
||||
let mut to_download = BTreeSet::new();
|
||||
|
||||
for id in root_ids {
|
||||
collect_used_deps(
|
||||
&mut to_download,
|
||||
resolve,
|
||||
*id,
|
||||
has_dev_units,
|
||||
requested_kind,
|
||||
target_data,
|
||||
)?;
|
||||
}
|
||||
self.get_many(to_download.into_iter())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn sources(&self) -> Ref<'_, SourceMap<'cfg>> {
|
||||
self.sources.borrow()
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ use crate::core::compiler::{CompileKind, RustcTargetData};
|
|||
use crate::core::dependency::{DepKind, Dependency};
|
||||
use crate::core::resolver::types::FeaturesSet;
|
||||
use crate::core::resolver::Resolve;
|
||||
use crate::core::{FeatureValue, InternedString, PackageId, PackageIdSpec, Workspace};
|
||||
use crate::core::{FeatureValue, InternedString, PackageId, PackageIdSpec, PackageSet, Workspace};
|
||||
use crate::util::{CargoResult, Config};
|
||||
use std::collections::{BTreeSet, HashMap, HashSet};
|
||||
use std::rc::Rc;
|
||||
|
@ -85,6 +85,7 @@ struct FeatureOpts {
|
|||
/// dependencies are computed, and can result in longer build times with
|
||||
/// `cargo test` because the lib may need to be built 3 times instead of
|
||||
/// twice.
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum HasDevUnits {
|
||||
Yes,
|
||||
No,
|
||||
|
@ -231,6 +232,7 @@ pub struct FeatureResolver<'a, 'cfg> {
|
|||
/// The platform to build for, requested by the user.
|
||||
requested_target: CompileKind,
|
||||
resolve: &'a Resolve,
|
||||
package_set: &'a PackageSet<'cfg>,
|
||||
/// Options that change how the feature resolver operates.
|
||||
opts: FeatureOpts,
|
||||
/// Map of features activated for each package.
|
||||
|
@ -247,6 +249,7 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
|
|||
ws: &Workspace<'cfg>,
|
||||
target_data: &RustcTargetData,
|
||||
resolve: &Resolve,
|
||||
package_set: &'a PackageSet<'cfg>,
|
||||
requested_features: &RequestedFeatures,
|
||||
specs: &[PackageIdSpec],
|
||||
requested_target: CompileKind,
|
||||
|
@ -269,6 +272,7 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
|
|||
target_data,
|
||||
requested_target,
|
||||
resolve,
|
||||
package_set,
|
||||
opts,
|
||||
activated_features: HashMap::new(),
|
||||
processed_deps: HashSet::new(),
|
||||
|
@ -294,8 +298,7 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
|
|||
let member_features = self.ws.members_with_features(specs, requested_features)?;
|
||||
for (member, requested_features) in &member_features {
|
||||
let fvs = self.fvs_from_requested(member.package_id(), requested_features);
|
||||
let for_host = self.opts.decouple_host_deps
|
||||
&& self.resolve.summary(member.package_id()).proc_macro();
|
||||
let for_host = self.opts.decouple_host_deps && self.is_proc_macro(member.package_id());
|
||||
self.activate_pkg(member.package_id(), &fvs, for_host)?;
|
||||
if for_host {
|
||||
// Also activate without for_host. This is needed if the
|
||||
|
@ -522,7 +525,7 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
|
|||
self.resolve
|
||||
.deps(pkg_id)
|
||||
.map(|(dep_id, deps)| {
|
||||
let is_proc_macro = self.resolve.summary(dep_id).proc_macro();
|
||||
let is_proc_macro = self.is_proc_macro(dep_id);
|
||||
let deps = deps
|
||||
.iter()
|
||||
.filter(|dep| {
|
||||
|
@ -566,4 +569,11 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
|
|||
panic!("feature mismatch");
|
||||
}
|
||||
}
|
||||
|
||||
fn is_proc_macro(&self, package_id: PackageId) -> bool {
|
||||
self.package_set
|
||||
.get_one(package_id)
|
||||
.expect("packages downloaded")
|
||||
.proc_macro()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,11 +30,6 @@ struct Inner {
|
|||
checksum: Option<String>,
|
||||
links: Option<InternedString>,
|
||||
namespaced_features: bool,
|
||||
/// Whether or not this package is a proc-macro library.
|
||||
///
|
||||
/// This was added in 2020. Packages published before this will always be
|
||||
/// `false`.
|
||||
proc_macro: bool,
|
||||
}
|
||||
|
||||
impl Summary {
|
||||
|
@ -44,7 +39,6 @@ impl Summary {
|
|||
features: &BTreeMap<K, Vec<impl AsRef<str>>>,
|
||||
links: Option<impl Into<InternedString>>,
|
||||
namespaced_features: bool,
|
||||
proc_macro: bool,
|
||||
) -> CargoResult<Summary>
|
||||
where
|
||||
K: Borrow<str> + Ord + Display,
|
||||
|
@ -74,7 +68,6 @@ impl Summary {
|
|||
checksum: None,
|
||||
links: links.map(|l| l.into()),
|
||||
namespaced_features,
|
||||
proc_macro,
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
@ -106,9 +99,6 @@ impl Summary {
|
|||
pub fn namespaced_features(&self) -> bool {
|
||||
self.inner.namespaced_features
|
||||
}
|
||||
pub fn proc_macro(&self) -> bool {
|
||||
self.inner.proc_macro
|
||||
}
|
||||
|
||||
pub fn override_id(mut self, id: PackageId) -> Summary {
|
||||
Rc::make_mut(&mut self.inner).package_id = id;
|
||||
|
|
|
@ -7,9 +7,11 @@ use crate::core::compiler::unit_dependencies;
|
|||
use crate::core::compiler::{BuildConfig, BuildContext, CompileKind, CompileMode, Context};
|
||||
use crate::core::compiler::{RustcTargetData, UnitInterner};
|
||||
use crate::core::profiles::{Profiles, UnitFor};
|
||||
use crate::core::resolver::features::{FeatureResolver, HasDevUnits, RequestedFeatures};
|
||||
use crate::core::resolver::features::HasDevUnits;
|
||||
use crate::core::resolver::ResolveOpts;
|
||||
use crate::core::{PackageIdSpec, Workspace};
|
||||
use crate::ops;
|
||||
use crate::ops::resolve::WorkspaceResolve;
|
||||
use crate::util::errors::{CargoResult, CargoResultExt};
|
||||
use crate::util::paths;
|
||||
use crate::util::Config;
|
||||
|
@ -57,15 +59,34 @@ pub fn clean(ws: &Workspace<'_>, opts: &CleanOptions<'_>) -> CargoResult<()> {
|
|||
if opts.spec.is_empty() {
|
||||
return rm_rf(&target_dir.into_path_unlocked(), config);
|
||||
}
|
||||
let (packages, resolve) = ops::resolve_ws(ws)?;
|
||||
|
||||
let interner = UnitInterner::new();
|
||||
let mut build_config = BuildConfig::new(config, Some(1), &opts.target, CompileMode::Build)?;
|
||||
build_config.requested_profile = opts.requested_profile;
|
||||
let target_data = RustcTargetData::new(ws, build_config.requested_kind)?;
|
||||
let resolve_opts = ResolveOpts::everything();
|
||||
let specs = opts
|
||||
.spec
|
||||
.iter()
|
||||
.map(|spec| PackageIdSpec::parse(spec))
|
||||
.collect::<CargoResult<Vec<_>>>()?;
|
||||
let ws_resolve = ops::resolve_ws_with_opts(
|
||||
ws,
|
||||
&target_data,
|
||||
build_config.requested_kind,
|
||||
&resolve_opts,
|
||||
&specs,
|
||||
HasDevUnits::Yes,
|
||||
)?;
|
||||
let WorkspaceResolve {
|
||||
pkg_set,
|
||||
targeted_resolve: resolve,
|
||||
resolved_features: features,
|
||||
..
|
||||
} = ws_resolve;
|
||||
|
||||
let interner = UnitInterner::new();
|
||||
let bcx = BuildContext::new(
|
||||
ws,
|
||||
&packages,
|
||||
&pkg_set,
|
||||
opts.config,
|
||||
&build_config,
|
||||
profiles,
|
||||
|
@ -73,27 +94,12 @@ pub fn clean(ws: &Workspace<'_>, opts: &CleanOptions<'_>) -> CargoResult<()> {
|
|||
HashMap::new(),
|
||||
target_data,
|
||||
)?;
|
||||
let requested_features = RequestedFeatures::new_all(true);
|
||||
let specs = opts
|
||||
.spec
|
||||
.iter()
|
||||
.map(|spec| PackageIdSpec::parse(spec))
|
||||
.collect::<CargoResult<Vec<_>>>()?;
|
||||
let features = FeatureResolver::resolve(
|
||||
ws,
|
||||
&bcx.target_data,
|
||||
&resolve,
|
||||
&requested_features,
|
||||
&specs,
|
||||
bcx.build_config.requested_kind,
|
||||
HasDevUnits::Yes,
|
||||
)?;
|
||||
let mut units = Vec::new();
|
||||
|
||||
for spec in opts.spec.iter() {
|
||||
// Translate the spec to a Package
|
||||
let pkgid = resolve.query(spec)?;
|
||||
let pkg = packages.get_one(pkgid)?;
|
||||
let pkg = pkg_set.get_one(pkgid)?;
|
||||
|
||||
// Generate all relevant `Unit` targets for this package
|
||||
for target in pkg.targets() {
|
||||
|
|
|
@ -356,6 +356,7 @@ pub fn compile_ws<'a>(
|
|||
.iter()
|
||||
.map(|s| s.query(resolve.iter()))
|
||||
.collect::<CargoResult<Vec<_>>>()?;
|
||||
|
||||
// Now get the `Package` for each `PackageId`. This may trigger a download
|
||||
// if the user specified `-p` for a dependency that is not downloaded.
|
||||
// Dependencies will be downloaded during build_unit_dependencies.
|
||||
|
@ -909,7 +910,12 @@ fn generate_targets<'a>(
|
|||
let unavailable_features = match target.required_features() {
|
||||
Some(rf) => {
|
||||
let features = features_map.entry(pkg).or_insert_with(|| {
|
||||
resolve_all_features(resolve, resolved_features, pkg.package_id())
|
||||
resolve_all_features(
|
||||
resolve,
|
||||
resolved_features,
|
||||
&bcx.packages,
|
||||
pkg.package_id(),
|
||||
)
|
||||
});
|
||||
rf.iter().filter(|f| !features.contains(*f)).collect()
|
||||
}
|
||||
|
@ -946,6 +952,7 @@ fn generate_targets<'a>(
|
|||
fn resolve_all_features(
|
||||
resolve_with_overrides: &Resolve,
|
||||
resolved_features: &features::ResolvedFeatures,
|
||||
package_set: &PackageSet<'_>,
|
||||
package_id: PackageId,
|
||||
) -> HashSet<String> {
|
||||
let mut features: HashSet<String> = resolved_features
|
||||
|
@ -957,7 +964,10 @@ fn resolve_all_features(
|
|||
// Include features enabled for use by dependencies so targets can also use them with the
|
||||
// required-features field when deciding whether to be built or skipped.
|
||||
for (dep_id, deps) in resolve_with_overrides.deps(package_id) {
|
||||
let is_proc_macro = resolve_with_overrides.summary(dep_id).proc_macro();
|
||||
let is_proc_macro = package_set
|
||||
.get_one(dep_id)
|
||||
.expect("packages downloaded")
|
||||
.proc_macro();
|
||||
for dep in deps {
|
||||
let features_for = if is_proc_macro || dep.is_build() {
|
||||
FeaturesFor::HostDep
|
||||
|
|
|
@ -7,9 +7,8 @@ use anyhow::{bail, format_err};
|
|||
use tempfile::Builder as TempFileBuilder;
|
||||
|
||||
use crate::core::compiler::Freshness;
|
||||
use crate::core::compiler::{CompileKind, DefaultExecutor, Executor, RustcTargetData};
|
||||
use crate::core::resolver::{HasDevUnits, ResolveOpts};
|
||||
use crate::core::{Edition, Package, PackageId, PackageIdSpec, Source, SourceId, Workspace};
|
||||
use crate::core::compiler::{CompileKind, DefaultExecutor, Executor};
|
||||
use crate::core::{Edition, Package, PackageId, Source, SourceId, Workspace};
|
||||
use crate::ops;
|
||||
use crate::ops::common_for_install_and_uninstall::*;
|
||||
use crate::sources::{GitSource, SourceConfigMap};
|
||||
|
@ -493,30 +492,17 @@ fn check_yanked_install(ws: &Workspace<'_>) -> CargoResult<()> {
|
|||
if ws.ignore_lock() || !ws.root().join("Cargo.lock").exists() {
|
||||
return Ok(());
|
||||
}
|
||||
let specs = vec![PackageIdSpec::from_package_id(ws.current()?.package_id())];
|
||||
// CompileKind here doesn't really matter, it's only needed for features.
|
||||
let target_data = RustcTargetData::new(ws, CompileKind::Host)?;
|
||||
// It would be best if `source` could be passed in here to avoid a
|
||||
// duplicate "Updating", but since `source` is taken by value, then it
|
||||
// wouldn't be available for `compile_ws`.
|
||||
// TODO: It would be easier to use resolve_ws, but it does not honor
|
||||
// require_optional_deps to avoid writing the lock file. It might be good
|
||||
// to try to fix that.
|
||||
let ws_resolve = ops::resolve_ws_with_opts(
|
||||
ws,
|
||||
&target_data,
|
||||
CompileKind::Host,
|
||||
&ResolveOpts::everything(),
|
||||
&specs,
|
||||
HasDevUnits::No,
|
||||
)?;
|
||||
let mut sources = ws_resolve.pkg_set.sources_mut();
|
||||
let (pkg_set, resolve) = ops::resolve_ws(ws)?;
|
||||
let mut sources = pkg_set.sources_mut();
|
||||
|
||||
// Checking the yanked status involves taking a look at the registry and
|
||||
// maybe updating files, so be sure to lock it here.
|
||||
let _lock = ws.config().acquire_package_cache_lock()?;
|
||||
|
||||
for pkg_id in ws_resolve.targeted_resolve.iter() {
|
||||
for pkg_id in resolve.iter() {
|
||||
if let Some(source) = sources.get_mut(pkg_id.source_id()) {
|
||||
if source.is_yanked(pkg_id)? {
|
||||
ws.config().shell().warn(format!(
|
||||
|
|
|
@ -255,7 +255,6 @@ fn transmit(
|
|||
)
|
||||
})
|
||||
.collect::<BTreeMap<String, Vec<String>>>();
|
||||
let proc_macro = pkg.targets().iter().any(|target| target.proc_macro());
|
||||
|
||||
let publish = registry.publish(
|
||||
&NewCrate {
|
||||
|
@ -276,7 +275,6 @@ fn transmit(
|
|||
license_file: license_file.clone(),
|
||||
badges: badges.clone(),
|
||||
links: links.clone(),
|
||||
proc_macro,
|
||||
},
|
||||
tarball,
|
||||
);
|
||||
|
|
|
@ -126,10 +126,24 @@ pub fn resolve_ws_with_opts<'cfg>(
|
|||
|
||||
let pkg_set = get_resolved_packages(&resolved_with_overrides, registry)?;
|
||||
|
||||
let member_ids = ws
|
||||
.members_with_features(&specs, &opts.features)?
|
||||
.into_iter()
|
||||
.map(|(p, _fts)| p.package_id())
|
||||
.collect::<Vec<_>>();
|
||||
pkg_set.download_accessible(
|
||||
&resolved_with_overrides,
|
||||
&member_ids,
|
||||
has_dev_units,
|
||||
requested_target,
|
||||
&target_data,
|
||||
)?;
|
||||
|
||||
let resolved_features = FeatureResolver::resolve(
|
||||
ws,
|
||||
target_data,
|
||||
&resolved_with_overrides,
|
||||
&pkg_set,
|
||||
&opts.features,
|
||||
specs,
|
||||
requested_target,
|
||||
|
@ -159,7 +173,7 @@ fn resolve_with_registry<'cfg>(
|
|||
true,
|
||||
)?;
|
||||
|
||||
if !ws.is_ephemeral() {
|
||||
if !ws.is_ephemeral() && ws.require_optional_deps() {
|
||||
ops::write_pkg_lockfile(ws, &resolve)?;
|
||||
}
|
||||
Ok(resolve)
|
||||
|
|
|
@ -715,7 +715,6 @@ impl IndexSummary {
|
|||
features,
|
||||
yanked,
|
||||
links,
|
||||
pm,
|
||||
} = serde_json::from_slice(line)?;
|
||||
log::trace!("json parsed registry {}/{}", name, vers);
|
||||
let pkgid = PackageId::new(name, &vers, source_id)?;
|
||||
|
@ -724,14 +723,7 @@ impl IndexSummary {
|
|||
.map(|dep| dep.into_dep(source_id))
|
||||
.collect::<CargoResult<Vec<_>>>()?;
|
||||
let namespaced_features = false;
|
||||
let mut summary = Summary::new(
|
||||
pkgid,
|
||||
deps,
|
||||
&features,
|
||||
links,
|
||||
namespaced_features,
|
||||
pm.unwrap_or(false),
|
||||
)?;
|
||||
let mut summary = Summary::new(pkgid, deps, &features, links, namespaced_features)?;
|
||||
summary.set_checksum(cksum);
|
||||
Ok(IndexSummary {
|
||||
summary,
|
||||
|
|
|
@ -236,11 +236,6 @@ pub struct RegistryPackage<'a> {
|
|||
/// Added early 2018 (see https://github.com/rust-lang/cargo/pull/4978),
|
||||
/// can be `None` if published before then.
|
||||
links: Option<InternedString>,
|
||||
/// Whether or not this package is a proc-macro library.
|
||||
///
|
||||
/// If `None`, then the status is unknown (crate was published before this
|
||||
/// field was added), and generally should be treated as `false.`
|
||||
pm: Option<bool>,
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -1155,14 +1155,12 @@ impl TomlManifest {
|
|||
.collect()
|
||||
})
|
||||
.unwrap_or_else(BTreeMap::new);
|
||||
let proc_macro = targets.iter().any(|target| target.proc_macro());
|
||||
let summary = Summary::new(
|
||||
pkgid,
|
||||
deps,
|
||||
&summary_features,
|
||||
project.links.as_deref(),
|
||||
project.namespaced_features.unwrap_or(false),
|
||||
proc_macro,
|
||||
)?;
|
||||
let metadata = ManifestMetadata {
|
||||
description: project.description.clone(),
|
||||
|
|
|
@ -239,11 +239,7 @@ explaining the format of the entry.
|
|||
"yanked": false,
|
||||
// The `links` string value from the package's manifest, or null if not
|
||||
// specified. This field is optional and defaults to null.
|
||||
"links": null,
|
||||
// This is `true` if the package is a proc-macro.
|
||||
// Note: This field was added in Rust 1.44. Packages published with
|
||||
// earlier versions will not set this field.
|
||||
"pm": false,
|
||||
"links": null
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -407,11 +403,7 @@ considered as an exhaustive list of restrictions [crates.io] imposes.
|
|||
},
|
||||
// The `links` string value from the package's manifest, or null if not
|
||||
// specified. This field is optional and defaults to null.
|
||||
"links": null,
|
||||
// This is `true` if the package is a proc-macro.
|
||||
// Note: This field was added in Rust 1.44. Packages published with
|
||||
// earlier versions will not set this field.
|
||||
"proc_macro": false,
|
||||
"links": null
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -357,7 +357,6 @@ fn publish_with_registry_dependency() {
|
|||
"license_file": null,
|
||||
"links": null,
|
||||
"name": "foo",
|
||||
"proc_macro": false,
|
||||
"readme": null,
|
||||
"readme_file": null,
|
||||
"repository": null,
|
||||
|
@ -457,7 +456,6 @@ fn publish_to_alt_registry() {
|
|||
"license_file": null,
|
||||
"links": null,
|
||||
"name": "foo",
|
||||
"proc_macro": false,
|
||||
"readme": null,
|
||||
"readme_file": null,
|
||||
"repository": null,
|
||||
|
@ -521,7 +519,6 @@ fn publish_with_crates_io_dep() {
|
|||
"license_file": null,
|
||||
"links": null,
|
||||
"name": "foo",
|
||||
"proc_macro": false,
|
||||
"readme": null,
|
||||
"readme_file": null,
|
||||
"repository": null,
|
||||
|
|
|
@ -322,7 +322,7 @@ fn compile_offline_while_transitive_dep_not_cached() {
|
|||
.with_status(101)
|
||||
.with_stderr(
|
||||
"\
|
||||
[ERROR] failed to download `baz v1.0.0`
|
||||
[ERROR] failed to download `bar v0.1.0`
|
||||
|
||||
Caused by:
|
||||
can't make HTTP request in the offline mode
|
||||
|
|
|
@ -23,7 +23,6 @@ const CLEAN_FOO_JSON: &str = r#"
|
|||
"license_file": null,
|
||||
"links": null,
|
||||
"name": "foo",
|
||||
"proc_macro": false,
|
||||
"readme": null,
|
||||
"readme_file": null,
|
||||
"repository": "foo",
|
||||
|
@ -48,7 +47,6 @@ fn validate_upload_foo() {
|
|||
"license_file": null,
|
||||
"links": null,
|
||||
"name": "foo",
|
||||
"proc_macro": false,
|
||||
"readme": null,
|
||||
"readme_file": null,
|
||||
"repository": null,
|
||||
|
@ -981,7 +979,6 @@ fn publish_with_patch() {
|
|||
"license_file": null,
|
||||
"links": null,
|
||||
"name": "foo",
|
||||
"proc_macro": false,
|
||||
"readme": null,
|
||||
"readme_file": null,
|
||||
"repository": null,
|
||||
|
@ -1151,7 +1148,6 @@ fn publish_git_with_version() {
|
|||
"license_file": null,
|
||||
"links": null,
|
||||
"name": "foo",
|
||||
"proc_macro": false,
|
||||
"readme": null,
|
||||
"readme_file": null,
|
||||
"repository": null,
|
||||
|
@ -1239,7 +1235,6 @@ fn publish_dev_dep_no_version() {
|
|||
"license_file": null,
|
||||
"links": null,
|
||||
"name": "foo",
|
||||
"proc_macro": false,
|
||||
"readme": null,
|
||||
"readme_file": null,
|
||||
"repository": "foo",
|
||||
|
@ -1300,66 +1295,3 @@ fn credentials_ambiguous_filename() {
|
|||
|
||||
validate_upload_foo();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn publish_proc_macro() {
|
||||
registry::init();
|
||||
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
[project]
|
||||
name = "foo"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
license = "MIT"
|
||||
description = "foo"
|
||||
edition = "2018"
|
||||
homepage = "https://example.com"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
"#,
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("publish --no-verify --index")
|
||||
.arg(registry_url().to_string())
|
||||
.with_stderr(
|
||||
"\
|
||||
[UPDATING] [..]
|
||||
[PACKAGING] foo v0.0.1 ([CWD])
|
||||
[UPLOADING] foo v0.0.1 ([CWD])
|
||||
",
|
||||
)
|
||||
.run();
|
||||
|
||||
publish::validate_upload(
|
||||
r#"
|
||||
{
|
||||
"authors": [],
|
||||
"badges": {},
|
||||
"categories": [],
|
||||
"deps": [],
|
||||
"description": "foo",
|
||||
"documentation": null,
|
||||
"features": {},
|
||||
"homepage": "https://example.com",
|
||||
"keywords": [],
|
||||
"license": "MIT",
|
||||
"license_file": null,
|
||||
"links": null,
|
||||
"name": "foo",
|
||||
"proc_macro": true,
|
||||
"readme": null,
|
||||
"readme_file": null,
|
||||
"repository": null,
|
||||
"vers": "0.0.1"
|
||||
}
|
||||
"#,
|
||||
"foo-0.0.1.crate",
|
||||
&["Cargo.toml", "Cargo.toml.orig", "src/lib.rs"],
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue