Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 45 additions & 1 deletion src/cli/command_info.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use clap::CommandFactory;
use is_executable::IsExecutable;
use miette::{Context, IntoDiagnostic};
use std::env;
use std::path::PathBuf;
use std::{collections::HashSet, env};
use tracing::warn;

use super::{Command, get_styles};

Expand All @@ -17,6 +18,49 @@ pub fn find_external_subcommand(cmd: &str) -> Option<PathBuf> {
})
}

pub fn find_all_external_commands() -> HashSet<PathBuf> {
let all_search_directories = search_directories().unwrap_or_default();
let mut all_executables_on_path = HashSet::new();

for dir in &all_search_directories {
if !dir.is_dir() {
continue;
}
match std::fs::read_dir(dir) {
Ok(read_dir) => {
for entry in read_dir {
match entry {
Ok(entry) => {
if entry.path().is_executable()
&& entry
.path()
.file_name()
.unwrap()
.to_string_lossy()
.starts_with("pixi-")
{
all_executables_on_path.insert(entry.path());
}
}
Err(e) => {
warn!("Couldn't read entry: {}", e);
}
}
}
}
Err(e) => {
warn!(
"Couldn't read directory {}: {}",
dir.to_string_lossy().to_string(),
e
);
}
}
}

all_executables_on_path
}

/// Execute an external subcommand
pub fn execute_external_command(args: Vec<String>) -> miette::Result<()> {
// There should be always at least one argument, the command itself.
Expand Down
67 changes: 67 additions & 0 deletions src/cli/extensions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use std::collections::HashMap;

use clap::Parser;
use itertools::Itertools;

use crate::cli::command_info::find_all_external_commands;

#[derive(Parser, Debug)]
#[clap(verbatim_doc_comment)]
pub struct Args;

pub async fn execute(_args: Args) -> miette::Result<()> {
let known_extensions = HashMap::from([
(
"pixi-pack".to_string(),
"Pack conda environments created with pixi".to_string(),
),
(
"pixi-unpack".to_string(),
"Unpack conda environments packaged with pixi-pack".to_string(),
),
(
"pixi-diff".to_string(),
"Generate JSON diffs between pixi lockfiles".to_string(),
),
(
"pixi-diff-to-markdown".to_string(),
"Generate markdown summaries from pixi update".to_string(),
),
(
"pixi-inject".to_string(),
"Inject conda packages into an already existing conda prefix".to_string(),
),
(
"pixi-install-to-prefix".to_string(),
"Install pixi environments to an arbitrary prefix".to_string(),
),
]);

let extensions = find_all_external_commands();

println!(
"{}",
console::style("Available Extensions:")
.green()
.underlined()
.bold()
);

for extension in extensions.iter().sorted() {
let Some(name) = extension
.as_path()
.file_stem()
.map(|p| p.to_string_lossy().to_string())
else {
continue;
};
print!(" {}", console::style(&name).cyan());
if let Some(description) = known_extensions.get(&name) {
println!("\t{}", description);
} else {
println!();
}
}

Ok(())
}
3 changes: 3 additions & 0 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub mod command_info;
pub mod completion;
pub mod config;
pub mod exec;
pub mod extensions;
pub mod global;
pub mod has_specs;
pub mod info;
Expand Down Expand Up @@ -136,6 +137,7 @@ pub enum Command {
Config(config::Args),
#[clap(visible_alias = "x")]
Exec(exec::Args),
Extensions(extensions::Args),
#[clap(visible_alias = "g")]
Global(global::Args),
Info(info::Args),
Expand Down Expand Up @@ -296,6 +298,7 @@ pub async fn execute_command(
Command::Lock(cmd) => lock::execute(cmd).await,
Command::Exec(args) => exec::execute(args).await,
Command::Build(args) => build::execute(args).await,
Command::Extensions(args) => extensions::execute(args).await,
Command::External(args) => command_info::execute_external_command(args),
}
}
Expand Down
Loading