Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions crates/uv-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,13 @@ pub enum Commands {
Build(BuildArgs),
/// Upload distributions to an index.
Publish(PublishArgs),
/// Manage workspaces.
#[command(
after_help = "Use `uv help workspace` for more details.",
after_long_help = "",
hide = true
)]
Workspace(WorkspaceNamespace),
/// The implementation of the build backend.
///
/// These commands are not directly exposed to the user, instead users invoke their build
Expand Down Expand Up @@ -6835,6 +6842,22 @@ pub struct PublishArgs {
pub dry_run: bool,
}

#[derive(Args)]
pub struct WorkspaceNamespace {
#[command(subcommand)]
pub command: WorkspaceCommand,
}

#[derive(Subcommand)]
pub enum WorkspaceCommand {
/// Display package metadata.
#[command(hide = true)]
Metadata(MetadataArgs),
}

#[derive(Args, Debug)]
pub struct MetadataArgs;

/// See [PEP 517](https://peps.python.org/pep-0517/) and
/// [PEP 660](https://peps.python.org/pep-0660/) for specifications of the parameters.
#[derive(Subcommand)]
Expand Down
4 changes: 3 additions & 1 deletion crates/uv-preview/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ bitflags::bitflags! {
const S3_ENDPOINT = 1 << 10;
const CACHE_SIZE = 1 << 11;
const INIT_PROJECT_FLAG = 1 << 12;
const WORKSPACE_METADATA = 1 << 13;
}
}

Expand All @@ -44,6 +45,7 @@ impl PreviewFeatures {
Self::S3_ENDPOINT => "s3-endpoint",
Self::CACHE_SIZE => "cache-size",
Self::INIT_PROJECT_FLAG => "init-project-flag",
Self::WORKSPACE_METADATA => "workspace-metadata",
_ => panic!("`flag_as_str` can only be used for exactly one feature flag"),
}
}
Expand Down Expand Up @@ -94,12 +96,12 @@ impl FromStr for PreviewFeatures {
"s3-endpoint" => Self::S3_ENDPOINT,
"cache-size" => Self::CACHE_SIZE,
"init-project-flag" => Self::INIT_PROJECT_FLAG,
"workspace-metadata" => Self::WORKSPACE_METADATA,
_ => {
warn_user_once!("Unknown preview feature: `{part}`");
continue;
}
};

flags |= flag;
}

Expand Down
2 changes: 2 additions & 0 deletions crates/uv/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ use uv_normalize::PackageName;
use uv_python::PythonEnvironment;
use uv_scripts::Pep723Script;
pub(crate) use venv::venv;
pub(crate) use workspace::metadata::metadata;

use crate::printer::Printer;

Expand All @@ -88,6 +89,7 @@ pub(crate) mod reporters;
mod self_update;
mod tool;
mod venv;
mod workspace;

#[derive(Copy, Clone)]
pub(crate) enum ExitStatus {
Expand Down
91 changes: 91 additions & 0 deletions crates/uv/src/commands/workspace/metadata.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use std::fmt::Write;
use std::path::Path;

use anyhow::Result;
use serde::Serialize;

use uv_fs::PortablePathBuf;
use uv_normalize::PackageName;
use uv_preview::{Preview, PreviewFeatures};
use uv_warnings::warn_user;
use uv_workspace::{DiscoveryOptions, Workspace, WorkspaceCache};

use crate::commands::ExitStatus;
use crate::printer::Printer;

/// The schema version for the metadata report.
#[derive(Serialize, Debug, Default)]
#[serde(rename_all = "snake_case")]
enum SchemaVersion {
/// An unstable, experimental schema.
#[default]
Preview,
}

/// The schema metadata for the metadata report.
#[derive(Serialize, Debug, Default)]
struct SchemaReport {
/// The version of the schema.
version: SchemaVersion,
}

/// Report for a single workspace member.
#[derive(Serialize, Debug)]
struct WorkspaceMemberReport {
/// The name of the workspace member.
name: PackageName,
/// The path to the workspace member's root directory.
path: PortablePathBuf,
}

/// The report for a metadata operation.
#[derive(Serialize, Debug)]
struct MetadataReport {
/// The schema of this report.
schema: SchemaReport,
/// The workspace root directory.
workspace_root: PortablePathBuf,
/// The workspace members.
members: Vec<WorkspaceMemberReport>,
}

/// Display metadata about the workspace.
pub(crate) async fn metadata(
project_dir: &Path,
preview: Preview,
printer: Printer,
) -> Result<ExitStatus> {
if preview.is_enabled(PreviewFeatures::WORKSPACE_METADATA) {
warn_user!(
"The `uv workspace metadata` command is experimental and may change without warning. Pass `--preview-features {}` to disable this warning.",
PreviewFeatures::WORKSPACE_METADATA
);
}

let workspace_cache = WorkspaceCache::default();
let workspace =
Workspace::discover(project_dir, &DiscoveryOptions::default(), &workspace_cache).await?;

let members = workspace
.packages()
.values()
.map(|package| WorkspaceMemberReport {
name: package.project().name.clone(),
path: PortablePathBuf::from(package.root().as_path()),
})
.collect();

let report = MetadataReport {
schema: SchemaReport::default(),
workspace_root: PortablePathBuf::from(workspace.install_path().as_path()),
members,
};

writeln!(
printer.stdout(),
"{}",
serde_json::to_string_pretty(&report)?
)?;

Ok(ExitStatus::Success)
}
1 change: 1 addition & 0 deletions crates/uv/src/commands/workspace/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub(crate) mod metadata;
8 changes: 7 additions & 1 deletion crates/uv/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ use uv_cli::SelfUpdateArgs;
use uv_cli::{
AuthCommand, AuthNamespace, BuildBackendCommand, CacheCommand, CacheNamespace, Cli, Commands,
PipCommand, PipNamespace, ProjectCommand, PythonCommand, PythonNamespace, SelfCommand,
SelfNamespace, ToolCommand, ToolNamespace, TopLevelArgs, compat::CompatArgs,
SelfNamespace, ToolCommand, ToolNamespace, TopLevelArgs, WorkspaceCommand, WorkspaceNamespace,
compat::CompatArgs,
};
use uv_client::BaseClientBuilder;
use uv_configuration::min_stack_size;
Expand Down Expand Up @@ -1733,6 +1734,11 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
)
.await
}
Commands::Workspace(WorkspaceNamespace { command }) => match command {
WorkspaceCommand::Metadata(_args) => {
commands::metadata(&project_dir, globals.preview, printer).await
}
},
Commands::BuildBackend { command } => spawn_blocking(move || match command {
BuildBackendCommand::BuildSdist { sdist_directory } => {
commands::build_backend::build_sdist(&sdist_directory)
Expand Down
8 changes: 8 additions & 0 deletions crates/uv/tests/it/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1064,6 +1064,14 @@ impl TestContext {
command
}

/// Create a `uv workspace metadata` command with options shared across scenarios.
pub fn workspace_metadata(&self) -> Command {
let mut command = Self::new_command();
command.arg("workspace").arg("metadata");
self.add_shared_options(&mut command, false);
command
}

/// Create a `uv export` command with options shared across scenarios.
pub fn export(&self) -> Command {
let mut command = Self::new_command();
Expand Down
1 change: 1 addition & 0 deletions crates/uv/tests/it/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,4 @@ mod workflow;

mod extract;
mod workspace;
mod workspace_metadata;
4 changes: 2 additions & 2 deletions crates/uv/tests/it/show_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7831,7 +7831,7 @@ fn preview_features() {
show_settings: true,
preview: Preview {
flags: PreviewFeatures(
PYTHON_INSTALL_DEFAULT | PYTHON_UPGRADE | JSON_OUTPUT | PYLOCK | ADD_BOUNDS | PACKAGE_CONFLICTS | EXTRA_BUILD_DEPENDENCIES | DETECT_MODULE_CONFLICTS | FORMAT | NATIVE_AUTH | S3_ENDPOINT | CACHE_SIZE | INIT_PROJECT_FLAG,
PYTHON_INSTALL_DEFAULT | PYTHON_UPGRADE | JSON_OUTPUT | PYLOCK | ADD_BOUNDS | PACKAGE_CONFLICTS | EXTRA_BUILD_DEPENDENCIES | DETECT_MODULE_CONFLICTS | FORMAT | NATIVE_AUTH | S3_ENDPOINT | CACHE_SIZE | INIT_PROJECT_FLAG | WORKSPACE_METADATA,
),
},
python_preference: Managed,
Expand Down Expand Up @@ -8059,7 +8059,7 @@ fn preview_features() {
show_settings: true,
preview: Preview {
flags: PreviewFeatures(
PYTHON_INSTALL_DEFAULT | PYTHON_UPGRADE | JSON_OUTPUT | PYLOCK | ADD_BOUNDS | PACKAGE_CONFLICTS | EXTRA_BUILD_DEPENDENCIES | DETECT_MODULE_CONFLICTS | FORMAT | NATIVE_AUTH | S3_ENDPOINT | CACHE_SIZE | INIT_PROJECT_FLAG,
PYTHON_INSTALL_DEFAULT | PYTHON_UPGRADE | JSON_OUTPUT | PYLOCK | ADD_BOUNDS | PACKAGE_CONFLICTS | EXTRA_BUILD_DEPENDENCIES | DETECT_MODULE_CONFLICTS | FORMAT | NATIVE_AUTH | S3_ENDPOINT | CACHE_SIZE | INIT_PROJECT_FLAG | WORKSPACE_METADATA,
),
},
python_preference: Managed,
Expand Down
Loading
Loading