From aa6ab74cad362480cf7a5132b451b373cc2affc8 Mon Sep 17 00:00:00 2001 From: Krzysztof Nazarewski Date: Tue, 28 Mar 2023 12:21:02 +0200 Subject: [PATCH] flakes CLI: add container commands --- flake-module.nix | 52 +++++++++++++++----- src/devenv-devShell.nix | 53 +++++--------------- src/devenv-devShell.sh | 94 ++++++++++++++++++++++++++++++++++++ src/devenv.nix | 10 ++-- src/modules/containers.nix | 57 +++++++++++----------- templates/flake-parts/.envrc | 8 +++ templates/simple/.envrc | 3 -- 7 files changed, 187 insertions(+), 90 deletions(-) create mode 100755 src/devenv-devShell.sh create mode 100644 templates/flake-parts/.envrc diff --git a/flake-module.nix b/flake-module.nix index 7d8b11d99..b579a3fcd 100644 --- a/flake-module.nix +++ b/flake-module.nix @@ -10,8 +10,6 @@ devenvFlake: { flake-parts-lib, lib, inputs, ... }: { }; }]; }).type; - - shellPrefix = shellName: if shellName == "default" then "" else "${shellName}-"; in { @@ -44,7 +42,7 @@ devenvFlake: { flake-parts-lib, lib, inputs, ... }: { (shellName: devenv: lib.concatMapAttrs (containerName: container: { - "${shellPrefix shellName}container-${containerName}-spec" = container.derivation; + "${shellName}-container-${containerName}-spec" = container.derivation; }) devenv.containers ) @@ -54,16 +52,44 @@ devenvFlake: { flake-parts-lib, lib, inputs, ... }: { lib.concatMapAttrs (shellName: devenv: lib.concatMapAttrs - (containerName: container: { - "${shellPrefix shellName}container-${containerName}" = { - type = "app"; - program = "${container.run}"; - }; - "${shellPrefix shellName}container-${containerName}-copy-to" = { - type = "app"; - program = "${container.copyTo}"; - }; - }) + (containerName: config: + let prefix = "devenv-${shellName}-container-${containerName}"; in { + "${prefix}-copy-to" = { + type = "app"; + program = pkgs.writeShellApplication { + name = "${shellName}-container-${containerName}-copy-to"; + text = '' + ${config.copyScript} ${config.derivation} "$@" + ''; + }; + }; + "${prefix}-docker-run" = { + type = "app"; + program = "${config.dockerRun}"; + }; + "${prefix}-docker-load" = { + type = "app"; + program = pkgs.writeShellApplication { + name = "${shellName}-container-${containerName}-docker-load"; + text = '' + ${config.copyScript} ${config.derivation} local-docker + ''; + }; + }; + "${prefix}-podman-run" = { + type = "app"; + program = "${config.podmanRun}"; + }; + "${prefix}-podman-load" = { + type = "app"; + program = pkgs.writeShellApplication { + name = "${shellName}-container-${containerName}-podman-load"; + text = '' + ${config.copyScript} ${config.derivation} local + ''; + }; + }; + }) devenv.containers ) config.devenv.shells; diff --git a/src/devenv-devShell.nix b/src/devenv-devShell.nix index 2efb7bfb8..397350874 100644 --- a/src/devenv-devShell.nix +++ b/src/devenv-devShell.nix @@ -1,46 +1,17 @@ { config, pkgs }: let lib = pkgs.lib; - version = lib.fileContents ./modules/latest-version; -in -pkgs.writeScriptBin "devenv" '' - #!/usr/bin/env bash - - # we want subshells to fail the program - set -e - NIX_FLAGS="--show-trace --extra-experimental-features nix-command --extra-experimental-features flakes" + app = pkgs.writeShellApplication { + name = "devenv-flake-cli"; + runtimeInputs = with pkgs; [ docopts ]; + text = builtins.readFile ./devenv-devShell.sh; + }; - command=$1 - if [[ ! -z $command ]]; then - shift - fi - - case $command in - up) - procfilescript=${config.procfileScript} - if [ "$(cat $procfilescript|tail -n +2)" = "" ]; then - echo "No 'processes' option defined: https://devenv.sh/processes/" - exit 1 - else - $procfilescript - fi - ;; - version) - echo "devenv: ${version}" - ;; - *) - echo "https://devenv.sh (version ${version}): Fast, Declarative, Reproducible, and Composable Developer Environments" - echo - echo "This is a flake integration wrapper that comes with a subset of functionality from the flakeless devenv CLI." - echo - echo "Usage: devenv command" - echo - echo "Commands:" - echo - echo "up Starts processes in foreground. See http://devenv.sh/processes" - echo "version Display devenv version" - echo - exit 1 - esac -'' + envs = lib.concatStringsSep " " (lib.mapAttrsToList lib.toShellVar { + PROCFILESCRIPT = config.procfileScript; + VERSION = lib.fileContents ./modules/latest-version; + CUSTOM_NIX = "${pkgs.nix}/bin/nix"; + }); +in +pkgs.writeScriptBin "devenv" ''${envs} "${app}/bin/devenv-flake-cli" "$@"'' diff --git a/src/devenv-devShell.sh b/src/devenv-devShell.sh new file mode 100755 index 000000000..38bf5f70b --- /dev/null +++ b/src/devenv-devShell.sh @@ -0,0 +1,94 @@ +#!/usr/bin/env bash +set -eEuo pipefail + +if [ "${DEBUG:-}" == 1 ]; then + set -x +fi +PROCFILESCRIPT="${PROCFILESCRIPT:-"placeholder"}" +VERSION="${VERSION:-"placeholder"}" +CUSTOM_NIX="${CUSTOM_NIX:-"nix"}" + +NIX_FLAGS=(--show-trace --extra-experimental-features 'nix-command flakes') + +function nix { + "$CUSTOM_NIX" "${NIX_FLAGS[@]}" "${@}" +} + +function container { + declare -A args + set -x + # shellcheck disable=SC2016 + eval "$(docopts -A args -h ' +Usage: container [options] [--] [...] + +Options: + -s , --shell `devenv.shells.` to use. [default: default] + -r , --registry Registry to copy the container to. + Available shortcuts: config, local-docker, local [default: config] + --copy Copy the container to the registry. + --copy-args Arguments passed to `skopeo copy`. + --docker-run Execute `docker run`. + --podman-run Execute `podman run`. +' : "$@")" + + local registry="${args['--registry']}" + + local app_prefix="${DEVENV_ROOT}#devenv-${args['--shell']}-container-${args['']}" + + if [[ "${args['--copy']}" != false || "${args['--docker-run']}" != false || "${args['--podman-run']}" != false ]]; then + if [[ ${args['--docker-run']} == true ]]; then + registry=local-docker + elif [[ ${args['--podman-run']} == true ]]; then + registry=local + fi + # shellcheck disable=SC2086 + nix run "${app_prefix}-copy-to" "${registry}" ${args['--copy-args']} + fi + + # shellcheck disable=SC1090 + source "$(command -v docopts.sh)" + + if [[ "${args['--docker-run']}" != false ]]; then + # shellcheck disable=SC2046 + nix run "${app_prefix}-docker-run" -- $(docopt_get_values args '') + elif [[ "${args['--podman-run']}" != false ]]; then + # shellcheck disable=SC2046 + nix run "${app_prefix}-podman-run" -- $(docopt_get_values args '') + fi +} + +command="${1:-}" +if [[ -n "$command" ]]; then + shift +fi + +case "$command" in +up) + if [ "$(tail -n +2 <<<"$PROCFILESCRIPT")" = "" ]; then + echo "No 'processes' option defined: https://devenv.sh/processes/" + exit 1 + else + "$PROCFILESCRIPT" + fi + ;; +container) + container "$@" + ;; +version) + echo "devenv: ${VERSION}" + ;; +*) + echo "https://devenv.sh (version ${VERSION}): Fast, Declarative, Reproducible, and Composable Developer Environments" + echo + echo "This is a flake integration wrapper that comes with a subset of functionality from the flakeless devenv CLI." + echo + echo "Usage: devenv command" + echo + echo "Commands:" + echo + echo "up Starts processes in foreground. See http://devenv.sh/processes" + echo "version Display devenv version" + echo + exit 1 + ;; +esac diff --git a/src/devenv.nix b/src/devenv.nix index 164890fde..70b48f555 100644 --- a/src/devenv.nix +++ b/src/devenv.nix @@ -111,6 +111,7 @@ pkgs.writeScriptBin "devenv" '' --copy Copy the container to the registry. --copy-args= Arguments passed to `skopeo copy`. --docker-run Execute `docker run`. + --podman-run Execute `podman run`. EOF ) @@ -124,20 +125,23 @@ pkgs.writeScriptBin "devenv" '' echo $spec # copy container - if [[ ''${subcommand[--copy]} != false || ''${subcommand[--docker-run]} != false ]]; then + if [[ ''${subcommand[--copy]} != false || ''${subcommand[--docker-run]} != false || ''${subcommand[--podman-run]} != false ]]; then copyScript=$($CUSTOM_NIX/bin/nix $NIX_FLAGS build --print-out-paths --no-link --impure ".#devenv.containers.\"$container\".copyScript") if [[ ''${subcommand[--docker-run]} == true ]]; then - registry=docker-daemon: + registry=local-docker + elif [[ ''${subcommand[--podman-run]} == true ]]; then + registry=local else registry="''${subcommand[--registry]}" fi $copyScript $spec $registry ''${subcommand[--copy-args]} fi - # docker run if [[ ''${subcommand[--docker-run]} != false ]]; then $($CUSTOM_NIX/bin/nix $NIX_FLAGS build --print-out-paths --no-link --impure ".#devenv.containers.\"$container\".dockerRun") + if [[ ''${subcommand[--podman-run]} != false ]]; then + $($CUSTOM_NIX/bin/nix $NIX_FLAGS build --print-out-paths --no-link --impure ".#devenv.containers.\"$container\".podmanRun") fi ;; search) diff --git a/src/modules/containers.nix b/src/modules/containers.nix index 79a1ab68c..23a36c320 100644 --- a/src/modules/containers.nix +++ b/src/modules/containers.nix @@ -56,14 +56,17 @@ let # mkCopyScript = cfg: pkgs.writeScript "copy-container" '' - container=$1 + spec=$1 shift - if [[ "$1" == false ]]; then - registry=${cfg.registry} - else - registry="$1" - fi + case "$1" in + false|config) registry="${cfg.registry}" ;; + local-docker) registry="docker-daemon:" ;; + local|local-podman|local-containers|local-buildah) + registry="containers-storage:" + ;; + *) registry="$1" ;; + esac shift dest="''${registry}${cfg.name}:${cfg.version}" @@ -75,10 +78,10 @@ let fi echo - echo "Copying container $container to $dest" + echo "Copying container $spec to $dest" echo - ${nix2container.skopeo-nix2container}/bin/skopeo --insecure-policy copy "nix:$container" "$dest" "''${args[@]}" + ${nix2container.skopeo-nix2container}/bin/skopeo --insecure-policy copy "nix:$spec" "$dest" "''${args[@]}" ''; containerOptions = types.submodule ({ name, config, ... }: { options = { @@ -154,28 +157,31 @@ let internal = true; default = pkgs.writeScript "docker-run" '' #!${pkgs.bash}/bin/bash + set -eEuo pipefail - docker run -it ${config.name}:${config.version} "$@" - ''; - }; + container_args=() + runtime_args=() - copyTo = lib.mkOption { - type = types.package; - internal = true; - default = pkgs.writeScript "devenv-container-copy-to" '' - ${config.copyScript} ${config.derivation} "''${1:-"containers-storage:localhost/"}" "''${@:2}" + for arg in "$@" ; do + if [ "$arg" == "--" ] ; then + runtime_args=("''${container_args[@]}") + container_args=() + else + container_args+=("$arg") + fi + done + + docker run -it "''${runtime_args[@]}" '${config.name}:${config.version}' "''${container_args[@]}" ''; }; - run = lib.mkOption { + podmanRun = lib.mkOption { type = types.package; internal = true; - default = pkgs.writeScript "devenv-container-run" '' + default = pkgs.writeScript "podman-run" '' #!${pkgs.bash}/bin/bash set -eEuo pipefail - ${config.copyScript} ${config.derivation} "containers-storage:localhost/" - container_args=() runtime_args=() @@ -188,16 +194,7 @@ let fi done - args=( run -it "''${runtime_args[@]}" '${config.name}:${config.version}' "''${container_args[@]}" ) - - if command -v docker >/dev/null ; then - docker "''${args[@]}" - elif command -v podman >/dev/null ; then - podman "''${args[@]}" - else - echo "Found neither docker nor podman." >&2 - exit 1 - fi + podman run -it "''${runtime_args[@]}" '${config.name}:${config.version}' "''${container_args[@]}" ''; }; }; diff --git a/templates/flake-parts/.envrc b/templates/flake-parts/.envrc new file mode 100644 index 000000000..64038852a --- /dev/null +++ b/templates/flake-parts/.envrc @@ -0,0 +1,8 @@ +if ! has nix_direnv_version || ! nix_direnv_version 2.2.1; then + source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.2.1/direnvrc" "sha256-zelF0vLbEl5uaqrfIzbgNzJWGmLzCmYAkInj/LNxvKs=" +fi + +if ! use flake . --impure +then + echo "devenv could not be build. The devenv environment was not loaded. Make the necessary changes to devenv.nix and hit enter to try again." >&2 +fi diff --git a/templates/simple/.envrc b/templates/simple/.envrc index ce4386fd0..64038852a 100644 --- a/templates/simple/.envrc +++ b/templates/simple/.envrc @@ -2,9 +2,6 @@ if ! has nix_direnv_version || ! nix_direnv_version 2.2.1; then source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.2.1/direnvrc" "sha256-zelF0vLbEl5uaqrfIzbgNzJWGmLzCmYAkInj/LNxvKs=" fi -nix_direnv_watch_file devenv.nix -nix_direnv_watch_file devenv.lock -nix_direnv_watch_file devenv.yaml if ! use flake . --impure then echo "devenv could not be build. The devenv environment was not loaded. Make the necessary changes to devenv.nix and hit enter to try again." >&2