Skip to content

Commit

Permalink
Add --only-dev
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Sep 16, 2024
1 parent 23494d8 commit b889159
Show file tree
Hide file tree
Showing 14 changed files with 288 additions and 77 deletions.
18 changes: 18 additions & 0 deletions crates/uv-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2395,6 +2395,12 @@ pub struct RunArgs {
#[arg(long, overrides_with("dev"))]
pub no_dev: bool,

/// Omit non-development dependencies.
///
/// The project itself will also be omitted.
#[arg(long, conflicts_with("no_dev"))]
pub only_dev: bool,

/// The command to run.
///
/// If the path to a Python script (i.e., ending in `.py`), it will be
Expand Down Expand Up @@ -2541,6 +2547,12 @@ pub struct SyncArgs {
#[arg(long, overrides_with("dev"))]
pub no_dev: bool,

/// Omit non-development dependencies.
///
/// The project itself will also be omitted.
#[arg(long, conflicts_with("no_dev"))]
pub only_dev: bool,

/// Do not remove extraneous packages present in the environment.
///
/// When enabled, uv will make the minimum necessary changes to satisfy the requirements.
Expand Down Expand Up @@ -2977,6 +2989,12 @@ pub struct ExportArgs {
#[arg(long, overrides_with("dev"))]
pub no_dev: bool,

/// Omit non-development dependencies.
///
/// The project itself will also be omitted.
#[arg(long, conflicts_with("no_dev"))]
pub only_dev: bool,

/// Include hashes for all dependencies.
#[arg(long, overrides_with("no_hashes"), hide = true)]
pub hashes: bool,
Expand Down
53 changes: 53 additions & 0 deletions crates/uv-configuration/src/dev.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use either::Either;
use uv_normalize::GroupName;

#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum DevMode {
/// Include development dependencies.
#[default]
Include,
/// Exclude development dependencies.
Exclude,
/// Only include development dependencies, excluding all other dependencies.
Only,
}

impl DevMode {
/// Determine the [`DevMode`] policy from the command-line arguments.
pub fn from_args(dev: bool, no_dev: bool, only_dev: bool) -> Self {
if only_dev {
Self::Only
} else if no_dev {
Self::Exclude
} else if dev {
Self::Include
} else {
Self::default()
}
}
}

#[derive(Debug, Copy, Clone)]
pub enum DevSpecification<'group> {
/// Include dev dependencies from the specified group.
Include(&'group [GroupName]),
/// Do not include dev dependencies.
Exclude,
/// Include dev dependencies from the specified group, and exclude all non-dev dependencies.
Only(&'group [GroupName]),
}

impl<'group> DevSpecification<'group> {
/// Returns an [`Iterator`] over the group names to include.
pub fn iter(&self) -> impl Iterator<Item = &GroupName> {
match self {
Self::Exclude => Either::Left(std::iter::empty()),
Self::Include(groups) | Self::Only(groups) => Either::Right(groups.iter()),
}
}

/// Returns `true` if the specification allows for production dependencies.
pub fn prod(&self) -> bool {
matches!(self, Self::Exclude | Self::Include(_))
}
}
2 changes: 2 additions & 0 deletions crates/uv-configuration/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pub use build_options::*;
pub use concurrency::*;
pub use config_settings::*;
pub use constraints::*;
pub use dev::*;
pub use export_format::*;
pub use extras::*;
pub use hash::*;
Expand All @@ -20,6 +21,7 @@ mod build_options;
mod concurrency;
mod config_settings;
mod constraints;
mod dev;
mod export_format;
mod extras;
mod hash;
Expand Down
34 changes: 18 additions & 16 deletions crates/uv-resolver/src/lock/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use pypi_types::{
redact_git_credentials, HashDigest, ParsedArchiveUrl, ParsedGitUrl, Requirement,
RequirementSource, ResolverMarkerEnvironment,
};
use uv_configuration::{BuildOptions, ExtrasSpecification, InstallOptions};
use uv_configuration::{BuildOptions, DevSpecification, ExtrasSpecification, InstallOptions};
use uv_distribution::DistributionDatabase;
use uv_fs::{relative_to, PortablePath, PortablePathBuf};
use uv_git::{GitReference, GitSha, RepositoryReference, ResolvedRepositoryReference};
Expand Down Expand Up @@ -540,7 +540,7 @@ impl Lock {
marker_env: &ResolverMarkerEnvironment,
tags: &Tags,
extras: &ExtrasSpecification,
dev: &[GroupName],
dev: DevSpecification<'_>,
build_options: &BuildOptions,
install_options: &InstallOptions,
) -> Result<Resolution, LockError> {
Expand All @@ -558,26 +558,28 @@ impl Lock {
name: root_name.clone(),
})?;

// Add the base package.
queue.push_back((root, None));
if dev.prod() {
// Add the base package.
queue.push_back((root, None));

// Add any extras.
match extras {
ExtrasSpecification::None => {}
ExtrasSpecification::All => {
for extra in root.optional_dependencies.keys() {
queue.push_back((root, Some(extra)));
// Add any extras.
match extras {
ExtrasSpecification::None => {}
ExtrasSpecification::All => {
for extra in root.optional_dependencies.keys() {
queue.push_back((root, Some(extra)));
}
}
}
ExtrasSpecification::Some(extras) => {
for extra in extras {
queue.push_back((root, Some(extra)));
ExtrasSpecification::Some(extras) => {
for extra in extras {
queue.push_back((root, Some(extra)));
}
}
}
}

// Add any dev dependencies.
for group in dev {
for group in dev.iter() {
for dep in root.dev_dependencies.get(group).into_iter().flatten() {
if dep.complexified_marker.evaluate(marker_env, &[]) {
let dep_dist = self.find_by_id(&dep.package_id);
Expand All @@ -596,7 +598,7 @@ impl Lock {

// Add any dependency groups that are exclusive to the workspace root (e.g., dev
// dependencies in (legacy) non-project workspace roots).
for group in dev {
for group in dev.iter() {
for dependency in project.group(group) {
if dependency.marker.evaluate(marker_env, &[]) {
let root_name = &dependency.name;
Expand Down
70 changes: 44 additions & 26 deletions crates/uv-resolver/src/lock/requirements_txt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ use std::path::{Component, Path, PathBuf};
use either::Either;
use petgraph::visit::IntoNodeReferences;
use petgraph::{Directed, Graph};
use rustc_hash::{FxHashMap, FxHashSet};
use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
use url::Url;

use distribution_filename::{DistExtension, SourceDistExtension};
use pep508_rs::MarkerTree;
use pypi_types::{ParsedArchiveUrl, ParsedGitUrl};
use uv_configuration::{ExtrasSpecification, InstallOptions};
use uv_configuration::{DevSpecification, ExtrasSpecification, InstallOptions};
use uv_fs::Simplified;
use uv_git::GitReference;
use uv_normalize::{ExtraName, GroupName, PackageName};
use uv_normalize::{ExtraName, PackageName};

use crate::graph_ops::marker_reachability;
use crate::lock::{Package, PackageId, Source};
Expand All @@ -42,46 +42,68 @@ impl<'lock> RequirementsTxtExport<'lock> {
lock: &'lock Lock,
root_name: &PackageName,
extras: &ExtrasSpecification,
dev: &[GroupName],
dev: DevSpecification<'_>,
hashes: bool,
install_options: &'lock InstallOptions,
) -> Result<Self, LockError> {
let size_guess = lock.packages.len();
let mut petgraph = LockGraph::with_capacity(size_guess, size_guess);
let mut inverse = FxHashMap::with_capacity_and_hasher(size_guess, FxBuildHasher);

let mut queue: VecDeque<(&Package, Option<&ExtraName>)> = VecDeque::new();
let mut inverse = FxHashMap::default();
let mut seen = FxHashSet::default();

// Add the workspace package to the queue.
let root = lock
.find_by_name(root_name)
.expect("found too many packages matching root")
.expect("could not find root");

// Add the base package.
queue.push_back((root, None));
if dev.prod() {
// Add the base package.
queue.push_back((root, None));

// Add any extras.
match extras {
ExtrasSpecification::None => {}
ExtrasSpecification::All => {
for extra in root.optional_dependencies.keys() {
queue.push_back((root, Some(extra)));
// Add any extras.
match extras {
ExtrasSpecification::None => {}
ExtrasSpecification::All => {
for extra in root.optional_dependencies.keys() {
queue.push_back((root, Some(extra)));
}
}
}
ExtrasSpecification::Some(extras) => {
for extra in extras {
queue.push_back((root, Some(extra)));
ExtrasSpecification::Some(extras) => {
for extra in extras {
queue.push_back((root, Some(extra)));
}
}
}

// Add the root package to the graph.
inverse.insert(&root.id, petgraph.add_node(root));
}

// Add the root package to the graph.
inverse.insert(&root.id, petgraph.add_node(root));
// Add any dev dependencies.
for group in dev.iter() {
for dep in root.dev_dependencies.get(group).into_iter().flatten() {
let dep_dist = lock.find_by_id(&dep.package_id);

// Create all the relevant nodes.
let mut seen = FxHashSet::default();
// Add the dependency to the graph.
if let Entry::Vacant(entry) = inverse.entry(&dep.package_id) {
entry.insert(petgraph.add_node(dep_dist));
}

if seen.insert((&dep.package_id, None)) {
queue.push_back((dep_dist, None));
}
for extra in &dep.extra {
if seen.insert((&dep.package_id, Some(extra))) {
queue.push_back((dep_dist, Some(extra)));
}
}
}
}

// Create all the relevant nodes.
while let Some((package, extra)) = queue.pop_front() {
let index = inverse[&package.id];

Expand All @@ -94,11 +116,7 @@ impl<'lock> RequirementsTxtExport<'lock> {
.flatten(),
)
} else {
Either::Right(package.dependencies.iter().chain(
dev.iter().flat_map(|group| {
package.dev_dependencies.get(group).into_iter().flatten()
}),
))
Either::Right(package.dependencies.iter())
};

for dep in deps {
Expand Down
8 changes: 4 additions & 4 deletions crates/uv/src/commands/project/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use uv_auth::{store_credentials_from_url, Credentials};
use uv_cache::Cache;
use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{
Concurrency, Constraints, ExtrasSpecification, InstallOptions, SourceStrategy,
Concurrency, Constraints, DevMode, ExtrasSpecification, InstallOptions, SourceStrategy,
};
use uv_dispatch::BuildDispatch;
use uv_distribution::DistributionDatabase;
Expand Down Expand Up @@ -729,17 +729,17 @@ async fn lock_and_sync(
let (extras, dev) = match dependency_type {
DependencyType::Production => {
let extras = ExtrasSpecification::None;
let dev = false;
let dev = DevMode::Exclude;
(extras, dev)
}
DependencyType::Dev => {
let extras = ExtrasSpecification::None;
let dev = true;
let dev = DevMode::Include;
(extras, dev)
}
DependencyType::Optional(ref group_name) => {
let extras = ExtrasSpecification::Some(vec![group_name.clone()]);
let dev = false;
let dev = DevMode::Exclude;
(extras, dev)
}
};
Expand Down
16 changes: 9 additions & 7 deletions crates/uv/src/commands/project/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ use std::path::PathBuf;

use uv_cache::Cache;
use uv_client::Connectivity;
use uv_configuration::{Concurrency, ExportFormat, ExtrasSpecification, InstallOptions};
use uv_configuration::{
Concurrency, DevMode, DevSpecification, ExportFormat, ExtrasSpecification, InstallOptions,
};
use uv_fs::CWD;
use uv_normalize::{PackageName, DEV_DEPENDENCIES};
use uv_python::{PythonDownloads, PythonPreference, PythonRequest};
Expand All @@ -30,7 +32,7 @@ pub(crate) async fn export(
install_options: InstallOptions,
output_file: Option<PathBuf>,
extras: ExtrasSpecification,
dev: bool,
dev: DevMode,
locked: bool,
frozen: bool,
python: Option<String>,
Expand Down Expand Up @@ -111,10 +113,10 @@ pub(crate) async fn export(
};

// Include development dependencies, if requested.
let dev = if dev {
vec![DEV_DEPENDENCIES.clone()]
} else {
vec![]
let dev = match dev {
DevMode::Include => DevSpecification::Include(std::slice::from_ref(&DEV_DEPENDENCIES)),
DevMode::Exclude => DevSpecification::Exclude,
DevMode::Only => DevSpecification::Only(std::slice::from_ref(&DEV_DEPENDENCIES)),
};

// Write the resolved dependencies to the output channel.
Expand All @@ -127,7 +129,7 @@ pub(crate) async fn export(
&lock,
project.project_name(),
&extras,
&dev,
dev,
hashes,
&install_options,
)?;
Expand Down
4 changes: 2 additions & 2 deletions crates/uv/src/commands/project/remove.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use owo_colors::OwoColorize;
use pep508_rs::PackageName;
use uv_cache::Cache;
use uv_client::Connectivity;
use uv_configuration::{Concurrency, ExtrasSpecification, InstallOptions};
use uv_configuration::{Concurrency, DevMode, ExtrasSpecification, InstallOptions};
use uv_fs::{Simplified, CWD};
use uv_python::{PythonDownloads, PythonPreference, PythonRequest};
use uv_scripts::Pep723Script;
Expand Down Expand Up @@ -189,7 +189,7 @@ pub(crate) async fn remove(
// Perform a full sync, because we don't know what exactly is affected by the removal.
// TODO(ibraheem): Should we accept CLI overrides for this? Should we even sync here?
let extras = ExtrasSpecification::All;
let dev = true;
let dev = DevMode::Include;
let install_options = InstallOptions::default();

// Initialize any shared state.
Expand Down
Loading

0 comments on commit b889159

Please sign in to comment.