1
1
forked from extern/flakelight

Allow apps to be scripts

This enables setting the app to arbitrary bash scripts which will be
written to a store path and used for the app's program attr.
This commit is contained in:
Archit Gupta 2024-02-21 18:43:05 -08:00
parent 41ec64361f
commit e72626b0a9
2 changed files with 57 additions and 22 deletions

View File

@ -4,31 +4,58 @@
{ config, lib, flakelight, genSystems, ... }: { config, lib, flakelight, genSystems, ... }:
let let
inherit (lib) isStringLike mapAttrs mkIf mkMerge mkOption mkOptionType; inherit (builtins) match storeDir;
inherit (lib.types) coercedTo lazyAttrsOf pathInStore; inherit (lib) defaultFunctor fix isFunction last mapAttrs mergeDefinitions
inherit (lib.options) mergeEqualOption; mkIf mkMerge mkOption mkOptionType;
inherit (flakelight.types) nullable optFunctionTo; inherit (lib.types) coercedTo enum lazyAttrsOf
optionDescriptionPhrase pathInStore submodule;
inherit (flakelight.types) nullable optFunctionTo stringLike;
app = mkOptionType { isStorePath = s: match "${storeDir}/[^.][^ \n]*" s != null;
name = "app";
description = "flake app"; app = submodule {
descriptionClass = "noun"; options = {
check = x: (x ? type) && (x.type == "app") && type = mkOption { type = enum [ "app" ]; default = "app"; };
(x ? program) && (pathInStore.check x.program); program = mkOption { type = pathInStore // { check = isStorePath; }; };
merge = mergeEqualOption; };
}; };
stringLike = mkOptionType { mkApp = name: pkgs: s:
name = "stringLike"; let s' = "${s}"; in {
description = "string-convertible value"; program =
descriptionClass = "noun"; if isStorePath s' then s'
check = isStringLike; else "${pkgs.writeShellScript "app-${name}" s'}";
merge = mergeEqualOption; };
};
mkApp = app: { type = "app"; program = "${app}"; }; parameterize = value: fn: fix fn value;
appType = optFunctionTo (coercedTo stringLike mkApp app); appType = parameterize app (self': app: (mkOptionType rec {
name = "appType";
description =
let
targetDesc = optionDescriptionPhrase
(class: class == "noun" || class == "composite")
(coercedTo stringLike (abort "") app);
in
"${targetDesc} or function that evaluates to it";
descriptionClass = "composite";
check = x: isFunction x || app.check x || stringLike.check x;
merge = loc: defs: pkgs:
let
targetType = coercedTo stringLike (mkApp (last loc) pkgs) app;
in
(mergeDefinitions loc targetType (map
(fn: {
inherit (fn) file;
value = if isFunction fn.value then fn.value pkgs else fn.value;
})
defs)).mergedValue;
inherit (app) getSubOptions getSubModules;
substSubModules = m: self' (app.substSubModules m);
functor = (defaultFunctor name) // { wrapped = app; };
nestedTypes.coercedType = stringLike;
nestedTypes.finalType = app;
}));
in in
{ {
options = { options = {

View File

@ -7,8 +7,8 @@ let
inherit (inputs) nixpkgs; inherit (inputs) nixpkgs;
inherit (builtins) isAttrs isPath readDir; inherit (builtins) isAttrs isPath readDir;
inherit (nixpkgs.lib) all attrNames composeManyExtensions evalModules filter inherit (nixpkgs.lib) all attrNames composeManyExtensions evalModules filter
findFirst fix genAttrs getValues hasSuffix isFunction isList mapAttrs findFirst fix genAttrs getValues hasSuffix isFunction isList isStringLike
mapAttrsToList mkDefault mkOptionType pathExists pipe removePrefix mapAttrs mapAttrsToList mkDefault mkOptionType pathExists pipe removePrefix
removeSuffix singleton warn; removeSuffix singleton warn;
inherit (nixpkgs.lib.types) coercedTo defaultFunctor functionTo listOf inherit (nixpkgs.lib.types) coercedTo defaultFunctor functionTo listOf
optionDescriptionPhrase; optionDescriptionPhrase;
@ -74,6 +74,14 @@ let
merge = mergeOneOption; merge = mergeOneOption;
}; };
stringLike = mkOptionType {
name = "stringLike";
description = "string-convertible value";
descriptionClass = "noun";
check = isStringLike;
merge = mergeEqualOption;
};
module = mkOptionType { module = mkOptionType {
name = "module"; name = "module";
description = "module"; description = "module";