Builtin Block Types
A few Block Types are packaged with std
.
In practical terms, Block Types distinguish themselves through the actions they provide to a particular Cell Block.
It is entirely possible to define custom Block Types with custom Actions according to the needs of your project.
Arion
{
nixpkgs,
mkCommand,
}: let
l = nixpkgs.lib // builtins;
/*
Use the arion for arionCompose Jobs - https://docs.hercules-ci.com/arion/
Available actions:
- up
- ps
- stop
- rm
- config
- arion
*/
arion = name: {
inherit name;
type = "arion";
actions = {
currentSystem,
fragment,
fragmentRelPath,
target,
}: let
pkgs = nixpkgs.legacyPackages.${currentSystem};
cmd = "${pkgs.arion}/bin/arion --prebuilt-file ${target.config.out.dockerComposeYaml}";
in [
(mkCommand currentSystem {
name = "up";
description = "arion up";
command = ''
${cmd} up "$@"
'';
})
(mkCommand currentSystem {
name = "ps";
description = "exec this arion task to ps";
command = ''
${cmd} ps "$@"
'';
})
(mkCommand currentSystem {
name = "stop";
description = "arion stop";
command = ''
${cmd} stop "$@"
'';
})
(mkCommand currentSystem {
name = "rm";
description = "arion rm";
command = ''
${cmd} rm "$@"
'';
})
(mkCommand currentSystem {
name = "config";
description = "check the docker-compose yaml file";
command = ''
${cmd} config "$@"
'';
})
(mkCommand currentSystem {
name = "arion";
description = "pass any command to arion";
command = ''
${cmd} "$@"
'';
})
];
};
in
arion
Runnables (todo: vs installables)
{
nixpkgs,
mkCommand,
sharedActions,
}: let
lib = nixpkgs.lib // builtins;
/*
Use the Runnables Blocktype for targets that you want to
make accessible with a 'run' action on the TUI.
*/
runnables = name: {
__functor = import ./__functor.nix;
inherit name;
type = "runnables";
actions = {
currentSystem,
fragment,
fragmentRelPath,
target,
}: [
(sharedActions.build currentSystem target)
(sharedActions.run currentSystem target)
];
};
in
runnables
Installables (todo: vs runnables)
{
nixpkgs,
mkCommand,
sharedActions,
}: let
l = nixpkgs.lib // builtins;
/*
Use the Installables Blocktype for targets that you want to
make availabe for installation into the user's nix profile.
Available actions:
- install
- upgrade
- remove
- build
- bundle
- bundleImage
- bundleAppImage
*/
installables = name: {
__functor = import ./__functor.nix;
inherit name;
type = "installables";
actions = {
currentSystem,
fragment,
fragmentRelPath,
target,
}: [
(sharedActions.build currentSystem target)
# profile commands require a flake ref
(mkCommand currentSystem {
name = "install";
description = "install this target";
command = ''
# ${target}
if test -z "$PRJ_ROOT"; then
echo "PRJ_ROOT is not set. Action aborting."
exit 1
fi
nix profile install $PRJ_ROOT#${fragment}
'';
})
(mkCommand currentSystem {
name = "upgrade";
description = "upgrade this target";
command = ''
# ${target}
if test -z "$PRJ_ROOT"; then
echo "PRJ_ROOT is not set. Action aborting."
exit 1
fi
nix profile upgrade $PRJ_ROOT#${fragment}
'';
})
(mkCommand currentSystem {
name = "remove";
description = "remove this target";
command = ''
# ${target}
if test -z "$PRJ_ROOT"; then
echo "PRJ_ROOT is not set. Action aborting."
exit 1
fi
nix profile remove $PRJ_ROOT#${fragment}
'';
})
# TODO: use target. `nix bundle` requires a flake ref, but we may be able to use nix-bundle instead as a workaround
(mkCommand currentSystem {
name = "bundle";
description = "bundle this target";
command = ''
# ${target}
if test -z "$PRJ_ROOT"; then
echo "PRJ_ROOT is not set. Action aborting."
exit 1
fi
nix bundle --bundler github:Ninlives/relocatable.nix --refresh $PRJ_ROOT#${fragment}
'';
})
(mkCommand currentSystem {
name = "bundleImage";
description = "bundle this target to image";
command = ''
# ${target}
if test -z "$PRJ_ROOT"; then
echo "PRJ_ROOT is not set. Action aborting."
exit 1
fi
nix bundle --bundler github:NixOS/bundlers#toDockerImage --refresh $PRJ_ROOT#${fragment}
'';
})
(mkCommand currentSystem {
name = "bundleAppImage";
description = "bundle this target to AppImage";
command = ''
# ${target}
if test -z "$PRJ_ROOT"; then
echo "PRJ_ROOT is not set. Action aborting."
exit 1
fi
nix bundle --bundler github:ralismark/nix-appimage --refresh $PRJ_ROOT#${fragment}
'';
})
];
};
in
installables
Pkgs
{...}: let
/*
Use the Pkgs Blocktype if you need to construct your custom
variant of nixpkgs with overlays.
Targets will be excluded from the CLI / TUI and thus not
slow them down.
*/
pkgs = name: {
inherit name;
type = "pkgs";
cli = false; # its special power
};
in
pkgs
Devshells
{
nixpkgs,
mkCommand,
sharedActions,
}: let
l = nixpkgs.lib // builtins;
mkDevelopDrv = import ../devshell-drv.nix;
/*
Use the Devshells Blocktype for devShells.
Available actions:
- build
- enter
*/
devshells = name: {
__functor = import ./__functor.nix;
inherit name;
type = "devshells";
actions = {
currentSystem,
fragment,
fragmentRelPath,
target,
}: let
developDrv = mkDevelopDrv target;
in [
(sharedActions.build currentSystem target)
(mkCommand currentSystem {
name = "enter";
description = "enter this devshell";
command = ''
if test -z "$PRJ_ROOT"; then
echo "PRJ_ROOT is not set. Action aborting."
exit 1
fi
if test -z "$PRJ_DATA_DIR"; then
echo "PRJ_DATA_DIR is not set. Action aborting."
exit 1
fi
profile_path="$PRJ_DATA_DIR/${fragmentRelPath}"
mkdir -p "$profile_path"
# ${developDrv}
nix_args=(
"${builtins.unsafeDiscardStringContext developDrv.drvPath}"
"--no-update-lock-file"
"--no-write-lock-file"
"--no-warn-dirty"
"--accept-flake-config"
"--no-link"
"--build-poll-interval" "0"
"--builders-use-substitutes"
)
nix build "''${nix_args[@]}" --profile "$profile_path/shell-profile"
_SHELL="$SHELL"
eval "$(nix print-dev-env ${developDrv})"
SHELL="$_SHELL"
if ! [[ -v STD_DIRENV ]]; then
if declare -F __devshell-motd &>/dev/null; then
__devshell-motd
fi
exec $SHELL -i
fi
'';
})
];
};
in
devshells
Nixago
{
nixpkgs,
mkCommand,
}: let
l = nixpkgs.lib // builtins;
/*
Use the Nixago Blocktype for nixago pebbles.
Use Nixago pebbles to ensure files are present
or symlinked into your repository. You may typically
use this for repo dotfiles.
For more information, see: https://github.com/nix-community/nixago.
Available actions:
- ensure
- explore
*/
nixago = name: {
inherit name;
type = "nixago";
actions = {
currentSystem,
fragment,
fragmentRelPath,
target,
}: [
(mkCommand currentSystem {
name = "populate";
description = "populate this nixago file into the repo";
command = ''
${target.install}/bin/nixago_shell_hook
'';
})
(mkCommand currentSystem {
name = "explore";
description = "interactively explore the nixago file";
command = ''
${nixpkgs.legacyPackages.${currentSystem}.bat}/bin/bat "${target.config}"
'';
})
];
};
in
nixago
Containers
{
nixpkgs,
n2c, # nix2container
mkCommand,
sharedActions,
}: let
l = nixpkgs.lib // builtins;
/*
Use the Containers Blocktype for OCI-images built with nix2container.
Available actions:
- print-image
- publish
- load
*/
containers = name: {
__functor = import ./__functor.nix;
inherit name;
type = "containers";
actions = {
currentSystem,
fragment,
fragmentRelPath,
target,
}: let
inherit (n2c.packages.${currentSystem}) skopeo-nix2container;
img = builtins.unsafeDiscardStringContext target.imageName;
tags = target.meta.tags or [(builtins.unsafeDiscardStringContext target.imageTag)];
tags' =
builtins.toFile "${target.name}-tags.json" (builtins.unsafeDiscardStringContext (builtins.concatStringsSep "\n" tags));
copyFn = let
skopeo = "skopeo --insecure-policy";
in ''
export PATH=${skopeo-nix2container}/bin:$PATH
copy() {
local uri prev_tag
uri=$1
shift
for tag in $(<${tags'}); do
if ! [[ -v prev_tag ]]; then
${skopeo} copy nix:${target} "$uri:$tag" "$@"
else
# speedup: copy from the previous tag to avoid superflous network bandwidth
${skopeo} copy "$uri:$prev_tag" "$uri:$tag" "$@"
fi
echo "Done: $uri:$tag"
prev_tag="$tag"
done
}
'';
in [
(sharedActions.build currentSystem target)
(mkCommand currentSystem {
name = "print-image";
description = "print out the image name with all tags";
command = ''
echo
for tag in $(<${tags'}); do
echo "${img}:$tag"
done
'';
})
(mkCommand currentSystem {
name = "publish";
description = "copy the image to its remote registry";
command = ''
${copyFn}
copy docker://${img}
'';
meta.images = map (tag: "${img}:${tag}") tags;
proviso = let
filter = ./container-publish-filter.jq;
in
l.toFile "container-proviso" ''
function scopeo_inspect() {
local image
image="$1"
if command skopeo inspect --insecure-policy "docker://$image" &>/dev/null; then
echo "$image"
fi
}
export -f scopeo_inspect
command jq --raw-output \
--from-file "${filter}" \
--arg available "$(
parallel -j0 scopeo_inspect ::: "$(
command jq --raw-output 'map(.meta.images[0]|strings)[]' <<< "$1"
)"
)" <<< "$1"
unset -f scopeo_inspect
unset images
'';
})
(mkCommand currentSystem {
name = "load";
description = "load image to the local docker daemon";
command = ''
${copyFn}
if command -v podman &> /dev/null; then
echo "Podman detected: copy to local podman"
copy containers-storage:${img} "$@"
fi
if command -v docker &> /dev/null; then
echo "Docker detected: copy to local docker"
copy docker-daemon:${img} "$@"
fi
'';
})
(mkCommand currentSystem {
name = "copy-to-registry";
description = "deprecated: use 'publish' instead";
command = "echo 'copy-to-registry' is deprecated; use 'publish' action instead && exit 1";
})
(mkCommand currentSystem {
name = "copy-to-docker";
description = "deprecated: use 'load' instead";
command = "echo 'copy-to-docker' is deprecated; use 'load' action instead && exit 1";
})
(mkCommand currentSystem {
name = "copy-to-podman";
description = "deprecated: use 'load' instead";
command = "echo 'copy-to-podman' is deprecated; use 'load' action instead && exit 1";
})
];
};
in
containers
Data
{
nixpkgs,
mkCommand,
}: let
l = nixpkgs.lib // builtins;
/*
Use the Data Blocktype for json serializable data.
Available actions:
- write
- explore
For all actions is true:
Nix-proper 'stringContext'-carried dependency will be realized
to the store, if present.
*/
data = name: {
inherit name;
type = "data";
actions = {
currentSystem,
fragment,
fragmentRelPath,
target,
}: let
inherit (nixpkgs.legacyPackages.${currentSystem}) pkgs;
# if target ? __std_data_wrapper, then we need to unpack from `.data`
json = pkgs.writeTextFile {
name = "data.json";
text = builtins.toJSON (
if target ? __std_data_wrapper
then target.data
else target
);
};
jq = ["${pkgs.jq}/bin/jq" "-r" "'.'" "${json}"];
fx = ["|" "${pkgs.fx}/bin/fx"];
in [
(mkCommand currentSystem {
name = "write";
description = "write to file";
command = "echo ${json}";
})
(mkCommand currentSystem {
name = "explore";
description = "interactively explore";
command = l.concatStringsSep "\t" (jq ++ fx);
})
];
};
in
data
Functions
{
nixpkgs,
mkCommand,
}: let
l = nixpkgs.lib // builtins;
/*
Use the Functions Blocktype for reusable nix functions that you would
call elswhere in the code.
Also use this for all types of modules and profiles, since they are
implemented as functions.
Consequently, there are no actions available for functions.
*/
functions = name: {
inherit name;
type = "functions";
};
in
functions
Anything
Note: while the implementation is the same as functions
, the semantics are different. Implementations may diverge in the future.
{
nixpkgs,
mkCommand,
}: let
l = nixpkgs.lib // builtins;
/*
Use the Anything Blocktype as a fallback.
It doesn't have actions.
*/
anything = name: {
inherit name;
type = "anything";
};
in
anything