diff --git a/nix/eval-machine-info.nix b/nix/eval-machine-info.nix index 0ee2cb1ae..208acda90 100644 --- a/nix/eval-machine-info.nix +++ b/nix/eval-machine-info.nix @@ -5,13 +5,15 @@ , deploymentName , args , pluginNixExprs +, evalFile ? null }: with import { inherit system; }; with lib; - -rec { +let + evaluator = if evalFile != null then (import evalFile) else id; +in evaluator (rec { importedPluginNixExprs = map (expr: import expr) @@ -200,4 +202,4 @@ rec { getNixOpsArgs = fs: lib.zipAttrs (lib.unique (lib.concatMap fileToArgs (getNixOpsExprs fs))); nixopsArguments = getNixOpsArgs networkExprs; -} +}) diff --git a/nixops/__main__.py b/nixops/__main__.py index 3bc45f247..593483195 100755 --- a/nixops/__main__.py +++ b/nixops/__main__.py @@ -527,6 +527,16 @@ help="include the physical specification in the evaluation", ) +subparser = add_subparser( + subparsers, "eval", help="eval the given file is nix code in the network expression" +) +subparser.set_defaults(op=op_eval) +subparser.add_argument("code", metavar="CODE", help="code") +subparser.add_argument( + "--json", action="store_true", help="print the option value in JSON format" +) +subparser.add_argument("--strict", action="store_true", help="enable strict evaluation") + subparser = add_subparser( subparsers, "list-generations", diff --git a/nixops/deployment.py b/nixops/deployment.py index 5171613e9..7573f4b90 100644 --- a/nixops/deployment.py +++ b/nixops/deployment.py @@ -395,7 +395,7 @@ def _eval_flags(self, exprs: List[str]) -> List[str]: "--arg", "pluginNixExprs", py2nix(extraexprs), - "", + self.expr_path + "/eval-machine-info.nix", ] ) return flags @@ -503,6 +503,37 @@ def evaluate(self) -> None: ) self.definitions[name] = defn + def evaluate_code(self, code: str, json: bool = False, strict: bool = False) -> str: + """Evaluate nix code in the deployment specification.""" + + exprs = self.nix_exprs + phys_expr = self.tempdir + "/physical.nix" + with open(phys_expr, "w") as f: + f.write(self.get_physical_spec()) + exprs.append(phys_expr) + + try: + return subprocess.check_output( + ["nix-instantiate"] + + self.extra_nix_eval_flags + + self._eval_flags(exprs) + + [ + "--eval-only", + "--arg", + "checkConfigurationOptions", + "false", + "--arg", + "evalFile", + code, + ] + + (["--strict"] if strict else []) + + (["--json"] if json else []), + stderr=self.logger.log_file, + text=True, + ) + except subprocess.CalledProcessError: + raise NixEvalError + def evaluate_option_value( self, machine_name: str, diff --git a/nixops/script_defs.py b/nixops/script_defs.py index 567f163d7..faac0d3b7 100644 --- a/nixops/script_defs.py +++ b/nixops/script_defs.py @@ -893,6 +893,14 @@ def op_show_option(args): ) +def op_eval(args): + with deployment(args) as depl: + depl.evaluate() + sys.stdout.write( + depl.evaluate_code(args.code, json=args.json, strict=args.strict) + ) + + @contextlib.contextmanager def deployment_with_rollback(args): with deployment(args) as depl: