Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Specify multiple commands with the shell option #91

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
141 changes: 94 additions & 47 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,11 @@ fn index_database_pick(command: &str, picker: &str) -> Option<String> {

fn run_command_or_open_shell(
use_channel: bool,
choice: &str,
derivations: &[String],
command: &str,
trail: &[String],
nixpkgs_flake: &str,
) {
) -> ! {
let mut run_cmd = Command::new("nix");

run_cmd.args([
Expand All @@ -99,9 +99,12 @@ fn run_command_or_open_shell(
]);

if use_channel {
run_cmd.args(["-f", "<nixpkgs>", choice]);
run_cmd.args(["-f", "<nixpkgs>"]);
run_cmd.args(derivations);
} else {
run_cmd.args([format!("{nixpkgs_flake}#{choice}")]);
for derivation in derivations {
run_cmd.args([format!("{nixpkgs_flake}#{derivation}")]);
}
}

if !command.is_empty() {
Expand All @@ -111,28 +114,43 @@ fn run_command_or_open_shell(
}
};

run_cmd.exec();
let res = run_cmd.exec();
panic!("Failed to exec: {res}");
}

fn main() -> ExitCode {
let args = Opt::parse();

let mut cache = Cache::new();
if let Err(ref e) = cache {
eprintln!("failed to initialize cache, disabling related functionality: {e}");
}
let mut cache = Cache::new()
.map_err(|e| {
eprintln!("failed to initialize cache, disabling related functionality: {e}");
})
.ok();

if args.update {
eprintln!("\"comma --update\" has been deprecated. either obtain a prebuilt database from https://github.com/Mic92/nix-index-database or use \"nix run 'nixpkgs#nix-index' --extra-experimental-features 'nix-command flakes'\"");
index::update_database();
}

if args.empty_cache {
if let Ok(ref mut cache) = cache {
if let Some(ref mut cache) = cache {
cache.empty();
}
}

let use_channel = env::var("NIX_PATH").is_ok_and(|p| p.contains("nixpkgs="));

if !args.shell.is_empty() {
return open_shell(
args.shell,
args.delete_entry,
&args.picker,
cache,
use_channel,
args.nixpkgs_flake,
);
}

// The command may not be given if `--update` was specified.
if args.cmd.is_empty() {
return if args.update || args.empty_cache {
Expand All @@ -146,7 +164,7 @@ fn main() -> ExitCode {
let trail = &args.cmd[1..];

if args.delete_entry {
if let Ok(ref mut cache) = cache {
if let Some(ref mut cache) = cache {
cache.delete(command);
}
}
Expand All @@ -169,46 +187,24 @@ fn main() -> ExitCode {
}
}

let derivation = match cache {
Ok(mut cache) => cache.query(command).or_else(|| {
index_database_pick(command, &args.picker).map(|derivation| {
cache.update(command, &derivation);
derivation
})
}),
Err(_) => index_database_pick(command, &args.picker),
let Some(derivation) = find_program(command, &args.picker, cache.as_mut(), args.delete_entry)
else {
eprint!("Error");
return ExitCode::FAILURE;
};

let derivation = match derivation {
Some(d) => d,
None => return ExitCode::FAILURE,
};

// Explicitly drop cache because exec doesn't call destructors
drop(cache);
let basename = derivation.rsplit('.').last().unwrap();

let use_channel = match env::var("NIX_PATH") {
Ok(val) => val,
Err(_) => String::new(),
}
.contains("nixpkgs=");

if args.install {
Command::new("nix-env")
.args(["-f", "<nixpkgs>", "-iA", basename])
.exec();
} else if args.shell {
let shell_cmd = shell::select_shell_from_pid(process::id()).unwrap_or("bash".into());
run_command_or_open_shell(
use_channel,
&derivation,
&shell_cmd,
&[],
&args.nixpkgs_flake,
);
ExitCode::SUCCESS
} else if args.print_path {
run_command_or_open_shell(
use_channel,
&derivation,
&[derivation],
"sh",
&[
String::from("-c"),
Expand All @@ -219,14 +215,65 @@ fn main() -> ExitCode {
} else {
run_command_or_open_shell(
use_channel,
&derivation,
&[derivation],
command,
trail,
&args.nixpkgs_flake,
);
}
}

fn open_shell(
commands: Vec<String>,
empty_cache: bool,
picker: &str,
mut cache: Option<Cache>,
use_channel: bool,
nixpkgs_flake: String,
) -> ExitCode {
let shell_cmd = shell::select_shell_from_pid(process::id()).unwrap_or("bash".into());
let mut programs = Vec::new();
for prog in commands {
let Some(derivation) = find_program(&prog, picker, cache.as_mut(), empty_cache) else {
eprint!("Couldn't find program for {prog}");
return ExitCode::FAILURE;
};
programs.push(derivation);
}

// Explicitly drop cache because exec doesn't call destructors
drop(cache);

ExitCode::SUCCESS
run_command_or_open_shell(
use_channel,
&programs,
&shell_cmd,
&[],
nixpkgs_flake.as_str(),
);
}

/// Try to find and select a program from a command
fn find_program(
command: &str,
picker: &str,
cache: Option<&mut Cache>,
delete_entry: bool,
) -> Option<String> {
cache.map_or_else(
|| index_database_pick(command, picker),
|cache| {
if delete_entry {
cache.delete(command);
}
cache.query(command).or_else(|| {
index_database_pick(command, picker).map(|derivation| {
cache.update(command, &derivation);
derivation
})
})
},
)
}

/// Runs programs without installing them
Expand All @@ -237,9 +284,9 @@ struct Opt {
#[clap(short, long)]
install: bool,

/// Open a shell containing the derivation containing the executable
#[clap(short, long)]
shell: bool,
/// Open a shell with the derivations of the specified installables
#[clap(short, long, conflicts_with_all(["cmd", "install"]), num_args(1..), value_name("cmd"))]
shell: Vec<String>,

#[clap(short = 'P', long, env = "COMMA_PICKER", default_value = "fzy")]
picker: String,
Expand Down Expand Up @@ -274,6 +321,6 @@ struct Opt {
delete_entry: bool,

/// Command to run
#[clap(required_unless_present_any = ["update", "empty_cache"], name = "cmd")]
#[clap(required_unless_present_any = ["update", "empty_cache", "shell"], name = "cmd")]
cmd: Vec<String>,
}
Loading