diff --git a/docs/cli.md b/docs/cli.md index 2d186fc24..8781716ef 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -419,12 +419,14 @@ Search a package, output will list the latest version of the package. - `--manifest-path `: the path to `pixi.toml`, by default it searches for one in the parent directories. - `--channel (-c)`: specify a channel that the project uses. Defaults to `conda-forge`. (Allowed to be used more than once) -- `--limit (-l)`: Limit the number of search results (default: 15) +- `--limit (-l)`: optionally limit the number of search results +- `--platform (-p)`: specify a platform that you want to search for. (default: current platform) ```zsh pixi search pixi -pixi search -l 30 py* -pixi search -c robostack plotjuggler* +pixi search --limit 30 "py*" +# search in a different channel and for a specific platform +pixi search -c robostack --platform linux-64 "plotjuggler*" ``` ## `self-update` diff --git a/src/cli/search.rs b/src/cli/search.rs index c306421c2..0b199cfb7 100644 --- a/src/cli/search.rs +++ b/src/cli/search.rs @@ -34,9 +34,13 @@ pub struct Args { #[arg(long)] pub manifest_path: Option, + /// The platform to search for, defaults to current platform + #[arg(short, long, default_value_t = Platform::current())] + pub platform: Platform, + /// Limit the number of search results - #[clap(short, long, default_value_t = 15)] - limit: usize, + #[clap(short, long)] + limit: Option, } /// fetch packages from `repo_data` based on `filter_func` @@ -112,7 +116,7 @@ pub async fn execute(args: Args) -> miette::Result<()> { let repo_data = Arc::new( fetch_sparse_repodata( channels.iter().map(AsRef::as_ref), - [Platform::current()], + [args.platform], &authenticated_client, ) .await?, @@ -123,10 +127,14 @@ pub async fn execute(args: Args) -> miette::Result<()> { let package_name_without_filter = package_name_filter.replace('*', ""); let package_name = PackageName::try_from(package_name_without_filter).into_diagnostic()?; - let limit = args.limit; - - search_package_by_wildcard(package_name, &package_name_filter, repo_data, limit, stdout) - .await?; + search_package_by_wildcard( + package_name, + &package_name_filter, + repo_data, + args.limit, + stdout, + ) + .await?; } // If package name filter doesn't contain * (wildcard), it will search and display specific package info (if any package is found) else { @@ -278,7 +286,7 @@ async fn search_package_by_wildcard( package_name: PackageName, package_name_filter: &str, repo_data: Arc>, - limit: usize, + limit: Option, out: W, ) -> miette::Result<()> { let wildcard_pattern = Regex::new(&format!("^{}$", &package_name_filter.replace('*', ".*"))) @@ -331,12 +339,7 @@ async fn search_package_by_wildcard( return Err(miette::miette!("Could not find {normalized_package_name}")); } - // split off at `limit`, discard the second half - if packages.len() > limit { - let _ = packages.split_off(limit); - } - - if let Err(e) = print_matching_packages(packages, out) { + if let Err(e) = print_matching_packages(&packages, out, limit) { if e.kind() != std::io::ErrorKind::BrokenPipe { return Err(e).into_diagnostic(); } @@ -345,7 +348,11 @@ async fn search_package_by_wildcard( Ok(()) } -fn print_matching_packages(packages: Vec, mut out: W) -> io::Result<()> { +fn print_matching_packages( + packages: &[RepoDataRecord], + mut out: W, + limit: Option, +) -> io::Result<()> { writeln!( out, "{:40} {:19} {:19}", @@ -354,14 +361,29 @@ fn print_matching_packages(packages: Vec, mut out: W) console::style("Channel").bold(), )?; + // split off at `limit`, discard the second half + let limit = limit.unwrap_or(usize::MAX); + + let (packages, remaining_packages) = if limit < packages.len() { + packages.split_at(limit) + } else { + (packages, &[][..]) + }; + for package in packages { // TODO: change channel fetch logic to be more robust // currently it relies on channel field being a url with trailing slash // https://github.com/mamba-org/rattler/issues/146 - let channel = package.channel.split('/').collect::>(); - let channel_name = channel[channel.len() - 2]; + let channel_name = + if let Some(channel) = package.channel.strip_prefix("https://conda.anaconda.org/") { + channel.trim_end_matches('/') + } else { + package.channel.as_str() + }; - let package_name = package.package_record.name; + let channel_name = format!("{}/{}", channel_name, package.package_record.subdir); + + let package_name = &package.package_record.name; let version = package.package_record.version.as_str(); writeln!( @@ -373,5 +395,9 @@ fn print_matching_packages(packages: Vec, mut out: W) )?; } + if !remaining_packages.is_empty() { + println!("... and {} more", remaining_packages.len()); + } + Ok(()) }