opt.nix

nix语言中只有let ... in来定义局部变量,没有提供全局变量的语法支持。 但在我的nix配置中又很需要一些“全局变量”来方便统一的管理多个配置文件。 有2种可行的方案来实现全局变量:module和import。

module

nixpkgs的module能够还不错地实现“全局变量”。 想了解module?可以去看看NixOS wikiL modules。 或者看看nixpkgs源码关于modules.nix的部分<nixpkgs>/lib/modules.nix

要注意的是,基于module的“全局变量”也会有局限的。 module是用过imports变量导入的,若在imports语句访问“全局变量”,nix的lazy evaluation的特性会导致死循环。 这也是为什么老版本的home.nix中判断是否需要导入./usr/gui.nix, 我没有使用config.isGui而是再次使用getEnv访问环境变量。 当然这个不足也是我放弃使用的module主要原因。

import

通过在配置文件中import opt.nix也能还不错的实现“全局变量”。 import方法的最大优势是能够在module imports语句中避免死循环。

这个方法的不足之处在于每个需要使用全局变量的文件都需要import opt.nix。 但这个不方便之处,相对imports死循环,没那么让人难受。

{
  isMinimalConfig = false;

proxyPort:代理端口号,诸多网络程序需要用,比如clash和tailscale。

  proxyPort = 8889;

isCliisGui:通过环境变量DISPLAY来判断是否是CLI或GUI环境。 这个方法有局限,比如ssh连接到一台有GUI的电脑上,ssh里是没有设置环境变量DISPLAY的。 因此更好的方法是在opt-local.nix中写入固定的isCli和isGui值。

  isCli = (builtins.getEnv "DISPLAY")=="";
  isGui = (builtins.getEnv "DISPLAY")!="";

isNixOnDroid:通过用户名来判断是否是nix-on-droid。

  isNixOnDroid = (builtins.getEnv "USER")=="nix-on-droid";

isWSL2:通过环境变量WSL_DISTRO_NAME来判断是否是WSL2。

  isWSL2 = (builtins.getEnv "WSL_DISTRO_NAME")!="";
}

本地配置

引入opt-local.nix,方便本地进行自定义,避免我的nix配置中出现过多设备特定代码(即一堆if else判断语句)。 为了减少设备特定代码,每个设备都有自己的opt-local.nix。 目前的想法是不将opt-local.nix加入git仓库,以实现“设备特定”。 相比opt.nix,opt-local.nix的配置具备更高的优先级。

// (
  if (builtins.pathExists ./opt-local.nix)
  then import ./opt-local.nix
  else {}
)