From e39a9b1ab5bf3b0818306d937d25f15c743097ef Mon Sep 17 00:00:00 2001 From: Marcel <34819524+MarcelCoding@users.noreply.github.com> Date: Mon, 14 Oct 2024 15:39:45 +0200 Subject: [PATCH] declaration: allow store paths (#11) --- Cargo.lock | 1 + ixx/src/action/index.rs | 113 +++++++++++++++++++++++++++++++--------- ixx/src/args.rs | 5 +- ixx/src/option.rs | 16 +++--- libixx/Cargo.toml | 1 + libixx/src/option.rs | 3 +- 6 files changed, 106 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1edd0b9..758af3c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -249,6 +249,7 @@ dependencies = [ "serde", "serde_json", "thiserror", + "url", ] [[package]] diff --git a/ixx/src/action/index.rs b/ixx/src/action/index.rs index d7d17c6..24554ba 100644 --- a/ixx/src/action/index.rs +++ b/ixx/src/action/index.rs @@ -1,9 +1,10 @@ use std::{ collections::{BTreeMap, HashMap}, fs::File, - path::{Path, PathBuf}, + path::PathBuf, }; +use anyhow::anyhow; use libixx::Index; use serde::Deserialize; use url::Url; @@ -23,7 +24,7 @@ pub(crate) struct Config { #[serde(rename_all = "camelCase")] pub(crate) struct Scope { options_json: PathBuf, - url_prefix: Option, + url_prefix: Url, options_prefix: Option, } @@ -48,7 +49,7 @@ pub(crate) fn index(module: IndexModule) -> anyhow::Result<()> { Some(prefix) => format!("{}.{}", prefix, name), None => name, }; - let option = into_option(&name, option); + let option = into_option(&scope.url_prefix, &name, option)?; raw_options.insert(name, option); } } @@ -58,52 +59,114 @@ pub(crate) fn index(module: IndexModule) -> anyhow::Result<()> { let mut index = Index::default(); raw_options.keys().for_each(|name| index.push(name)); - println!("Writing index to {}", module.output.to_string_lossy()); + println!("Writing index to {}", module.index_output.to_string_lossy()); - let mut output = File::create(module.output)?; + let mut output = File::create(module.index_output)?; index.write_into(&mut output)?; - println!("Writing meta"); + println!("Writing meta to {}", module.meta_output.to_string_lossy()); - if !Path::new("meta").exists() { - std::fs::create_dir("meta")?; + if !module.meta_output.exists() { + std::fs::create_dir(&module.meta_output)?; } let options: Vec = raw_options.into_values().collect(); for (idx, chunk) in options.chunks(module.chunk_size).enumerate() { - let mut file = File::create(format!("meta/{}.json", idx))?; + let mut file = File::create(module.meta_output.join(format!("{}.json", idx)))?; serde_json::to_writer(&mut file, &chunk)?; } Ok(()) } -fn into_option(name: &str, option: option::Option) -> libixx::Option { - libixx::Option { +fn into_option( + url_prefix: &Url, + name: &str, + option: option::Option, +) -> anyhow::Result { + Ok(libixx::Option { declarations: option .declarations .into_iter() - .map(update_declaration) - .collect(), + .map(|declaration| update_declaration(url_prefix, declaration)) + .collect::>()?, default: option.default.map(|option| option.render()), description: option.description, example: option.example.map(|example| example.render()), read_only: option.read_only, r#type: option.r#type, name: name.to_string(), + }) +} + +fn update_declaration(url_prefix: &Url, declaration: Declaration) -> anyhow::Result { + match declaration { + Declaration::StorePath(path) => { + let idx = path + .match_indices('/') + .nth(3) + .ok_or_else(|| anyhow!("Invalid store path: {}", path))? + .0 + // +1 to also remove the / itself, when we join it with a url, the path in the url would + // get removed if we won't remove it. + + 1; + Ok(url_prefix.join(path.split_at(idx).1)?) + } + Declaration::Url { name: _, url } => Ok(url), } } -fn update_declaration(declaration: Declaration) -> String { - // NOTE: Is the url actually optional? If its true, this can be ignored. - // Otherwise the fallback with building the url outself is required. - // - // if "url" in declaration: - // return declaration["url"] - // if declaration.startswith("/nix/store/"): - // # strip prefix: /nix/store/0a0mxyfmad6kaknkkr0ysraifws856i7-source - // return f"{url}{declaration[51:]}" - // return declaration - - declaration.url +#[cfg(test)] +mod test { + use url::Url; + + use crate::{action::index::update_declaration, option::Declaration}; + + #[test] + fn test_update_declaration() { + assert_eq!( + update_declaration( + &Url::parse("https://example.com/some/path").unwrap(), + Declaration::StorePath( + "/nix/store/vgvk6q3zsjgb66f8s5cm8djz6nmcag1i-source/modules/initrd.nix".to_string() + ) + ) + .unwrap(), + Url::parse("https://example.com/some/modules/initrd.nix").unwrap() + ); + + assert_eq!( + update_declaration( + &Url::parse("https://example.com/some/path/").unwrap(), + Declaration::StorePath( + "/nix/store/vgvk6q3zsjgb66f8s5cm8djz6nmcag1i-source/modules/initrd.nix".to_string() + ) + ) + .unwrap(), + Url::parse("https://example.com/some/path/modules/initrd.nix").unwrap() + ); + + assert_eq!( + update_declaration( + &Url::parse("https://example.com/some/path/").unwrap(), + Declaration::StorePath( + "/nix/store/vgvk6q3zsjgb66f8s5cm8djz6nmcag1i-source-idk/modules/initrd.nix".to_string() + ) + ) + .unwrap(), + Url::parse("https://example.com/some/path/modules/initrd.nix").unwrap() + ); + + assert_eq!( + update_declaration( + &Url::parse("https://example.com/some/path").unwrap(), + Declaration::Url { + name: "idk".to_string(), + url: Url::parse("https://example.com/some/path").unwrap(), + } + ) + .unwrap(), + Url::parse("https://example.com/some/path").unwrap() + ); + } } diff --git a/ixx/src/args.rs b/ixx/src/args.rs index 92d008c..0c86415 100644 --- a/ixx/src/args.rs +++ b/ixx/src/args.rs @@ -18,7 +18,10 @@ pub(super) struct IndexModule { pub(super) config: PathBuf, #[clap(short, long, default_value = "index.ixx")] - pub(super) output: PathBuf, + pub(super) index_output: PathBuf, + + #[clap(short, long, default_value = "meta")] + pub(crate) meta_output: PathBuf, #[clap(short, long, default_value = "100")] pub(super) chunk_size: usize, diff --git a/ixx/src/option.rs b/ixx/src/option.rs index 337ea02..0dc34af 100644 --- a/ixx/src/option.rs +++ b/ixx/src/option.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use url::Url; use crate::utils::highlight; @@ -15,12 +16,15 @@ pub struct Option { pub related_packages: std::option::Option, } -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct Declaration { - // TODO: is this optional? - pub name: String, - pub url: String, +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase", untagged)] +pub enum Declaration { + /// Example Value: `/nix/store/vgvk6q3zsjgb66f8s5cm8djz6nmcag1i-source/modules/initrd.nix` + StorePath(String), + Url { + name: String, + url: Url, + }, } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] diff --git a/libixx/Cargo.toml b/libixx/Cargo.toml index 4ca5bbe..10fd2ff 100644 --- a/libixx/Cargo.toml +++ b/libixx/Cargo.toml @@ -7,6 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] serde = { version = "1.0", features = ["derive"] } +url = { version = "2.5", features = ["serde"] } thiserror = "1.0" binrw = "0.14" diff --git a/libixx/src/option.rs b/libixx/src/option.rs index c253174..19e1a02 100644 --- a/libixx/src/option.rs +++ b/libixx/src/option.rs @@ -1,8 +1,9 @@ use serde::{Deserialize, Serialize}; +use url::Url; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Option { - pub declarations: Vec, + pub declarations: Vec, pub default: std::option::Option, pub description: String, pub example: std::option::Option,