diff --git a/crates/pixi/tests/integration_rust/common/mod.rs b/crates/pixi/tests/integration_rust/common/mod.rs index 774946e3fe..6db2947e6e 100644 --- a/crates/pixi/tests/integration_rust/common/mod.rs +++ b/crates/pixi/tests/integration_rust/common/mod.rs @@ -429,6 +429,7 @@ impl PixiControl { }, config: Default::default(), editable: false, + channel: None, }, } } diff --git a/crates/pixi_api/src/context.rs b/crates/pixi_api/src/context.rs index 50a07ad580..d07cd4116e 100644 --- a/crates/pixi_api/src/context.rs +++ b/crates/pixi_api/src/context.rs @@ -10,7 +10,9 @@ use pixi_manifest::{ }; use pixi_pypi_spec::{PixiPypiSpec, PypiPackageName}; use pixi_spec::PixiSpec; -use rattler_conda_types::{Channel, MatchSpec, PackageName, Platform, RepoDataRecord}; +use rattler_conda_types::{ + Channel, MatchSpec, NamedChannelOrUrl, PackageName, Platform, RepoDataRecord, +}; use crate::interface::Interface; use crate::workspace::add::GitOptions; @@ -175,6 +177,7 @@ impl WorkspaceContext { spec_type: SpecType, dep_options: DependencyOptions, git_options: GitOptions, + channel: Option>, ) -> miette::Result> { Box::pin(crate::workspace::add::add_conda_dep( self.workspace_mut()?, @@ -182,6 +185,7 @@ impl WorkspaceContext { spec_type, dep_options, git_options, + channel, )) .await } diff --git a/crates/pixi_api/src/workspace/add/mod.rs b/crates/pixi_api/src/workspace/add/mod.rs index 22b46a0b2d..3dd37896fc 100644 --- a/crates/pixi_api/src/workspace/add/mod.rs +++ b/crates/pixi_api/src/workspace/add/mod.rs @@ -4,10 +4,11 @@ use pixi_core::{ environment::sanity_check_workspace, workspace::{PypiDeps, UpdateDeps, WorkspaceMut}, }; +use pixi_manifest::PrioritizedChannel; use pixi_manifest::{FeatureName, KnownPreviewFeature, SpecType}; use pixi_spec::{GitSpec, SourceLocationSpec, SourceSpec}; -use rattler_conda_types::{MatchSpec, PackageName}; - +use rattler_conda_types::{MatchSpec, NamedChannelOrUrl, PackageName}; +use std::str::FromStr; mod options; pub use options::{DependencyOptions, GitOptions}; @@ -18,6 +19,7 @@ pub async fn add_conda_dep( spec_type: SpecType, dep_options: DependencyOptions, git_options: GitOptions, + channel: Option>, ) -> miette::Result> { sanity_check_workspace(workspace.workspace()).await?; @@ -29,6 +31,30 @@ pub async fn add_conda_dep( let mut match_specs = IndexMap::default(); let mut source_specs = IndexMap::default(); + // Add a channel if specified + + if channel.is_some() { + for ch in channel.unwrap() { + workspace.manifest().add_channels( + [PrioritizedChannel::from(ch.clone())], + &dep_options.feature, + false, + )?; + } + } + + for (_, spec) in &specs { + if let Some(channel) = spec.channel.as_ref() { + let channel = NamedChannelOrUrl::from_str(channel.as_ref().base_url.as_str()).unwrap(); + workspace.manifest().add_channels( + [PrioritizedChannel::from(channel)], + &dep_options.feature, + false, + )?; + } else { + continue; + } + } // if user passed some git configuration // we will use it to create pixi source specs let passed_specs: IndexMap = specs diff --git a/crates/pixi_cli/src/add.rs b/crates/pixi_cli/src/add.rs index e3daa084f4..7c8ba17f2d 100644 --- a/crates/pixi_cli/src/add.rs +++ b/crates/pixi_cli/src/add.rs @@ -5,6 +5,7 @@ use pixi_api::{ }; use pixi_config::ConfigCli; use pixi_core::{DependencyType, WorkspaceLocator}; +use rattler_conda_types::NamedChannelOrUrl; use crate::{ cli_config::{DependencyConfig, LockFileUpdateConfig, NoInstallConfig, WorkspaceConfig}, @@ -92,6 +93,10 @@ pub struct Args { /// Whether the pypi requirement should be editable #[arg(long, requires = "pypi")] pub editable: bool, + + // Specify channel + #[arg(long)] + pub channel: Option>, } impl TryFrom<&Args> for DependencyOptions { @@ -154,6 +159,7 @@ pub async fn execute(args: Args) -> miette::Result<()> { spec_type, (&args).try_into()?, git_options, + args.channel, ) .await? } diff --git a/docs/reference/cli/pixi/add.md b/docs/reference/cli/pixi/add.md index 70235b96ef..a0025ae794 100644 --- a/docs/reference/cli/pixi/add.md +++ b/docs/reference/cli/pixi/add.md @@ -26,6 +26,8 @@ pixi add [OPTIONS] ... - `--feature (-f) ` : The feature for which the dependency should be modified
**default**: `default` +- `--channel` +: Specify channel for the dependency - `--editable` : Whether the pypi requirement should be editable diff --git a/tests/integration_python/test_main_cli.py b/tests/integration_python/test_main_cli.py index 8c5ea8bd21..312cf7f5c3 100644 --- a/tests/integration_python/test_main_cli.py +++ b/tests/integration_python/test_main_cli.py @@ -1380,7 +1380,7 @@ def test_add_url_no_channel(pixi: Path, tmp_pixi_workspace: Path) -> None: verify_cli_command([pixi, "init", tmp_pixi_workspace]) - # helpful error for missing channel + # verify channel can be added using matchspec syntax verify_cli_command( [ pixi, @@ -1389,102 +1389,31 @@ def test_add_url_no_channel(pixi: Path, tmp_pixi_workspace: Path) -> None: "--manifest-path", tmp_pixi_workspace, ], - expected_exit_code=ExitCode.FAILURE, - stderr_contains="pixi workspace channel add https://repo.prefix.dev/bioconda", ) + # test channel parameter with url verify_cli_command( [ pixi, - "workspace", - "channel", - "add", - "https://repo.prefix.dev/bioconda", - "--manifest-path", - tmp_pixi_workspace, - ], - ) - # successful after adding the channel - verify_cli_command( - [ - pixi, - "add", - "https://repo.prefix.dev/bioconda::snakemake-minimal", - "--manifest-path", - tmp_pixi_workspace, - ], - stderr_contains="Added https://repo.prefix.dev/bioconda::snakemake-minimal", - ) - - # no message for initially unused feature... - verify_cli_command( - [ - pixi, - "add", - "https://conda.anaconda.org/conda-forge::xz", - "--feature=prefix", - "--manifest-path", - tmp_pixi_workspace, - ], - ) - verify_cli_command( - [ - pixi, - "workspace", - "environment", "add", - "prefix", - "--feature=prefix", - "--manifest-path", - tmp_pixi_workspace, - ], - ) - # ...but decent message on install: - verify_cli_command( - [ - pixi, - "install", - "--environment=prefix", - "--manifest-path", - tmp_pixi_workspace, - ], - expected_exit_code=ExitCode.FAILURE, - stderr_contains="unavailable channel 'https://conda.anaconda.org/conda-forge/'", - ) - # and helpful message now feature is used: - verify_cli_command( - [ - pixi, - "add", - "https://conda.anaconda.org/conda-forge::libzlib", - "--feature=prefix", - "--manifest-path", - tmp_pixi_workspace, - ], - expected_exit_code=ExitCode.FAILURE, - stderr_contains="pixi workspace channel add https://conda.anaconda.org/conda-forge", - ) - - verify_cli_command( - [ - pixi, - "workspace", - "channel", - "add", - "--feature=prefix", + "--channel", "https://conda.anaconda.org/conda-forge", + "libzlib", "--manifest-path", tmp_pixi_workspace, ], + stderr_contains="Added libzlib", ) - # successful after adding the channel + # test channel parameter with name verify_cli_command( [ pixi, - "install", - "--environment=prefix", + "add", + "--channel", + "conda-forge", + "libzlib", "--manifest-path", tmp_pixi_workspace, ], - stderr_contains="The prefix environment has been installed", + stderr_contains="Added libzlib", )