Cannot evaluate a function that has an argument without a value ('runCommand')

runCommand

Years ago I had a try at NixOs. I remembered that JGrahamC had a “docbook rocks” page up and I dug up the corresponding repository. It seems however that the nix files aren’t up to date (fair enough, repo is in archival mode) but I would like to adapt it.

See the default.nix: docbook.rocks/default.nix at ab1c85c52145d18d2cf12119cf2a56436f16e789 · grahamc/docbook.rocks · GitHub
I did adjust it a little to fix obvious name mismatches

{ runCommand, stdenv, lib, jing, libxslt, docbook5, docbook_xsl_ns,
  libxml2, callPackage }:
let
  documentation-highlighter = callPackage ./documentation-highlighter {};
  manualXsltprocOptions = toString [
    "--param section.autolabel 1"
    "--param section.label.includes.component.label 1"
    "--stringparam html.stylesheet style.css"
    "--stringparam html.script './highlightjs/highlight.pack.js ./highlightjs/loader.js'"
    "--param xref.with.number.and.title 1"
    "--param toc.section.depth 3"
    "--stringparam admon.style ''"
    "--stringparam callout.graphics.extension .svg"
    "--stringparam current.docid book-docbook-rocks"
    #"--param chunk.first.sections 1"
    #"--param use.id.as.filename 1"
    "--param make.clean.html 1"
    "--param suppress.navigation 1"
    #"--stringparam generate.toc 'book chapter section'"
    "--param id.warnings 1"
  ];

in stdenv.mkDerivation {
  name = "docbook.rocks";

  src = ./.;
  buildInputs = [ jing libxslt libxml2 ];

  installPhase = ''
    jing ${docbook5}/xml/rng/docbook/docbook.rng $combined

    # Generate the HTML manual.
    dst=$out/
    mkdir -p $dst

    xmllint --xinclude --output ./combined.xml ./book.xml

    xsltproc \
      ${manualXsltprocOptions} \
      --nonet --output $dst/index.html \
      ${docbook_xsl_ns}/xml/xsl/docbook/xhtml/docbook.xsl \
      ./combined.xml

    sed -i -e 's#</head>#<meta name="viewport" content="width=device-width, initial-scale=1" /></head>#' $out/index.html

    mkdir -p $dst/images
    cp -r ${docbook_xsl_ns}/xml/xsl/docbook/images/callouts $dst/images/callouts

    cp ${./style.css} $dst/style.css
    mkdir $dst/highlightjs/
    cp ${documentation-highlighter}/highlight.pack.js \
       ${documentation-highlighter}/LICENSE \
       ${documentation-highlighter}/loader.js \
       $dst/highlightjs/
  '';
}

But then I get an error of

 % nix-build
error: cannot evaluate a function that has an argument without a value ('runCommand')

       Nix attempted to evaluate a function as a top level expression; in
       this case it must have its arguments supplied either by default
       values, or passed explicitly with '--arg' or '--argstr'. See
       https://nixos.org/manual/nix/stable/expressions/language-constructs.html#functions.

       at /Users/holger/ext/docbook.rocks/default.nix:1:3:

            1| { runCommand, stdenv, lib, jing, libxslt, docbook5, docbook_xsl_ns,
             |   ^
            2|   libxml2, callPackage }

This is not intended to be built with a raw nix-build, it’s supposed to be invoked with nixpkgs’ callPackage. Instead you could use:

nix-build -E 'let pkgs = import <nixpkgs> { }; in pkgs.callPackage ./docbook.nix {}'

But well, this is designed more as a nix package than a nix project. You’d just use that snippet in a nixos config or shell.nix or such.

ok, that works.

One think that I don’t know how to do with a nix-shell setup is how to extract the paths that are needed for the schemas. For example jing ${docbook5}/xml/rng/docbook/docbook.rng $combined pulls in docbook.rng as distributed with the docbook5 package. How would I obtain the docbook5 document root in the nix file hierarchy in a shell script that I launch with a nix-shell shebang?

That’s very tricky. I think generally I wouldn’t recommend using those shebangs, unless you really have no choice. They’re not exactly reproducible (because they rely on host channel versions).

I’m actually not sure it’s possible with this package, since it doesn’t expose anything via $out/bin or such. Double check if there’s something useful in the env of such a script if you really want to use a shebang for it.

I would probably create a shell.nix, or a separate package that just contains a shell script instead. How exactly do you want to deploy this?

We typically set an environment variable in the shell derivation:

and then use that in the code: