mirror of
https://github.com/astral-sh/uv.git
synced 2025-11-03 05:03:46 +00:00
Implement pip compatible --no-binary and --only-binary options (#1268)
Updates our `--no-binary` option and adds a `--only-binary` option for compatibility with `pip` which uses `:all:`, `:none:` and `<name>` for specifying packages. This required adding support for `--only-binary <name>` into our resolver, previously it was only a boolean toggle. Retains`--no-build` which is equivalent to `--only-binary :all:`. This is common enough for safety that I would prefer it is available without pip's awkward `:all:` syntax. --------- Co-authored-by: konsti <konstin@mailbox.org>
This commit is contained in:
parent
d98b3c3070
commit
a37b08808e
17 changed files with 440 additions and 141 deletions
|
|
@ -132,7 +132,7 @@ pub enum BuiltDist {
|
||||||
Path(PathBuiltDist),
|
Path(PathBuiltDist),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A source distribution, with its three possible origins (index, url, path, git)
|
/// A source distribution, with its possible origins (index, url, path, git)
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[allow(clippy::large_enum_variant)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
pub enum SourceDist {
|
pub enum SourceDist {
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ use puffin_dispatch::BuildDispatch;
|
||||||
use puffin_installer::NoBinary;
|
use puffin_installer::NoBinary;
|
||||||
use puffin_interpreter::Virtualenv;
|
use puffin_interpreter::Virtualenv;
|
||||||
use puffin_resolver::InMemoryIndex;
|
use puffin_resolver::InMemoryIndex;
|
||||||
use puffin_traits::{BuildContext, BuildKind, InFlight, SetupPyStrategy};
|
use puffin_traits::{BuildContext, BuildKind, InFlight, NoBuild, SetupPyStrategy};
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
pub(crate) struct BuildArgs {
|
pub(crate) struct BuildArgs {
|
||||||
|
|
@ -72,7 +72,7 @@ pub(crate) async fn build(args: BuildArgs) -> Result<PathBuf> {
|
||||||
&in_flight,
|
&in_flight,
|
||||||
venv.python_executable(),
|
venv.python_executable(),
|
||||||
setup_py,
|
setup_py,
|
||||||
false,
|
&NoBuild::None,
|
||||||
&NoBinary::None,
|
&NoBinary::None,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ use puffin_installer::{Downloader, NoBinary};
|
||||||
use puffin_interpreter::Virtualenv;
|
use puffin_interpreter::Virtualenv;
|
||||||
use puffin_normalize::PackageName;
|
use puffin_normalize::PackageName;
|
||||||
use puffin_resolver::{DistFinder, InMemoryIndex};
|
use puffin_resolver::{DistFinder, InMemoryIndex};
|
||||||
use puffin_traits::{BuildContext, InFlight, SetupPyStrategy};
|
use puffin_traits::{BuildContext, InFlight, NoBuild, SetupPyStrategy};
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
pub(crate) struct InstallManyArgs {
|
pub(crate) struct InstallManyArgs {
|
||||||
|
|
@ -66,6 +66,12 @@ pub(crate) async fn install_many(args: InstallManyArgs) -> Result<()> {
|
||||||
let in_flight = InFlight::default();
|
let in_flight = InFlight::default();
|
||||||
let tags = venv.interpreter().tags()?;
|
let tags = venv.interpreter().tags()?;
|
||||||
|
|
||||||
|
let no_build = if args.no_build {
|
||||||
|
NoBuild::All
|
||||||
|
} else {
|
||||||
|
NoBuild::None
|
||||||
|
};
|
||||||
|
|
||||||
let build_dispatch = BuildDispatch::new(
|
let build_dispatch = BuildDispatch::new(
|
||||||
&client,
|
&client,
|
||||||
&cache,
|
&cache,
|
||||||
|
|
@ -76,7 +82,7 @@ pub(crate) async fn install_many(args: InstallManyArgs) -> Result<()> {
|
||||||
&in_flight,
|
&in_flight,
|
||||||
venv.python_executable(),
|
venv.python_executable(),
|
||||||
setup_py,
|
setup_py,
|
||||||
args.no_build,
|
&no_build,
|
||||||
&NoBinary::None,
|
&NoBinary::None,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -129,7 +135,9 @@ async fn install_chunk(
|
||||||
info!("Failed to find {} wheel(s)", failures.len());
|
info!("Failed to find {} wheel(s)", failures.len());
|
||||||
}
|
}
|
||||||
let wheels_and_source_dist = resolution.len();
|
let wheels_and_source_dist = resolution.len();
|
||||||
let resolution = if build_dispatch.no_build() {
|
let resolution = if build_dispatch.no_build().is_none() {
|
||||||
|
resolution
|
||||||
|
} else {
|
||||||
let only_wheels: FxHashMap<_, _> = resolution
|
let only_wheels: FxHashMap<_, _> = resolution
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|(_, dist)| match dist {
|
.filter(|(_, dist)| match dist {
|
||||||
|
|
@ -142,9 +150,8 @@ async fn install_chunk(
|
||||||
wheels_and_source_dist - only_wheels.len()
|
wheels_and_source_dist - only_wheels.len()
|
||||||
);
|
);
|
||||||
only_wheels
|
only_wheels
|
||||||
} else {
|
|
||||||
resolution
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let dists = Resolution::new(resolution)
|
let dists = Resolution::new(resolution)
|
||||||
.into_distributions()
|
.into_distributions()
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ use puffin_dispatch::BuildDispatch;
|
||||||
use puffin_installer::NoBinary;
|
use puffin_installer::NoBinary;
|
||||||
use puffin_interpreter::Virtualenv;
|
use puffin_interpreter::Virtualenv;
|
||||||
use puffin_resolver::{InMemoryIndex, Manifest, Options, Resolver};
|
use puffin_resolver::{InMemoryIndex, Manifest, Options, Resolver};
|
||||||
use puffin_traits::{InFlight, SetupPyStrategy};
|
use puffin_traits::{InFlight, NoBuild, SetupPyStrategy};
|
||||||
|
|
||||||
#[derive(ValueEnum, Default, Clone)]
|
#[derive(ValueEnum, Default, Clone)]
|
||||||
pub(crate) enum ResolveCliFormat {
|
pub(crate) enum ResolveCliFormat {
|
||||||
|
|
@ -69,6 +69,12 @@ pub(crate) async fn resolve_cli(args: ResolveCliArgs) -> Result<()> {
|
||||||
let index = InMemoryIndex::default();
|
let index = InMemoryIndex::default();
|
||||||
let in_flight = InFlight::default();
|
let in_flight = InFlight::default();
|
||||||
|
|
||||||
|
let no_build = if args.no_build {
|
||||||
|
NoBuild::All
|
||||||
|
} else {
|
||||||
|
NoBuild::None
|
||||||
|
};
|
||||||
|
|
||||||
let build_dispatch = BuildDispatch::new(
|
let build_dispatch = BuildDispatch::new(
|
||||||
&client,
|
&client,
|
||||||
&cache,
|
&cache,
|
||||||
|
|
@ -79,7 +85,7 @@ pub(crate) async fn resolve_cli(args: ResolveCliArgs) -> Result<()> {
|
||||||
&in_flight,
|
&in_flight,
|
||||||
venv.python_executable(),
|
venv.python_executable(),
|
||||||
SetupPyStrategy::default(),
|
SetupPyStrategy::default(),
|
||||||
args.no_build,
|
&no_build,
|
||||||
&NoBinary::None,
|
&NoBinary::None,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ use puffin_installer::NoBinary;
|
||||||
use puffin_interpreter::Virtualenv;
|
use puffin_interpreter::Virtualenv;
|
||||||
use puffin_normalize::PackageName;
|
use puffin_normalize::PackageName;
|
||||||
use puffin_resolver::InMemoryIndex;
|
use puffin_resolver::InMemoryIndex;
|
||||||
use puffin_traits::{BuildContext, InFlight, SetupPyStrategy};
|
use puffin_traits::{BuildContext, InFlight, NoBuild, SetupPyStrategy};
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
pub(crate) struct ResolveManyArgs {
|
pub(crate) struct ResolveManyArgs {
|
||||||
|
|
@ -82,6 +82,12 @@ pub(crate) async fn resolve_many(args: ResolveManyArgs) -> Result<()> {
|
||||||
header_span.pb_set_length(total as u64);
|
header_span.pb_set_length(total as u64);
|
||||||
let _header_span_enter = header_span.enter();
|
let _header_span_enter = header_span.enter();
|
||||||
|
|
||||||
|
let no_build = if args.no_build {
|
||||||
|
NoBuild::All
|
||||||
|
} else {
|
||||||
|
NoBuild::None
|
||||||
|
};
|
||||||
|
|
||||||
let mut tasks = futures::stream::iter(requirements)
|
let mut tasks = futures::stream::iter(requirements)
|
||||||
.map(|requirement| {
|
.map(|requirement| {
|
||||||
async {
|
async {
|
||||||
|
|
@ -102,7 +108,7 @@ pub(crate) async fn resolve_many(args: ResolveManyArgs) -> Result<()> {
|
||||||
&in_flight,
|
&in_flight,
|
||||||
venv.python_executable(),
|
venv.python_executable(),
|
||||||
setup_py,
|
setup_py,
|
||||||
args.no_build,
|
&no_build,
|
||||||
&NoBinary::None,
|
&NoBinary::None,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use anyhow::{bail, Context, Result};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use tracing::{debug, instrument};
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
use distribution_types::{IndexLocations, Name, Resolution};
|
use distribution_types::{IndexLocations, Name, Resolution, SourceDist};
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use pep508_rs::Requirement;
|
use pep508_rs::Requirement;
|
||||||
use puffin_build::{SourceBuild, SourceBuildContext};
|
use puffin_build::{SourceBuild, SourceBuildContext};
|
||||||
|
|
@ -18,7 +18,7 @@ use puffin_client::{FlatIndex, RegistryClient};
|
||||||
use puffin_installer::{Downloader, Installer, NoBinary, Plan, Planner, Reinstall, SitePackages};
|
use puffin_installer::{Downloader, Installer, NoBinary, Plan, Planner, Reinstall, SitePackages};
|
||||||
use puffin_interpreter::{Interpreter, Virtualenv};
|
use puffin_interpreter::{Interpreter, Virtualenv};
|
||||||
use puffin_resolver::{InMemoryIndex, Manifest, Options, Resolver};
|
use puffin_resolver::{InMemoryIndex, Manifest, Options, Resolver};
|
||||||
use puffin_traits::{BuildContext, BuildKind, InFlight, SetupPyStrategy};
|
use puffin_traits::{BuildContext, BuildKind, InFlight, NoBuild, SetupPyStrategy};
|
||||||
|
|
||||||
/// The main implementation of [`BuildContext`], used by the CLI, see [`BuildContext`]
|
/// The main implementation of [`BuildContext`], used by the CLI, see [`BuildContext`]
|
||||||
/// documentation.
|
/// documentation.
|
||||||
|
|
@ -32,7 +32,7 @@ pub struct BuildDispatch<'a> {
|
||||||
in_flight: &'a InFlight,
|
in_flight: &'a InFlight,
|
||||||
base_python: PathBuf,
|
base_python: PathBuf,
|
||||||
setup_py: SetupPyStrategy,
|
setup_py: SetupPyStrategy,
|
||||||
no_build: bool,
|
no_build: &'a NoBuild,
|
||||||
no_binary: &'a NoBinary,
|
no_binary: &'a NoBinary,
|
||||||
source_build_context: SourceBuildContext,
|
source_build_context: SourceBuildContext,
|
||||||
options: Options,
|
options: Options,
|
||||||
|
|
@ -50,7 +50,7 @@ impl<'a> BuildDispatch<'a> {
|
||||||
in_flight: &'a InFlight,
|
in_flight: &'a InFlight,
|
||||||
base_python: PathBuf,
|
base_python: PathBuf,
|
||||||
setup_py: SetupPyStrategy,
|
setup_py: SetupPyStrategy,
|
||||||
no_build: bool,
|
no_build: &'a NoBuild,
|
||||||
no_binary: &'a NoBinary,
|
no_binary: &'a NoBinary,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
@ -92,7 +92,7 @@ impl<'a> BuildContext for BuildDispatch<'a> {
|
||||||
&self.base_python
|
&self.base_python
|
||||||
}
|
}
|
||||||
|
|
||||||
fn no_build(&self) -> bool {
|
fn no_build(&self) -> &NoBuild {
|
||||||
self.no_build
|
self.no_build
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -246,10 +246,29 @@ impl<'a> BuildContext for BuildDispatch<'a> {
|
||||||
source: &'data Path,
|
source: &'data Path,
|
||||||
subdirectory: Option<&'data Path>,
|
subdirectory: Option<&'data Path>,
|
||||||
package_id: &'data str,
|
package_id: &'data str,
|
||||||
|
dist: Option<&'data SourceDist>,
|
||||||
build_kind: BuildKind,
|
build_kind: BuildKind,
|
||||||
) -> Result<SourceBuild> {
|
) -> Result<SourceBuild> {
|
||||||
if self.no_build {
|
match self.no_build {
|
||||||
bail!("Building source distributions is disabled");
|
NoBuild::All => bail!("Building source distributions is disabled"),
|
||||||
|
NoBuild::None => {}
|
||||||
|
NoBuild::Packages(packages) => {
|
||||||
|
if let Some(dist) = dist {
|
||||||
|
// We can only prevent builds by name for packages with names
|
||||||
|
// which is unknown before build of editable source distributions
|
||||||
|
if packages.contains(dist.name()) {
|
||||||
|
bail!(
|
||||||
|
"Building source distributions for {} is disabled",
|
||||||
|
dist.name()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
debug_assert!(
|
||||||
|
matches!(build_kind, BuildKind::Editable),
|
||||||
|
"Only editable builds are exempt from 'no build' checks"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let builder = SourceBuild::setup(
|
let builder = SourceBuild::setup(
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ use puffin_cache::{Cache, CacheBucket, Timestamp, WheelCache};
|
||||||
use puffin_client::{CacheControl, CachedClientError, RegistryClient};
|
use puffin_client::{CacheControl, CachedClientError, RegistryClient};
|
||||||
use puffin_fs::metadata_if_exists;
|
use puffin_fs::metadata_if_exists;
|
||||||
use puffin_git::GitSource;
|
use puffin_git::GitSource;
|
||||||
use puffin_traits::{BuildContext, NoBinary};
|
use puffin_traits::{BuildContext, NoBinary, NoBuild};
|
||||||
use pypi_types::Metadata21;
|
use pypi_types::Metadata21;
|
||||||
|
|
||||||
use crate::download::{BuiltWheel, UnzippedWheel};
|
use crate::download::{BuiltWheel, UnzippedWheel};
|
||||||
|
|
@ -340,8 +340,13 @@ impl<'a, Context: BuildContext + Send + Sync> DistributionDatabase<'a, Context>
|
||||||
Ok((self.client.wheel_metadata(built_dist).boxed().await?, None))
|
Ok((self.client.wheel_metadata(built_dist).boxed().await?, None))
|
||||||
}
|
}
|
||||||
Dist::Source(source_dist) => {
|
Dist::Source(source_dist) => {
|
||||||
|
let no_build = match self.build_context.no_build() {
|
||||||
|
NoBuild::All => true,
|
||||||
|
NoBuild::None => false,
|
||||||
|
NoBuild::Packages(packages) => packages.contains(source_dist.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 self.build_context.no_build() {
|
if no_build {
|
||||||
return Err(Error::NoBuild);
|
return Err(Error::NoBuild);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ use puffin_cache::{
|
||||||
use puffin_client::{CacheControl, CachedClient, CachedClientError, DataWithCachePolicy};
|
use puffin_client::{CacheControl, CachedClient, CachedClientError, DataWithCachePolicy};
|
||||||
use puffin_fs::{write_atomic, LockedFile};
|
use puffin_fs::{write_atomic, LockedFile};
|
||||||
use puffin_git::{Fetch, GitSource};
|
use puffin_git::{Fetch, GitSource};
|
||||||
use puffin_traits::{BuildContext, BuildKind, SourceBuildTrait};
|
use puffin_traits::{BuildContext, BuildKind, NoBuild, SourceBuildTrait};
|
||||||
use pypi_types::Metadata21;
|
use pypi_types::Metadata21;
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
|
|
@ -823,7 +823,13 @@ impl<'a, T: BuildContext> SourceDistCachedBuilder<'a, T> {
|
||||||
) -> Result<(String, WheelFilename, Metadata21), Error> {
|
) -> Result<(String, WheelFilename, Metadata21), Error> {
|
||||||
debug!("Building: {dist}");
|
debug!("Building: {dist}");
|
||||||
|
|
||||||
if self.build_context.no_build() {
|
// Guard against build of source distributions when disabled
|
||||||
|
let no_build = match self.build_context.no_build() {
|
||||||
|
NoBuild::All => true,
|
||||||
|
NoBuild::None => false,
|
||||||
|
NoBuild::Packages(packages) => packages.contains(dist.name()),
|
||||||
|
};
|
||||||
|
if no_build {
|
||||||
return Err(Error::NoBuild);
|
return Err(Error::NoBuild);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -837,6 +843,7 @@ impl<'a, T: BuildContext> SourceDistCachedBuilder<'a, T> {
|
||||||
source_dist,
|
source_dist,
|
||||||
subdirectory,
|
subdirectory,
|
||||||
&dist.to_string(),
|
&dist.to_string(),
|
||||||
|
Some(dist),
|
||||||
BuildKind::Wheel,
|
BuildKind::Wheel,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|
@ -878,6 +885,7 @@ impl<'a, T: BuildContext> SourceDistCachedBuilder<'a, T> {
|
||||||
source_dist,
|
source_dist,
|
||||||
subdirectory,
|
subdirectory,
|
||||||
&dist.to_string(),
|
&dist.to_string(),
|
||||||
|
Some(dist),
|
||||||
BuildKind::Wheel,
|
BuildKind::Wheel,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|
@ -923,6 +931,7 @@ impl<'a, T: BuildContext> SourceDistCachedBuilder<'a, T> {
|
||||||
&editable.path,
|
&editable.path,
|
||||||
None,
|
None,
|
||||||
&editable.to_string(),
|
&editable.to_string(),
|
||||||
|
None,
|
||||||
BuildKind::Editable,
|
BuildKind::Editable,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ use anyhow::Result;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use distribution_types::{IndexLocations, Resolution};
|
use distribution_types::{IndexLocations, Resolution, SourceDist};
|
||||||
use pep508_rs::{MarkerEnvironment, Requirement, StringVersion};
|
use pep508_rs::{MarkerEnvironment, Requirement, StringVersion};
|
||||||
use platform_host::{Arch, Os, Platform};
|
use platform_host::{Arch, Os, Platform};
|
||||||
use platform_tags::Tags;
|
use platform_tags::Tags;
|
||||||
|
|
@ -21,7 +21,9 @@ use puffin_resolver::{
|
||||||
DisplayResolutionGraph, InMemoryIndex, Manifest, Options, OptionsBuilder, PreReleaseMode,
|
DisplayResolutionGraph, InMemoryIndex, Manifest, Options, OptionsBuilder, PreReleaseMode,
|
||||||
ResolutionGraph, ResolutionMode, Resolver,
|
ResolutionGraph, ResolutionMode, Resolver,
|
||||||
};
|
};
|
||||||
use puffin_traits::{BuildContext, BuildKind, NoBinary, SetupPyStrategy, SourceBuildTrait};
|
use puffin_traits::{
|
||||||
|
BuildContext, BuildKind, NoBinary, NoBuild, SetupPyStrategy, SourceBuildTrait,
|
||||||
|
};
|
||||||
|
|
||||||
// Exclude any packages uploaded after this date.
|
// Exclude any packages uploaded after this date.
|
||||||
static EXCLUDE_NEWER: Lazy<DateTime<Utc>> = Lazy::new(|| {
|
static EXCLUDE_NEWER: Lazy<DateTime<Utc>> = Lazy::new(|| {
|
||||||
|
|
@ -61,8 +63,8 @@ impl BuildContext for DummyContext {
|
||||||
panic!("The test should not need to build source distributions")
|
panic!("The test should not need to build source distributions")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn no_build(&self) -> bool {
|
fn no_build(&self) -> &NoBuild {
|
||||||
false
|
&NoBuild::None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn no_binary(&self) -> &NoBinary {
|
fn no_binary(&self) -> &NoBinary {
|
||||||
|
|
@ -94,6 +96,7 @@ impl BuildContext for DummyContext {
|
||||||
_source: &'a Path,
|
_source: &'a Path,
|
||||||
_subdirectory: Option<&'a Path>,
|
_subdirectory: Option<&'a Path>,
|
||||||
_package_id: &'a str,
|
_package_id: &'a str,
|
||||||
|
_dist: Option<&'a SourceDist>,
|
||||||
_build_kind: BuildKind,
|
_build_kind: BuildKind,
|
||||||
) -> Result<Self::SourceDistBuilder> {
|
) -> Result<Self::SourceDistBuilder> {
|
||||||
Ok(DummyBuilder)
|
Ok(DummyBuilder)
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,11 @@
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
use distribution_types::{CachedDist, DistributionId, IndexLocations, Resolution};
|
use distribution_types::{CachedDist, DistributionId, IndexLocations, Resolution, SourceDist};
|
||||||
use once_map::OnceMap;
|
use once_map::OnceMap;
|
||||||
use pep508_rs::Requirement;
|
use pep508_rs::Requirement;
|
||||||
use puffin_cache::Cache;
|
use puffin_cache::Cache;
|
||||||
|
|
@ -67,7 +68,7 @@ pub trait BuildContext: Sync {
|
||||||
/// Whether source distribution building is disabled. This [`BuildContext::setup_build`] calls
|
/// Whether source distribution building is disabled. This [`BuildContext::setup_build`] calls
|
||||||
/// will fail in this case. This method exists to avoid fetching source distributions if we know
|
/// will fail in this case. This method exists to avoid fetching source distributions if we know
|
||||||
/// we can't build them
|
/// we can't build them
|
||||||
fn no_build(&self) -> bool;
|
fn no_build(&self) -> &NoBuild;
|
||||||
|
|
||||||
/// Whether using pre-built wheels is disabled.
|
/// Whether using pre-built wheels is disabled.
|
||||||
fn no_binary(&self) -> &NoBinary;
|
fn no_binary(&self) -> &NoBinary;
|
||||||
|
|
@ -98,11 +99,13 @@ pub trait BuildContext: Sync {
|
||||||
/// For PEP 517 builds, this calls `get_requires_for_build_wheel`.
|
/// For PEP 517 builds, this calls `get_requires_for_build_wheel`.
|
||||||
///
|
///
|
||||||
/// `package_id` is for error reporting only.
|
/// `package_id` is for error reporting only.
|
||||||
|
/// `dist` is for safety checks and may be null for editable builds.
|
||||||
fn setup_build<'a>(
|
fn setup_build<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
source: &'a Path,
|
source: &'a Path,
|
||||||
subdirectory: Option<&'a Path>,
|
subdirectory: Option<&'a Path>,
|
||||||
package_id: &'a str,
|
package_id: &'a str,
|
||||||
|
dist: Option<&'a SourceDist>,
|
||||||
build_kind: BuildKind,
|
build_kind: BuildKind,
|
||||||
) -> impl Future<Output = Result<Self::SourceDistBuilder>> + Send + 'a;
|
) -> impl Future<Output = Result<Self::SourceDistBuilder>> + Send + 'a;
|
||||||
}
|
}
|
||||||
|
|
@ -163,6 +166,62 @@ impl Display for BuildKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum PackageNameSpecifier {
|
||||||
|
All,
|
||||||
|
None,
|
||||||
|
Package(PackageName),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for PackageNameSpecifier {
|
||||||
|
type Err = puffin_normalize::InvalidNameError;
|
||||||
|
|
||||||
|
fn from_str(name: &str) -> Result<Self, Self::Err> {
|
||||||
|
match name {
|
||||||
|
":all:" => Ok(Self::All),
|
||||||
|
":none:" => Ok(Self::None),
|
||||||
|
_ => Ok(Self::Package(PackageName::from_str(name)?)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum PackageNameSpecifiers {
|
||||||
|
All,
|
||||||
|
None,
|
||||||
|
Packages(Vec<PackageName>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PackageNameSpecifiers {
|
||||||
|
fn from_iter(specifiers: impl Iterator<Item = PackageNameSpecifier>) -> Self {
|
||||||
|
let mut packages = Vec::new();
|
||||||
|
let mut all: bool = false;
|
||||||
|
|
||||||
|
for specifier in specifiers {
|
||||||
|
match specifier {
|
||||||
|
PackageNameSpecifier::None => {
|
||||||
|
packages.clear();
|
||||||
|
all = false;
|
||||||
|
}
|
||||||
|
PackageNameSpecifier::All => {
|
||||||
|
all = true;
|
||||||
|
}
|
||||||
|
PackageNameSpecifier::Package(name) => {
|
||||||
|
packages.push(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if all {
|
||||||
|
Self::All
|
||||||
|
} else if packages.is_empty() {
|
||||||
|
Self::None
|
||||||
|
} else {
|
||||||
|
Self::Packages(packages)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum NoBinary {
|
pub enum NoBinary {
|
||||||
/// Allow installation of any wheel.
|
/// Allow installation of any wheel.
|
||||||
|
|
@ -177,13 +236,117 @@ pub enum NoBinary {
|
||||||
|
|
||||||
impl NoBinary {
|
impl NoBinary {
|
||||||
/// Determine the binary installation strategy to use.
|
/// Determine the binary installation strategy to use.
|
||||||
pub fn from_args(no_binary: bool, no_binary_package: Vec<PackageName>) -> Self {
|
pub fn from_args(no_binary: Vec<PackageNameSpecifier>) -> Self {
|
||||||
if no_binary {
|
let combined = PackageNameSpecifiers::from_iter(no_binary.into_iter());
|
||||||
Self::All
|
match combined {
|
||||||
} else if !no_binary_package.is_empty() {
|
PackageNameSpecifiers::All => Self::All,
|
||||||
Self::Packages(no_binary_package)
|
PackageNameSpecifiers::None => Self::None,
|
||||||
} else {
|
PackageNameSpecifiers::Packages(packages) => Self::Packages(packages),
|
||||||
Self::None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl NoBinary {
|
||||||
|
/// Returns `true` if all wheels are allowed.
|
||||||
|
pub fn is_none(&self) -> bool {
|
||||||
|
matches!(self, Self::None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum NoBuild {
|
||||||
|
/// Allow building wheels from any source distribution.
|
||||||
|
None,
|
||||||
|
|
||||||
|
/// Do not allow building wheels from any source distribution.
|
||||||
|
All,
|
||||||
|
|
||||||
|
/// Do not allow building wheels from the given package's source distributions.
|
||||||
|
Packages(Vec<PackageName>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NoBuild {
|
||||||
|
/// Determine the build strategy to use.
|
||||||
|
pub fn from_args(only_binary: Vec<PackageNameSpecifier>, no_build: bool) -> Self {
|
||||||
|
if no_build {
|
||||||
|
Self::All
|
||||||
|
} else {
|
||||||
|
let combined = PackageNameSpecifiers::from_iter(only_binary.into_iter());
|
||||||
|
match combined {
|
||||||
|
PackageNameSpecifiers::All => Self::All,
|
||||||
|
PackageNameSpecifiers::None => Self::None,
|
||||||
|
PackageNameSpecifiers::Packages(packages) => Self::Packages(packages),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NoBuild {
|
||||||
|
/// Returns `true` if all builds are allowed.
|
||||||
|
pub fn is_none(&self) -> bool {
|
||||||
|
matches!(self, Self::None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use anyhow::Error;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_build_from_args() -> Result<(), Error> {
|
||||||
|
assert_eq!(
|
||||||
|
NoBuild::from_args(vec![PackageNameSpecifier::from_str(":all:")?], false),
|
||||||
|
NoBuild::All,
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
NoBuild::from_args(vec![PackageNameSpecifier::from_str(":all:")?], true),
|
||||||
|
NoBuild::All,
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
NoBuild::from_args(vec![PackageNameSpecifier::from_str(":none:")?], true),
|
||||||
|
NoBuild::All,
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
NoBuild::from_args(vec![PackageNameSpecifier::from_str(":none:")?], false),
|
||||||
|
NoBuild::None,
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
NoBuild::from_args(
|
||||||
|
vec![
|
||||||
|
PackageNameSpecifier::from_str("foo")?,
|
||||||
|
PackageNameSpecifier::from_str("bar")?
|
||||||
|
],
|
||||||
|
false
|
||||||
|
),
|
||||||
|
NoBuild::Packages(vec![
|
||||||
|
PackageName::from_str("foo")?,
|
||||||
|
PackageName::from_str("bar")?
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
NoBuild::from_args(
|
||||||
|
vec![
|
||||||
|
PackageNameSpecifier::from_str("test")?,
|
||||||
|
PackageNameSpecifier::All
|
||||||
|
],
|
||||||
|
false
|
||||||
|
),
|
||||||
|
NoBuild::All,
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
NoBuild::from_args(
|
||||||
|
vec![
|
||||||
|
PackageNameSpecifier::from_str("foo")?,
|
||||||
|
PackageNameSpecifier::from_str(":none:")?,
|
||||||
|
PackageNameSpecifier::from_str("bar")?
|
||||||
|
],
|
||||||
|
false
|
||||||
|
),
|
||||||
|
NoBuild::Packages(vec![PackageName::from_str("bar")?]),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ use puffin_resolver::{
|
||||||
DisplayResolutionGraph, InMemoryIndex, Manifest, OptionsBuilder, PreReleaseMode,
|
DisplayResolutionGraph, InMemoryIndex, Manifest, OptionsBuilder, PreReleaseMode,
|
||||||
ResolutionMode, Resolver,
|
ResolutionMode, Resolver,
|
||||||
};
|
};
|
||||||
use puffin_traits::{InFlight, SetupPyStrategy};
|
use puffin_traits::{InFlight, NoBuild, SetupPyStrategy};
|
||||||
use puffin_warnings::warn_user;
|
use puffin_warnings::warn_user;
|
||||||
use requirements_txt::EditableRequirement;
|
use requirements_txt::EditableRequirement;
|
||||||
|
|
||||||
|
|
@ -59,7 +59,7 @@ pub(crate) async fn pip_compile(
|
||||||
include_find_links: bool,
|
include_find_links: bool,
|
||||||
index_locations: IndexLocations,
|
index_locations: IndexLocations,
|
||||||
setup_py: SetupPyStrategy,
|
setup_py: SetupPyStrategy,
|
||||||
no_build: bool,
|
no_build: &NoBuild,
|
||||||
python_version: Option<PythonVersion>,
|
python_version: Option<PythonVersion>,
|
||||||
exclude_newer: Option<DateTime<Utc>>,
|
exclude_newer: Option<DateTime<Utc>>,
|
||||||
cache: Cache,
|
cache: Cache,
|
||||||
|
|
@ -152,7 +152,7 @@ pub(crate) async fn pip_compile(
|
||||||
python_version.major() == interpreter.python_major()
|
python_version.major() == interpreter.python_major()
|
||||||
&& python_version.minor() == interpreter.python_minor()
|
&& python_version.minor() == interpreter.python_minor()
|
||||||
};
|
};
|
||||||
if !no_build
|
if no_build.is_none()
|
||||||
&& python_version.version() != interpreter.python_version()
|
&& python_version.version() != interpreter.python_version()
|
||||||
&& (python_version.patch().is_some() || !matches_without_patch)
|
&& (python_version.patch().is_some() || !matches_without_patch)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ use puffin_resolver::{
|
||||||
DependencyMode, InMemoryIndex, Manifest, Options, OptionsBuilder, PreReleaseMode,
|
DependencyMode, InMemoryIndex, Manifest, Options, OptionsBuilder, PreReleaseMode,
|
||||||
ResolutionGraph, ResolutionMode, Resolver,
|
ResolutionGraph, ResolutionMode, Resolver,
|
||||||
};
|
};
|
||||||
use puffin_traits::{InFlight, SetupPyStrategy};
|
use puffin_traits::{InFlight, NoBuild, SetupPyStrategy};
|
||||||
use pypi_types::Yanked;
|
use pypi_types::Yanked;
|
||||||
use requirements_txt::EditableRequirement;
|
use requirements_txt::EditableRequirement;
|
||||||
|
|
||||||
|
|
@ -52,7 +52,7 @@ pub(crate) async fn pip_install(
|
||||||
reinstall: &Reinstall,
|
reinstall: &Reinstall,
|
||||||
link_mode: LinkMode,
|
link_mode: LinkMode,
|
||||||
setup_py: SetupPyStrategy,
|
setup_py: SetupPyStrategy,
|
||||||
no_build: bool,
|
no_build: &NoBuild,
|
||||||
no_binary: &NoBinary,
|
no_binary: &NoBinary,
|
||||||
strict: bool,
|
strict: bool,
|
||||||
exclude_newer: Option<DateTime<Utc>>,
|
exclude_newer: Option<DateTime<Utc>>,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ use puffin_installer::{
|
||||||
};
|
};
|
||||||
use puffin_interpreter::Virtualenv;
|
use puffin_interpreter::Virtualenv;
|
||||||
use puffin_resolver::InMemoryIndex;
|
use puffin_resolver::InMemoryIndex;
|
||||||
use puffin_traits::{InFlight, SetupPyStrategy};
|
use puffin_traits::{InFlight, NoBuild, SetupPyStrategy};
|
||||||
use pypi_types::Yanked;
|
use pypi_types::Yanked;
|
||||||
use requirements_txt::EditableRequirement;
|
use requirements_txt::EditableRequirement;
|
||||||
|
|
||||||
|
|
@ -35,7 +35,7 @@ pub(crate) async fn pip_sync(
|
||||||
link_mode: LinkMode,
|
link_mode: LinkMode,
|
||||||
index_locations: IndexLocations,
|
index_locations: IndexLocations,
|
||||||
setup_py: SetupPyStrategy,
|
setup_py: SetupPyStrategy,
|
||||||
no_build: bool,
|
no_build: &NoBuild,
|
||||||
no_binary: &NoBinary,
|
no_binary: &NoBinary,
|
||||||
strict: bool,
|
strict: bool,
|
||||||
cache: Cache,
|
cache: Cache,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ use puffin_fs::Normalized;
|
||||||
use puffin_installer::NoBinary;
|
use puffin_installer::NoBinary;
|
||||||
use puffin_interpreter::{find_default_python, find_requested_python, Error};
|
use puffin_interpreter::{find_default_python, find_requested_python, Error};
|
||||||
use puffin_resolver::InMemoryIndex;
|
use puffin_resolver::InMemoryIndex;
|
||||||
use puffin_traits::{BuildContext, InFlight, SetupPyStrategy};
|
use puffin_traits::{BuildContext, InFlight, NoBuild, SetupPyStrategy};
|
||||||
|
|
||||||
use crate::commands::ExitStatus;
|
use crate::commands::ExitStatus;
|
||||||
use crate::printer::Printer;
|
use crate::printer::Printer;
|
||||||
|
|
@ -135,7 +135,7 @@ async fn venv_impl(
|
||||||
&in_flight,
|
&in_flight,
|
||||||
venv.python_executable(),
|
venv.python_executable(),
|
||||||
SetupPyStrategy::default(),
|
SetupPyStrategy::default(),
|
||||||
true,
|
&NoBuild::All,
|
||||||
&NoBinary::None,
|
&NoBinary::None,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ use puffin_installer::{NoBinary, Reinstall};
|
||||||
use puffin_interpreter::PythonVersion;
|
use puffin_interpreter::PythonVersion;
|
||||||
use puffin_normalize::{ExtraName, PackageName};
|
use puffin_normalize::{ExtraName, PackageName};
|
||||||
use puffin_resolver::{DependencyMode, PreReleaseMode, ResolutionMode};
|
use puffin_resolver::{DependencyMode, PreReleaseMode, ResolutionMode};
|
||||||
use puffin_traits::SetupPyStrategy;
|
use puffin_traits::{NoBuild, PackageNameSpecifier, SetupPyStrategy};
|
||||||
use requirements::ExtrasSpecification;
|
use requirements::ExtrasSpecification;
|
||||||
|
|
||||||
use crate::commands::{extra_name_with_clap_error, ExitStatus, Upgrade};
|
use crate::commands::{extra_name_with_clap_error, ExitStatus, Upgrade};
|
||||||
|
|
@ -259,9 +259,22 @@ struct PipCompileArgs {
|
||||||
/// When enabled, resolving will not run arbitrary code. The cached wheels of already-built
|
/// When enabled, resolving will not run arbitrary code. The cached wheels of already-built
|
||||||
/// source distributions will be reused, but operations that require building distributions will
|
/// source distributions will be reused, but operations that require building distributions will
|
||||||
/// exit with an error.
|
/// exit with an error.
|
||||||
#[clap(long)]
|
///
|
||||||
|
/// Alias for `--only-binary :all:`.
|
||||||
|
#[clap(long, conflicts_with = "only_binary")]
|
||||||
no_build: bool,
|
no_build: bool,
|
||||||
|
|
||||||
|
/// Only use pre-built wheels; don't build source distributions.
|
||||||
|
///
|
||||||
|
/// When enabled, resolving will not run code from the given packages. The cached wheels of already-built
|
||||||
|
/// source distributions will be reused, but operations that require building distributions will
|
||||||
|
/// exit with an error.
|
||||||
|
///
|
||||||
|
/// Multiple packages may be provided. Disable binaries for all packages with `:all:`.
|
||||||
|
/// Clear previously specified packages with `:none:`.
|
||||||
|
#[clap(long, conflicts_with = "no_build")]
|
||||||
|
only_binary: Vec<PackageNameSpecifier>,
|
||||||
|
|
||||||
/// The minimum Python version that should be supported by the compiled requirements (e.g.,
|
/// The minimum Python version that should be supported by the compiled requirements (e.g.,
|
||||||
/// `3.7` or `3.7.9`).
|
/// `3.7` or `3.7.9`).
|
||||||
///
|
///
|
||||||
|
|
@ -353,22 +366,31 @@ struct PipSyncArgs {
|
||||||
/// When enabled, resolving will not run arbitrary code. The cached wheels of already-built
|
/// When enabled, resolving will not run arbitrary code. The cached wheels of already-built
|
||||||
/// source distributions will be reused, but operations that require building distributions will
|
/// source distributions will be reused, but operations that require building distributions will
|
||||||
/// exit with an error.
|
/// exit with an error.
|
||||||
#[clap(long)]
|
///
|
||||||
|
/// Alias for `--only-binary :all:`.
|
||||||
|
#[clap(long, conflicts_with = "no_binary", conflicts_with = "only_binary")]
|
||||||
no_build: bool,
|
no_build: bool,
|
||||||
|
|
||||||
/// Don't install pre-built wheels.
|
/// Don't install pre-built wheels.
|
||||||
///
|
///
|
||||||
/// When enabled, all installed packages will be installed from a source distribution. The resolver
|
/// The given packages will be installed from a source distribution. The resolver
|
||||||
/// will still use pre-built wheels for metadata.
|
/// will still use pre-built wheels for metadata.
|
||||||
#[clap(long)]
|
|
||||||
no_binary: bool,
|
|
||||||
|
|
||||||
/// Don't install pre-built wheels for a specific package.
|
|
||||||
///
|
///
|
||||||
/// When enabled, the specified packages will be installed from a source distribution. The resolver
|
/// Multiple packages may be provided. Disable binaries for all packages with `:all:`.
|
||||||
/// will still use pre-built wheels for metadata.
|
/// Clear previously specified packages with `:none:`.
|
||||||
#[clap(long)]
|
#[clap(long, conflicts_with = "no_build")]
|
||||||
no_binary_package: Vec<PackageName>,
|
no_binary: Vec<PackageNameSpecifier>,
|
||||||
|
|
||||||
|
/// Only use pre-built wheels; don't build source distributions.
|
||||||
|
///
|
||||||
|
/// When enabled, resolving will not run code from the given packages. The cached wheels of already-built
|
||||||
|
/// source distributions will be reused, but operations that require building distributions will
|
||||||
|
/// exit with an error.
|
||||||
|
///
|
||||||
|
/// Multiple packages may be provided. Disable binaries for all packages with `:all:`.
|
||||||
|
/// Clear previously specified packages with `:none:`.
|
||||||
|
#[clap(long, conflicts_with = "no_build")]
|
||||||
|
only_binary: Vec<PackageNameSpecifier>,
|
||||||
|
|
||||||
/// Validate the virtual environment after completing the installation, to detect packages with
|
/// Validate the virtual environment after completing the installation, to detect packages with
|
||||||
/// missing dependencies or other issues.
|
/// missing dependencies or other issues.
|
||||||
|
|
@ -492,22 +514,31 @@ struct PipInstallArgs {
|
||||||
/// When enabled, resolving will not run arbitrary code. The cached wheels of already-built
|
/// When enabled, resolving will not run arbitrary code. The cached wheels of already-built
|
||||||
/// source distributions will be reused, but operations that require building distributions will
|
/// source distributions will be reused, but operations that require building distributions will
|
||||||
/// exit with an error.
|
/// exit with an error.
|
||||||
#[clap(long)]
|
///
|
||||||
|
/// Alias for `--only-binary :all:`.
|
||||||
|
#[clap(long, conflicts_with = "no_binary", conflicts_with = "only_binary")]
|
||||||
no_build: bool,
|
no_build: bool,
|
||||||
|
|
||||||
/// Don't install pre-built wheels.
|
/// Don't install pre-built wheels.
|
||||||
///
|
///
|
||||||
/// When enabled, all installed packages will be installed from a source distribution. The resolver
|
/// The given packages will be installed from a source distribution. The resolver
|
||||||
/// will still use pre-built wheels for metadata.
|
/// will still use pre-built wheels for metadata.
|
||||||
#[clap(long)]
|
|
||||||
no_binary: bool,
|
|
||||||
|
|
||||||
/// Don't install pre-built wheels for a specific package.
|
|
||||||
///
|
///
|
||||||
/// When enabled, the specified packages will be installed from a source distribution. The resolver
|
/// Multiple packages may be provided. Disable binaries for all packages with `:all:`.
|
||||||
/// will still use pre-built wheels for metadata.
|
/// Clear previously specified packages with `:none:`.
|
||||||
#[clap(long)]
|
#[clap(long, conflicts_with = "no_build")]
|
||||||
no_binary_package: Vec<PackageName>,
|
no_binary: Vec<PackageNameSpecifier>,
|
||||||
|
|
||||||
|
/// Only use pre-built wheels; don't build source distributions.
|
||||||
|
///
|
||||||
|
/// When enabled, resolving will not run code from the given packages. The cached wheels of already-built
|
||||||
|
/// source distributions will be reused, but operations that require building distributions will
|
||||||
|
/// exit with an error.
|
||||||
|
///
|
||||||
|
/// Multiple packages may be provided. Disable binaries for all packages with `:all:`.
|
||||||
|
/// Clear previously specified packages with `:none:`.
|
||||||
|
#[clap(long, conflicts_with = "no_build")]
|
||||||
|
only_binary: Vec<PackageNameSpecifier>,
|
||||||
|
|
||||||
/// Validate the virtual environment after completing the installation, to detect packages with
|
/// Validate the virtual environment after completing the installation, to detect packages with
|
||||||
/// missing dependencies or other issues.
|
/// missing dependencies or other issues.
|
||||||
|
|
@ -741,6 +772,7 @@ async fn run() -> Result<ExitStatus> {
|
||||||
ExtrasSpecification::Some(&args.extra)
|
ExtrasSpecification::Some(&args.extra)
|
||||||
};
|
};
|
||||||
let upgrade = Upgrade::from_args(args.upgrade, args.upgrade_package);
|
let upgrade = Upgrade::from_args(args.upgrade, args.upgrade_package);
|
||||||
|
let no_build = NoBuild::from_args(args.only_binary, args.no_build);
|
||||||
commands::pip_compile(
|
commands::pip_compile(
|
||||||
&requirements,
|
&requirements,
|
||||||
&constraints,
|
&constraints,
|
||||||
|
|
@ -761,7 +793,7 @@ async fn run() -> Result<ExitStatus> {
|
||||||
} else {
|
} else {
|
||||||
SetupPyStrategy::Pep517
|
SetupPyStrategy::Pep517
|
||||||
},
|
},
|
||||||
args.no_build,
|
&no_build,
|
||||||
args.python_version,
|
args.python_version,
|
||||||
args.exclude_newer,
|
args.exclude_newer,
|
||||||
cache,
|
cache,
|
||||||
|
|
@ -787,7 +819,8 @@ async fn run() -> Result<ExitStatus> {
|
||||||
.map(RequirementsSource::from_path)
|
.map(RequirementsSource::from_path)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let reinstall = Reinstall::from_args(args.reinstall, args.reinstall_package);
|
let reinstall = Reinstall::from_args(args.reinstall, args.reinstall_package);
|
||||||
let no_binary = NoBinary::from_args(args.no_binary, args.no_binary_package);
|
let no_binary = NoBinary::from_args(args.no_binary);
|
||||||
|
let no_build = NoBuild::from_args(args.only_binary, args.no_build);
|
||||||
commands::pip_sync(
|
commands::pip_sync(
|
||||||
&sources,
|
&sources,
|
||||||
&reinstall,
|
&reinstall,
|
||||||
|
|
@ -798,7 +831,7 @@ async fn run() -> Result<ExitStatus> {
|
||||||
} else {
|
} else {
|
||||||
SetupPyStrategy::Pep517
|
SetupPyStrategy::Pep517
|
||||||
},
|
},
|
||||||
args.no_build,
|
&no_build,
|
||||||
&no_binary,
|
&no_binary,
|
||||||
args.strict,
|
args.strict,
|
||||||
cache,
|
cache,
|
||||||
|
|
@ -845,7 +878,8 @@ async fn run() -> Result<ExitStatus> {
|
||||||
ExtrasSpecification::Some(&args.extra)
|
ExtrasSpecification::Some(&args.extra)
|
||||||
};
|
};
|
||||||
let reinstall = Reinstall::from_args(args.reinstall, args.reinstall_package);
|
let reinstall = Reinstall::from_args(args.reinstall, args.reinstall_package);
|
||||||
let no_binary = NoBinary::from_args(args.no_binary, args.no_binary_package);
|
let no_binary = NoBinary::from_args(args.no_binary);
|
||||||
|
let no_build = NoBuild::from_args(args.only_binary, args.no_build);
|
||||||
let dependency_mode = if args.no_deps {
|
let dependency_mode = if args.no_deps {
|
||||||
DependencyMode::Direct
|
DependencyMode::Direct
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -867,7 +901,7 @@ async fn run() -> Result<ExitStatus> {
|
||||||
} else {
|
} else {
|
||||||
SetupPyStrategy::Pep517
|
SetupPyStrategy::Pep517
|
||||||
},
|
},
|
||||||
args.no_build,
|
&no_build,
|
||||||
&no_binary,
|
&no_binary,
|
||||||
args.strict,
|
args.strict,
|
||||||
args.exclude_newer,
|
args.exclude_newer,
|
||||||
|
|
|
||||||
|
|
@ -668,7 +668,11 @@ fn install_no_binary() {
|
||||||
let context = TestContext::new("3.12");
|
let context = TestContext::new("3.12");
|
||||||
|
|
||||||
let mut command = command(&context);
|
let mut command = command(&context);
|
||||||
command.arg("Flask").arg("--no-binary").arg("--strict");
|
command
|
||||||
|
.arg("jinja2")
|
||||||
|
.arg("--no-binary")
|
||||||
|
.arg(":all:")
|
||||||
|
.arg("--strict");
|
||||||
if cfg!(all(windows, debug_assertions)) {
|
if cfg!(all(windows, debug_assertions)) {
|
||||||
// TODO(konstin): Reduce stack usage in debug mode enough that the tests pass with the
|
// TODO(konstin): Reduce stack usage in debug mode enough that the tests pass with the
|
||||||
// default windows stack of 1MB
|
// default windows stack of 1MB
|
||||||
|
|
@ -680,20 +684,15 @@ fn install_no_binary() {
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
Resolved 7 packages in [TIME]
|
Resolved 2 packages in [TIME]
|
||||||
Downloaded 7 packages in [TIME]
|
Downloaded 2 packages in [TIME]
|
||||||
Installed 7 packages in [TIME]
|
Installed 2 packages in [TIME]
|
||||||
+ blinker==1.7.0
|
|
||||||
+ click==8.1.7
|
|
||||||
+ flask==3.0.0
|
|
||||||
+ itsdangerous==2.1.2
|
|
||||||
+ jinja2==3.1.2
|
+ jinja2==3.1.2
|
||||||
+ markupsafe==2.1.3
|
+ markupsafe==2.1.3
|
||||||
+ werkzeug==3.0.1
|
|
||||||
"###
|
"###
|
||||||
);
|
);
|
||||||
|
|
||||||
context.assert_command("import flask").success();
|
context.assert_command("import jinja2").success();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Install a package without using pre-built wheels for a subset of packages.
|
/// Install a package without using pre-built wheels for a subset of packages.
|
||||||
|
|
@ -702,31 +701,78 @@ fn install_no_binary_subset() {
|
||||||
let context = TestContext::new("3.12");
|
let context = TestContext::new("3.12");
|
||||||
|
|
||||||
puffin_snapshot!(command(&context)
|
puffin_snapshot!(command(&context)
|
||||||
.arg("Flask")
|
.arg("jinja2")
|
||||||
.arg("--no-binary-package")
|
.arg("--no-binary")
|
||||||
.arg("click")
|
.arg("jinja2")
|
||||||
.arg("--no-binary-package")
|
.arg("--no-binary")
|
||||||
.arg("flask")
|
.arg("markupsafe")
|
||||||
.arg("--strict"), @r###"
|
.arg("--strict"), @r###"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
Resolved 7 packages in [TIME]
|
Resolved 2 packages in [TIME]
|
||||||
Downloaded 7 packages in [TIME]
|
Downloaded 2 packages in [TIME]
|
||||||
Installed 7 packages in [TIME]
|
Installed 2 packages in [TIME]
|
||||||
+ blinker==1.7.0
|
|
||||||
+ click==8.1.7
|
|
||||||
+ flask==3.0.0
|
|
||||||
+ itsdangerous==2.1.2
|
|
||||||
+ jinja2==3.1.2
|
+ jinja2==3.1.2
|
||||||
+ markupsafe==2.1.3
|
+ markupsafe==2.1.3
|
||||||
+ werkzeug==3.0.1
|
|
||||||
"###
|
"###
|
||||||
);
|
);
|
||||||
|
|
||||||
context.assert_command("import flask").success();
|
context.assert_command("import jinja2").success();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Install a package only using pre-built wheels.
|
||||||
|
#[test]
|
||||||
|
fn install_only_binary() {
|
||||||
|
let context = TestContext::new("3.12");
|
||||||
|
|
||||||
|
puffin_snapshot!(command(&context)
|
||||||
|
.arg("jinja2")
|
||||||
|
.arg("--only-binary")
|
||||||
|
.arg(":all:")
|
||||||
|
.arg("--strict"), @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Resolved 2 packages in [TIME]
|
||||||
|
Downloaded 2 packages in [TIME]
|
||||||
|
Installed 2 packages in [TIME]
|
||||||
|
+ jinja2==3.1.2
|
||||||
|
+ markupsafe==2.1.3
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
|
||||||
|
context.assert_command("import jinja2").success();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Install a package only using pre-built wheels for a subset of packages.
|
||||||
|
#[test]
|
||||||
|
fn install_only_binary_subset() {
|
||||||
|
let context = TestContext::new("3.12");
|
||||||
|
|
||||||
|
puffin_snapshot!(command(&context)
|
||||||
|
.arg("jinja2")
|
||||||
|
.arg("--only-binary")
|
||||||
|
.arg("markupsafe")
|
||||||
|
.arg("--strict"), @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Resolved 2 packages in [TIME]
|
||||||
|
Downloaded 2 packages in [TIME]
|
||||||
|
Installed 2 packages in [TIME]
|
||||||
|
+ jinja2==3.1.2
|
||||||
|
+ markupsafe==2.1.3
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
|
||||||
|
context.assert_command("import jinja2").success();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Install a package without using pre-built wheels.
|
/// Install a package without using pre-built wheels.
|
||||||
|
|
@ -736,7 +782,7 @@ fn reinstall_no_binary() {
|
||||||
|
|
||||||
// The first installation should use a pre-built wheel
|
// The first installation should use a pre-built wheel
|
||||||
let mut command = command(&context);
|
let mut command = command(&context);
|
||||||
command.arg("Flask").arg("--strict");
|
command.arg("jinja2").arg("--strict");
|
||||||
if cfg!(all(windows, debug_assertions)) {
|
if cfg!(all(windows, debug_assertions)) {
|
||||||
// TODO(konstin): Reduce stack usage in debug mode enough that the tests pass with the
|
// TODO(konstin): Reduce stack usage in debug mode enough that the tests pass with the
|
||||||
// default windows stack of 1MB
|
// default windows stack of 1MB
|
||||||
|
|
@ -748,25 +794,24 @@ fn reinstall_no_binary() {
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
Resolved 7 packages in [TIME]
|
Resolved 2 packages in [TIME]
|
||||||
Downloaded 7 packages in [TIME]
|
Downloaded 2 packages in [TIME]
|
||||||
Installed 7 packages in [TIME]
|
Installed 2 packages in [TIME]
|
||||||
+ blinker==1.7.0
|
|
||||||
+ click==8.1.7
|
|
||||||
+ flask==3.0.0
|
|
||||||
+ itsdangerous==2.1.2
|
|
||||||
+ jinja2==3.1.2
|
+ jinja2==3.1.2
|
||||||
+ markupsafe==2.1.3
|
+ markupsafe==2.1.3
|
||||||
+ werkzeug==3.0.1
|
|
||||||
"###
|
"###
|
||||||
);
|
);
|
||||||
|
|
||||||
context.assert_command("import flask").success();
|
context.assert_command("import jinja2").success();
|
||||||
|
|
||||||
// Running installation again with `--no-binary` should be a no-op
|
// Running installation again with `--no-binary` should be a no-op
|
||||||
// The first installation should use a pre-built wheel
|
// The first installation should use a pre-built wheel
|
||||||
let mut command = crate::command(&context);
|
let mut command = crate::command(&context);
|
||||||
command.arg("Flask").arg("--no-binary").arg("--strict");
|
command
|
||||||
|
.arg("jinja2")
|
||||||
|
.arg("--no-binary")
|
||||||
|
.arg(":all:")
|
||||||
|
.arg("--strict");
|
||||||
if cfg!(all(windows, debug_assertions)) {
|
if cfg!(all(windows, debug_assertions)) {
|
||||||
// TODO(konstin): Reduce stack usage in debug mode enough that the tests pass with the
|
// TODO(konstin): Reduce stack usage in debug mode enough that the tests pass with the
|
||||||
// default windows stack of 1MB
|
// default windows stack of 1MB
|
||||||
|
|
@ -782,7 +827,7 @@ fn reinstall_no_binary() {
|
||||||
"###
|
"###
|
||||||
);
|
);
|
||||||
|
|
||||||
context.assert_command("import flask").success();
|
context.assert_command("import jinja2").success();
|
||||||
|
|
||||||
// With `--reinstall`, `--no-binary` should have an affect
|
// With `--reinstall`, `--no-binary` should have an affect
|
||||||
let filters = if cfg!(windows) {
|
let filters = if cfg!(windows) {
|
||||||
|
|
@ -797,10 +842,11 @@ fn reinstall_no_binary() {
|
||||||
};
|
};
|
||||||
let mut command = crate::command(&context);
|
let mut command = crate::command(&context);
|
||||||
command
|
command
|
||||||
.arg("Flask")
|
.arg("jinja2")
|
||||||
.arg("--no-binary")
|
.arg("--no-binary")
|
||||||
|
.arg(":all:")
|
||||||
.arg("--reinstall-package")
|
.arg("--reinstall-package")
|
||||||
.arg("Flask")
|
.arg("jinja2")
|
||||||
.arg("--strict");
|
.arg("--strict");
|
||||||
if cfg!(all(windows, debug_assertions)) {
|
if cfg!(all(windows, debug_assertions)) {
|
||||||
// TODO(konstin): Reduce stack usage in debug mode enough that the tests pass with the
|
// TODO(konstin): Reduce stack usage in debug mode enough that the tests pass with the
|
||||||
|
|
@ -813,14 +859,14 @@ fn reinstall_no_binary() {
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
Resolved 7 packages in [TIME]
|
Resolved 2 packages in [TIME]
|
||||||
Installed 1 package in [TIME]
|
Installed 1 package in [TIME]
|
||||||
- flask==3.0.0
|
- jinja2==3.1.2
|
||||||
+ flask==3.0.0
|
+ jinja2==3.1.2
|
||||||
"###
|
"###
|
||||||
);
|
);
|
||||||
|
|
||||||
context.assert_command("import flask").success();
|
context.assert_command("import jinja2").success();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Install a package into a virtual environment, and ensuring that the executable permissions
|
/// Install a package into a virtual environment, and ensuring that the executable permissions
|
||||||
|
|
|
||||||
|
|
@ -821,6 +821,7 @@ fn install_no_binary() -> Result<()> {
|
||||||
command
|
command
|
||||||
.arg("requirements.txt")
|
.arg("requirements.txt")
|
||||||
.arg("--no-binary")
|
.arg("--no-binary")
|
||||||
|
.arg(":all:")
|
||||||
.arg("--strict");
|
.arg("--strict");
|
||||||
if cfg!(all(windows, debug_assertions)) {
|
if cfg!(all(windows, debug_assertions)) {
|
||||||
// TODO(konstin): Reduce stack usage in debug mode enough that the tests pass with the
|
// TODO(konstin): Reduce stack usage in debug mode enough that the tests pass with the
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue