From d46a9e34ac50ab0a5c0ca79a2985ab460d3e571b Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Tue, 10 Sep 2024 18:11:02 -0400 Subject: [PATCH] Add --only-dev --- crates/uv-cli/src/lib.rs | 18 ++++++ crates/uv-configuration/src/dev.rs | 53 +++++++++++++++++ crates/uv-configuration/src/lib.rs | 2 + crates/uv-resolver/src/lock/mod.rs | 34 ++++++----- .../uv-resolver/src/lock/requirements_txt.rs | 58 +++++++++++-------- crates/uv/src/commands/project/add.rs | 8 +-- crates/uv/src/commands/project/export.rs | 16 ++--- crates/uv/src/commands/project/remove.rs | 4 +- crates/uv/src/commands/project/run.rs | 19 ++++-- crates/uv/src/commands/project/sync.rs | 17 +++--- crates/uv/src/settings.rs | 21 ++++--- docs/reference/cli.md | 12 ++++ 12 files changed, 188 insertions(+), 74 deletions(-) create mode 100644 crates/uv-configuration/src/dev.rs diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs index 46896ff1cfa51..cf8113a35cf74 100644 --- a/crates/uv-cli/src/lib.rs +++ b/crates/uv-cli/src/lib.rs @@ -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 @@ -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. @@ -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, diff --git a/crates/uv-configuration/src/dev.rs b/crates/uv-configuration/src/dev.rs new file mode 100644 index 0000000000000..ab11c55fadcad --- /dev/null +++ b/crates/uv-configuration/src/dev.rs @@ -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 { + 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(_)) + } +} diff --git a/crates/uv-configuration/src/lib.rs b/crates/uv-configuration/src/lib.rs index fad24007e19f4..6ad8cdc685289 100644 --- a/crates/uv-configuration/src/lib.rs +++ b/crates/uv-configuration/src/lib.rs @@ -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::*; @@ -20,6 +21,7 @@ mod build_options; mod concurrency; mod config_settings; mod constraints; +mod dev; mod export_format; mod extras; mod hash; diff --git a/crates/uv-resolver/src/lock/mod.rs b/crates/uv-resolver/src/lock/mod.rs index f0e615c5e012d..7c510d719c9ad 100644 --- a/crates/uv-resolver/src/lock/mod.rs +++ b/crates/uv-resolver/src/lock/mod.rs @@ -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}; @@ -540,7 +540,7 @@ impl Lock { marker_env: &ResolverMarkerEnvironment, tags: &Tags, extras: &ExtrasSpecification, - dev: &[GroupName], + dev: DevSpecification<'_>, build_options: &BuildOptions, install_options: &InstallOptions, ) -> Result { @@ -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); @@ -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; diff --git a/crates/uv-resolver/src/lock/requirements_txt.rs b/crates/uv-resolver/src/lock/requirements_txt.rs index b7f25dba4b906..6e89ed45196c2 100644 --- a/crates/uv-resolver/src/lock/requirements_txt.rs +++ b/crates/uv-resolver/src/lock/requirements_txt.rs @@ -6,16 +6,16 @@ use std::path::{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}; @@ -41,15 +41,16 @@ impl<'lock> RequirementsTxtExport<'lock> { lock: &'lock Lock, root_name: &PackageName, extras: &ExtrasSpecification, - dev: &[GroupName], + dev: DevSpecification<'_>, hashes: bool, install_options: &'lock InstallOptions, ) -> Result { 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 @@ -57,20 +58,37 @@ impl<'lock> RequirementsTxtExport<'lock> { .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 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); + 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))); + } } } } @@ -79,8 +97,6 @@ impl<'lock> RequirementsTxtExport<'lock> { inverse.insert(&root.id, petgraph.add_node(root)); // Create all the relevant nodes. - let mut seen = FxHashSet::default(); - while let Some((package, extra)) = queue.pop_front() { let index = inverse[&package.id]; @@ -93,11 +109,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 { diff --git a/crates/uv/src/commands/project/add.rs b/crates/uv/src/commands/project/add.rs index fc266178695a2..e52cf793a6851 100644 --- a/crates/uv/src/commands/project/add.rs +++ b/crates/uv/src/commands/project/add.rs @@ -14,7 +14,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; @@ -705,17 +705,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) } }; diff --git a/crates/uv/src/commands/project/export.rs b/crates/uv/src/commands/project/export.rs index b3a58573232e0..3eebd1032169d 100644 --- a/crates/uv/src/commands/project/export.rs +++ b/crates/uv/src/commands/project/export.rs @@ -4,7 +4,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}; @@ -27,7 +29,7 @@ pub(crate) async fn export( install_options: InstallOptions, output_file: Option, extras: ExtrasSpecification, - dev: bool, + dev: DevMode, locked: bool, frozen: bool, python: Option, @@ -108,10 +110,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. @@ -124,7 +126,7 @@ pub(crate) async fn export( &lock, project.project_name(), &extras, - &dev, + dev, hashes, &install_options, )?; diff --git a/crates/uv/src/commands/project/remove.rs b/crates/uv/src/commands/project/remove.rs index e7644354652f0..5dee4c70c1cbd 100644 --- a/crates/uv/src/commands/project/remove.rs +++ b/crates/uv/src/commands/project/remove.rs @@ -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; @@ -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. diff --git a/crates/uv/src/commands/project/run.rs b/crates/uv/src/commands/project/run.rs index 253087c9680d4..7e31989509166 100644 --- a/crates/uv/src/commands/project/run.rs +++ b/crates/uv/src/commands/project/run.rs @@ -14,7 +14,7 @@ use tracing::{debug, warn}; use uv_cache::Cache; use uv_cli::ExternalCommand; use uv_client::{BaseClientBuilder, Connectivity}; -use uv_configuration::{Concurrency, ExtrasSpecification, InstallOptions}; +use uv_configuration::{Concurrency, DevMode, ExtrasSpecification, InstallOptions}; use uv_distribution::LoweredRequirement; use uv_fs::{PythonExt, Simplified, CWD}; use uv_installer::{SatisfiesResult, SitePackages}; @@ -57,7 +57,7 @@ pub(crate) async fn run( no_project: bool, no_config: bool, extras: ExtrasSpecification, - dev: bool, + dev: DevMode, python: Option, settings: ResolverInstallerSettings, python_preference: PythonPreference, @@ -264,9 +264,12 @@ pub(crate) async fn run( if !extras.is_empty() { warn_user!("Extras are not supported for Python scripts with inline metadata"); } - if !dev { + if matches!(dev, DevMode::Exclude) { warn_user!("`--no-dev` is not supported for Python scripts with inline metadata"); } + if matches!(dev, DevMode::Only) { + warn_user!("`--only-dev` is not supported for Python scripts with inline metadata"); + } if package.is_some() { warn_user!( "`--package` is a no-op for Python scripts with inline metadata, which always run in isolation" @@ -338,9 +341,12 @@ pub(crate) async fn run( if !extras.is_empty() { warn_user!("Extras have no effect when used alongside `--no-project`"); } - if !dev { + if matches!(dev, DevMode::Exclude) { warn_user!("`--no-dev` has no effect when used alongside `--no-project`"); } + if matches!(dev, DevMode::Only) { + warn_user!("`--only-dev` has no effect when used alongside `--no-project`"); + } if locked { warn_user!("`--locked` has no effect when used alongside `--no-project`"); } @@ -355,9 +361,12 @@ pub(crate) async fn run( if !extras.is_empty() { warn_user!("Extras have no effect when used outside of a project"); } - if !dev { + if matches!(dev, DevMode::Exclude) { warn_user!("`--no-dev` has no effect when used outside of a project"); } + if matches!(dev, DevMode::Only) { + warn_user!("`--only-dev` has no effect when used outside of a project"); + } if locked { warn_user!("`--locked` has no effect when used outside of a project"); } diff --git a/crates/uv/src/commands/project/sync.rs b/crates/uv/src/commands/project/sync.rs index 31ed1c1a88e8e..e134754d0e701 100644 --- a/crates/uv/src/commands/project/sync.rs +++ b/crates/uv/src/commands/project/sync.rs @@ -7,7 +7,8 @@ use uv_auth::store_credentials_from_url; use uv_cache::Cache; use uv_client::{Connectivity, FlatIndexClient, RegistryClientBuilder}; use uv_configuration::{ - Concurrency, Constraints, ExtrasSpecification, HashCheckingMode, InstallOptions, + Concurrency, Constraints, DevMode, DevSpecification, ExtrasSpecification, HashCheckingMode, + InstallOptions, }; use uv_dispatch::BuildDispatch; use uv_fs::CWD; @@ -33,7 +34,7 @@ pub(crate) async fn sync( frozen: bool, package: Option, extras: ExtrasSpecification, - dev: bool, + dev: DevMode, install_options: InstallOptions, modifications: Modifications, python: Option, @@ -146,7 +147,7 @@ pub(super) async fn do_sync( venv: &PythonEnvironment, lock: &Lock, extras: &ExtrasSpecification, - dev: bool, + dev: DevMode, install_options: InstallOptions, modifications: Modifications, settings: InstallerSettingsRef<'_>, @@ -209,10 +210,10 @@ pub(super) async fn do_sync( } // 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)), }; // Determine the tags to use for resolution. @@ -224,7 +225,7 @@ pub(super) async fn do_sync( &markers, tags, extras, - &dev, + dev, build_options, &install_options, )?; diff --git a/crates/uv/src/settings.rs b/crates/uv/src/settings.rs index 1bf7a398d0502..a2b7ca8563c34 100644 --- a/crates/uv/src/settings.rs +++ b/crates/uv/src/settings.rs @@ -22,9 +22,9 @@ use uv_cli::{ }; use uv_client::Connectivity; use uv_configuration::{ - BuildOptions, Concurrency, ConfigSettings, ExportFormat, ExtrasSpecification, HashCheckingMode, - IndexStrategy, InstallOptions, KeyringProviderType, NoBinary, NoBuild, PreviewMode, Reinstall, - SourceStrategy, TargetTriple, TrustedHost, Upgrade, + BuildOptions, Concurrency, ConfigSettings, DevMode, ExportFormat, ExtrasSpecification, + HashCheckingMode, IndexStrategy, InstallOptions, KeyringProviderType, NoBinary, NoBuild, + PreviewMode, Reinstall, SourceStrategy, TargetTriple, TrustedHost, Upgrade, }; use uv_normalize::PackageName; use uv_python::{Prefix, PythonDownloads, PythonPreference, PythonVersion, Target}; @@ -209,7 +209,7 @@ pub(crate) struct RunSettings { pub(crate) locked: bool, pub(crate) frozen: bool, pub(crate) extras: ExtrasSpecification, - pub(crate) dev: bool, + pub(crate) dev: DevMode, pub(crate) with: Vec, pub(crate) with_editable: Vec, pub(crate) with_requirements: Vec, @@ -233,6 +233,7 @@ impl RunSettings { no_all_extras, dev, no_dev, + only_dev, command: _, with, with_editable, @@ -257,7 +258,7 @@ impl RunSettings { flag(all_extras, no_all_extras).unwrap_or_default(), extra.unwrap_or_default(), ), - dev: flag(dev, no_dev).unwrap_or(true), + dev: DevMode::from_args(dev, no_dev, only_dev), with, with_editable, with_requirements: with_requirements @@ -659,7 +660,7 @@ pub(crate) struct SyncSettings { pub(crate) locked: bool, pub(crate) frozen: bool, pub(crate) extras: ExtrasSpecification, - pub(crate) dev: bool, + pub(crate) dev: DevMode, pub(crate) install_options: InstallOptions, pub(crate) modifications: Modifications, pub(crate) package: Option, @@ -678,6 +679,7 @@ impl SyncSettings { no_all_extras, dev, no_dev, + only_dev, inexact, exact, no_install_project, @@ -704,7 +706,7 @@ impl SyncSettings { flag(all_extras, no_all_extras).unwrap_or_default(), extra.unwrap_or_default(), ), - dev: flag(dev, no_dev).unwrap_or(true), + dev: DevMode::from_args(dev, no_dev, only_dev), install_options: InstallOptions::new( no_install_project, no_install_workspace, @@ -958,7 +960,7 @@ pub(crate) struct ExportSettings { pub(crate) format: ExportFormat, pub(crate) package: Option, pub(crate) extras: ExtrasSpecification, - pub(crate) dev: bool, + pub(crate) dev: DevMode, pub(crate) hashes: bool, pub(crate) install_options: InstallOptions, pub(crate) output_file: Option, @@ -981,6 +983,7 @@ impl ExportSettings { no_all_extras, dev, no_dev, + only_dev, hashes, no_hashes, output_file, @@ -1002,7 +1005,7 @@ impl ExportSettings { flag(all_extras, no_all_extras).unwrap_or_default(), extra.unwrap_or_default(), ), - dev: flag(dev, no_dev).unwrap_or(true), + dev: DevMode::from_args(dev, no_dev, only_dev), hashes: flag(hashes, no_hashes).unwrap_or(true), install_options: InstallOptions::new( no_emit_project, diff --git a/docs/reference/cli.md b/docs/reference/cli.md index b8613fe87bc97..e8c69935c427b 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -273,6 +273,10 @@ uv run [OPTIONS]

When disabled, uv will only use locally cached data and locally available files.

+
--only-dev

Omit non-development dependencies.

+ +

The project itself will also be omitted.

+
--package package

Run the command in a specific package in the workspace.

If the workspace member does not exist, uv will exit with an error.

@@ -1335,6 +1339,10 @@ uv sync [OPTIONS]

When disabled, uv will only use locally cached data and locally available files.

+
--only-dev

Omit non-development dependencies.

+ +

The project itself will also be omitted.

+
--package package

Sync for a specific package in the workspace.

The workspace’s environment (.venv) is updated to reflect the subset of dependencies declared by the specified workspace member package.

@@ -1889,6 +1897,10 @@ uv export [OPTIONS]

When disabled, uv will only use locally cached data and locally available files.

+
--only-dev

Omit non-development dependencies.

+ +

The project itself will also be omitted.

+
--output-file, -o output-file

Write the exported requirements to the given file

--package package

Export the dependencies for a specific package in the workspace.