Add BuildOptions for centralized combination of NoBuild and NoBinary (#4284)

As requested in review of https://github.com/astral-sh/uv/pull/4067
This commit is contained in:
Zanie Blue 2024-06-12 17:33:33 -04:00 committed by GitHub
parent 1ab4041baa
commit 5a007b6b9f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 186 additions and 267 deletions

View file

@ -81,7 +81,7 @@ mod resolver {
use uv_cache::Cache; use uv_cache::Cache;
use uv_client::RegistryClient; use uv_client::RegistryClient;
use uv_configuration::{ use uv_configuration::{
Concurrency, ConfigSettings, NoBinary, NoBuild, PreviewMode, SetupPyStrategy, BuildOptions, Concurrency, ConfigSettings, PreviewMode, SetupPyStrategy,
}; };
use uv_dispatch::BuildDispatch; use uv_dispatch::BuildDispatch;
use uv_distribution::DistributionDatabase; use uv_distribution::DistributionDatabase;
@ -137,6 +137,7 @@ mod resolver {
let installed_packages = EmptyInstalledPackages; let installed_packages = EmptyInstalledPackages;
let interpreter = venv.interpreter(); let interpreter = venv.interpreter();
let python_requirement = PythonRequirement::from_interpreter(interpreter); let python_requirement = PythonRequirement::from_interpreter(interpreter);
let build_options = BuildOptions::default();
let build_context = BuildDispatch::new( let build_context = BuildDispatch::new(
client, client,
@ -151,8 +152,7 @@ mod resolver {
&config_settings, &config_settings,
build_isolation, build_isolation,
LinkMode::default(), LinkMode::default(),
&NoBuild::None, &build_options,
&NoBinary::None,
concurrency, concurrency,
PreviewMode::Disabled, PreviewMode::Disabled,
); );

View file

@ -32,6 +32,67 @@ impl Display for BuildKind {
} }
} }
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct BuildOptions {
no_binary: NoBinary,
no_build: NoBuild,
}
impl BuildOptions {
pub fn new(no_binary: NoBinary, no_build: NoBuild) -> Self {
Self {
no_binary,
no_build,
}
}
pub fn no_binary_package(&self, package_name: &PackageName) -> bool {
match &self.no_binary {
NoBinary::None => false,
NoBinary::All => match &self.no_build {
// Allow `all` to be overridden by specific build exclusions
NoBuild::Packages(packages) => !packages.contains(package_name),
_ => true,
},
NoBinary::Packages(packages) => packages.contains(package_name),
}
}
pub fn no_build_package(&self, package_name: &PackageName) -> bool {
match &self.no_build {
NoBuild::All => match &self.no_binary {
// Allow `all` to be overridden by specific binary exclusions
NoBinary::Packages(packages) => !packages.contains(package_name),
_ => true,
},
NoBuild::None => false,
NoBuild::Packages(packages) => packages.contains(package_name),
}
}
pub fn no_build(&self, package_name: Option<&PackageName>) -> bool {
match package_name {
Some(name) => self.no_build_package(name),
None => self.no_build_all(),
}
}
pub fn no_binary(&self, package_name: Option<&PackageName>) -> bool {
match package_name {
Some(name) => self.no_binary_package(name),
None => self.no_binary_all(),
}
}
pub fn no_build_all(&self) -> bool {
matches!(self.no_build, NoBuild::All)
}
pub fn no_binary_all(&self) -> bool {
matches!(self.no_binary, NoBinary::All)
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq)] #[derive(Debug, Default, Clone, PartialEq, Eq)]
pub enum NoBinary { pub enum NoBinary {
/// Allow installation of any wheel. /// Allow installation of any wheel.

View file

@ -11,7 +11,7 @@ use uv_build::{SourceBuild, SourceBuildContext};
use uv_cache::{Cache, CacheArgs}; use uv_cache::{Cache, CacheArgs};
use uv_client::RegistryClientBuilder; use uv_client::RegistryClientBuilder;
use uv_configuration::{ use uv_configuration::{
BuildKind, Concurrency, ConfigSettings, NoBinary, NoBuild, PreviewMode, SetupPyStrategy, BuildKind, BuildOptions, Concurrency, ConfigSettings, PreviewMode, SetupPyStrategy,
}; };
use uv_dispatch::BuildDispatch; use uv_dispatch::BuildDispatch;
use uv_git::GitResolver; use uv_git::GitResolver;
@ -66,6 +66,7 @@ pub(crate) async fn build(args: BuildArgs) -> Result<PathBuf> {
let index_urls = IndexLocations::default(); let index_urls = IndexLocations::default();
let setup_py = SetupPyStrategy::default(); let setup_py = SetupPyStrategy::default();
let toolchain = Toolchain::find_virtualenv(&cache)?; let toolchain = Toolchain::find_virtualenv(&cache)?;
let build_options = BuildOptions::default();
let build_dispatch = BuildDispatch::new( let build_dispatch = BuildDispatch::new(
&client, &client,
@ -80,8 +81,7 @@ pub(crate) async fn build(args: BuildArgs) -> Result<PathBuf> {
&config_settings, &config_settings,
BuildIsolation::Isolated, BuildIsolation::Isolated,
install_wheel_rs::linker::LinkMode::default(), install_wheel_rs::linker::LinkMode::default(),
&NoBuild::None, &build_options,
&NoBinary::None,
concurrency, concurrency,
PreviewMode::Enabled, PreviewMode::Enabled,
); );

View file

@ -5,7 +5,7 @@
use std::ffi::{OsStr, OsString}; use std::ffi::{OsStr, OsString};
use std::path::Path; use std::path::Path;
use anyhow::{bail, Context, Result}; use anyhow::{anyhow, Context, Result};
use futures::FutureExt; use futures::FutureExt;
use itertools::Itertools; use itertools::Itertools;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
@ -16,7 +16,7 @@ use pypi_types::Requirement;
use uv_build::{SourceBuild, SourceBuildContext}; use uv_build::{SourceBuild, SourceBuildContext};
use uv_cache::Cache; use uv_cache::Cache;
use uv_client::RegistryClient; use uv_client::RegistryClient;
use uv_configuration::{BuildKind, ConfigSettings, NoBinary, NoBuild, Reinstall, SetupPyStrategy}; use uv_configuration::{BuildKind, BuildOptions, ConfigSettings, Reinstall, SetupPyStrategy};
use uv_configuration::{Concurrency, PreviewMode}; use uv_configuration::{Concurrency, PreviewMode};
use uv_distribution::DistributionDatabase; use uv_distribution::DistributionDatabase;
use uv_git::GitResolver; use uv_git::GitResolver;
@ -39,8 +39,7 @@ pub struct BuildDispatch<'a> {
setup_py: SetupPyStrategy, setup_py: SetupPyStrategy,
build_isolation: BuildIsolation<'a>, build_isolation: BuildIsolation<'a>,
link_mode: install_wheel_rs::linker::LinkMode, link_mode: install_wheel_rs::linker::LinkMode,
no_build: &'a NoBuild, build_options: &'a BuildOptions,
no_binary: &'a NoBinary,
config_settings: &'a ConfigSettings, config_settings: &'a ConfigSettings,
source_build_context: SourceBuildContext, source_build_context: SourceBuildContext,
options: Options, options: Options,
@ -64,8 +63,7 @@ impl<'a> BuildDispatch<'a> {
config_settings: &'a ConfigSettings, config_settings: &'a ConfigSettings,
build_isolation: BuildIsolation<'a>, build_isolation: BuildIsolation<'a>,
link_mode: install_wheel_rs::linker::LinkMode, link_mode: install_wheel_rs::linker::LinkMode,
no_build: &'a NoBuild, build_options: &'a BuildOptions,
no_binary: &'a NoBinary,
concurrency: Concurrency, concurrency: Concurrency,
preview_mode: PreviewMode, preview_mode: PreviewMode,
) -> Self { ) -> Self {
@ -82,8 +80,7 @@ impl<'a> BuildDispatch<'a> {
config_settings, config_settings,
build_isolation, build_isolation,
link_mode, link_mode,
no_build, build_options,
no_binary,
concurrency, concurrency,
source_build_context: SourceBuildContext::default(), source_build_context: SourceBuildContext::default(),
options: Options::default(), options: Options::default(),
@ -133,12 +130,8 @@ impl<'a> BuildContext for BuildDispatch<'a> {
self.build_isolation self.build_isolation
} }
fn no_build(&self) -> &NoBuild { fn build_options(&self) -> &BuildOptions {
self.no_build self.build_options
}
fn no_binary(&self) -> &NoBinary {
self.no_binary
} }
fn index_locations(&self) -> &IndexLocations { fn index_locations(&self) -> &IndexLocations {
@ -217,8 +210,7 @@ impl<'a> BuildContext for BuildDispatch<'a> {
} = Planner::new(&requirements).build( } = Planner::new(&requirements).build(
site_packages, site_packages,
&Reinstall::default(), &Reinstall::default(),
&NoBinary::default(), &BuildOptions::default(),
&NoBuild::default(),
&HashStrategy::default(), &HashStrategy::default(),
self.index_locations, self.index_locations,
self.cache(), self.cache(),
@ -315,34 +307,21 @@ impl<'a> BuildContext for BuildDispatch<'a> {
dist: Option<&'data SourceDist>, dist: Option<&'data SourceDist>,
build_kind: BuildKind, build_kind: BuildKind,
) -> Result<SourceBuild> { ) -> Result<SourceBuild> {
match self.no_build { // Note we can only prevent builds by name for packages with names
NoBuild::All => debug_assert!( // unless all builds are disabled.
match self.no_binary { if self
// Allow `all` to be overridden by specific binary exclusions .build_options
NoBinary::Packages(packages) => { .no_build(dist.map(distribution_types::Name::name))
// We always allow editable builds
&& !matches!(build_kind, BuildKind::Editable)
{
if let Some(dist) = dist { if let Some(dist) = dist {
packages.contains(dist.name()) return Err(anyhow!(
} else {
false
}
}
_ => false,
} || matches!(build_kind, BuildKind::Editable),
"Only editable builds are exempt from 'no build' checks"
),
NoBuild::None => {}
NoBuild::Packages(packages) => {
// We can only prevent builds by name for packages with names. For editable
// packages and unnamed requirements, we can't prevent the build.
if let Some(dist) = dist {
if packages.contains(dist.name()) {
bail!(
"Building source distributions for {} is disabled", "Building source distributions for {} is disabled",
dist.name() dist.name()
); ));
}
}
} }
return Err(anyhow!("Building source distributions is disabled"));
} }
let builder = SourceBuild::setup( let builder = SourceBuild::setup(

View file

@ -25,7 +25,7 @@ use uv_cache::{ArchiveId, ArchiveTimestamp, CacheBucket, CacheEntry, Timestamp,
use uv_client::{ use uv_client::{
CacheControl, CachedClientError, Connectivity, DataWithCachePolicy, RegistryClient, CacheControl, CachedClientError, Connectivity, DataWithCachePolicy, RegistryClient,
}; };
use uv_configuration::{NoBinary, NoBuild, PreviewMode}; use uv_configuration::PreviewMode;
use uv_extract::hash::Hasher; use uv_extract::hash::Hasher;
use uv_fs::write_atomic; use uv_fs::write_atomic;
use uv_types::BuildContext; use uv_types::BuildContext;
@ -145,17 +145,11 @@ impl<'a, Context: BuildContext> DistributionDatabase<'a, Context> {
dist: &BuiltDist, dist: &BuiltDist,
hashes: HashPolicy<'_>, hashes: HashPolicy<'_>,
) -> Result<LocalWheel, Error> { ) -> Result<LocalWheel, Error> {
let no_binary = match self.build_context.no_binary() { if self
NoBinary::None => false, .build_context
NoBinary::All => match self.build_context.no_build() { .build_options()
// Allow `all` to be overridden by specific build exclusions .no_binary_package(dist.name())
NoBuild::Packages(packages) => !packages.contains(dist.name()), {
_ => true,
},
NoBinary::Packages(packages) => packages.contains(dist.name()),
};
if no_binary {
return Err(Error::NoBinary); return Err(Error::NoBinary);
} }
@ -418,22 +412,8 @@ impl<'a, Context: BuildContext> DistributionDatabase<'a, Context> {
source: &BuildableSource<'_>, source: &BuildableSource<'_>,
hashes: HashPolicy<'_>, hashes: HashPolicy<'_>,
) -> Result<ArchiveMetadata, Error> { ) -> Result<ArchiveMetadata, Error> {
let no_build = match self.build_context.no_build() {
NoBuild::All => match self.build_context.no_binary() {
// Allow `all` to be overridden by specific binary exclusions
NoBinary::Packages(packages) => {
!source.name().is_some_and(|name| packages.contains(name))
}
_ => true,
},
NoBuild::None => false,
NoBuild::Packages(packages) => {
source.name().is_some_and(|name| packages.contains(name))
}
};
// Optimization: Skip source dist download when we must not build them anyway. // Optimization: Skip source dist download when we must not build them anyway.
if no_build { if self.build_context.build_options().no_build(source.name()) {
if source.is_editable() { if source.is_editable() {
debug!("Allowing build for editable source distribution: {source}"); debug!("Allowing build for editable source distribution: {source}");
} else { } else {

View file

@ -28,7 +28,7 @@ use uv_cache::{
use uv_client::{ use uv_client::{
CacheControl, CachedClientError, Connectivity, DataWithCachePolicy, RegistryClient, CacheControl, CachedClientError, Connectivity, DataWithCachePolicy, RegistryClient,
}; };
use uv_configuration::{BuildKind, NoBinary, NoBuild, PreviewMode}; use uv_configuration::{BuildKind, PreviewMode};
use uv_extract::hash::Hasher; use uv_extract::hash::Hasher;
use uv_fs::{write_atomic, LockedFile}; use uv_fs::{write_atomic, LockedFile};
use uv_types::{BuildContext, SourceBuildTrait}; use uv_types::{BuildContext, SourceBuildTrait};
@ -1390,21 +1390,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
debug!("Building: {source}"); debug!("Building: {source}");
// Guard against build of source distributions when disabled. // Guard against build of source distributions when disabled.
let no_build = match self.build_context.no_build() { if self.build_context.build_options().no_build(source.name()) {
NoBuild::All => match self.build_context.no_binary() {
// Allow `all` to be overridden by specific binary exclusions
NoBinary::Packages(packages) => {
!source.name().is_some_and(|name| packages.contains(name))
}
_ => true,
},
NoBuild::None => false,
NoBuild::Packages(packages) => {
source.name().is_some_and(|name| packages.contains(name))
}
};
if no_build {
if source.is_editable() { if source.is_editable() {
debug!("Allowing build for editable source distribution: {source}"); debug!("Allowing build for editable source distribution: {source}");
} else { } else {

View file

@ -16,7 +16,7 @@ use distribution_types::{
use platform_tags::Tags; use platform_tags::Tags;
use pypi_types::{Requirement, RequirementSource}; use pypi_types::{Requirement, RequirementSource};
use uv_cache::{ArchiveTimestamp, Cache, CacheBucket, WheelCache}; use uv_cache::{ArchiveTimestamp, Cache, CacheBucket, WheelCache};
use uv_configuration::{NoBinary, NoBuild, Reinstall}; use uv_configuration::{BuildOptions, Reinstall};
use uv_distribution::{ use uv_distribution::{
BuiltWheelIndex, HttpArchivePointer, LocalArchivePointer, RegistryWheelIndex, BuiltWheelIndex, HttpArchivePointer, LocalArchivePointer, RegistryWheelIndex,
}; };
@ -56,8 +56,7 @@ impl<'a> Planner<'a> {
self, self,
mut site_packages: SitePackages, mut site_packages: SitePackages,
reinstall: &Reinstall, reinstall: &Reinstall,
no_binary: &NoBinary, build_options: &BuildOptions,
no_build: &NoBuild,
hasher: &HashStrategy, hasher: &HashStrategy,
index_locations: &IndexLocations, index_locations: &IndexLocations,
cache: &Cache, cache: &Cache,
@ -108,15 +107,7 @@ impl<'a> Planner<'a> {
}; };
// Check if installation of a binary version of the package should be allowed. // Check if installation of a binary version of the package should be allowed.
let no_binary = match no_binary { let no_binary = build_options.no_binary_package(&requirement.name);
NoBinary::None => false,
NoBinary::All => match no_build {
// Allow `all` to be overridden by specific build exclusions
NoBuild::Packages(packages) => !packages.contains(&requirement.name),
_ => true,
},
NoBinary::Packages(packages) => packages.contains(&requirement.name),
};
let installed_dists = site_packages.remove_packages(&requirement.name); let installed_dists = site_packages.remove_packages(&requirement.name);

View file

@ -14,7 +14,7 @@ use pep440_rs::Version;
use platform_tags::{TagCompatibility, Tags}; use platform_tags::{TagCompatibility, Tags};
use pypi_types::HashDigest; use pypi_types::HashDigest;
use uv_client::FlatIndexEntries; use uv_client::FlatIndexEntries;
use uv_configuration::{NoBinary, NoBuild}; use uv_configuration::BuildOptions;
use uv_normalize::PackageName; use uv_normalize::PackageName;
use uv_types::HashStrategy; use uv_types::HashStrategy;
@ -36,8 +36,7 @@ impl FlatIndex {
entries: FlatIndexEntries, entries: FlatIndexEntries,
tags: Option<&Tags>, tags: Option<&Tags>,
hasher: &HashStrategy, hasher: &HashStrategy,
no_build: &NoBuild, build_options: &BuildOptions,
no_binary: &NoBinary,
) -> Self { ) -> Self {
// Collect compatible distributions. // Collect compatible distributions.
let mut index = FxHashMap::default(); let mut index = FxHashMap::default();
@ -49,8 +48,7 @@ impl FlatIndex {
filename, filename,
tags, tags,
hasher, hasher,
no_build, build_options,
no_binary,
url, url,
); );
} }
@ -68,8 +66,7 @@ impl FlatIndex {
filename: DistFilename, filename: DistFilename,
tags: Option<&Tags>, tags: Option<&Tags>,
hasher: &HashStrategy, hasher: &HashStrategy,
no_build: &NoBuild, build_options: &BuildOptions,
no_binary: &NoBinary,
index: IndexUrl, index: IndexUrl,
) { ) {
// No `requires-python` here: for source distributions, we don't have that information; // No `requires-python` here: for source distributions, we don't have that information;
@ -78,14 +75,8 @@ impl FlatIndex {
DistFilename::WheelFilename(filename) => { DistFilename::WheelFilename(filename) => {
let version = filename.version.clone(); let version = filename.version.clone();
let compatibility = Self::wheel_compatibility( let compatibility =
&filename, Self::wheel_compatibility(&filename, &file.hashes, tags, hasher, build_options);
&file.hashes,
tags,
hasher,
no_binary,
no_build,
);
let dist = RegistryBuiltWheel { let dist = RegistryBuiltWheel {
filename, filename,
file: Box::new(file), file: Box::new(file),
@ -101,13 +92,8 @@ impl FlatIndex {
} }
} }
DistFilename::SourceDistFilename(filename) => { DistFilename::SourceDistFilename(filename) => {
let compatibility = Self::source_dist_compatibility( let compatibility =
&filename, Self::source_dist_compatibility(&filename, &file.hashes, hasher, build_options);
&file.hashes,
hasher,
no_build,
no_binary,
);
let dist = RegistrySourceDist { let dist = RegistrySourceDist {
name: filename.name.clone(), name: filename.name.clone(),
version: filename.version.clone(), version: filename.version.clone(),
@ -131,21 +117,10 @@ impl FlatIndex {
filename: &SourceDistFilename, filename: &SourceDistFilename,
hashes: &[HashDigest], hashes: &[HashDigest],
hasher: &HashStrategy, hasher: &HashStrategy,
no_build: &NoBuild, build_options: &BuildOptions,
no_binary: &NoBinary,
) -> SourceDistCompatibility { ) -> SourceDistCompatibility {
// Check if source distributions are allowed for this package. // Check if source distributions are allowed for this package.
let no_build = match no_build { if build_options.no_build_package(&filename.name) {
NoBuild::None => false,
NoBuild::All => match no_binary {
// Allow `all` to be overridden by specific binary exclusions
NoBinary::Packages(packages) => !packages.contains(&filename.name),
_ => true,
},
NoBuild::Packages(packages) => packages.contains(&filename.name),
};
if no_build {
return SourceDistCompatibility::Incompatible(IncompatibleSource::NoBuild); return SourceDistCompatibility::Incompatible(IncompatibleSource::NoBuild);
} }
@ -170,21 +145,10 @@ impl FlatIndex {
hashes: &[HashDigest], hashes: &[HashDigest],
tags: Option<&Tags>, tags: Option<&Tags>,
hasher: &HashStrategy, hasher: &HashStrategy,
no_binary: &NoBinary, build_options: &BuildOptions,
no_build: &NoBuild,
) -> WheelCompatibility { ) -> WheelCompatibility {
// Check if binaries are allowed for this package. // Check if binaries are allowed for this package.
let no_binary = match no_binary { if build_options.no_binary_package(&filename.name) {
NoBinary::None => false,
NoBinary::All => match no_build {
// Allow `all` to be overridden by specific build exclusions
NoBuild::Packages(packages) => !packages.contains(&filename.name),
_ => true,
},
NoBinary::Packages(packages) => packages.contains(&filename.name),
};
if no_binary {
return WheelCompatibility::Incompatible(IncompatibleWheel::NoBinary); return WheelCompatibility::Incompatible(IncompatibleWheel::NoBinary);
} }

View file

@ -156,8 +156,7 @@ impl<'a, Context: BuildContext, InstalledPackages: InstalledPackagesProvider>
AllowedYanks::from_manifest(&manifest, markers, options.dependency_mode), AllowedYanks::from_manifest(&manifest, markers, options.dependency_mode),
hasher, hasher,
options.exclude_newer, options.exclude_newer,
build_context.no_binary(), build_context.build_options(),
build_context.no_build(),
); );
Self::new_custom_io( Self::new_custom_io(

View file

@ -2,7 +2,7 @@ use std::future::Future;
use distribution_types::{Dist, IndexLocations}; use distribution_types::{Dist, IndexLocations};
use platform_tags::Tags; use platform_tags::Tags;
use uv_configuration::{NoBinary, NoBuild}; use uv_configuration::BuildOptions;
use uv_distribution::{ArchiveMetadata, DistributionDatabase}; use uv_distribution::{ArchiveMetadata, DistributionDatabase};
use uv_normalize::PackageName; use uv_normalize::PackageName;
use uv_types::{BuildContext, HashStrategy}; use uv_types::{BuildContext, HashStrategy};
@ -81,8 +81,7 @@ pub struct DefaultResolverProvider<'a, Context: BuildContext> {
allowed_yanks: AllowedYanks, allowed_yanks: AllowedYanks,
hasher: HashStrategy, hasher: HashStrategy,
exclude_newer: Option<ExcludeNewer>, exclude_newer: Option<ExcludeNewer>,
no_binary: NoBinary, build_options: &'a BuildOptions,
no_build: NoBuild,
} }
impl<'a, Context: BuildContext> DefaultResolverProvider<'a, Context> { impl<'a, Context: BuildContext> DefaultResolverProvider<'a, Context> {
@ -96,8 +95,7 @@ impl<'a, Context: BuildContext> DefaultResolverProvider<'a, Context> {
allowed_yanks: AllowedYanks, allowed_yanks: AllowedYanks,
hasher: &'a HashStrategy, hasher: &'a HashStrategy,
exclude_newer: Option<ExcludeNewer>, exclude_newer: Option<ExcludeNewer>,
no_binary: &'a NoBinary, build_options: &'a BuildOptions,
no_build: &'a NoBuild,
) -> Self { ) -> Self {
Self { Self {
fetcher, fetcher,
@ -107,8 +105,7 @@ impl<'a, Context: BuildContext> DefaultResolverProvider<'a, Context> {
allowed_yanks, allowed_yanks,
hasher: hasher.clone(), hasher: hasher.clone(),
exclude_newer, exclude_newer,
no_binary: no_binary.clone(), build_options,
no_build: no_build.clone(),
} }
} }
} }
@ -140,8 +137,7 @@ impl<'a, Context: BuildContext> ResolverProvider for DefaultResolverProvider<'a,
&self.hasher, &self.hasher,
self.exclude_newer.as_ref(), self.exclude_newer.as_ref(),
self.flat_index.get(package_name).cloned(), self.flat_index.get(package_name).cloned(),
&self.no_binary, self.build_options,
&self.no_build,
) )
}) })
.collect(), .collect(),

View file

@ -15,7 +15,7 @@ use pep440_rs::{Version, VersionSpecifiers};
use platform_tags::{TagCompatibility, Tags}; use platform_tags::{TagCompatibility, Tags};
use pypi_types::{HashDigest, Yanked}; use pypi_types::{HashDigest, Yanked};
use uv_client::{OwnedArchive, SimpleMetadata, VersionFiles}; use uv_client::{OwnedArchive, SimpleMetadata, VersionFiles};
use uv_configuration::{NoBinary, NoBuild}; use uv_configuration::BuildOptions;
use uv_normalize::PackageName; use uv_normalize::PackageName;
use uv_types::HashStrategy; use uv_types::HashStrategy;
use uv_warnings::warn_user_once; use uv_warnings::warn_user_once;
@ -51,8 +51,7 @@ impl VersionMap {
hasher: &HashStrategy, hasher: &HashStrategy,
exclude_newer: Option<&ExcludeNewer>, exclude_newer: Option<&ExcludeNewer>,
flat_index: Option<FlatDistributions>, flat_index: Option<FlatDistributions>,
no_binary: &NoBinary, build_options: &BuildOptions,
no_build: &NoBuild,
) -> Self { ) -> Self {
let mut map = BTreeMap::new(); let mut map = BTreeMap::new();
// Create stubs for each entry in simple metadata. The full conversion // Create stubs for each entry in simple metadata. The full conversion
@ -96,28 +95,6 @@ impl VersionMap {
}, },
} }
} }
let (no_binary, no_build) = (
// Check if binaries are allowed for this package.
match no_binary {
NoBinary::None => false,
NoBinary::All => match no_build {
// Allow `all` to be overridden by specific build exclusions
NoBuild::Packages(packages) => !packages.contains(package_name),
_ => true,
},
NoBinary::Packages(packages) => packages.contains(package_name),
},
// Check if source distributions are allowed for this package.
match no_build {
NoBuild::None => false,
NoBuild::All => match no_binary {
// Allow `all` to be overridden by specific binary exclusions
NoBinary::Packages(packages) => !packages.contains(package_name),
_ => true,
},
NoBuild::Packages(packages) => packages.contains(package_name),
},
);
let allowed_yanks = allowed_yanks let allowed_yanks = allowed_yanks
.allowed_versions(package_name) .allowed_versions(package_name)
.cloned() .cloned()
@ -127,8 +104,8 @@ impl VersionMap {
inner: VersionMapInner::Lazy(VersionMapLazy { inner: VersionMapInner::Lazy(VersionMapLazy {
map, map,
simple_metadata, simple_metadata,
no_binary, no_binary: build_options.no_binary_package(package_name),
no_build, no_build: build_options.no_build_package(package_name),
index: index.clone(), index: index.clone(),
tags: tags.cloned(), tags: tags.cloned(),
python_requirement: python_requirement.clone(), python_requirement: python_requirement.clone(),

View file

@ -7,7 +7,7 @@ use distribution_types::{CachedDist, IndexLocations, InstalledDist, Resolution,
use pep508_rs::PackageName; use pep508_rs::PackageName;
use pypi_types::Requirement; use pypi_types::Requirement;
use uv_cache::Cache; use uv_cache::Cache;
use uv_configuration::{BuildKind, NoBinary, NoBuild, SetupPyStrategy}; use uv_configuration::{BuildKind, BuildOptions, SetupPyStrategy};
use uv_git::GitResolver; use uv_git::GitResolver;
use uv_toolchain::{Interpreter, PythonEnvironment}; use uv_toolchain::{Interpreter, PythonEnvironment};
@ -66,13 +66,11 @@ pub trait BuildContext {
/// Whether to enforce build isolation when building source distributions. /// Whether to enforce build isolation when building source distributions.
fn build_isolation(&self) -> BuildIsolation; fn build_isolation(&self) -> BuildIsolation;
/// Whether source distribution building is disabled. This [`BuildContext::setup_build`] calls /// Whether source distribution building or pre-built wheels is disabled.
/// will fail in this case. This method exists to avoid fetching source distributions if we know ///
/// we can't build them /// This [`BuildContext::setup_build`] calls will fail if builds are disabled.
fn no_build(&self) -> &NoBuild; /// This method exists to avoid fetching source distributions if we know we can't build them.
fn build_options(&self) -> &BuildOptions;
/// Whether using pre-built wheels is disabled.
fn no_binary(&self) -> &NoBinary;
/// The index locations being searched. /// The index locations being searched.
fn index_locations(&self) -> &IndexLocations; fn index_locations(&self) -> &IndexLocations;

View file

@ -21,8 +21,8 @@ use uv_auth::store_credentials_from_url;
use uv_cache::Cache; use uv_cache::Cache;
use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder}; use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{ use uv_configuration::{
Concurrency, ConfigSettings, Constraints, ExtrasSpecification, IndexStrategy, NoBinary, BuildOptions, Concurrency, ConfigSettings, Constraints, ExtrasSpecification, IndexStrategy,
NoBuild, Overrides, PreviewMode, SetupPyStrategy, Upgrade, NoBinary, NoBuild, Overrides, PreviewMode, SetupPyStrategy, Upgrade,
}; };
use uv_configuration::{KeyringProviderType, TargetTriple}; use uv_configuration::{KeyringProviderType, TargetTriple};
use uv_dispatch::BuildDispatch; use uv_dispatch::BuildDispatch;
@ -253,11 +253,15 @@ pub(crate) async fn pip_compile(
let preferences = read_requirements_txt(output_file, &upgrade).await?; let preferences = read_requirements_txt(output_file, &upgrade).await?;
let git = GitResolver::default(); let git = GitResolver::default();
// Combine the `--no-build` flags.
let no_build = no_build.combine(specified_no_build);
let build_options = BuildOptions::new(NoBinary::default(), no_build);
// Resolve the flat indexes from `--find-links`. // Resolve the flat indexes from `--find-links`.
let flat_index = { let flat_index = {
let client = FlatIndexClient::new(&client, &cache); let client = FlatIndexClient::new(&client, &cache);
let entries = client.fetch(index_locations.flat_index()).await?; let entries = client.fetch(index_locations.flat_index()).await?;
FlatIndex::from_entries(entries, Some(&tags), &hasher, &no_build, &NoBinary::None) FlatIndex::from_entries(entries, Some(&tags), &hasher, &build_options)
}; };
// Track in-flight downloads, builds, etc., across resolutions. // Track in-flight downloads, builds, etc., across resolutions.
@ -272,9 +276,6 @@ pub(crate) async fn pip_compile(
BuildIsolation::Isolated BuildIsolation::Isolated
}; };
// Combine the `--no-build` flags.
let no_build = no_build.combine(specified_no_build);
let build_dispatch = BuildDispatch::new( let build_dispatch = BuildDispatch::new(
&client, &client,
&cache, &cache,
@ -288,8 +289,7 @@ pub(crate) async fn pip_compile(
&config_settings, &config_settings,
build_isolation, build_isolation,
link_mode, link_mode,
&no_build, &build_options,
&NoBinary::None,
concurrency, concurrency,
preview, preview,
) )

View file

@ -12,8 +12,8 @@ use uv_auth::store_credentials_from_url;
use uv_cache::Cache; use uv_cache::Cache;
use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder}; use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{ use uv_configuration::{
Concurrency, ConfigSettings, ExtrasSpecification, IndexStrategy, NoBinary, NoBuild, BuildOptions, Concurrency, ConfigSettings, ExtrasSpecification, IndexStrategy, NoBinary,
PreviewMode, Reinstall, SetupPyStrategy, Upgrade, NoBuild, PreviewMode, Reinstall, SetupPyStrategy, Upgrade,
}; };
use uv_configuration::{KeyringProviderType, TargetTriple}; use uv_configuration::{KeyringProviderType, TargetTriple};
use uv_dispatch::BuildDispatch; use uv_dispatch::BuildDispatch;
@ -263,11 +263,16 @@ pub(crate) async fn pip_install(
.platform(interpreter.platform()) .platform(interpreter.platform())
.build(); .build();
// Combine the `--no-binary` and `--no-build` flags.
let no_binary = no_binary.combine(specified_no_binary);
let no_build = no_build.combine(specified_no_build);
let build_options = BuildOptions::new(no_binary, no_build);
// Resolve the flat indexes from `--find-links`. // Resolve the flat indexes from `--find-links`.
let flat_index = { let flat_index = {
let client = FlatIndexClient::new(&client, &cache); let client = FlatIndexClient::new(&client, &cache);
let entries = client.fetch(index_locations.flat_index()).await?; let entries = client.fetch(index_locations.flat_index()).await?;
FlatIndex::from_entries(entries, Some(&tags), &hasher, &no_build, &no_binary) FlatIndex::from_entries(entries, Some(&tags), &hasher, &build_options)
}; };
// Determine whether to enable build isolation. // Determine whether to enable build isolation.
@ -277,10 +282,6 @@ pub(crate) async fn pip_install(
BuildIsolation::Isolated BuildIsolation::Isolated
}; };
// Combine the `--no-binary` and `--no-build` flags.
let no_binary = no_binary.combine(specified_no_binary);
let no_build = no_build.combine(specified_no_build);
// Create a shared in-memory index. // Create a shared in-memory index.
let index = InMemoryIndex::default(); let index = InMemoryIndex::default();
@ -301,8 +302,7 @@ pub(crate) async fn pip_install(
config_settings, config_settings,
build_isolation, build_isolation,
link_mode, link_mode,
&no_build, &build_options,
&no_binary,
concurrency, concurrency,
preview, preview,
) )
@ -376,8 +376,7 @@ pub(crate) async fn pip_install(
config_settings, config_settings,
build_isolation, build_isolation,
link_mode, link_mode,
&no_build, &build_options,
&no_binary,
concurrency, concurrency,
preview, preview,
) )
@ -390,8 +389,7 @@ pub(crate) async fn pip_install(
site_packages, site_packages,
Modifications::Sufficient, Modifications::Sufficient,
&reinstall, &reinstall,
&no_binary, &build_options,
&no_build,
link_mode, link_mode,
compile, compile,
&index_locations, &index_locations,

View file

@ -21,8 +21,8 @@ use pypi_types::Requirement;
use uv_cache::Cache; use uv_cache::Cache;
use uv_client::{BaseClientBuilder, RegistryClient}; use uv_client::{BaseClientBuilder, RegistryClient};
use uv_configuration::{ use uv_configuration::{
Concurrency, Constraints, ExtrasSpecification, NoBinary, NoBuild, Overrides, PreviewMode, BuildOptions, Concurrency, Constraints, ExtrasSpecification, Overrides, PreviewMode, Reinstall,
Reinstall, Upgrade, Upgrade,
}; };
use uv_dispatch::BuildDispatch; use uv_dispatch::BuildDispatch;
use uv_distribution::DistributionDatabase; use uv_distribution::DistributionDatabase;
@ -289,8 +289,7 @@ pub(crate) async fn install(
site_packages: SitePackages, site_packages: SitePackages,
modifications: Modifications, modifications: Modifications,
reinstall: &Reinstall, reinstall: &Reinstall,
no_binary: &NoBinary, build_options: &BuildOptions,
no_build: &NoBuild,
link_mode: LinkMode, link_mode: LinkMode,
compile: bool, compile: bool,
index_urls: &IndexLocations, index_urls: &IndexLocations,
@ -317,8 +316,7 @@ pub(crate) async fn install(
.build( .build(
site_packages, site_packages,
reinstall, reinstall,
no_binary, build_options,
no_build,
hasher, hasher,
index_urls, index_urls,
cache, cache,

View file

@ -11,8 +11,8 @@ use uv_auth::store_credentials_from_url;
use uv_cache::Cache; use uv_cache::Cache;
use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder}; use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{ use uv_configuration::{
Concurrency, ConfigSettings, ExtrasSpecification, IndexStrategy, NoBinary, NoBuild, BuildOptions, Concurrency, ConfigSettings, ExtrasSpecification, IndexStrategy, NoBinary,
PreviewMode, Reinstall, SetupPyStrategy, Upgrade, NoBuild, PreviewMode, Reinstall, SetupPyStrategy, Upgrade,
}; };
use uv_configuration::{KeyringProviderType, TargetTriple}; use uv_configuration::{KeyringProviderType, TargetTriple};
use uv_dispatch::BuildDispatch; use uv_dispatch::BuildDispatch;
@ -206,11 +206,16 @@ pub(crate) async fn pip_sync(
.platform(interpreter.platform()) .platform(interpreter.platform())
.build(); .build();
// Combine the `--no-binary` and `--no-build` flags.
let no_binary = no_binary.combine(specified_no_binary);
let no_build = no_build.combine(specified_no_build);
let build_options = BuildOptions::new(no_binary, no_build);
// Resolve the flat indexes from `--find-links`. // Resolve the flat indexes from `--find-links`.
let flat_index = { let flat_index = {
let client = FlatIndexClient::new(&client, &cache); let client = FlatIndexClient::new(&client, &cache);
let entries = client.fetch(index_locations.flat_index()).await?; let entries = client.fetch(index_locations.flat_index()).await?;
FlatIndex::from_entries(entries, Some(&tags), &hasher, &no_build, &no_binary) FlatIndex::from_entries(entries, Some(&tags), &hasher, &build_options)
}; };
// Determine whether to enable build isolation. // Determine whether to enable build isolation.
@ -220,10 +225,6 @@ pub(crate) async fn pip_sync(
BuildIsolation::Isolated BuildIsolation::Isolated
}; };
// Combine the `--no-binary` and `--no-build` flags.
let no_binary = no_binary.combine(specified_no_binary);
let no_build = no_build.combine(specified_no_build);
// Create a shared in-memory index. // Create a shared in-memory index.
let index = InMemoryIndex::default(); let index = InMemoryIndex::default();
@ -251,8 +252,7 @@ pub(crate) async fn pip_sync(
config_settings, config_settings,
build_isolation, build_isolation,
link_mode, link_mode,
&no_build, &build_options,
&no_binary,
concurrency, concurrency,
preview, preview,
) )
@ -328,8 +328,7 @@ pub(crate) async fn pip_sync(
config_settings, config_settings,
build_isolation, build_isolation,
link_mode, link_mode,
&no_build, &build_options,
&no_binary,
concurrency, concurrency,
preview, preview,
) )
@ -342,8 +341,7 @@ pub(crate) async fn pip_sync(
site_packages, site_packages,
Modifications::Exact, Modifications::Exact,
reinstall, reinstall,
&no_binary, &build_options,
&no_build,
link_mode, link_mode,
compile, compile,
&index_locations, &index_locations,

View file

@ -7,7 +7,7 @@ use install_wheel_rs::linker::LinkMode;
use uv_cache::Cache; use uv_cache::Cache;
use uv_client::{FlatIndexClient, RegistryClientBuilder}; use uv_client::{FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{ use uv_configuration::{
Concurrency, ConfigSettings, ExtrasSpecification, NoBinary, NoBuild, PreviewMode, Reinstall, BuildOptions, Concurrency, ConfigSettings, ExtrasSpecification, PreviewMode, Reinstall,
SetupPyStrategy, Upgrade, SetupPyStrategy, Upgrade,
}; };
use uv_dispatch::BuildDispatch; use uv_dispatch::BuildDispatch;
@ -162,8 +162,7 @@ pub(super) async fn do_lock(
let in_flight = InFlight::default(); let in_flight = InFlight::default();
let index = InMemoryIndex::default(); let index = InMemoryIndex::default();
let link_mode = LinkMode::default(); let link_mode = LinkMode::default();
let no_binary = NoBinary::default(); let build_options = BuildOptions::default();
let no_build = NoBuild::default();
let reinstall = Reinstall::default(); let reinstall = Reinstall::default();
let setup_py = SetupPyStrategy::default(); let setup_py = SetupPyStrategy::default();
@ -174,7 +173,7 @@ pub(super) async fn do_lock(
let flat_index = { let flat_index = {
let client = FlatIndexClient::new(&client, cache); let client = FlatIndexClient::new(&client, cache);
let entries = client.fetch(index_locations.flat_index()).await?; let entries = client.fetch(index_locations.flat_index()).await?;
FlatIndex::from_entries(entries, None, &hasher, &no_build, &no_binary) FlatIndex::from_entries(entries, None, &hasher, &build_options)
}; };
// If an existing lockfile exists, build up a set of preferences. // If an existing lockfile exists, build up a set of preferences.
@ -197,8 +196,7 @@ pub(super) async fn do_lock(
&config_settings, &config_settings,
build_isolation, build_isolation,
link_mode, link_mode,
&no_build, &build_options,
&no_binary,
concurrency, concurrency,
preview, preview,
); );

View file

@ -11,7 +11,7 @@ use pep440_rs::{Version, VersionSpecifiers};
use uv_cache::Cache; use uv_cache::Cache;
use uv_client::{BaseClientBuilder, Connectivity, RegistryClientBuilder}; use uv_client::{BaseClientBuilder, Connectivity, RegistryClientBuilder};
use uv_configuration::{ use uv_configuration::{
Concurrency, ConfigSettings, ExtrasSpecification, NoBinary, NoBuild, PreviewMode, Reinstall, BuildOptions, Concurrency, ConfigSettings, ExtrasSpecification, PreviewMode, Reinstall,
SetupPyStrategy, Upgrade, SetupPyStrategy, Upgrade,
}; };
use uv_dispatch::BuildDispatch; use uv_dispatch::BuildDispatch;
@ -306,8 +306,7 @@ pub(crate) async fn update_environment(
let in_flight = InFlight::default(); let in_flight = InFlight::default();
let index = InMemoryIndex::default(); let index = InMemoryIndex::default();
let link_mode = LinkMode::default(); let link_mode = LinkMode::default();
let no_binary = NoBinary::default(); let build_options = BuildOptions::default();
let no_build = NoBuild::default();
let options = Options::default(); let options = Options::default();
let preferences = Vec::default(); let preferences = Vec::default();
let reinstall = Reinstall::default(); let reinstall = Reinstall::default();
@ -328,8 +327,7 @@ pub(crate) async fn update_environment(
&config_settings, &config_settings,
build_isolation, build_isolation,
link_mode, link_mode,
&no_build, &build_options,
&no_binary,
concurrency, concurrency,
preview, preview,
); );
@ -388,8 +386,7 @@ pub(crate) async fn update_environment(
&config_settings, &config_settings,
build_isolation, build_isolation,
link_mode, link_mode,
&no_build, &build_options,
&no_binary,
concurrency, concurrency,
preview, preview,
) )
@ -401,8 +398,7 @@ pub(crate) async fn update_environment(
site_packages, site_packages,
pip::operations::Modifications::Sufficient, pip::operations::Modifications::Sufficient,
&reinstall, &reinstall,
&no_binary, &build_options,
&no_build,
link_mode, link_mode,
compile, compile,
index_locations, index_locations,

View file

@ -6,7 +6,7 @@ use install_wheel_rs::linker::LinkMode;
use uv_cache::Cache; use uv_cache::Cache;
use uv_client::{FlatIndexClient, RegistryClientBuilder}; use uv_client::{FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{ use uv_configuration::{
Concurrency, ConfigSettings, ExtrasSpecification, NoBinary, NoBuild, PreviewMode, Reinstall, BuildOptions, Concurrency, ConfigSettings, ExtrasSpecification, PreviewMode, Reinstall,
SetupPyStrategy, SetupPyStrategy,
}; };
use uv_dispatch::BuildDispatch; use uv_dispatch::BuildDispatch;
@ -127,8 +127,7 @@ pub(super) async fn do_sync(
let in_flight = InFlight::default(); let in_flight = InFlight::default();
let index = InMemoryIndex::default(); let index = InMemoryIndex::default();
let link_mode = LinkMode::default(); let link_mode = LinkMode::default();
let no_binary = NoBinary::default(); let build_options = BuildOptions::default();
let no_build = NoBuild::default();
let reinstall = Reinstall::default(); let reinstall = Reinstall::default();
let setup_py = SetupPyStrategy::default(); let setup_py = SetupPyStrategy::default();
@ -136,7 +135,7 @@ pub(super) async fn do_sync(
let flat_index = { let flat_index = {
let client = FlatIndexClient::new(&client, cache); let client = FlatIndexClient::new(&client, cache);
let entries = client.fetch(index_locations.flat_index()).await?; let entries = client.fetch(index_locations.flat_index()).await?;
FlatIndex::from_entries(entries, Some(tags), &hasher, &no_build, &no_binary) FlatIndex::from_entries(entries, Some(tags), &hasher, &build_options)
}; };
// Create a build dispatch. // Create a build dispatch.
@ -153,8 +152,7 @@ pub(super) async fn do_sync(
&config_settings, &config_settings,
build_isolation, build_isolation,
link_mode, link_mode,
&no_build, &build_options,
&no_binary,
concurrency, concurrency,
preview, preview,
); );
@ -167,8 +165,7 @@ pub(super) async fn do_sync(
site_packages, site_packages,
Modifications::Sufficient, Modifications::Sufficient,
&reinstall, &reinstall,
&no_binary, &build_options,
&no_build,
link_mode, link_mode,
compile, compile,
index_locations, index_locations,

View file

@ -15,8 +15,10 @@ use pypi_types::Requirement;
use uv_auth::store_credentials_from_url; use uv_auth::store_credentials_from_url;
use uv_cache::Cache; use uv_cache::Cache;
use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder}; use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{Concurrency, KeyringProviderType, PreviewMode}; use uv_configuration::{
use uv_configuration::{ConfigSettings, IndexStrategy, NoBinary, NoBuild, SetupPyStrategy}; BuildOptions, Concurrency, ConfigSettings, IndexStrategy, KeyringProviderType, NoBinary,
NoBuild, PreviewMode, SetupPyStrategy,
};
use uv_dispatch::BuildDispatch; use uv_dispatch::BuildDispatch;
use uv_fs::Simplified; use uv_fs::Simplified;
use uv_git::GitResolver; use uv_git::GitResolver;
@ -193,8 +195,7 @@ async fn venv_impl(
entries, entries,
Some(tags), Some(tags),
&HashStrategy::None, &HashStrategy::None,
&NoBuild::All, &BuildOptions::new(NoBinary::None, NoBuild::All),
&NoBinary::None,
) )
}; };
@ -209,6 +210,9 @@ async fn venv_impl(
let config_settings = ConfigSettings::default(); let config_settings = ConfigSettings::default();
let concurrency = Concurrency::default(); let concurrency = Concurrency::default();
// Do not allow builds
let build_options = BuildOptions::new(NoBinary::None, NoBuild::All);
// Prep the build context. // Prep the build context.
let build_dispatch = BuildDispatch::new( let build_dispatch = BuildDispatch::new(
&client, &client,
@ -223,8 +227,7 @@ async fn venv_impl(
&config_settings, &config_settings,
BuildIsolation::Isolated, BuildIsolation::Isolated,
link_mode, link_mode,
&NoBuild::All, &build_options,
&NoBinary::None,
concurrency, concurrency,
preview, preview,
) )