background

All Journals

Currently at page #2 in 2 pages

4 entries in this page

Nix flake template 可以有 welcomeText 这一个字段,在 nix flake init 写入文件后就会展示这些文字,并且自带 Markdown 渲染。

纯 Nix 实现的 nix-eval-jobs —— eval-jobs.nix 来了(

{ lib }:
let
  # If cond is true, then return the value, return null otherwise.
  optionalNullable = # ... -> Nullable x
    cond: # Bool
    x: # x
    if cond then x else null;

  # Map elements to other elements or nulls and filter out nulls.
  mapNullables = # ... -> [x] -> [x]
    f: # x -> Nullable x
    lib.lists.concatMap (
      x:
      let
        y = f x;
      in
      if y != null then [ y ] else [ ]
    );

  # Transform the attrset and optionally filter out some elements.
  filterMapAttrsRecursiveCond = # ... -> Attrset
    recursePred: # AttrSet -> Bool | Whether to recurse into this attrset or treat it as leaf.
    mapper: # [String] -> Any -> Nullable Any | Map this leaf element given its path.
    attrs: # AttrSet | The attrset to transform.
    let
      recurseImpl = # ... -> Attrset
        path: # [String]
        attrs: # Attrset
        lib.pipe attrs [
          lib.attrsets.attrsToList
          (mapNullables (
            { name, value }:
            let
              subPath = path ++ [ name ];
              shouldRecurse = lib.isAttrs value && recursePred value;
              newValue = if shouldRecurse then recurseImpl subPath value else mapper subPath value;
            in
            lib.mapNullable (lib.attrsets.nameValuePair name) newValue
          ))
          lib.attrsets.listToAttrs
        ];
    in
    recurseImpl [ ] attrs;

  # Selectively retrieve packages with some convenient metadata and filter out non-derivation
  # elements using a custom predicate.
  evalJobsWithPred = # ... -> [AttrSet]
    drvPred: # Derivation -> Bool | Whether to build this derivation.
    packageSet: # AttrSet | Package set to process.
    let
      toJobMetadata = path: drv: {
        inherit drv;
        inherit (drv)
          name
          drvPath
          outputs
          system
          ;
        attr = lib.strings.concatStringsSep "." path;
        attrPath = path;
        outPaths = lib.lists.map (outputName: drv.${outputName}.outPath) drv.outputs;
        type = "jobMetadata";
      };

      filteredPkgs = filterMapAttrsRecursiveCond (attrs: !(lib.isDerivation attrs)) (
        path: value: optionalNullable (lib.isDerivation value && drvPred value) (toJobMetadata path value)
      ) packageSet;

      flattenedPkgsList =
        let
          flattenImpl =
            value:
            if lib.isAttrs value then
              if value.type or "" == "jobMetadata" then
                [ value ]
              else
                lib.lists.concatMap flattenImpl (lib.attrsets.attrValues value)
            else
              [ ];
        in
        flattenImpl filteredPkgs;
    in
    flattenedPkgsList;

  # Default predicate for filter derivations that needn't to built.
  defaultDrvPred = # ... -> Bool
    drv: # Derivation
    let
      isBuildable =
        drv:
        let
          licenseFromMeta = drv.meta.license or [ ];
          licenseList = if lib.isList licenseFromMeta then licenseFromMeta else [ licenseFromMeta ];
        in
        !(drv.meta.broken or false) && lib.lists.all (license: license.free or true) licenseList;

      isCacheable = drv: !(drv.preferLocalBuild or false);
    in
    isBuildable drv && isCacheable drv;

  # Selectively retrieve packages with some convenient metadata and filter out non-derivation
  # elements.
  evalJobs = # ... -> [AttrSet]
    packageSet: # AttrSet | Package set to process.
    evalJobsWithPred defaultDrvPred packageSet;
in
{
  inherit
    evalJobs
    evalJobsWithPred
    defaultDrvPred
    ;
}

最近更新了 NVIDIA,结果 Niri 变得非常卡顿。原因是 NVIDIA 的 DRM 设备路径从 /dev/dri/renderD129 改变为了 /dev/dri/renderD128,Niri 因此使用了 Intel 显卡的 DRM 设备。因此建议在引用设备文件路径时,尽可能使用稳定的表示,比如这里 /dev/dri/by-path/pci-0000:01:00.0-render 就相对更加稳定;又比如在指定硬盘设备文件路径时使用 /dev/disk/by-id,这是按照硬盘型号来选择的。

Nix 打包时可能会遇到需要引用包自身的情况,如果 finalAttrs 可用,则可以用 finalAttrs.finalPackage。但是如果没办法使用 finalAttrs,情况就不一样了。finalPackage 可以通过 package.nix 这个 lambda 的参数传入,在 callPackage 后利用 let in 或 fix 函数来把这个结果传入进去。这样的问题在于传入的 finalPackage 不会跟随 override 和 overrideAttrs 变化。

我的解决方案是在 callPackage 后替换原有的 override 和 overrideAttrs 为自己的版本,调用原来的 override/overrideAttrs 后额外 override 一次 finalPackage 参数。

假设有以下 package.nix:

{
  stdenvNoCC,
  testFinalPackage,
  myText ? "myText",
}:

stdenvNoCC.mkDerivation {
  pname = "test-package";
  version = "0";

  dontUnpack = true;

  installPhase = ''
    echo ${myText} > $out
  '';

  passthru.finalPackage = testFinalPackage;
}

以下代码片段实现了 override 和 overrideAttrs 自动传入新 finalPackage:

let
  pkgs = import <nixpkgs> { };
  lib = pkgs.lib;
in

let
  makePackageOverridable =
    finalPackageName: package:
    package
    // {
      override =
        args:
        let
          overriddenPackage = ((package.override args).override { ${finalPackageName} = newPackage; });
          newPackage = makePackageOverridable finalPackageName overriddenPackage;
        in
        newPackage;

      overrideAttrs =
        args:
        let
          overriddenPackage = ((package.overrideAttrs args).override { ${finalPackageName} = newPackage; });
          newPackage = makePackageOverridable finalPackageName overriddenPackage;
        in
        newPackage;
    };

  finalPackageAwareCallPackage =
    callPackage: func: finalPackageName: attrs:
    let
      called = callPackage func (attrs // { ${finalPackageName} = finalPackage; });
      finalPackage = makePackageOverridable finalPackageName called;
    in
    finalPackage;

  p = finalPackageAwareCallPackage pkgs.callPackage ./package.nix "testFinalPackage" { };
in
{
  inherit pkgs lib;

  inherit p;
}

在 Nix REPL 中测试:

nix-repl> :l ./test.nix
Added 3 variables.

nix-repl> p
«derivation /nix/store/a5a5pykbm30fgyhy40nqz0iis969k6yc-test-package-0.drv»

nix-repl> p.finalPackage
«derivation /nix/store/a5a5pykbm30fgyhy40nqz0iis969k6yc-test-package-0.drv»

nix-repl> p2 = (p.override { myText = "myText2"; }).overrideAttrs { version = "1"; }
Updated p2.

nix-repl> p2
«derivation /nix/store/wpxlrqdqminbhhsn3g1yws2160lnwn5k-test-package-1.drv»

nix-repl> p2.finalPackage
«derivation /nix/store/wpxlrqdqminbhhsn3g1yws2160lnwn5k-test-package-1.drv»