Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion crates/nix_health/crate.nix
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ in
inherit (rust-project.crates."nix_rs".crane.args)
DEVOUR_FLAKE
DEFAULT_FLAKE_SCHEMAS
NIX_FLAKE_SCHEMAS_BIN
INSPECT_FLAKE
;
nativeBuildInputs = with pkgs; [
nix # Tests need nix cli
Expand Down
2 changes: 1 addition & 1 deletion crates/nix_rs/crate.nix
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ in
name = "flake-schemas";
src = flake.inputs.self + /nix/flake-schemas;
};
NIX_FLAKE_SCHEMAS_BIN = lib.getExe pkgs.nix-flake-schemas;
INSPECT_FLAKE = inputs.inspect;
};
};
}
2 changes: 1 addition & 1 deletion crates/nix_rs/src/flake/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ impl Flake {
nix_config: &NixConfig,
url: FlakeUrl,
) -> Result<Flake, NixCmdError> {
let output = FlakeOutputs::from_nix(nix_cmd, &url).await?;
let output = FlakeOutputs::from_nix(nix_cmd, &url, &nix_config.system.value).await?;
let schema = FlakeSchema::from(&output, &nix_config.system.value);
Ok(Flake {
url,
Expand Down
106 changes: 46 additions & 60 deletions crates/nix_rs/src/flake/outputs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,69 @@ use std::{
fmt::Display,
};

/// Absolute path to the `nix` binary compiled with flake schemas support
/// Flake URL of the default flake schemas
///
/// We expect this environment to be set in Nix build and shell.
pub const NIX_FLAKE_SCHEMAS_BIN: &str = env!("NIX_FLAKE_SCHEMAS_BIN");
pub const DEFAULT_FLAKE_SCHEMAS: &str = env!("DEFAULT_FLAKE_SCHEMAS");

/// Flake URL of the default flake schemas
/// Flake URL of the flake that defines functions for inspecting flake outputs
///
/// We expect this environment to be set in Nix build and shell.
pub const DEFAULT_FLAKE_SCHEMAS: &str = env!("DEFAULT_FLAKE_SCHEMAS");
pub const INSPECT_FLAKE: &str = env!("INSPECT_FLAKE");

/// Represents the "outputs" of a flake
///
/// This structure is currently produced by `nix flake show`, thus to parse it we must toggle serde untagged.
/// TODO: Rename this to `FlakeSchema` while generalizing the existing `schema.rs` module.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum FlakeOutputs {
pub struct FlakeOutputs {
pub inventory: BTreeMap<String, InventoryItem>,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum InventoryItem {
Leaf(Leaf),
Attrset(BTreeMap<String, FlakeOutputs>),
Attrset(BTreeMap<String, InventoryItem>),
}

impl FlakeOutputs {
/// Run `nix flake show` on the given flake url
pub async fn from_nix(
nix_cmd: &crate::command::NixCmd,
flake_url: &super::url::FlakeUrl,
system: &super::System,
) -> Result<Self, crate::command::NixCmdError> {
let v = FlakeOutputsUntagged::from_nix(nix_cmd, flake_url).await?;
Ok(v.into_flake_outputs())
let v = nix_cmd
.run_with_args_expecting_json(&[
"eval",
"--json",
"--override-input",
"flake-schemas",
env!("DEFAULT_FLAKE_SCHEMAS"),
"--override-input",
"flake",
flake_url,
"--override-input",
"systems",
// TODO: Move `SystemsListFlakeRef` to `nix_rs` and use it here.
&format!("github:nix-systems/{}", system),
"--no-write-lock-file",
// Why `exculdingOutputPaths`?
// This function is much faster than `includingOutputPaths` and also solves <https://github.com/juspay/omnix/discussions/231>
// Also See: https://github.com/DeterminateSystems/inspect/blob/7f0275abbdc46b3487ca69e2acd932ce666a03ff/flake.nix#L139
//
//
// Note: We might need to use `includingOutputPaths` in the future, when replacing `devour-flake`.
// In which case, `om ci` and `om show` can invoke the appropriate function from `INSPECT_FLAKE`.
//
&format!("{}#contents.excludingOutputPaths", env!("INSPECT_FLAKE")),
])
.await?;
Ok(v)
}
}

impl InventoryItem {
/// Get the non-attrset leaf
pub fn as_leaf(&self) -> Option<&Leaf> {
match self {
Expand All @@ -44,7 +78,7 @@ impl FlakeOutputs {
}

/// Ensure the value is an attrset, and get it
pub fn as_attrset(&self) -> Option<&BTreeMap<String, FlakeOutputs>> {
pub fn as_attrset(&self) -> Option<&BTreeMap<String, InventoryItem>> {
match self {
Self::Attrset(v) => Some(v),
_ => None,
Expand All @@ -55,8 +89,8 @@ impl FlakeOutputs {
///
/// # Example
/// ```no_run
/// let tree : &nix_rs::flake::outputs::FlakeOutputs = todo!();
/// let val = tree.pop(&["packages", "aarch64-darwin", "default"]);
/// let tree : &nix_rs::flake::outputs::InventoryItem = todo!();
/// let val = tree.pop(&["aarch64-darwin", "default"]);
/// ```
pub fn pop(&mut self, path: &[&str]) -> Option<Self> {
let mut curr = self;
Expand Down Expand Up @@ -193,51 +227,3 @@ impl Display for Type {
f.write_str(&format!("{:?}", self))
}
}

/// This type is identical to [FlakeOutputs] except for the serde untagged attribute, which enables parsing the JSON output of `nix flake show`.
///
/// This separation exists to workaround <https://github.com/DioxusLabs/dioxus-std/issues/20>
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(untagged)]
enum FlakeOutputsUntagged {
ULeaf(Leaf),
UAttrset(BTreeMap<String, FlakeOutputsUntagged>),
}

impl FlakeOutputsUntagged {
/// Run `nix flake show` on the given flake url
#[tracing::instrument(name = "flake-show")]
async fn from_nix(
nix_cmd: &crate::command::NixCmd,
flake_url: &super::url::FlakeUrl,
) -> Result<Self, crate::command::NixCmdError> {
let mut nix_flake_schemas_cmd = nix_cmd.clone();
nix_flake_schemas_cmd.command = Some(env!("NIX_FLAKE_SCHEMAS_BIN").to_string());

let v = nix_flake_schemas_cmd
.run_with_args_expecting_json(&[
"flake",
"show",
"--legacy", // for showing nixpkgs legacyPackages
"--allow-import-from-derivation",
"--json",
"--default-flake-schemas",
env!("DEFAULT_FLAKE_SCHEMAS"),
flake_url,
])
.await?;
Ok(v)
}

/// Convert to [FlakeOutputs]
fn into_flake_outputs(self) -> FlakeOutputs {
match self {
Self::ULeaf(v) => FlakeOutputs::Leaf(v),
Self::UAttrset(v) => FlakeOutputs::Attrset(
v.into_iter()
.map(|(k, v)| (k, v.into_flake_outputs()))
.collect(),
),
}
}
}
76 changes: 43 additions & 33 deletions crates/nix_rs/src/flake/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};

use super::{
outputs::{FlakeOutputs, Leaf},
outputs::{FlakeOutputs, InventoryItem, Leaf},
System,
};

Expand All @@ -31,7 +31,7 @@ pub struct FlakeSchema {
pub templates: BTreeMap<String, Leaf>,
pub schemas: BTreeMap<String, Leaf>,
/// Other unrecognized keys.
pub other: Option<BTreeMap<String, FlakeOutputs>>,
pub other: Option<FlakeOutputs>,
}

impl FlakeSchema {
Expand All @@ -41,35 +41,39 @@ impl FlakeSchema {
/// as is (in [FlakeSchema::other]).
pub fn from(output: &FlakeOutputs, system: &System) -> Self {
let output: &mut FlakeOutputs = &mut output.clone();
let pop_tree = |output: &mut FlakeOutputs, ks: &[&str]| -> BTreeMap<String, Leaf> {
let mut f = || -> Option<BTreeMap<String, Leaf>> {
let out = output.pop(ks)?;
let outs = out.as_attrset()?;
let r = outs
.iter()
.filter_map(|(k, v)| {
let v = v.as_leaf()?;
Some((k.clone(), v.clone()))
})
.collect();
Some(r)
};
let mr = f();
output.pop(ks);
mr.unwrap_or(BTreeMap::new())
let pop_tree = |inventory_item: &mut Option<&mut InventoryItem>,
ks: &[&str]|
-> BTreeMap<String, Leaf> {
let mut result = BTreeMap::new();

if let Some(item) = inventory_item {
if let Some(out) = item.pop(ks) {
if let Some(outs) = out.as_attrset() {
for (k, v) in outs {
if let Some(leaf) = v.as_leaf() {
result.insert(k.clone(), leaf.clone());
}
}
}
}
item.pop(ks);
}

result
};
let pop_per_system_tree = |output: &mut FlakeOutputs, k: &str| -> BTreeMap<String, Leaf> {
pop_tree(
output,
&[k, "output", "children", system.as_ref(), "children"],
&mut output.inventory.get_mut(k),
&["children", system.as_ref(), "children"],
)
};
let pop_leaf_type = |output: &mut FlakeOutputs, k: &str| -> Option<Leaf> {
let leaf = output
.pop(&[k, "output", "children", system.as_ref()])?
let inventory_item = output.inventory.get_mut(k)?;
let leaf = inventory_item
.pop(&["children", system.as_ref()])?
.as_leaf()?
.clone();
output.pop(&[k]);
inventory_item.pop(&[k]);
Some(leaf)
};

Expand All @@ -81,18 +85,24 @@ impl FlakeSchema {
checks: pop_per_system_tree(output, "checks"),
apps: pop_per_system_tree(output, "apps"),
formatter: pop_leaf_type(output, "formatter"),
nixos_configurations: pop_tree(output, &["nixosConfigurations", "output", "children"]),
nixos_configurations: pop_tree(
&mut output.inventory.get_mut("nixosConfigurations"),
&["children"],
),
darwin_configurations: pop_tree(
output,
&["darwinConfigurations", "output", "children"],
&mut output.inventory.get_mut("darwinConfigurations"),
&["children"],
),
home_configurations: pop_tree(
&mut output.inventory.get_mut("homeConfigurations"),
&["children"],
),
home_configurations: pop_tree(output, &["homeConfigurations", "output", "children"]),
nixos_modules: pop_tree(output, &["nixosModules", "output", "children"]),
docker_images: pop_tree(output, &["dockerImages", "output", "children"]),
overlays: pop_tree(output, &["overlays", "output", "children"]),
templates: pop_tree(output, &["templates", "output", "children"]),
schemas: pop_tree(output, &["schemas", "output", "children"]),
other: (*output).as_attrset().cloned(),
nixos_modules: pop_tree(&mut output.inventory.get_mut("nixosModules"), &["children"]),
docker_images: pop_tree(&mut output.inventory.get_mut("dockerImages"), &["children"]),
overlays: pop_tree(&mut output.inventory.get_mut("overlays"), &["children"]),
templates: pop_tree(&mut output.inventory.get_mut("templates"), &["children"]),
schemas: pop_tree(&mut output.inventory.get_mut("schemas"), &["children"]),
other: Some(output.clone()),
}
}
}
2 changes: 1 addition & 1 deletion crates/nixci/crate.nix
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ in
inherit (rust-project.crates."nix_rs".crane.args)
DEVOUR_FLAKE
DEFAULT_FLAKE_SCHEMAS
NIX_FLAKE_SCHEMAS_BIN
INSPECT_FLAKE
;
OMNIX_SOURCE = inputs.self;
};
Expand Down
2 changes: 1 addition & 1 deletion crates/omnix-cli/crate.nix
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ in
inherit (rust-project.crates."nix_rs".crane.args)
DEVOUR_FLAKE
DEFAULT_FLAKE_SCHEMAS
NIX_FLAKE_SCHEMAS_BIN
INSPECT_FLAKE
;
inherit (rust-project.crates."nixci".crane.args)
OMNIX_SOURCE
Expand Down
5 changes: 3 additions & 2 deletions crates/omnix-cli/src/command/show.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,9 @@ impl Row {
name,
description: leaf
.as_val()
.and_then(|val| val.short_description.as_deref())
.unwrap_or("N/A")
.and_then(|val| val.short_description.as_ref())
.filter(|s| !s.is_empty())
.unwrap_or(&String::from("N/A"))
.to_owned(),
})
.collect()
Expand Down
2 changes: 1 addition & 1 deletion crates/omnix-cli/tests/command/show.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use super::core::om;
/// `om show` runs, and succeeds for a local flake.
#[test]
fn om_show_local() -> anyhow::Result<()> {
om()?.arg("show").arg(".").assert().success().stdout(
om()?.arg("show").arg("../..").assert().success().stdout(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nix flake show walks up the directory tree to find the flake, while nix eval doesn't

contains("Packages")
.and(contains("Apps"))
.and(contains("Devshells"))
Expand Down
2 changes: 1 addition & 1 deletion crates/omnix-common/crate.nix
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
inherit (rust-project.crates."nix_rs".crane.args)
DEVOUR_FLAKE
DEFAULT_FLAKE_SCHEMAS
NIX_FLAKE_SCHEMAS_BIN
INSPECT_FLAKE
;
};
};
Expand Down
1 change: 0 additions & 1 deletion crates/omnix-gui/crate.nix
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ in
dioxus-cli
pkgs.nix # cargo tests need nix
];
NIX_FLAKE_SCHEMAS_BIN = lib.getExe pkgs.nix-flake-schemas;
inherit (rust-project.crates."omnix-cli".crane.args)
DEFAULT_FLAKE_SCHEMAS;
meta.description = "Graphical user interface for Omnix";
Expand Down
2 changes: 1 addition & 1 deletion crates/omnix-init/crate.nix
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
inherit (rust-project.crates."nix_rs".crane.args)
DEVOUR_FLAKE
DEFAULT_FLAKE_SCHEMAS
NIX_FLAKE_SCHEMAS_BIN
INSPECT_FLAKE
;
OM_INIT_REGISTRY =
lib.cleanSourceWith {
Expand Down
Loading