学一点点nix打包

学一点点nix打包

nix要做Reproducible builds and deployments.感觉上和虚拟环境的包管理有点像(python那种),但实现方式上有区别,用起来简单

2023-08-25:packaging-existing-software

icat.nix:

{ lib
, stdenv
, fetchFromGitHub
, imlib2
, xorg
}:
 
stdenv.mkDerivation {
  name = "icat";
 
  src = fetchFromGitHub {
    owner = "atextor";
    repo = "icat";
    rev = "v0.5";
    sha256 = "0wyy2ksxp95vnh71ybj1bbmqd5ggp13x3mk37pzr99ljs9awy8ka";
  };
 
  buildInputs = [ imlib2 xorg.libX11.dev ];
 
  installPhase = ''
    mkdir -p $out/bin
    cp icat $out/bin
  '';
}

icat.nix:

let
  pkgs = import <nixpkgs> { };
in
{
  icat = pkgs.callPackage ./icat.nix { };
}

import <nixpkgs> 导入nixpkgs并返回包含所有可用包的集合

pkgs.callPackage是在这个集合中查找和调用指定包定义的方法

hello.nix没有显式从nixpkgs中使用任何东西。之所以可在nixpkgs环境中工作,是因为在调用这个打包函数时,会默认传入nixpkgs中定义的变量,如stdenv, fetchzip等

Nix中函数调用需以{ attr = value; }的形式提供AttrSet,即使不需任何参数,也要提供空的{ },表示调用这个函数时不传入任何参数

callPackage参数格式有点特殊:

  • Nix中,callPackage的完整签名是: callPackage : PkgSet -> Path -> AttrSet -> Derivation。它接受3个参数:
    1. PkgSet - 存放所有包定义的集合,通常是import <nixpkgs> 返回的结果。callPackage内部会自动使用这个pkgs集合,不需传递
    2. Path - 指向具体包定义文件的路径,如 ./hello.nix
    3. AttrSet - 传递给包定义函数的配置参数
    4. Derivation - 这个->在Nix的函数签名中,指向最后一个参数是返回值类型

尽管callPackage是函数调用,但其参数中既包含常规的参数(AttrSet),也包含非参数形式的参数(PkgSet和Path)

因为callPackage是特殊的接口函数,它将找到包定义文件和调用包定义函数这两个动作组合在一起

这实际上是Nix一个特殊的语法点,允许某些"函数"像语言构造一样使用,让包的导入更方便


Nix 中 derivation 是构建过程的描述,指定如何构建包(package)

可创建 overlay 来添加或重写包。Overlay 是函数,接受包集合(pkgs)作为输入,返回修改后的包集合


在 NixOS 或使用 Nix 的 home-manager 管理环境中,xdg.configFile 是一个配置选项,用于管理遵循 XDG 基础目录规范的配置文件。这里的 xdg 代表 "XDG Base Directory Specification"。

XDG Base Directory Specification 是由 FreeDesktop.org 定义的标准,旨在规范 UNIX 类系统中用户配置文件、数据文件和缓存文件的存储位置。这个规范旨在替代传统的将所有配置文件放在用户家目录下的做法(例如,大量的点文件(dotfiles)和点目录(dot directories)),从而提供一种更有组织的方式来管理这些文件。

根据 XDG 规范,配置文件通常存放在 $HOME/.config 目录下。因此,在 home-manager 中使用 xdg.configFile 时,你可以指定在 .config 目录下的特定路径和文件内容。例如:

xdg.configFile."hypr/hyprland.conf".text = ''
  # hyprland 配置内容
  ...
'';

这个配置将会在用户的 .config/hypr/ 目录下创建一个名为 hyprland.conf 的文件,并填充指定的内容。


(pkgs.python3.withPackages (ps: with ps; [
    # ...
]))

withPackages:

  • withPackages 是一个函数,属于 python3 对象。它的作用是创建一个包含指定 Python 包的环境。
  • 这个函数接受另一个函数作为参数,这个参数函数用于定义需要包含的 Python 包。

(ps: with ps; [ ... ]):

  • 这是传递给 withPackages 的函数。它的参数 ps 代表 Python 包的集合。
  • with ps; 是一个 Nix 语言的构造,它允许在后续的表达式中直接使用 ps 中的属性,而不需要再次写 ps. 前缀。这样做的目的是为了简化代码。
  • [ ... ] 是一个列表,你可以在这个列表中指定你希望包含在你的 Python 环境中的所有包。例如,ps.lxml 和 ps.requests 是 ps 集合中的两个包。

mkOption 用于创建一个模块选项的定义,这个选项之后可以在 NixOS 的配置文件中设置。这个函数允许你指定一些关键的属性:

  • type: 这个属性定义了选项值的类型,比如 string, int, bool 等。
  • default: 定义了这个选项的默认值。
  • description: 提供了对这个选项的描述,通常用于生成文档和帮助信息。
  • example: 给出一个或多个这个选项的使用示例。

通过使用 mkOption,你可以创建一个结构化的、有类型的配置选项,这使得 NixOS 的配置既灵活又具有自我文档化的特点。

例如,如果你想在你的 NixOS 配置中添加一个新的选项来控制某个服务的日志级别,你可能会这样使用 mkOption:

services.yourService.logLevel = mkOption {
  type = types.enum ["debug" "info" "warn" "error"];
  default = "info";
  description = "The log level for your service.";
};

如何查找谁依赖samba这个包?

先找到当前系统是什么

export CURRENT_NIXOS_SYSTEM=$(readlink -f /nix/var/nix/profiles/system)
 
echo $CURRENT_NIXOS_SYSTEM
# /nix/store/bs80l2lbz1dpa8xi2s7z3nh2r9zfqwbd-nixos-system-Mikan-24.05.20231207.26a3184

找到samba这个包在哪里:

nix-store -q --requisites $CURRENT_NIXOS_SYSTEM | grep -i samba
# /nix/store/1xria1n7sk0s2k6fb3jg54wj5f8ai3kx-samba-4.19.2

然后查

nix-store --query --referrers /nix/store/1xria1n7sk0s2k6fb3jg54wj5f8ai3kx-samba-4.19.2

Nix 系统中存在两套命令行接口(CLI)模式,这通常指的是传统的 Nix 命令(如 nix-build)和新的基于 nix 命令的接口(如 nix build)。这种区别主要是由 Nix 的发展和迭代引起的。


let
  hostname = "mikan";
in
{
  modules-left = [
    "custom/weather"
    "battery"
    "hyprland/workspaces"
  ] ++ lib.optional (hostname == "mikan") ["acpi" "privacy"]
}

lib.optional根据条件决定是否包含给定的元素