Render Markdown in option docs for flakes and longDescription (#539)

This commit is contained in:
Naïm Favier 2022-10-28 15:49:15 +02:00 committed by GitHub
parent e7ceafb0d4
commit ba0b05b998
Failed to generate hash of commit
17 changed files with 356 additions and 325 deletions

View file

@ -1 +1 @@
31 32

5
flake-info/Cargo.lock generated
View file

@ -341,7 +341,6 @@ dependencies = [
"serde_path_to_error", "serde_path_to_error",
"sha2", "sha2",
"structopt", "structopt",
"tempfile",
"thiserror", "thiserror",
"tokio", "tokio",
"toml", "toml",
@ -866,9 +865,9 @@ dependencies = [
[[package]] [[package]]
name = "pandoc" name = "pandoc"
version = "0.8.8" version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eac785b7de8de25c5ec48b3a9df1be552de03906f99145ed6d7da3d696c0dbb" checksum = "2eb8469d27ed9fd7925629076a3675fea964c3f44c49662bdf549a8b7ddf0820"
dependencies = [ dependencies = [
"itertools", "itertools",
] ]

View file

@ -18,13 +18,12 @@ structopt = "0.3"
command-run = "0.13" command-run = "0.13"
env_logger = "0.9" env_logger = "0.9"
log = "0.4" log = "0.4"
tempfile = "3"
lazy_static = "1.4" lazy_static = "1.4"
fancy-regex = "0.6" fancy-regex = "0.6"
tokio = { version = "*", features = ["full"] } tokio = { version = "*", features = ["full"] }
reqwest = { version = "0.11", features = ["json", "blocking"] } reqwest = { version = "0.11", features = ["json", "blocking"] }
sha2 = "0.9" sha2 = "0.9"
pandoc = "0.8" pandoc = "0.8.10"
semver = "1.0" semver = "1.0"
elasticsearch = {git = "https://github.com/elastic/elasticsearch-rs", features = ["rustls-tls"], optional = true} elasticsearch = {git = "https://github.com/elastic/elasticsearch-rs", features = ["rustls-tls"], optional = true}

View file

@ -19,6 +19,7 @@ let
readPackages = system: drvs: lib.mapAttrsToList ( readPackages = system: drvs: lib.mapAttrsToList (
attribute_name: drv: ( attribute_name: drv: (
{ {
entry_type = "package";
attribute_name = attribute_name; attribute_name = attribute_name;
system = system; system = system;
name = drv.name; name = drv.name;
@ -35,6 +36,7 @@ let
readApps = system: apps: lib.mapAttrsToList ( readApps = system: apps: lib.mapAttrsToList (
attribute_name: app: ( attribute_name: app: (
{ {
entry_type = "app";
attribute_name = attribute_name; attribute_name = attribute_name;
system = system; system = system;
} }
@ -86,6 +88,7 @@ let
x; x;
in in
opt opt
// { entry_type = "option"; }
// applyOnAttr "default" substFunction // applyOnAttr "default" substFunction
// applyOnAttr "example" substFunction # (_: { __type = "function"; }) // applyOnAttr "example" substFunction # (_: { __type = "function"; })
// applyOnAttr "type" substFunction // applyOnAttr "type" substFunction

View file

@ -20,19 +20,20 @@ pkgs.rustPlatform.buildRustPackage rec {
libiconv libiconv
darwin.apple_sdk.frameworks.Security darwin.apple_sdk.frameworks.Security
]; ];
checkInputs = with pkgs; [ pandoc ]; checkInputs = with pkgs; [ pandoc ];
ROOTDIR = builtins.placeholder "out";
NIXPKGS_PANDOC_FILTERS_PATH = "${pkgs.path + "/doc/build-aux/pandoc-filters"}"; NIXPKGS_PANDOC_FILTERS_PATH = "${pkgs.path + "/doc/build-aux/pandoc-filters"}";
checkFlags = [ checkFlags = [
"--skip elastic::tests" "--skip elastic::tests"
"--skip nix_gc::tests"
]; ];
postInstall = '' postInstall = ''
cp -rt "$out" assets
wrapProgram $out/bin/flake-info \ wrapProgram $out/bin/flake-info \
--set NIXPKGS_PANDOC_FILTERS_PATH "${NIXPKGS_PANDOC_FILTERS_PATH}" \
--set NIXOS_CHANNELS '${builtins.toJSON nixosChannels}' \ --set NIXOS_CHANNELS '${builtins.toJSON nixosChannels}' \
--prefix PATH : ${pkgs.pandoc}/bin --prefix PATH : ${pkgs.pandoc}/bin
''; '';

View file

@ -6,3 +6,10 @@ pub use nix_check_version::{check_nix_version, NixCheckError};
pub use nix_flake_attrs::get_derivation_info; pub use nix_flake_attrs::get_derivation_info;
pub use nix_flake_info::get_flake_info; pub use nix_flake_info::get_flake_info;
pub use nixpkgs_info::{get_nixpkgs_info, get_nixpkgs_options}; pub use nixpkgs_info::{get_nixpkgs_info, get_nixpkgs_options};
use lazy_static::lazy_static;
use std::path::PathBuf;
lazy_static! {
static ref EXTRACT_SCRIPT: PathBuf = crate::DATADIR.join("commands/flake_info.nix");
}

View file

@ -3,11 +3,8 @@ use anyhow::{Context, Result};
use command_run::{Command, LogTo}; use command_run::{Command, LogTo};
use serde_json::Deserializer; use serde_json::Deserializer;
use std::fmt::Display; use std::fmt::Display;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf; use std::path::PathBuf;
const SCRIPT: &str = include_str!("flake_info.nix");
const ARGS: [&str; 4] = [ const ARGS: [&str; 4] = [
"eval", "eval",
"--json", "--json",
@ -23,12 +20,8 @@ pub fn get_derivation_info<T: AsRef<str> + Display>(
temp_store: bool, temp_store: bool,
extra: &[String], extra: &[String],
) -> Result<Vec<FlakeEntry>> { ) -> Result<Vec<FlakeEntry>> {
let script_dir = tempfile::tempdir()?;
let script_path = script_dir.path().join("extract.nix");
writeln!(File::create(&script_path)?, "{}", SCRIPT)?;
let mut command = Command::with_args("nix", ARGS.iter()); let mut command = Command::with_args("nix", ARGS.iter());
command.add_arg_pair("-f", script_path.as_os_str()); command.add_arg_pair("-f", super::EXTRACT_SCRIPT.clone());
command.add_arg_pair("-I", "nixpkgs=channel:nixpkgs-unstable"); command.add_arg_pair("-I", "nixpkgs=channel:nixpkgs-unstable");
command.add_args(["--override-flake", "input-flake", flake_ref.as_ref()].iter()); command.add_args(["--override-flake", "input-flake", flake_ref.as_ref()].iter());
command.add_args(["--argstr", "flake", flake_ref.as_ref()].iter()); command.add_args(["--argstr", "flake", flake_ref.as_ref()].iter());

View file

@ -1,15 +1,12 @@
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use serde_json::Deserializer; use serde_json::Deserializer;
use std::io::Write; use std::{collections::HashMap, fmt::Display};
use std::{collections::HashMap, fmt::Display, fs::File};
use command_run::{Command, LogTo}; use command_run::{Command, LogTo};
use log::error; use log::error;
use crate::data::import::{NixOption, NixpkgsEntry, Package}; use crate::data::import::{NixOption, NixpkgsEntry, Package};
const FLAKE_INFO_SCRIPT: &str = include_str!("flake_info.nix");
pub fn get_nixpkgs_info<T: AsRef<str> + Display>(nixpkgs_channel: T) -> Result<Vec<NixpkgsEntry>> { pub fn get_nixpkgs_info<T: AsRef<str> + Display>(nixpkgs_channel: T) -> Result<Vec<NixpkgsEntry>> {
let mut command = Command::new("nix-env"); let mut command = Command::new("nix-env");
command.add_args(&[ command.add_args(&[
@ -54,20 +51,10 @@ pub fn get_nixpkgs_info<T: AsRef<str> + Display>(nixpkgs_channel: T) -> Result<V
pub fn get_nixpkgs_options<T: AsRef<str> + Display>( pub fn get_nixpkgs_options<T: AsRef<str> + Display>(
nixpkgs_channel: T, nixpkgs_channel: T,
) -> Result<Vec<NixpkgsEntry>> { ) -> Result<Vec<NixpkgsEntry>> {
let script_dir = tempfile::tempdir()?; let mut command = Command::with_args("nix", &["eval", "--json"]);
let script_path = script_dir.path().join("flake_info.nix"); command.add_arg_pair("-f", super::EXTRACT_SCRIPT.clone());
writeln!(File::create(&script_path)?, "{}", FLAKE_INFO_SCRIPT)?; command.add_arg_pair("-I", format!("nixpkgs={}", nixpkgs_channel.as_ref()));
command.add_arg("nixos-options");
let mut command = Command::new("nix");
command.add_args(&[
"eval",
"--json",
"-f",
script_path.to_str().unwrap(),
"-I",
format!("nixpkgs={}", nixpkgs_channel.as_ref()).as_str(),
"nixos-options",
]);
command.enable_capture(); command.enable_capture();
command.log_to = LogTo::Log; command.log_to = LogTo::Log;

View file

@ -6,26 +6,14 @@ use std::{
path::PathBuf, path::PathBuf,
}; };
use super::{
import::{DocValue, ModulePath},
pandoc::PandocExt,
};
use crate::data::import::NixOption;
use anyhow::Context;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::{ use super::{
import, import::{self, DocString, DocValue, ModulePath, NixOption},
pandoc::PandocExt,
system::System, system::System,
utility::{AttributeQuery, Flatten, OneOrMany, Reverse}, utility::{AttributeQuery, Flatten, OneOrMany, Reverse},
}; };
use lazy_static::lazy_static;
lazy_static! {
static ref FILTERS_PATH: PathBuf = std::env::var("NIXPKGS_PANDOC_FILTERS_PATH")
.unwrap_or("".into())
.into();
}
type Flake = super::Flake; type Flake = super::Flake;
@ -107,8 +95,7 @@ pub enum Derivation {
option_name_query: AttributeQuery, option_name_query: AttributeQuery,
option_name_query_reverse: Reverse<AttributeQuery>, option_name_query_reverse: Reverse<AttributeQuery>,
option_description: Option<String>, option_description: Option<DocString>,
option_description_reverse: Option<Reverse<String>>,
option_type: Option<String>, option_type: Option<String>,
@ -147,7 +134,12 @@ impl TryFrom<(import::FlakeEntry, super::Flake)> for Derivation {
let package_attr_set_reverse = Reverse(package_attr_set.clone()); let package_attr_set_reverse = Reverse(package_attr_set.clone());
let package_license: Vec<License> = vec![license.into()]; let package_license: Vec<License> = license
.map(OneOrMany::into_list)
.unwrap_or_default()
.into_iter()
.map(|sos| sos.0.into())
.collect();
let package_license_set: Vec<String> = package_license let package_license_set: Vec<String> = package_license
.iter() .iter()
.clone() .clone()
@ -215,7 +207,7 @@ impl TryFrom<import::NixpkgsEntry> for Derivation {
let package_attr_set_reverse = Reverse(package_attr_set.clone()); let package_attr_set_reverse = Reverse(package_attr_set.clone());
let package_license: Vec<_> = package let package_license: Vec<License> = package
.meta .meta
.license .license
.map(OneOrMany::into_list) .map(OneOrMany::into_list)
@ -242,6 +234,12 @@ impl TryFrom<import::NixpkgsEntry> for Derivation {
.flat_map(|m| m.name.to_owned()) .flat_map(|m| m.name.to_owned())
.collect(); .collect();
let long_description = package
.meta
.long_description
.map(|s| s.render_markdown())
.transpose()?;
let position: Option<String> = package.meta.position.map(|p| { let position: Option<String> = package.meta.position.map(|p| {
if p.starts_with("/nix/store") { if p.starts_with("/nix/store") {
p.split("/").skip(4).collect::<Vec<&str>>().join("/") p.split("/").skip(4).collect::<Vec<&str>>().join("/")
@ -273,8 +271,8 @@ impl TryFrom<import::NixpkgsEntry> for Derivation {
package_maintainers_set, package_maintainers_set,
package_description: package.meta.description.clone(), package_description: package.meta.description.clone(),
package_description_reverse: package.meta.description.map(Reverse), package_description_reverse: package.meta.description.map(Reverse),
package_longDescription: package.meta.long_description.clone(), package_longDescription: long_description.clone(),
package_longDescription_reverse: package.meta.long_description.map(Reverse), package_longDescription_reverse: long_description.map(Reverse),
package_hydra: (), package_hydra: (),
package_system: package.system, package_system: package.system,
package_homepage: package package_homepage: package
@ -303,32 +301,13 @@ impl TryFrom<import::NixOption> for Derivation {
flake, flake,
}: import::NixOption, }: import::NixOption,
) -> Result<Self, Self::Error> { ) -> Result<Self, Self::Error> {
let description = description
.as_ref()
.map(PandocExt::render)
.transpose()
.with_context(|| format!("While rendering the description for option `{}`", name))?;
let option_default = default;
// .map(TryInto::try_into)
// .transpose()
// .with_context(|| format!("While rendering the default for option `{}`", name))?;
let option_example = example;
// .map(TryInto::try_into)
// .transpose()
// .with_context(|| format!("While rendering the example for option `{}`", name))?;
let option_type = option_type;
// .map(TryInto::try_into)
// .transpose()
// .with_context(|| format!("While rendering the type for option `{}`", name))?;
Ok(Derivation::Option { Ok(Derivation::Option {
option_source: declarations.get(0).map(Clone::clone), option_source: declarations.get(0).map(Clone::clone),
option_name: name.clone(), option_name: name.clone(),
option_name_reverse: Reverse(name.clone()), option_name_reverse: Reverse(name.clone()),
option_description: description.clone(), option_description: description,
option_description_reverse: description.map(Reverse), option_default: default,
option_default, option_example: example,
option_example,
option_flake: flake, option_flake: flake,
option_type, option_type,
option_name_query: AttributeQuery::new(&name), option_name_query: AttributeQuery::new(&name),

View file

@ -16,7 +16,7 @@ use super::utility::{Flatten, OneOrMany};
/// Holds information about a specific derivation /// Holds information about a specific derivation
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)] #[serde(tag = "entry_type", rename_all = "lowercase")]
pub enum FlakeEntry { pub enum FlakeEntry {
/// A package as it may be defined in a flake /// A package as it may be defined in a flake
/// ///
@ -31,8 +31,7 @@ pub enum FlakeEntry {
outputs: Vec<String>, outputs: Vec<String>,
default_output: String, default_output: String,
description: Option<String>, description: Option<String>,
#[serde(deserialize_with = "string_or_struct", default)] license: Option<OneOrMany<StringOrStruct<License>>>,
license: License,
}, },
/// An "application" that can be called using nix run <..> /// An "application" that can be called using nix run <..>
App { App {
@ -52,7 +51,7 @@ pub struct NixOption {
/// Location of the defining module(s) /// Location of the defining module(s)
pub declarations: Vec<String>, pub declarations: Vec<String>,
pub description: Option<String>, pub description: Option<DocString>,
pub name: String, pub name: String,
#[serde(rename = "type")] #[serde(rename = "type")]
@ -79,6 +78,20 @@ pub enum ModulePath {
NamedModule((String, String)), NamedModule((String, String)),
} }
#[derive(Debug, Clone, PartialEq, Deserialize)]
#[serde(untagged)]
pub enum DocString {
DocFormat(DocFormat),
String(String),
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
#[serde(tag = "_type", content = "text")]
pub enum DocFormat {
#[serde(rename = "mdDoc")]
MarkdownDoc(String),
}
#[derive(Debug, Clone, PartialEq, Deserialize)] #[derive(Debug, Clone, PartialEq, Deserialize)]
#[serde(untagged)] #[serde(untagged)]
pub enum DocValue { pub enum DocValue {
@ -89,12 +102,34 @@ pub enum DocValue {
#[derive(Debug, Clone, PartialEq, Deserialize)] #[derive(Debug, Clone, PartialEq, Deserialize)]
#[serde(tag = "_type", content = "text")] #[serde(tag = "_type", content = "text")]
pub enum Literal { pub enum Literal {
#[serde(rename = "literalExpression")] #[serde(rename = "literalExpression", alias = "literalExample")]
LiteralExpression(String), LiteralExpression(String),
#[serde(rename = "literalExample")]
LiteralExample(String),
#[serde(rename = "literalDocBook")] #[serde(rename = "literalDocBook")]
LiteralDocBook(String), LiteralDocBook(String),
#[serde(rename = "literalMD")]
LiteralMarkdown(String),
}
impl Serialize for DocString {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
DocString::String(db) => {
serializer.serialize_str(&db.render_docbook().unwrap_or_else(|e| {
warn!("Could not render DocBook content: {}", e);
db.to_owned()
}))
}
DocString::DocFormat(DocFormat::MarkdownDoc(md)) => {
serializer.serialize_str(&md.render_markdown().unwrap_or_else(|e| {
warn!("Could not render Markdown content: {}", e);
md.to_owned()
}))
}
}
}
} }
impl Serialize for DocValue { impl Serialize for DocValue {
@ -103,14 +138,18 @@ impl Serialize for DocValue {
S: Serializer, S: Serializer,
{ {
match self { match self {
DocValue::Literal(Literal::LiteralExample(s) | Literal::LiteralExpression(s)) => { DocValue::Literal(Literal::LiteralExpression(s)) => serializer.serialize_str(&s),
return serializer.serialize_str(&s); DocValue::Literal(Literal::LiteralDocBook(db)) => {
serializer.serialize_str(&db.render_docbook().unwrap_or_else(|e| {
warn!("Could not render DocBook content: {}", e);
db.to_owned()
}))
} }
DocValue::Literal(Literal::LiteralDocBook(doc_book)) => { DocValue::Literal(Literal::LiteralMarkdown(md)) => {
return serializer.serialize_str(&doc_book.render().unwrap_or_else(|e| { serializer.serialize_str(&md.render_markdown().unwrap_or_else(|e| {
warn!("Could not render docbook content: {}", e); warn!("Could not render Markdown content: {}", e);
doc_book.to_owned() md.to_owned()
})); }))
} }
DocValue::Value(v) => serializer.serialize_str(&print_value(v.to_owned())), DocValue::Value(v) => serializer.serialize_str(&print_value(v.to_owned())),
} }

View file

@ -1,48 +1,34 @@
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use pandoc::{ use std::path::{Path, PathBuf};
InputFormat, InputKind, OutputFormat, OutputKind, PandocError, PandocOption, PandocOutput,
};
const XREF_FILTER: &str = include_str!("fix-xrefs.lua"); use pandoc::*;
const FILTERS_PATH: &str = env!("NIXPKGS_PANDOC_FILTERS_PATH");
lazy_static! { lazy_static! {
static ref FILTERS_PATH: PathBuf = std::env::var("NIXPKGS_PANDOC_FILTERS_PATH") static ref DOCBOOK_ROLES_FILTER: PathBuf =
.unwrap_or("".into()) Path::new(FILTERS_PATH).join("docbook-reader/citerefentry-to-rst-role.lua");
.into(); static ref MARKDOWN_ROLES_FILTER: PathBuf =
Path::new(FILTERS_PATH).join("myst-reader/roles.lua");
static ref MANPAGE_LINK_FILTER: PathBuf =
Path::new(FILTERS_PATH).join("link-unix-man-references.lua");
static ref XREF_FILTER: PathBuf = crate::DATADIR.join("data/fix-xrefs.lua");
} }
pub trait PandocExt { pub trait PandocExt {
fn render(&self) -> Result<String, PandocError>; fn render_docbook(&self) -> Result<String, PandocError>;
fn render_markdown(&self) -> Result<String, PandocError>;
} }
impl<T: AsRef<str>> PandocExt for T { impl<T: AsRef<str>> PandocExt for T {
fn render(&self) -> Result<String, PandocError> { fn render_docbook(&self) -> Result<String, PandocError> {
if !self.as_ref().contains("<") { if !self.as_ref().contains("<") {
return Ok(format!( return Ok(format!(
"<rendered-docbook>{}</rendered-docbook>", "<rendered-html><p>{}</p></rendered-html>",
self.as_ref() self.as_ref()
)); ));
} }
let citeref_filter = {
let mut p = FILTERS_PATH.clone();
p.push("docbook-reader/citerefentry-to-rst-role.lua");
p
};
let man_filter = {
let mut p = FILTERS_PATH.clone();
p.push("link-unix-man-references.lua");
p
};
let tmpdir = tempfile::tempdir()?;
let xref_filter = tmpdir.path().join("fix-xrefs.lua");
writeln!(File::create(&xref_filter)?, "{}", XREF_FILTER)?;
let mut pandoc = pandoc::new();
let wrapper_xml = format!( let wrapper_xml = format!(
" "
<xml xmlns:xlink=\"http://www.w3.org/1999/xlink\"> <xml xmlns:xlink=\"http://www.w3.org/1999/xlink\">
@ -52,19 +38,52 @@ impl<T: AsRef<str>> PandocExt for T {
self.as_ref() self.as_ref()
); );
let mut pandoc = pandoc::new();
pandoc.set_input(InputKind::Pipe(wrapper_xml)); pandoc.set_input(InputKind::Pipe(wrapper_xml));
pandoc.set_input_format(InputFormat::DocBook, Vec::new()); pandoc.set_input_format(InputFormat::DocBook, Vec::new());
pandoc.set_output(OutputKind::Pipe); pandoc.set_output(OutputKind::Pipe);
pandoc.set_output_format(OutputFormat::Html, Vec::new()); pandoc.set_output_format(OutputFormat::Html, Vec::new());
pandoc.add_options(&[ pandoc.add_options(&[
PandocOption::LuaFilter(citeref_filter), PandocOption::LuaFilter(DOCBOOK_ROLES_FILTER.clone()),
PandocOption::LuaFilter(man_filter), PandocOption::LuaFilter(MANPAGE_LINK_FILTER.clone()),
PandocOption::LuaFilter(xref_filter), PandocOption::LuaFilter(XREF_FILTER.clone()),
]); ]);
pandoc.execute().map(|result| match result { pandoc.execute().map(|result| match result {
PandocOutput::ToBuffer(description) => { PandocOutput::ToBuffer(html) => {
format!("<rendered-docbook>{}</rendered-docbook>", description) format!("<rendered-html>{}</rendered-html>", html)
}
_ => unreachable!(),
})
}
fn render_markdown(&self) -> Result<String, PandocError> {
let mut pandoc = pandoc::new();
pandoc.set_input(InputKind::Pipe(self.as_ref().into()));
pandoc.set_input_format(
InputFormat::Commonmark,
[
MarkdownExtension::Attributes,
MarkdownExtension::BracketedSpans,
MarkdownExtension::DefinitionLists,
MarkdownExtension::FencedDivs,
MarkdownExtension::PipeTables,
MarkdownExtension::RawAttribute,
MarkdownExtension::Smart,
]
.to_vec(),
);
pandoc.set_output(OutputKind::Pipe);
pandoc.set_output_format(OutputFormat::Html, Vec::new());
pandoc.add_options(&[
PandocOption::LuaFilter(MARKDOWN_ROLES_FILTER.clone()),
PandocOption::LuaFilter(MANPAGE_LINK_FILTER.clone()),
PandocOption::LuaFilter(XREF_FILTER.clone()),
]);
pandoc.execute().map(|result| match result {
PandocOutput::ToBuffer(html) => {
format!("<rendered-html>{}</rendered-html>", html)
} }
_ => unreachable!(), _ => unreachable!(),
}) })

View file

@ -174,11 +174,6 @@ lazy_static! {
"analyzer": "english", "analyzer": "english",
"fields": {"edge": {"type": "text", "analyzer": "edge"}}, "fields": {"edge": {"type": "text", "analyzer": "edge"}},
}, },
"option_description_reverse": {
"type": "text",
"analyzer": "english",
"fields": {"edge": {"type": "text", "analyzer": "edge"}},
},
"option_type": {"type": "keyword"}, "option_type": {"type": "keyword"},
"option_default": {"type": "text"}, "option_default": {"type": "text"},
"option_example": {"type": "text"}, "option_example": {"type": "text"},

View file

@ -2,6 +2,8 @@
use anyhow::Result; use anyhow::Result;
use data::{import::Kind, Export, Flake, Source}; use data::{import::Kind, Export, Flake, Source};
use lazy_static::lazy_static;
use std::path::{Path, PathBuf};
pub mod commands; pub mod commands;
pub mod data; pub mod data;
@ -12,6 +14,11 @@ pub mod elastic;
pub use commands::get_flake_info; pub use commands::get_flake_info;
use log::trace; use log::trace;
lazy_static! {
static ref DATADIR: PathBuf =
Path::new(option_env!("ROOTDIR").unwrap_or(env!("CARGO_MANIFEST_DIR"))).join("assets");
}
pub fn process_flake( pub fn process_flake(
source: &Source, source: &Source,
kind: &data::import::Kind, kind: &data::import::Kind,

View file

@ -39,8 +39,6 @@ import Html.Events
exposing exposing
( onClick ( onClick
) )
import Html.Parser
import Html.Parser.Util
import Http exposing (Body) import Http exposing (Body)
import Json.Decode import Json.Decode
import Json.Decode.Pipeline import Json.Decode.Pipeline
@ -51,6 +49,7 @@ import Search
, NixOSChannel , NixOSChannel
, decodeResolvedFlake , decodeResolvedFlake
) )
import Utils
@ -185,17 +184,6 @@ viewResultItem :
-> Html Msg -> Html Msg
viewResultItem nixosChannels channel _ show item = viewResultItem nixosChannels channel _ show item =
let let
showHtml value =
case Html.Parser.run <| String.trim value of
Ok [ Html.Parser.Element "rendered-docbook" _ nodes ] ->
Just <| Html.Parser.Util.toVirtualDom nodes
Ok _ ->
Nothing
Err _ ->
Nothing
asPre value = asPre value =
pre [] [ text value ] pre [] [ text value ]
@ -210,7 +198,7 @@ viewResultItem nixosChannels channel _ show item =
, div [] [ asPreCode item.source.name ] , div [] [ asPreCode item.source.name ]
] ]
++ (item.source.description ++ (item.source.description
|> Maybe.andThen showHtml |> Maybe.andThen Utils.showHtml
|> Maybe.map |> Maybe.map
(\description -> (\description ->
[ div [] [ text "Description" ] [ div [] [ text "Description" ]
@ -232,7 +220,7 @@ viewResultItem nixosChannels channel _ show item =
|> Maybe.map |> Maybe.map
(\default -> (\default ->
[ div [] [ text "Default" ] [ div [] [ text "Default" ]
, div [] <| Maybe.withDefault [ asPreCode default ] (showHtml default) , div [] <| Maybe.withDefault [ asPreCode default ] (Utils.showHtml default)
] ]
) )
|> Maybe.withDefault [] |> Maybe.withDefault []
@ -241,7 +229,7 @@ viewResultItem nixosChannels channel _ show item =
|> Maybe.map |> Maybe.map
(\example -> (\example ->
[ div [] [ text "Example" ] [ div [] [ text "Example" ]
, div [] <| Maybe.withDefault [ asPreCode example ] (showHtml example) , div [] <| Maybe.withDefault [ asPreCode example ] (Utils.showHtml example)
] ]
) )
|> Maybe.withDefault [] |> Maybe.withDefault []

View file

@ -507,93 +507,93 @@ viewResultItem nixosChannels channel showInstallDetails show item =
[ div [ trapClick ] [ div [ trapClick ]
(div [] (div []
(item.source.longDescription (item.source.longDescription
|> Maybe.map (\desc -> [ p [] [ text desc ] ]) |> Maybe.andThen Utils.showHtml
|> Maybe.withDefault [] |> Maybe.withDefault []
) )
:: div [] :: div []
[ h4 [] [ h4 []
[ text "How to install " [ text "How to install "
, em [] [ text item.source.attr_name ] , em [] [ text item.source.attr_name ]
, text "?" , text "?"
]
, ul [ class "nav nav-tabs" ] <|
Maybe.withDefault
[ li
[ classList
[ ( "active", List.member showInstallDetails [ Search.Unset, Search.ViaNixShell, Search.FromFlake ] )
, ( "pull-right", True )
]
]
[ a
[ href "#"
, Search.onClickStop <|
SearchMsg <|
Search.ShowInstallDetails Search.ViaNixShell
]
[ text "nix-shell" ]
]
, li
[ classList
[ ( "active", showInstallDetails == Search.ViaNixOS )
, ( "pull-right", True )
]
]
[ a
[ href "#"
, Search.onClickStop <|
SearchMsg <|
Search.ShowInstallDetails Search.ViaNixOS
]
[ text "NixOS Configuration" ]
]
, li
[ classList
[ ( "active", showInstallDetails == Search.ViaNixEnv )
, ( "pull-right", True )
]
]
[ a
[ href "#"
, Search.onClickStop <|
SearchMsg <|
Search.ShowInstallDetails Search.ViaNixEnv
]
[ text "nix-env" ]
]
] ]
<| , ul [ class "nav nav-tabs" ] <|
Maybe.map Maybe.withDefault
(\_ -> [ li
[ li [ classList
[ classList [ ( "active", List.member showInstallDetails [ Search.Unset, Search.ViaNixShell, Search.FromFlake ] )
[ ( "active", True ) , ( "pull-right", True )
, ( "pull-right", True )
]
]
[ a
[ href "#"
, Search.onClickStop <|
SearchMsg <|
Search.ShowInstallDetails Search.FromFlake
]
[ text "Install from flake" ]
] ]
] ]
) [ a
item.source.flakeUrl [ href "#"
, div , Search.onClickStop <|
[ class "tab-content" ] SearchMsg <|
<| Search.ShowInstallDetails Search.ViaNixShell
Maybe.withDefault ]
[ div [ text "nix-shell" ]
[ classList ]
[ ( "tab-pane", True ) , li
, ( "active", showInstallDetails == Search.ViaNixEnv ) [ classList
[ ( "active", showInstallDetails == Search.ViaNixOS )
, ( "pull-right", True )
]
]
[ a
[ href "#"
, Search.onClickStop <|
SearchMsg <|
Search.ShowInstallDetails Search.ViaNixOS
]
[ text "NixOS Configuration" ]
]
, li
[ classList
[ ( "active", showInstallDetails == Search.ViaNixEnv )
, ( "pull-right", True )
]
]
[ a
[ href "#"
, Search.onClickStop <|
SearchMsg <|
Search.ShowInstallDetails Search.ViaNixEnv
]
[ text "nix-env" ]
] ]
] ]
[ p [] <|
[ strong [] [ text "Warning:" ] Maybe.map
, text """ (\_ ->
[ li
[ classList
[ ( "active", True )
, ( "pull-right", True )
]
]
[ a
[ href "#"
, Search.onClickStop <|
SearchMsg <|
Search.ShowInstallDetails Search.FromFlake
]
[ text "Install from flake" ]
]
]
)
item.source.flakeUrl
, div
[ class "tab-content" ]
<|
Maybe.withDefault
[ div
[ classList
[ ( "tab-pane", True )
, ( "active", showInstallDetails == Search.ViaNixEnv )
]
]
[ p []
[ strong [] [ text "Warning:" ]
, text """
Using nix-env permanently modifies a Using nix-env permanently modifies a
local profile of installed packages. local profile of installed packages.
This must be cleaned up, updated and This must be cleaned up, updated and
@ -603,124 +603,124 @@ viewResultItem nixosChannels channel showInstallDetails show item =
configuration is recommended configuration is recommended
instead. instead.
""" """
]
] ]
] , div
, div [ classList
[ classList [ ( "active", showInstallDetails == Search.ViaNixEnv )
[ ( "active", showInstallDetails == Search.ViaNixEnv ) ]
, class "tab-pane"
] ]
, class "tab-pane" [ p []
] [ strong [] [ text "On NixOS:" ] ]
[ p []
[ strong [] [ text "On NixOS:" ] ]
]
, div
[ classList
[ ( "active", showInstallDetails == Search.ViaNixEnv )
] ]
, class "tab-pane" , div
, id "package-details-nixpkgs" [ classList
] [ ( "active", showInstallDetails == Search.ViaNixEnv )
[ pre [ class "code-block shell-command" ] ]
[ text "nix-env -iA nixos." , class "tab-pane"
, strong [] [ text item.source.attr_name ] , id "package-details-nixpkgs"
] ]
] [ pre [ class "code-block shell-command" ]
, div [] [ p [] [] ] [ text "nix-env -iA nixos."
, div , strong [] [ text item.source.attr_name ]
[ classList ]
[ ( "active", showInstallDetails == Search.ViaNixEnv )
] ]
, class "tab-pane" , div [] [ p [] [] ]
] , div
[ p [] [ classList
[ strong [] [ text "On Non NixOS:" ] ] [ ( "active", showInstallDetails == Search.ViaNixEnv )
] ]
, div , class "tab-pane"
[ classList
[ ( "active", showInstallDetails == Search.ViaNixEnv )
] ]
, class "tab-pane" [ p []
, id "package-details-nixpkgs" [ strong [] [ text "On Non NixOS:" ] ]
]
[ pre [ class "code-block shell-command" ]
[ text "nix-env -iA nixpkgs."
, strong [] [ text item.source.attr_name ]
] ]
] , div
, div [ classList
[ classList [ ( "active", showInstallDetails == Search.ViaNixEnv )
[ ( "tab-pane", True ) ]
, ( "active", showInstallDetails == Search.ViaNixOS ) , class "tab-pane"
, id "package-details-nixpkgs"
] ]
] [ pre [ class "code-block shell-command" ]
[ p [] [ text "nix-env -iA nixpkgs."
[ text "Add the following Nix code to your NixOS Configuration, usually located in " , strong [] [ text item.source.attr_name ]
, strong [] [ text "/etc/nixos/configuration.nix" ] ]
] ]
] , div
, div [ classList
[ classList [ ( "tab-pane", True )
[ ( "active", showInstallDetails == Search.ViaNixOS ) , ( "active", showInstallDetails == Search.ViaNixOS )
]
] ]
, class "tab-pane" [ p []
, id "package-details-nixpkgs" [ text "Add the following Nix code to your NixOS Configuration, usually located in "
] , strong [] [ text "/etc/nixos/configuration.nix" ]
[ pre [ class "code-block" ] ]
[ text <| " environment.systemPackages = [\n pkgs."
, strong [] [ text item.source.attr_name ]
, text <| "\n ];"
] ]
] , div
, div [ classList
[ classList [ ( "active", showInstallDetails == Search.ViaNixOS )
[ ( "tab-pane", True ) ]
, ( "active", List.member showInstallDetails [ Search.Unset, Search.ViaNixShell, Search.FromFlake ] ) , class "tab-pane"
, id "package-details-nixpkgs"
] ]
] [ pre [ class "code-block" ]
[ p [] [ text <| " environment.systemPackages = [\n pkgs."
[ text """ , strong [] [ text item.source.attr_name ]
, text <| "\n ];"
]
]
, div
[ classList
[ ( "tab-pane", True )
, ( "active", List.member showInstallDetails [ Search.Unset, Search.ViaNixShell, Search.FromFlake ] )
]
]
[ p []
[ text """
A nix-shell will temporarily modify A nix-shell will temporarily modify
your $PATH environment variable. your $PATH environment variable.
This can be used to try a piece of This can be used to try a piece of
software before deciding to software before deciding to
permanently install it. permanently install it.
""" """
]
]
, div
[ classList
[ ( "tab-pane", True )
, ( "active", List.member showInstallDetails [ Search.Unset, Search.ViaNixShell, Search.FromFlake ] )
]
]
[ pre [ class "code-block shell-command" ]
[ text "nix-shell -p "
, strong [] [ text item.source.attr_name ]
]
]
]
<|
Maybe.map
(\url ->
[ div
[ classList
[ ( "tab-pane", True )
, ( "active", True )
]
]
[ pre [ class "code-block shell-command" ]
[ text "nix build "
, strong [] [ text url ]
, text "#"
, em [] [ text item.source.attr_name ]
]
] ]
] ]
) , div
[ classList
[ ( "tab-pane", True )
, ( "active", List.member showInstallDetails [ Search.Unset, Search.ViaNixShell, Search.FromFlake ] )
]
]
[ pre [ class "code-block shell-command" ]
[ text "nix-shell -p "
, strong [] [ text item.source.attr_name ]
]
]
]
<| <|
Maybe.map Tuple.first item.source.flakeUrl Maybe.map
] (\url ->
[ div
[ classList
[ ( "tab-pane", True )
, ( "active", True )
]
]
[ pre [ class "code-block shell-command" ]
[ text "nix build "
, strong [] [ text url ]
, text "#"
, em [] [ text item.source.attr_name ]
]
]
]
)
<|
Maybe.map Tuple.first item.source.flakeUrl
]
:: maintainersAndPlatforms :: maintainersAndPlatforms
) )
] ]

View file

@ -1,4 +1,10 @@
module Utils exposing (toggleList) module Utils exposing
( showHtml
, toggleList
)
import Html.Parser
import Html.Parser.Util
toggleList : toggleList :
@ -11,3 +17,12 @@ toggleList list item =
else else
List.append list [ item ] List.append list [ item ]
showHtml value =
case Html.Parser.run <| String.trim value of
Ok [ Html.Parser.Element "rendered-html" _ nodes ] ->
Just <| Html.Parser.Util.toVirtualDom nodes
_ ->
Nothing