Skip to content

Commit

Permalink
Implement uv build (#6895)
Browse files Browse the repository at this point in the history
## Summary

This PR exposes uv's PEP 517 implementation via a `uv build` frontend,
such that you can use `uv build` to build source and binary
distributions (i.e., wheels and sdists) from a given directory.

There are some TODOs that I'll tackle in separate PRs:

- [x] Support building a wheel from a source distribution (rather than
from source) (#6898)
- [x] Stream the build output (#6912)

Closes #1510

Closes #1663.
  • Loading branch information
charliermarsh authored Sep 4, 2024
1 parent a3a1bfd commit df84d25
Show file tree
Hide file tree
Showing 16 changed files with 1,028 additions and 168 deletions.
10 changes: 2 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/uv-build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ static DEFAULT_BACKEND: LazyLock<Pep517Backend> = LazyLock::new(|| Pep517Backend
pub enum Error {
#[error(transparent)]
Io(#[from] io::Error),
#[error("{} does not appear to be a Python project, as neither `pyproject.toml` nor `setup.py` is present in the directory", _0.simplified_display())]
#[error("{} does not appear to be a Python project, as neither `pyproject.toml` nor `setup.py` are present in the directory", _0.simplified_display())]
InvalidSourceDist(PathBuf),
#[error("Invalid `pyproject.toml`")]
InvalidPyprojectToml(#[from] toml::de::Error),
Expand Down
92 changes: 78 additions & 14 deletions crates/uv-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,21 @@ pub enum Commands {
after_long_help = ""
)]
Venv(VenvArgs),
/// Build Python packages into source distributions and wheels.
///
/// By default, `uv build` will build a source distribution ("sdist")
/// from the source directory, and a binary distribution ("wheel") from
/// the source distribution.
///
/// `uv build --sdist` can be used to build only the source distribution,
/// `uv build --wheel` can be used to build only the binary distribution,
/// and `uv build --sdist --wheel` can be used to build both distributions
/// from source.
#[command(
after_help = "Use `uv help build` for more details.",
after_long_help = ""
)]
Build(BuildArgs),
/// Manage uv's cache.
#[command(
after_help = "Use `uv help cache` for more details.",
Expand Down Expand Up @@ -1126,7 +1141,7 @@ pub struct PipSyncArgs {

/// The Python interpreter into which packages should be installed.
///
/// By default, syncing requires a virtual environment. An path to an
/// By default, syncing requires a virtual environment. A path to an
/// alternative Python can be provided, but it is only recommended in
/// continuous integration (CI) environments and should be used with
/// caution, as it can modify the system Python installation.
Expand Down Expand Up @@ -1408,7 +1423,7 @@ pub struct PipInstallArgs {

/// The Python interpreter into which packages should be installed.
///
/// By default, installation requires a virtual environment. An path to an
/// By default, installation requires a virtual environment. A path to an
/// alternative Python can be provided, but it is only recommended in
/// continuous integration (CI) environments and should be used with
/// caution, as it can modify the system Python installation.
Expand Down Expand Up @@ -1573,7 +1588,7 @@ pub struct PipUninstallArgs {

/// The Python interpreter from which packages should be uninstalled.
///
/// By default, uninstallation requires a virtual environment. An path to an
/// By default, uninstallation requires a virtual environment. A path to an
/// alternative Python can be provided, but it is only recommended in
/// continuous integration (CI) environments and should be used with
/// caution, as it can modify the system Python installation.
Expand Down Expand Up @@ -1924,6 +1939,55 @@ pub struct PipTreeArgs {
pub compat_args: compat::PipGlobalCompatArgs,
}

#[derive(Args)]
#[allow(clippy::struct_excessive_bools)]
pub struct BuildArgs {
/// The directory from which distributions should be built.
///
/// Defaults to the current working directory.
#[arg(value_parser = parse_file_path)]
pub src_dir: Option<PathBuf>,

/// The output directory to which distributions should be written.
///
/// Defaults to the `dist` subdirectory within the source directory.
#[arg(long, short, value_parser = parse_file_path)]
pub out_dir: Option<PathBuf>,

/// Build a source distribution ("sdist") from the given directory.
#[arg(long)]
pub sdist: bool,

/// Build a binary distribution ("wheel") from the given directory.
#[arg(long)]
pub wheel: bool,

/// The Python interpreter to use for the build environment.
///
/// By default, builds are executed in isolated virtual environments. The
/// discovered interpreter will be used to create those environments, and
/// will be symlinked or copied in depending on the platform.
///
/// See `uv help python` to view supported request formats.
#[arg(
long,
short,
env = "UV_PYTHON",
verbatim_doc_comment,
help_heading = "Python options"
)]
pub python: Option<String>,

#[command(flatten)]
pub resolver: ResolverArgs,

#[command(flatten)]
pub build: BuildOptionsArgs,

#[command(flatten)]
pub refresh: RefreshArgs,
}

#[derive(Args)]
#[allow(clippy::struct_excessive_bools)]
pub struct VenvArgs {
Expand Down Expand Up @@ -2318,7 +2382,7 @@ pub struct RunArgs {
pub installer: ResolverInstallerArgs,

#[command(flatten)]
pub build: BuildArgs,
pub build: BuildOptionsArgs,

#[command(flatten)]
pub refresh: RefreshArgs,
Expand Down Expand Up @@ -2452,7 +2516,7 @@ pub struct SyncArgs {
pub installer: ResolverInstallerArgs,

#[command(flatten)]
pub build: BuildArgs,
pub build: BuildOptionsArgs,

#[command(flatten)]
pub refresh: RefreshArgs,
Expand Down Expand Up @@ -2505,7 +2569,7 @@ pub struct LockArgs {
pub resolver: ResolverArgs,

#[command(flatten)]
pub build: BuildArgs,
pub build: BuildOptionsArgs,

#[command(flatten)]
pub refresh: RefreshArgs,
Expand Down Expand Up @@ -2619,7 +2683,7 @@ pub struct AddArgs {
pub installer: ResolverInstallerArgs,

#[command(flatten)]
pub build: BuildArgs,
pub build: BuildOptionsArgs,

#[command(flatten)]
pub refresh: RefreshArgs,
Expand Down Expand Up @@ -2688,7 +2752,7 @@ pub struct RemoveArgs {
pub installer: ResolverInstallerArgs,

#[command(flatten)]
pub build: BuildArgs,
pub build: BuildOptionsArgs,

#[command(flatten)]
pub refresh: RefreshArgs,
Expand Down Expand Up @@ -2748,7 +2812,7 @@ pub struct TreeArgs {
pub frozen: bool,

#[command(flatten)]
pub build: BuildArgs,
pub build: BuildOptionsArgs,

#[command(flatten)]
pub resolver: ResolverArgs,
Expand Down Expand Up @@ -2853,7 +2917,7 @@ pub struct ExportArgs {
pub resolver: ResolverArgs,

#[command(flatten)]
pub build: BuildArgs,
pub build: BuildOptionsArgs,

#[command(flatten)]
pub refresh: RefreshArgs,
Expand Down Expand Up @@ -3000,7 +3064,7 @@ pub struct ToolRunArgs {
pub installer: ResolverInstallerArgs,

#[command(flatten)]
pub build: BuildArgs,
pub build: BuildOptionsArgs,

#[command(flatten)]
pub refresh: RefreshArgs,
Expand Down Expand Up @@ -3052,7 +3116,7 @@ pub struct ToolInstallArgs {
pub installer: ResolverInstallerArgs,

#[command(flatten)]
pub build: BuildArgs,
pub build: BuildOptionsArgs,

#[command(flatten)]
pub refresh: RefreshArgs,
Expand Down Expand Up @@ -3137,7 +3201,7 @@ pub struct ToolUpgradeArgs {
pub installer: ResolverInstallerArgs,

#[command(flatten)]
pub build: BuildArgs,
pub build: BuildOptionsArgs,
}

#[derive(Args)]
Expand Down Expand Up @@ -3441,7 +3505,7 @@ pub struct RefreshArgs {

#[derive(Args)]
#[allow(clippy::struct_excessive_bools)]
pub struct BuildArgs {
pub struct BuildOptionsArgs {
/// Don't build source distributions.
///
/// When enabled, resolving will not run arbitrary Python code. The cached wheels of
Expand Down
18 changes: 11 additions & 7 deletions crates/uv-cli/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ use uv_resolver::PrereleaseMode;
use uv_settings::{PipOptions, ResolverInstallerOptions, ResolverOptions};

use crate::{
BuildArgs, IndexArgs, InstallerArgs, Maybe, RefreshArgs, ResolverArgs, ResolverInstallerArgs,
BuildOptionsArgs, IndexArgs, InstallerArgs, Maybe, RefreshArgs, ResolverArgs,
ResolverInstallerArgs,
};

/// Given a boolean flag pair (like `--upgrade` and `--no-upgrade`), resolve the value of the flag.
Expand Down Expand Up @@ -206,8 +207,11 @@ impl From<IndexArgs> for PipOptions {
}
}

/// Construct the [`ResolverOptions`] from the [`ResolverArgs`] and [`BuildArgs`].
pub fn resolver_options(resolver_args: ResolverArgs, build_args: BuildArgs) -> ResolverOptions {
/// Construct the [`ResolverOptions`] from the [`ResolverArgs`] and [`BuildOptionsArgs`].
pub fn resolver_options(
resolver_args: ResolverArgs,
build_args: BuildOptionsArgs,
) -> ResolverOptions {
let ResolverArgs {
index_args,
upgrade,
Expand All @@ -228,7 +232,7 @@ pub fn resolver_options(resolver_args: ResolverArgs, build_args: BuildArgs) -> R
no_sources,
} = resolver_args;

let BuildArgs {
let BuildOptionsArgs {
no_build,
build,
no_build_package,
Expand Down Expand Up @@ -281,10 +285,10 @@ pub fn resolver_options(resolver_args: ResolverArgs, build_args: BuildArgs) -> R
}
}

/// Construct the [`ResolverInstallerOptions`] from the [`ResolverInstallerArgs`] and [`BuildArgs`].
/// Construct the [`ResolverInstallerOptions`] from the [`ResolverInstallerArgs`] and [`BuildOptionsArgs`].
pub fn resolver_installer_options(
resolver_installer_args: ResolverInstallerArgs,
build_args: BuildArgs,
build_args: BuildOptionsArgs,
) -> ResolverInstallerOptions {
let ResolverInstallerArgs {
index_args,
Expand All @@ -311,7 +315,7 @@ pub fn resolver_installer_options(
no_sources,
} = resolver_installer_args;

let BuildArgs {
let BuildOptionsArgs {
no_build,
build,
no_build_package,
Expand Down
10 changes: 1 addition & 9 deletions crates/uv-dev/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,16 @@ workspace = true
[dependencies]
distribution-filename = { workspace = true }
distribution-types = { workspace = true }
install-wheel-rs = { workspace = true }
pep508_rs = { workspace = true }
pypi-types = { workspace = true }
uv-build = { workspace = true }
uv-cache = { workspace = true, features = ["clap"] }
uv-cli = { workspace = true }
uv-client = { workspace = true }
uv-configuration = { workspace = true }
uv-dispatch = { workspace = true }
uv-git = { workspace = true }
uv-installer = { workspace = true }
uv-macros = { workspace = true }
uv-options-metadata = { workspace = true }
uv-python = { workspace = true }
uv-resolver = { workspace = true }
uv-settings = { workspace = true, features = ["schemars"] }
uv-types = { workspace = true }
uv-workspace = { workspace = true, features = ["schemars"] }

# Any dependencies that are exclusively used in `uv-dev` should be listed as non-workspace
Expand All @@ -44,12 +37,11 @@ anyhow = { workspace = true }
clap = { workspace = true, features = ["derive", "wrap_help"] }
fs-err = { workspace = true, features = ["tokio"] }
itertools = { workspace = true }
markdown = "0.3.0"
markdown = { version = "0.3.0" }
owo-colors = { workspace = true }
poloto = { version = "19.1.2", optional = true }
pretty_assertions = { version = "1.4.0" }
resvg = { version = "0.29.0", optional = true }
rustc-hash = { workspace = true }
schemars = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
Expand Down
Loading

0 comments on commit df84d25

Please sign in to comment.