diff --git a/src/nix/develop.cc b/src/nix/develop.cc index 9b2945ba3..ca04f297d 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -31,6 +31,11 @@ struct BuildEnvironment { bool exported; std::string value; + + bool operator == (const String & other) const + { + return exported == other.exported && value == other.value; + } }; using Array = std::vector; @@ -42,15 +47,13 @@ struct BuildEnvironment std::map vars; std::map bashFunctions; - static BuildEnvironment fromJSON(const Path & path) + static BuildEnvironment fromJSON(std::string_view in) { BuildEnvironment res; std::set exported; - debug("reading environment file '%s'", path); - - auto json = nlohmann::json::parse(readFile(path)); + auto json = nlohmann::json::parse(in); for (auto & [name, info] : json["variables"].items()) { std::string type = info["type"]; @@ -69,6 +72,38 @@ struct BuildEnvironment return res; } + std::string toJSON() const + { + auto res = nlohmann::json::object(); + + auto vars2 = nlohmann::json::object(); + for (auto & [name, value] : vars) { + auto info = nlohmann::json::object(); + if (auto str = std::get_if(&value)) { + info["type"] = str->exported ? "exported" : "var"; + info["value"] = str->value; + } + else if (auto arr = std::get_if(&value)) { + info["type"] = "array"; + info["value"] = *arr; + } + else if (auto arr = std::get_if(&value)) { + info["type"] = "associative"; + info["value"] = *arr; + } + vars2[name] = std::move(info); + } + res["variables"] = std::move(vars2); + + res["bashFunctions"] = bashFunctions; + + auto json = res.dump(); + + assert(BuildEnvironment::fromJSON(json) == *this); + + return json; + } + void toBash(std::ostream & out, const std::set & ignoreVars) const { for (auto & [name, value] : vars) { @@ -116,6 +151,11 @@ struct BuildEnvironment else throw Error("bash variable is not a string or array"); } + + bool operator == (const BuildEnvironment & other) const + { + return vars == other.vars && bashFunctions == other.bashFunctions; + } }; const static std::string getEnvSh = @@ -309,7 +349,9 @@ struct Common : InstallableCommand, MixProfile updateProfile(shellOutPath); - return {BuildEnvironment::fromJSON(strPath), strPath}; + debug("reading environment file '%s'", strPath); + + return {BuildEnvironment::fromJSON(readFile(strPath)), strPath}; } }; @@ -462,7 +504,7 @@ struct CmdDevelop : Common, MixEnvironment } }; -struct CmdPrintDevEnv : Common +struct CmdPrintDevEnv : Common, MixJSON { std::string description() override { @@ -484,7 +526,10 @@ struct CmdPrintDevEnv : Common stopProgressBar(); - std::cout << makeRcScript(store, buildEnvironment); + logger->writeToStdout( + json + ? buildEnvironment.toJSON() + : makeRcScript(store, buildEnvironment)); } }; diff --git a/src/nix/get-env.sh b/src/nix/get-env.sh index 20937b956..2df3e543f 100644 --- a/src/nix/get-env.sh +++ b/src/nix/get-env.sh @@ -49,6 +49,7 @@ __dumpEnv() { $__var_name = FUNCNAME || \ $__var_name = HISTCMD || \ $__var_name = HOSTNAME || \ + $__var_name = GROUPS || \ $__var_name = PIPESTATUS || \ $__var_name = PWD || \ $__var_name = RANDOM || \ diff --git a/src/nix/print-dev-env.md b/src/nix/print-dev-env.md index b80252acf..2aad491de 100644 --- a/src/nix/print-dev-env.md +++ b/src/nix/print-dev-env.md @@ -8,12 +8,43 @@ R""( # . <(nix print-dev-env nixpkgs#hello) ``` +* Get the build environment in JSON format: + + ```console + # nix print-dev-env nixpkgs#hello --json + ``` + + The output will look like this: + + ```json + { + "bashFunctions": { + "buildPhase": " \n runHook preBuild;\n...", + ... + }, + "variables": { + "src": { + "type": "exported", + "value": "/nix/store/3x7dwzq014bblazs7kq20p9hyzz0qh8g-hello-2.10.tar.gz" + }, + "postUnpackHooks": { + "type": "array", + "value": ["_updateSourceDateEpochFromSourceRoot"] + }, + ... + } + } + ``` + # Description -This command prints a shell script that can be sourced by `b`ash and -that sets the environment variables and shell functions defined by the -build process of *installable*. This allows you to get a similar build +This command prints a shell script that can be sourced by `bash` and +that sets the variables and shell functions defined by the build +process of *installable*. This allows you to get a similar build environment in your current shell rather than in a subshell (as with `nix develop`). +With `--json`, the output is a JSON serialisation of the variables and +functions defined by the build process. + )"" diff --git a/tests/nix-shell.sh b/tests/nix-shell.sh index ec43db349..f60102f9c 100644 --- a/tests/nix-shell.sh +++ b/tests/nix-shell.sh @@ -96,6 +96,8 @@ echo foo | nix develop -f shell.nix shellDrv -c cat | grep -q foo nix_develop -f shell.nix shellDrv -c echo foo |& grep -q foo # Test 'nix print-dev-env'. +[[ $(nix print-dev-env -f shell.nix shellDrv --json | jq -r .variables.arr1.value[2]) = '3 4' ]] + source <(nix print-dev-env -f shell.nix shellDrv) [[ -n $stdenv ]] [[ ${arr1[2]} = "3 4" ]]