use skim::{Skim, SkimOptionsBuilder};
use structopt::StructOpt;
use colored::*;
use nix_query::{cache, cache::CacheIoError, nix, proc::CommandError};
#[derive(Debug)]
enum MainErr {
Cache(CacheIoError),
Command(CommandError),
NixQuery(nix::NixQueryError),
}
impl From<CacheIoError> for MainErr {
fn from(e: CacheIoError) -> Self {
MainErr::Cache(e)
}
}
impl From<CommandError> for MainErr {
fn from(e: CommandError) -> Self {
MainErr::Command(e)
}
}
impl From<nix::NixQueryError> for MainErr {
fn from(e: nix::NixQueryError) -> Self {
MainErr::NixQuery(e)
}
}
#[derive(Debug, StructOpt)]
#[structopt(
name = "nix-query",
)]
struct Opt {
#[structopt(long)]
clear_cache: bool,
#[structopt(long)]
print_cache: bool,
#[structopt(long)]
info: Option<String>,
}
fn main() -> Result<(), MainErr> {
let opt = Opt::from_args();
if opt.clear_cache {
cache::clear_cache()?;
}
if let Some(attr) = opt.info {
colored::control::set_override(true);
print!("{}", nix::nix_query(&attr)?.console_fmt());
colored::control::unset_override();
return Ok(());
}
if !cache::cache_exists() {
eprintln!(
"{}",
"Populating the Nix package name cache (this may take a minute or two)..."
.bold()
.green(),
);
}
let all_attrs = cache::ensure_cache()?;
if opt.print_cache {
print!("{}", all_attrs);
return Ok(());
}
skim_attrs()?;
Ok(())
}
fn skim_attrs() -> Result<(), MainErr> {
use std::env;
use std::io::Cursor;
let preview_cmd = format!(
"{exe} --info {{}}",
exe = env::current_exe()
.map(|p| p.to_string_lossy().into_owned())
.unwrap_or_else(|_| "nix-query".to_string()),
);
let options = SkimOptionsBuilder::default()
.height(Some("100%"))
.multi(true)
.preview(Some(&preview_cmd))
.preview_window(Some("down:wrap:50%"))
.tiebreak(Some("score,end".to_string()))
.build()
.unwrap();
let input = cache::ensure_cache()?;
let selected_items = Skim::run_with(&options, Some(Box::new(Cursor::new(input))))
.map(|out| out.selected_items)
.unwrap_or_else(Vec::new);
for item in selected_items.iter() {
println!("{}", item.get_output_text());
}
Ok(())
}
pub fn check_pkg_schemas() {
use std::process::Command;
use nix_query::proc;
println!("Reading cache.");
let mut lines: Vec<String> = cache::ensure_cache()
.expect("Can read from cache")
.lines()
.by_ref()
.map(|s| s.to_string())
.collect();
println!("Sorting cache.");
lines.sort_unstable();
println!("Checking.");
let mut skipping = true;
for (inx, attr) in lines.iter().enumerate() {
if attr.starts_with("nixpkgs._")
|| attr.starts_with("nixos._")
|| attr.starts_with("unstable._")
{
continue;
}
if skipping {
if attr.starts_with("nixpkgs.lzip") {
skipping = false;
} else {
continue;
}
}
let json = proc::run_cmd_stdout(Command::new("nix-env").args(&[
"--query",
"--available",
"--json",
"--attr",
&attr,
]))
.unwrap_or_else(|_| panic!(
"Can query Nix for information about attribute {}",
attr
));
match serde_json::from_str::<nix::AllNixInfo>(&json) {
Err(d) => {
println!("{} | {}\n\t{}", attr, d, json);
}
Ok(i) => {
println!(
"OK: {attr} [{inx}/{len}]",
attr = attr,
inx = inx,
len = lines.len(),
);
i.attrs.values().next().unwrap_or_else(|| panic!(
"String -> NixInfo map for {} has at least one value.",
attr
));
}
}
}
}