Skip to content
Merged
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
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# NH Changelog

## 4.0.2

### Added

- Add `--json` to `nh search`, which will return results in JSON format. Useful
for parsing the output of `nh search` with, e.g., jq.

## 4.0.1

### Removed

- NixOS 24.05 is now marked as deprecated, and will emit an error if the search
command attempts to use it for the channel. While the Elasticsearch backend
still seems to support 24.05, it is deprecated in Nixpkgs and is actively
discouraged. Please update your system at your earliest convenience.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "nh"
version = "4.0.1"
version = "4.0.2"
edition = "2021"
license = "EUPL-1.2"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down
22 changes: 13 additions & 9 deletions src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use clap::{builder::Styles, Args, Parser, Subcommand};
use crate::installable::Installable;
use crate::Result;

fn make_style() -> Styles {
const fn make_style() -> Styles {
Styles::plain().header(Style::new().bold()).literal(
Style::new()
.bold()
Expand Down Expand Up @@ -55,18 +55,18 @@ pub enum NHCommand {
impl NHCommand {
pub fn run(self) -> Result<()> {
match self {
NHCommand::Os(args) => {
Self::Os(args) => {
std::env::set_var("NH_CURRENT_COMMAND", "os");
args.run()
}
NHCommand::Search(args) => args.run(),
NHCommand::Clean(proxy) => proxy.command.run(),
NHCommand::Completions(args) => args.run(),
NHCommand::Home(args) => {
Self::Search(args) => args.run(),
Self::Clean(proxy) => proxy.command.run(),
Self::Completions(args) => args.run(),
Self::Home(args) => {
std::env::set_var("NH_CURRENT_COMMAND", "home");
args.run()
}
NHCommand::Darwin(args) => {
Self::Darwin(args) => {
std::env::set_var("NH_CURRENT_COMMAND", "darwin");
args.run()
}
Expand All @@ -76,7 +76,7 @@ impl NHCommand {

#[derive(Args, Debug)]
#[clap(verbatim_doc_comment)]
/// NixOS functionality
/// `NixOS` functionality
///
/// Implements functionality mostly around but not exclusive to nixos-rebuild
pub struct OsArgs {
Expand Down Expand Up @@ -193,6 +193,10 @@ pub struct SearchArgs {
/// Show supported platforms for each package
pub platforms: bool,

#[arg(long, short = 'j', env = "NH_SEARCH_JSON", value_parser = clap::builder::BoolishValueParser::new())]
/// Output results as JSON
pub json: bool,

/// Name of the package to search
pub query: Vec<String>,
}
Expand Down Expand Up @@ -225,7 +229,7 @@ pub enum CleanMode {
#[clap(verbatim_doc_comment)]
/// Enhanced nix cleanup
///
/// For --keep-since, see the documentation of humantime for possible formats: https://docs.rs/humantime/latest/humantime/fn.parse_duration.html
/// For --keep-since, see the documentation of humantime for possible formats: <https://docs.rs/humantime/latest/humantime/fn.parse_duration.html>
pub struct CleanArgs {
#[arg(long, short, default_value = "1")]
/// At least keep this number of generations
Expand Down
56 changes: 41 additions & 15 deletions src/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@ use std::process::Stdio;
use std::time::Instant;

use color_eyre::eyre::{bail, Context};
use elasticsearch_dsl::*;
use elasticsearch_dsl::{Operator, Query, Search, SearchResponse, TextQueryType};
use interface::SearchArgs;
use regex::Regex;
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use tracing::{debug, trace, warn};

use crate::*;
use crate::{interface, Result};

// List of deprecated NixOS versions
// Add new versions as they become deprecated.
const DEPRECATED_VERSIONS: &[&str] = &["nixos-24.05"];

#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, Serialize)]
#[allow(non_snake_case, dead_code)]
struct SearchResult {
// r#type: String,
Expand Down Expand Up @@ -45,6 +45,14 @@ macro_rules! print_hyperlink {
};
}

#[derive(Debug, Serialize)]
struct JSONOutput {
query: String,
channel: String,
elapsed_ms: u128,
results: Vec<SearchResult>,
}

impl SearchArgs {
pub fn run(&self) -> Result<()> {
trace!("args: {self:?}");
Expand Down Expand Up @@ -97,10 +105,12 @@ impl SearchArgs {
),
);

println!(
"Querying search.nixos.org, with channel {}...",
self.channel
);
if !self.json {
println!(
"Querying search.nixos.org, with channel {}...",
self.channel
);
}
let then = Instant::now();

let client = reqwest::blocking::Client::new();
Expand All @@ -127,9 +137,12 @@ impl SearchArgs {
let elapsed = then.elapsed();
debug!(?elapsed);
trace!(?response);
println!("Took {}ms", elapsed.as_millis());
println!("Most relevant results at the end");
println!();

if !self.json {
println!("Took {}ms", elapsed.as_millis());
println!("Most relevant results at the end");
println!();
}

let parsed_response: SearchResponse = response
.json()
Expand All @@ -140,6 +153,19 @@ impl SearchArgs {
.documents::<SearchResult>()
.context("parsing search document")?;

if self.json {
// Output as JSON
let json_output = JSONOutput {
query: query_s,
channel: self.channel.clone(),
elapsed_ms: elapsed.as_millis(),
results: documents,
};

println!("{}", serde_json::to_string_pretty(&json_output)?);
return Ok(());
}

let hyperlinks = supports_hyperlinks::supports_hyperlinks();
debug!(?hyperlinks);

Expand Down Expand Up @@ -168,16 +194,16 @@ impl SearchArgs {
if let Some(ref desc) = elem.package_description {
let desc = desc.replace('\n', " ");
for line in textwrap::wrap(&desc, textwrap::Options::with_termwidth()) {
println!(" {}", line);
println!(" {line}");
}
}

for url in elem.package_homepage.iter() {
for url in &elem.package_homepage {
print!(" Homepage: ");
if hyperlinks {
print_hyperlink!(url, url);
} else {
println!("{}", url);
println!("{url}");
}
}

Expand All @@ -199,7 +225,7 @@ impl SearchArgs {
format!("file://{nixpkgs_path}/{position_trimmed}")
);
} else {
println!("{}", position);
println!("{position}");
}
}
}
Expand Down