Support flake attr nixosModule (#401)

* flake_info.nix: remove helper fn `default`

Nix has builtin syntax for fetching attrs with a default value.

* flake_info.nix: minor refactor

- Remove commented out code
- Simplify pkg filtering
- Break overlong line

* flake_info.nix: support flake attr `nixosModule`

* Support default modules in rust backend and elm

Co-authored-by: Yannik Sander <me@ysndr.de>
This commit is contained in:
erikarvstedt 2022-01-06 15:42:31 +01:00 committed by GitHub
parent 32700e3eee
commit 096ea9e49c
Failed to generate hash of commit
4 changed files with 99 additions and 54 deletions

View file

@ -5,43 +5,32 @@ let
nixpkgs = (import <nixpkgs> {});
lib = nixpkgs.lib;
default = drv: attr: default: if drv ? ${attr} then drv.${attr} else default;
# filter = lib.filterAttrs (key: _ : key == "apps" || key == "packages");
withSystem = fn: lib.mapAttrs (system: drvs: (fn system drvs));
isValid = d:
let
r = builtins.tryEval (lib.isDerivation d && ! (lib.attrByPath [ "meta" "broken" ] false d) && builtins.seq d.name true && d ? outputs);
r = builtins.tryEval (lib.isDerivation d && ! (lib.attrByPath [ "meta" "broken" ] false d) &&
builtins.seq d.name true && d ? outputs);
in
r.success && r.value;
all = pkgs:
let
validPkgs = lib.filterAttrs (k: v: isValid v) pkgs;
in
validPkgs;
validPkgs = lib.filterAttrs (k: v: isValid v);
readPackages = system: drvs: lib.mapAttrsToList (
attribute_name: drv: (
# if isValid drv then
{
attribute_name = attribute_name;
system = system;
name = drv.name;
# TODO consider using `builtins.parseDrvName`
version = default drv "version" "";
version = drv.version or "";
outputs = drv.outputs;
# paths = builtins.listToAttrs ( map (output: {name = output; value = drv.${output};}) drv.outputs );
}
// lib.optionalAttrs (drv ? meta && drv.meta ? description) { inherit (drv.meta) description; }
// lib.optionalAttrs (drv ? meta && drv.meta ? license) { inherit (drv.meta) license; }
# else {}
)
) (all drvs);
) (validPkgs drvs);
readApps = system: apps: lib.mapAttrsToList (
attribute_name: app: (
{
@ -54,8 +43,7 @@ let
)
) apps;
readOptions = modules: isNixOS: let
readOptions = let
declarations = module: (
lib.evalModules {
modules = (if lib.isList module then module else [ module ]) ++ [
@ -70,7 +58,7 @@ let
}
).options;
cleanUpOption = module: opt:
cleanUpOption = extraAttrs: opt:
let
applyOnAttr = n: f: lib.optionalAttrs (builtins.hasAttr n opt) { ${n} = f opt.${n}; };
mkDeclaration = decl:
@ -96,31 +84,47 @@ let
// applyOnAttr "example" substFunction # (_: { __type = "function"; })
// applyOnAttr "type" substFunction
// applyOnAttr "declarations" (map mkDeclaration)
// lib.optionalAttrs (!isNixOS) { flake = [ flake module ]; };
options = lib.mapAttrs (
attr: module: let
list = lib.optionAttrSetToDocList (declarations module);
// extraAttrs;
in
map (cleanUpOption attr) (lib.filter (x: !x.internal) list)
) modules;
{ module, modulePath ? null }: let
opts = lib.optionAttrSetToDocList (declarations module);
extraAttrs = lib.optionalAttrs (modulePath != null) {
flake = modulePath;
};
in
lib.flatten (builtins.attrValues options);
map (cleanUpOption extraAttrs) (lib.filter (x: !x.internal) opts);
readFlakeOptions = let
nixosModulesOpts = builtins.concatLists (lib.mapAttrsToList (moduleName: module:
readOptions {
inherit module;
modulePath = [ flake moduleName ];
}
) (resolved.nixosModules or {}));
nixosModuleOpts = lib.optionals (resolved ? nixosModule) (
readOptions {
module = resolved.nixosModule;
modulePath = [ flake ];
}
);
in
# We assume that `nixosModules` includes `nixosModule` when there
# are multiple modules
if nixosModulesOpts != [] then nixosModulesOpts else nixosModuleOpts;
read = reader: set: lib.flatten (lib.attrValues (withSystem reader set));
legacyPackages' = read readPackages (default resolved "legacyPackages" {});
packages' = read readPackages (default resolved "packages" {});
legacyPackages' = read readPackages (resolved.legacyPackages or {});
packages' = read readPackages (resolved.packages or {});
apps' = read readApps (default resolved "apps" {});
apps' = read readApps (resolved.apps or {});
collectSystems = lib.lists.foldr (
drv@{ attribute_name, system, ... }: set:
let
present = default set "${attribute_name}" ({ platforms = []; } // drv);
present = set."${attribute_name}" or ({ platforms = []; } // drv);
drv' = present // {
platforms = present.platforms ++ [ system ];
@ -138,11 +142,9 @@ rec {
legacyPackages = lib.attrValues (collectSystems legacyPackages');
packages = lib.attrValues (collectSystems packages');
apps = lib.attrValues (collectSystems apps');
options = readOptions (default resolved "nixosModules" {}) false;
nixos-options = readOptions (
{
"nixos" = import "${builtins.fetchTarball { url = flake; }}/nixos/modules/module-list.nix";
}
) true;
options = readFlakeOptions;
nixos-options = readOptions {
module = import "${builtins.fetchTarball { url = flake; }}/nixos/modules/module-list.nix";
};
all = packages ++ apps ++ options;
}

View file

@ -3,7 +3,7 @@
/// Flakes, or Nixpkgs.
use std::{convert::TryInto, path::PathBuf};
use super::{import::DocValue, pandoc::PandocExt};
use super::{import::{DocValue, ModulePath}, pandoc::PandocExt};
use crate::data::import::NixOption;
use log::error;
use serde::{Deserialize, Serialize};
@ -110,7 +110,7 @@ pub enum Derivation {
option_example: Option<DocValue>,
option_flake: Option<(String, String)>,
option_flake: Option<ModulePath>,
},
}

View file

@ -63,8 +63,18 @@ pub struct NixOption {
pub default: Option<DocValue>,
pub example: Option<DocValue>,
/// If defined in a flake, contains defining flake and module
pub flake: Option<(String, String)>,
/// If defined in a flake, contains defining flake and optionally a module
pub flake: Option<ModulePath>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ModulePath {
/// A module taken from <flake>.nixosModule
/// JSON representation is a list, therefore use a 1-Tuple as representation
DefaultModule((String,)),
/// A module taken from <flake>.nixosModules.<name>
NamedModule((String, String)),
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
@ -345,6 +355,32 @@ mod tests {
.collect();
}
#[test]
fn test_flake_option() {
let json = r#"
{
"declarations": [],
"name": "test-option",
"flake": ["flake", "module"]
}
"#;
serde_json::from_str::<NixOption>(json).unwrap();
}
#[test]
fn test_flake_option_default_module() {
let json = r#"
{
"declarations": [],
"name": "test-option",
"flake": ["flake"]
}
"#;
serde_json::from_str::<NixOption>(json).unwrap();
}
#[test]
fn test_option_parsing() {}
}

View file

@ -68,7 +68,7 @@ type alias ResultItemSource =
, source : Maybe String
-- flake
, flake : Maybe ( String, String )
, flake : Maybe (List String)
, flakeName : Maybe String
, flakeDescription : Maybe String
, flakeUrl : Maybe String
@ -274,17 +274,20 @@ viewResultItem channel _ show item =
Maybe.map asGithubLink item.source.source
flakeOrNixpkgs =
case ( item.source.flakeName, item.source.flake, item.source.flakeUrl ) of
let
mkLink flake url =
a [ href url ] [ text flake ]
in
case ( item.source.flake, item.source.flakeUrl ) of
-- its a flake
( Just name, Just ( flake, attr ), Just flakeUrl_ ) ->
( Just (flake :: []), Just url ) ->
Just
[ li []
[ a [ href flakeUrl_ ] [ text flake ]
, text "#"
, text attr
]
[ li [] [ mkLink flake url ]
]
( Just (flake :: moduleName :: []), Just url ) ->
Just [ li [] [ mkLink flake url, text "#", text moduleName ] ]
_ ->
Nothing
in
@ -344,12 +347,16 @@ findSource channel source =
flakeOrNixpkgs =
case ( source.flake, source.flakeUrl ) of
-- its a flake
( Just ( name, module_ ), Just flakeUrl_ ) ->
( Just (name :: attrs), Just flakeUrl_ ) ->
let
module_ =
Maybe.withDefault "(default)" <| Maybe.map (\m -> "(Module: " ++ m ++ ")") <| List.head attrs
in
Just <|
List.append
(Maybe.withDefault [] <| Maybe.map (\sourceFile_ -> [ sourceFile_, span [] [ text " in " ] ]) sourceFile)
[ span [] [ text "Flake: " ]
, a [ href flakeUrl_ ] [ text <| name ++ "(Module: " ++ module_ ++ ")" ]
, a [ href flakeUrl_ ] [ text <| name ++ module_ ]
]
( Nothing, _ ) ->
@ -420,7 +427,7 @@ decodeResultItemSource =
|> Json.Decode.Pipeline.optional "option_example" (Json.Decode.map Just Json.Decode.string) Nothing
|> Json.Decode.Pipeline.optional "option_source" (Json.Decode.map Just Json.Decode.string) Nothing
|> Json.Decode.Pipeline.optional "option_flake"
(Json.Decode.map Just <| Json.Decode.map2 Tuple.pair (Json.Decode.index 0 Json.Decode.string) (Json.Decode.index 1 Json.Decode.string))
(Json.Decode.map Just <| Json.Decode.list Json.Decode.string)
Nothing
|> Json.Decode.Pipeline.optional "flake_name" (Json.Decode.map Just Json.Decode.string) Nothing
|> Json.Decode.Pipeline.optional "flake_description" (Json.Decode.map Just Json.Decode.string) Nothing