Skip to content

Commit

Permalink
Move to submodule
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed May 8, 2024
1 parent e7b807c commit f8e9aa7
Show file tree
Hide file tree
Showing 13 changed files with 442 additions and 200 deletions.
3 changes: 2 additions & 1 deletion crates/uv-types/src/builds.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use uv_interpreter::PythonEnvironment;

/// Whether to enforce build isolation when building source distributions.
#[derive(Debug, Copy, Clone)]
#[derive(Debug, Default, Copy, Clone)]
pub enum BuildIsolation<'a> {
#[default]
Isolated,
Shared(&'a PythonEnvironment),
}
Expand Down
3 changes: 2 additions & 1 deletion crates/uv-types/src/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ use pep508_rs::MarkerEnvironment;
use pypi_types::{HashDigest, HashError};
use uv_normalize::PackageName;

#[derive(Debug, Clone)]
#[derive(Debug, Default, Clone)]
pub enum HashStrategy {
/// No hash policy is specified.
#[default]
None,
/// Hashes should be generated (specifically, a SHA-256 hash), but not validated.
Generate,
Expand Down
27 changes: 27 additions & 0 deletions crates/uv/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ pub(crate) enum Commands {
/// Sync the project's dependencies with the environment.
#[clap(hide = true)]
Sync(SyncArgs),
/// Resolve the project requirements into a lockfile.
#[clap(hide = true)]
Lock(LockArgs),
/// Display uv's version
Version {
#[arg(long, value_enum, default_value = "text")]
Expand Down Expand Up @@ -1880,6 +1883,30 @@ pub(crate) struct SyncArgs {
pub(crate) python: Option<String>,
}

#[derive(Args)]
#[allow(clippy::struct_excessive_bools)]
pub(crate) struct LockArgs {
/// The Python interpreter to use to build the run environment.
///
/// By default, `uv` uses the virtual environment in the current working directory or any parent
/// directory, falling back to searching for a Python executable in `PATH`. The `--python`
/// option allows you to specify a different interpreter.
///
/// Supported formats:
/// - `3.10` looks for an installed Python 3.10 using `py --list-paths` on Windows, or
/// `python3.10` on Linux and macOS.
/// - `python3.10` or `python.exe` looks for a binary with the given name in `PATH`.
/// - `/home/ferris/.local/bin/python3.10` uses the exact Python at the given path.
#[arg(
long,
short,
env = "UV_PYTHON",
verbatim_doc_comment,
group = "discovery"
)]
pub(crate) python: Option<String>,
}

#[derive(Args)]
#[allow(clippy::struct_excessive_bools)]
struct AddArgs {
Expand Down
9 changes: 4 additions & 5 deletions crates/uv/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,18 @@ pub(crate) use pip_list::pip_list;
pub(crate) use pip_show::pip_show;
pub(crate) use pip_sync::pip_sync;
pub(crate) use pip_uninstall::pip_uninstall;
pub(crate) use run::run;
#[cfg(feature = "self-update")]
pub(crate) use self_update::self_update;
pub(crate) use sync::sync;
use uv_cache::Cache;
use uv_fs::Simplified;
use uv_installer::compile_tree;
use uv_interpreter::PythonEnvironment;
use uv_normalize::PackageName;
pub(crate) use venv::venv;
pub(crate) use version::version;
pub(crate) use workspace::lock::lock;
pub(crate) use workspace::run::run;
pub(crate) use workspace::sync::sync;

use crate::printer::Printer;

Expand All @@ -41,14 +42,12 @@ mod pip_list;
mod pip_show;
mod pip_sync;
mod pip_uninstall;
mod project;
mod reporters;
mod run;
#[cfg(feature = "self-update")]
mod self_update;
mod sync;
mod venv;
mod version;
mod workspace;

#[derive(Copy, Clone)]
pub(crate) enum ExitStatus {
Expand Down
41 changes: 0 additions & 41 deletions crates/uv/src/commands/sync.rs

This file was deleted.

139 changes: 139 additions & 0 deletions crates/uv/src/commands/workspace/lock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
use anstream::eprint;
use anyhow::Result;

use distribution_types::IndexLocations;
use install_wheel_rs::linker::LinkMode;
use uv_cache::Cache;
use uv_client::{BaseClientBuilder, RegistryClientBuilder};
use uv_configuration::{ConfigSettings, NoBinary, NoBuild, PreviewMode, SetupPyStrategy};
use uv_dispatch::BuildDispatch;
use uv_interpreter::PythonEnvironment;
use uv_requirements::{ExtrasSpecification, RequirementsSpecification};
use uv_resolver::{FlatIndex, InMemoryIndex, OptionsBuilder};
use uv_types::{BuildIsolation, HashStrategy, InFlight};
use uv_warnings::warn_user;

use crate::commands::workspace::Error;
use crate::commands::{workspace, ExitStatus};
use crate::printer::Printer;

/// Resolve the project requirements into a lockfile.
#[allow(clippy::too_many_arguments)]
pub(crate) async fn lock(
preview: PreviewMode,
cache: &Cache,
printer: Printer,
) -> Result<ExitStatus> {
if preview.is_disabled() {
warn_user!("`uv lock` is experimental and may change without warning.");
}

// TODO(charlie): If the environment doesn't exist, create it.
let venv = PythonEnvironment::from_virtualenv(cache)?;

// Find the workspace requirements.
let Some(requirements) = workspace::find_workspace()? else {
return Err(anyhow::anyhow!(
"Unable to find `pyproject.toml` for project workspace."
));
};

// TODO(zanieb): Support client configuration
let client_builder = BaseClientBuilder::default();

// Read all requirements from the provided sources.
// TODO(zanieb): Consider allowing constraints and extras
// TODO(zanieb): Allow specifying extras somehow
let spec = RequirementsSpecification::from_sources(
&requirements,
&[],
&[],
&ExtrasSpecification::None,
&client_builder,
preview,
)
.await?;

// Determine the tags, markers, and interpreter to use for resolution.
let interpreter = venv.interpreter().clone();
let tags = venv.interpreter().tags()?;
let markers = venv.interpreter().markers();

// Initialize the registry client.
// TODO(zanieb): Support client options e.g. offline, tls, etc.
let client = RegistryClientBuilder::new(cache.clone())
.markers(markers)
.platform(venv.interpreter().platform())
.build();

// TODO(charlie): Respect project configuration.
let build_isolation = BuildIsolation::default();
let config_settings = ConfigSettings::default();
let flat_index = FlatIndex::default();
let hasher = HashStrategy::default();
let in_flight = InFlight::default();
let index = InMemoryIndex::default();
let index_locations = IndexLocations::default();
let link_mode = LinkMode::default();
let no_binary = NoBinary::default();
let no_build = NoBuild::default();
let setup_py = SetupPyStrategy::default();

// Create a build dispatch.
let build_dispatch = BuildDispatch::new(
&client,
cache,
&interpreter,
&index_locations,
&flat_index,
&index,
&in_flight,
setup_py,
&config_settings,
build_isolation,
link_mode,
&no_build,
&no_binary,
);

let options = OptionsBuilder::new()
// TODO(zanieb): Support resolver options
// .resolution_mode(resolution_mode)
// .prerelease_mode(prerelease_mode)
// .dependency_mode(dependency_mode)
// .exclude_newer(exclude_newer)
.build();

// Resolve the requirements.
let resolution = workspace::resolve(
spec,
&hasher,
&interpreter,
tags,
markers,
&client,
&flat_index,
&index,
&build_dispatch,
options,
printer,
)
.await;

let resolution = match resolution {
Err(Error::Resolve(uv_resolver::ResolveError::NoSolution(err))) => {
let report = miette::Report::msg(format!("{err}"))
.context("No solution found when resolving dependencies:");
eprint!("{report:?}");
return Ok(ExitStatus::Failure);
}
result => result,
}?;

// Write the lockfile to disk.
let lock = resolution.lock()?;
let encoded = toml::to_string_pretty(&lock)?;
fs_err::tokio::write("uv.lock", encoded.as_bytes()).await?;

Ok(ExitStatus::Success)
}
Loading

0 comments on commit f8e9aa7

Please sign in to comment.