NixOS 中来自 Haskell 的 运行 shell 命令

Running shell commands from Haskell in NixOS

我是 NixOS 的新手,我正在尝试使用以下函数从 Haskell 程序调用 emacs:

ediff :: String -> String -> String -> IO ()
ediff testName a b = do
  a' <- writeSystemTempFile (testName ++ ".expected") a
  b' <- writeSystemTempFile (testName ++ ".received") b
  let quote s = "\"" ++ s ++ "\""
  callCommand $ "emacs --eval \'(ediff-files " ++ quote a' ++ quote b' ++ ")\'"

当我运行使用stack test调用该命令的程序时,得到如下结果(穿插单元测试结果):

/bin/sh: emacs: command not found
Exception: callCommand: emacs --eval '(ediff-files "/run/user/1000/ast1780695788709393584.expected" "/run/user/1000/ast4917054031918502651.received")'

当我 运行 从我的 shell 上面 运行 失败的命令时,它完美地工作。我如何在 NixOS 中 运行 处理来自 Haskell 的进程,就像我直接调用它们一样,以便它们可以访问与我的用户相同的命令和配置?

你的 shell 和 callCommand 都使用 PATH 环境变量,所以看起来堆栈正在改变它。原来stack默认使用的是纯nixshell,但是你还想访问你的用户环境,就是'impure'.

引用 stack documenation

By default, stack will run the build in a pure Nix build environment (or shell), which means the build should fail if you haven't specified all the dependencies in the packages: section of the stack.yaml file, even if these dependencies are installed elsewhere on your system. This behaviour enforces a complete description of the build environment to facilitate reproducibility. To override this behaviour, add pure: false to your stack.yaml or pass the --no-nix-pure option to the command line.

另一种解决方案是将 Emacs 添加到 stack.yaml 中的 nix.dependencies(感谢@chepner)。它的好处是,当开发人员运行测试时,某些版本的 Emacs 将始终可用,但 Emacs 可能不是他们想要使用的 Emacs。您可以使用 ~/.config/nixpkgs/config.nix 之类的方法来解决这个问题,除非他们在其他地方配置了 Emacs,例如系统配置或家庭管理器。我更喜欢简单但不纯的 $PATH 解决方案。