mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 13:25:00 +00:00
Change install
to sync
(with sync semantics) (#24)
For better separate at this stage (and following `pip-tools`), it's now `puffin sync`, and it assumes `--no-deps`.
This commit is contained in:
parent
ff8e24a621
commit
dab70a661a
7 changed files with 70 additions and 39 deletions
|
@ -13,7 +13,7 @@ cargo run -p puffin-cli -- compile requirements.in
|
||||||
To install from a resolved `requirements.txt` file:
|
To install from a resolved `requirements.txt` file:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
cargo run -p puffin-cli -- install requirements.txt
|
cargo run -p puffin-cli -- sync requirements.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
## Benchmarks
|
## Benchmarks
|
||||||
|
|
|
@ -43,7 +43,14 @@ pub(crate) async fn compile(src: &Path, cache: Option<&Path>) -> Result<ExitStat
|
||||||
};
|
};
|
||||||
|
|
||||||
// Resolve the dependencies.
|
// Resolve the dependencies.
|
||||||
let resolution = puffin_resolver::resolve(&requirements, markers, &tags, &client).await?;
|
let resolution = puffin_resolver::resolve(
|
||||||
|
&requirements,
|
||||||
|
markers,
|
||||||
|
&tags,
|
||||||
|
&client,
|
||||||
|
puffin_resolver::Flags::default(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
for (name, package) in resolution.iter() {
|
for (name, package) in resolution.iter() {
|
||||||
#[allow(clippy::print_stdout)]
|
#[allow(clippy::print_stdout)]
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use std::process::ExitCode;
|
use std::process::ExitCode;
|
||||||
|
|
||||||
pub(crate) use compile::compile;
|
pub(crate) use compile::compile;
|
||||||
pub(crate) use install::install;
|
pub(crate) use sync::sync;
|
||||||
|
|
||||||
mod compile;
|
mod compile;
|
||||||
mod install;
|
mod sync;
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub(crate) enum ExitStatus {
|
pub(crate) enum ExitStatus {
|
||||||
|
|
|
@ -11,8 +11,8 @@ use puffin_platform::Platform;
|
||||||
|
|
||||||
use crate::commands::ExitStatus;
|
use crate::commands::ExitStatus;
|
||||||
|
|
||||||
/// Install a set of requirements into the current Python environment.
|
/// Install a set of locked requirements into the current Python environment.
|
||||||
pub(crate) async fn install(src: &Path, cache: Option<&Path>) -> Result<ExitStatus> {
|
pub(crate) async fn sync(src: &Path, cache: Option<&Path>) -> Result<ExitStatus> {
|
||||||
// Read the `requirements.txt` from disk.
|
// Read the `requirements.txt` from disk.
|
||||||
let requirements_txt = std::fs::read_to_string(src)?;
|
let requirements_txt = std::fs::read_to_string(src)?;
|
||||||
|
|
||||||
|
@ -43,12 +43,23 @@ pub(crate) async fn install(src: &Path, cache: Option<&Path>) -> Result<ExitStat
|
||||||
};
|
};
|
||||||
|
|
||||||
// Resolve the dependencies.
|
// Resolve the dependencies.
|
||||||
// TODO(charlie): When installing, assume `--no-deps`.
|
let resolution = puffin_resolver::resolve(
|
||||||
let resolution = puffin_resolver::resolve(&requirements, markers, &tags, &client).await?;
|
&requirements,
|
||||||
|
markers,
|
||||||
|
&tags,
|
||||||
|
&client,
|
||||||
|
puffin_resolver::Flags::NO_DEPS,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
// Install into the current environment.
|
// Install into the current environment.
|
||||||
let wheels = resolution.into_files().collect::<Vec<_>>();
|
let wheels = resolution.into_files().collect::<Vec<_>>();
|
||||||
puffin_installer::install(&wheels, &python, &client).await?;
|
puffin_installer::install(&wheels, &python, &client).await?;
|
||||||
|
|
||||||
|
#[allow(clippy::print_stdout)]
|
||||||
|
{
|
||||||
|
println!("Installed {} wheels", wheels.len());
|
||||||
|
}
|
||||||
|
|
||||||
Ok(ExitStatus::Success)
|
Ok(ExitStatus::Success)
|
||||||
}
|
}
|
|
@ -22,8 +22,8 @@ struct Cli {
|
||||||
enum Commands {
|
enum Commands {
|
||||||
/// Compile a `requirements.in` file to a `requirements.txt` file.
|
/// Compile a `requirements.in` file to a `requirements.txt` file.
|
||||||
Compile(CompileArgs),
|
Compile(CompileArgs),
|
||||||
/// Install dependencies from a `requirements.txt` file.
|
/// Sync dependencies from a `requirements.txt` file.
|
||||||
Install(InstallArgs),
|
Sync(SyncArgs),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Args)]
|
#[derive(Args)]
|
||||||
|
@ -37,7 +37,7 @@ struct CompileArgs {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Args)]
|
#[derive(Args)]
|
||||||
struct InstallArgs {
|
struct SyncArgs {
|
||||||
/// Path to the `requirements.txt` file to install.
|
/// Path to the `requirements.txt` file to install.
|
||||||
src: PathBuf,
|
src: PathBuf,
|
||||||
|
|
||||||
|
@ -59,16 +59,16 @@ async fn main() -> ExitCode {
|
||||||
commands::compile(
|
commands::compile(
|
||||||
&args.src,
|
&args.src,
|
||||||
dirs.as_ref()
|
dirs.as_ref()
|
||||||
.map(directories::ProjectDirs::cache_dir)
|
.map(ProjectDirs::cache_dir)
|
||||||
.filter(|_| !args.no_cache),
|
.filter(|_| !args.no_cache),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
Commands::Install(args) => {
|
Commands::Sync(args) => {
|
||||||
commands::install(
|
commands::sync(
|
||||||
&args.src,
|
&args.src,
|
||||||
dirs.as_ref()
|
dirs.as_ref()
|
||||||
.map(directories::ProjectDirs::cache_dir)
|
.map(ProjectDirs::cache_dir)
|
||||||
.filter(|_| !args.no_cache),
|
.filter(|_| !args.no_cache),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -19,3 +19,4 @@ futures = "0.3.28"
|
||||||
anyhow = "1.0.75"
|
anyhow = "1.0.75"
|
||||||
tracing = "0.1.37"
|
tracing = "0.1.37"
|
||||||
pep508_rs = "0.2.3"
|
pep508_rs = "0.2.3"
|
||||||
|
bitflags = "2.4.0"
|
||||||
|
|
|
@ -2,6 +2,7 @@ use std::collections::{HashMap, HashSet};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use bitflags::bitflags;
|
||||||
use futures::future::Either;
|
use futures::future::Either;
|
||||||
use futures::{StreamExt, TryFutureExt};
|
use futures::{StreamExt, TryFutureExt};
|
||||||
use pep440_rs::Version;
|
use pep440_rs::Version;
|
||||||
|
@ -42,12 +43,21 @@ impl PinnedPackage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
#[derive(Debug, Copy, Clone, Default)]
|
||||||
|
pub struct Flags: u8 {
|
||||||
|
/// Don't install package dependencies.
|
||||||
|
const NO_DEPS = 1 << 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Resolve a set of requirements into a set of pinned versions.
|
/// Resolve a set of requirements into a set of pinned versions.
|
||||||
pub async fn resolve(
|
pub async fn resolve(
|
||||||
requirements: &Requirements,
|
requirements: &Requirements,
|
||||||
markers: &MarkerEnvironment,
|
markers: &MarkerEnvironment,
|
||||||
tags: &Tags,
|
tags: &Tags,
|
||||||
client: &PypiClient,
|
client: &PypiClient,
|
||||||
|
flags: Flags,
|
||||||
) -> Result<Resolution> {
|
) -> Result<Resolution> {
|
||||||
// A channel to fetch package metadata (e.g., given `flask`, fetch all versions) and version
|
// A channel to fetch package metadata (e.g., given `flask`, fetch all versions) and version
|
||||||
// metadata (e.g., given `flask==1.0.0`, fetch the metadata for that version).
|
// metadata (e.g., given `flask==1.0.0`, fetch the metadata for that version).
|
||||||
|
@ -141,31 +151,33 @@ pub async fn resolve(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Enqueue its dependencies.
|
if !flags.intersects(Flags::NO_DEPS) {
|
||||||
for dependency in metadata.requires_dist {
|
// Enqueue its dependencies.
|
||||||
if !dependency.evaluate_markers(
|
for dependency in metadata.requires_dist {
|
||||||
markers,
|
if !dependency.evaluate_markers(
|
||||||
// TODO(charlie): Remove this clone.
|
markers,
|
||||||
requirement.extras.clone().unwrap_or_default(),
|
// TODO(charlie): Remove this clone.
|
||||||
) {
|
requirement.extras.clone().unwrap_or_default(),
|
||||||
debug!("--> ignoring {dependency} due to environment mismatch");
|
) {
|
||||||
continue;
|
debug!("--> ignoring {dependency} due to environment mismatch");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let normalized_name = PackageName::normalize(&dependency.name);
|
||||||
|
|
||||||
|
if resolution.contains_key(&normalized_name) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !in_flight.insert(normalized_name) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("--> adding transitive dependency: {}", dependency);
|
||||||
|
|
||||||
|
package_sink.unbounded_send(Request::Package(dependency))?;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
let normalized_name = PackageName::normalize(&dependency.name);
|
|
||||||
|
|
||||||
if resolution.contains_key(&normalized_name) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if !in_flight.insert(normalized_name) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!("--> adding transitive dependency: {}", dependency);
|
|
||||||
|
|
||||||
package_sink.unbounded_send(Request::Package(dependency))?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue