# Copyright (c) 2019-2022, see AUTHORS. Licensed under MIT License, see LICENSE.
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.build;
profileDirectory = "/nix/var/nix/profiles/nix-on-droid";
# Programs that always should be available on the activation
# script's PATH.
activationBinPaths = lib.makeBinPath [
pkgs.bash
pkgs.coreutils
pkgs.diffutils
pkgs.findutils
pkgs.gnugrep
pkgs.gnused
pkgs.ncurses # For `tput`.
config.nix.package
];
mkActivationCmds = activation: concatStringsSep "\n" (
mapAttrsToList
(name: value: ''
noteEcho "Activating ${name}"
${value}
'')
activation
);
activationScript = pkgs.writeScript "activation-script" ''
#!${pkgs.runtimeShell}
set -eu
set -o pipefail
export PATH="${activationBinPaths}"
_NOD_GENERATION_DIR="$(realpath "$(dirname "$0")")"
cd "$HOME"
${builtins.readFile ../lib-bash/color-echo.sh}
${builtins.readFile ../lib-bash/activation-init.sh}
${mkActivationCmds cfg.activationBefore}
${mkActivationCmds cfg.activation}
${mkActivationCmds cfg.activationAfter}
'';
activationOptionDescriptionSuffix = ''
Any script should respect the DRY_RUN
variable, if it is set then no actual action should be taken.
The variable DRY_RUN_CMD is set to
echo if dry run is enabled. Thus, many cases you
can use the idiom $DRY_RUN_CMD rm -rf /.
Any script block should also respect the
VERBOSE variable, and if set print
information on standard out that may be useful for debugging
any issue that may arise. The variable
VERBOSE_ARG is set to
if verbose output is enabled.
The variable VERBOSE_ECHO is set to
echo if verbose output is enabled, otherwise
falling back to true. So it can be used like
$VERBOSE_ECHO "any message".
'';
in
{
###### interface
options = {
build = {
activation = mkOption {
default = { };
type = types.attrs;
description = ''
Activation scripts for the Nix-on-Droid environment.
'' + activationOptionDescriptionSuffix;
};
activationBefore = mkOption {
default = { };
type = types.attrs;
description = ''
Activation scripts for the Nix-on-Droid environment that
need to be run first.
'' + activationOptionDescriptionSuffix;
};
activationAfter = mkOption {
default = { };
type = types.attrs;
description = ''
Activation scripts for the Nix-on-Droid environment that
need to be run last.
'' + activationOptionDescriptionSuffix;
};
activationPackage = mkOption {
type = types.package;
readOnly = true;
internal = true;
description = "Derivation with activation script.";
};
etc = mkOption {
type = types.package;
internal = true;
description = "Package containing /etc files.";
};
sessionInit = mkOption {
type = types.package;
internal = true;
description = ''
Package containing the session-init script in
/etc/profile.d/nix-on-droid-session-init.sh.
'';
};
};
};
###### implementation
config = {
build = {
activationAfter.linkProfile = ''
generationDir="$(dirname $0)"
if [[ $generationDir =~ ^${profileDirectory}-([0-9]+)-link$ ]]; then
$DRY_RUN_CMD nix-env --profile "${profileDirectory}" --switch-generation "''${BASH_REMATCH[1]}"
else
$DRY_RUN_CMD nix-env --profile "${profileDirectory}" --set "$_NOD_GENERATION_DIR"
fi
'';
activationPackage =
pkgs.runCommand
"nix-on-droid-generation"
{
preferLocalBuild = true;
allowSubstitutes = false;
}
''
mkdir --parents $out/filesystem/{bin,usr/{bin,lib}}
cp ${activationScript} $out/activate
ln --symbolic ${config.build.etc}/etc $out/etc
ln --symbolic ${config.environment.path} $out/nix-on-droid-path
ln --symbolic ${config.environment.files.login} $out/filesystem/bin/login
ln --symbolic ${config.environment.files.loginInner} $out/filesystem/usr/lib/login-inner
ln --symbolic ${config.environment.files.prootStatic}/bin/proot-static $out/filesystem/bin/proot-static
ln --symbolic ${config.environment.binSh} $out/filesystem/bin/sh
ln --symbolic ${config.environment.usrBinEnv} $out/filesystem/usr/bin/env
'';
};
};
}