Skip to content

Commit

Permalink
feat: improve pixi search with platform selection and making limit …
Browse files Browse the repository at this point in the history
…optional (#979)

Co-authored-by: Ruben Arts <[email protected]>
Co-authored-by: Ruben Arts <[email protected]>
  • Loading branch information
3 people authored Mar 14, 2024
1 parent 4af3bca commit 835df28
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 21 deletions.
8 changes: 5 additions & 3 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -419,12 +419,14 @@ Search a package, output will list the latest version of the package.

- `--manifest-path <MANIFEST_PATH>`: the path to `pixi.toml`, by default it searches for one in the parent directories.
- `--channel <CHANNEL> (-c)`: specify a channel that the project uses. Defaults to `conda-forge`. (Allowed to be used more than once)
- `--limit <LIMIT> (-l)`: Limit the number of search results (default: 15)
- `--limit <LIMIT> (-l)`: optionally limit the number of search results
- `--platform <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`
Expand Down
62 changes: 44 additions & 18 deletions src/cli/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,13 @@ pub struct Args {
#[arg(long)]
pub manifest_path: Option<PathBuf>,

/// 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<usize>,
}

/// fetch packages from `repo_data` based on `filter_func`
Expand Down Expand Up @@ -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?,
Expand All @@ -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 {
Expand Down Expand Up @@ -278,7 +286,7 @@ async fn search_package_by_wildcard<W: Write>(
package_name: PackageName,
package_name_filter: &str,
repo_data: Arc<IndexMap<(Channel, Platform), SparseRepoData>>,
limit: usize,
limit: Option<usize>,
out: W,
) -> miette::Result<()> {
let wildcard_pattern = Regex::new(&format!("^{}$", &package_name_filter.replace('*', ".*")))
Expand Down Expand Up @@ -331,12 +339,7 @@ async fn search_package_by_wildcard<W: Write>(
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();
}
Expand All @@ -345,7 +348,11 @@ async fn search_package_by_wildcard<W: Write>(
Ok(())
}

fn print_matching_packages<W: Write>(packages: Vec<RepoDataRecord>, mut out: W) -> io::Result<()> {
fn print_matching_packages<W: Write>(
packages: &[RepoDataRecord],
mut out: W,
limit: Option<usize>,
) -> io::Result<()> {
writeln!(
out,
"{:40} {:19} {:19}",
Expand All @@ -354,14 +361,29 @@ fn print_matching_packages<W: Write>(packages: Vec<RepoDataRecord>, 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::<Vec<_>>();
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!(
Expand All @@ -373,5 +395,9 @@ fn print_matching_packages<W: Write>(packages: Vec<RepoDataRecord>, mut out: W)
)?;
}

if !remaining_packages.is_empty() {
println!("... and {} more", remaining_packages.len());
}

Ok(())
}

0 comments on commit 835df28

Please sign in to comment.