I notice that descriptions of various nixos commands refer to something called the "active Nix expression". For example, the man page for nix-env includes:
--file / -f path
Specifies the Nix expression (designated below as the active Nix expression) used by the --install, --upgrade, and --query
--available operations to obtain derivations. The default is ~/.nix-defexpr.
What is this "active Nix expression"? Where is it defined? Is it simply what is written in /etc/nixos/configuration.nix ordinarily or instead what was defined by nix-shell otherwise?
This is the file from which the Nix expression in which any attribute specified with -A is evaluated. (Absent -A, that content is expected to directly be a derivation).
Let's say you have a mydir/default.nix file that evaluates to an attrset with keys foo, bar, and baz, each of which maps to a derivation as a value.
In this case, running nix-env -f mydir -iA foo will load mydir/default.nix, evaluate foo in the context of that loaded code, run any associated build steps, and add that software to your active environment.
Related
If I create a derivation using nix and then run nix-env --set <derivation name>, then commands like nix-env and nix are now missing from my nix profile and so I get the error Command 'nix-env' not found. I then have to mess around with symlinks in my nix profile to get it back.
This of course makes sense, because the nix package itself is not part of my derivation. Is there a way that I can use nix-env --set without losing access to nix itself?
I'm trying to create a script that starts a docker container and mounts a local folder that contains spaces in the name. I can get it to work fine when I run a *.bat file with the docker run command:
docker run -p 8081:8081 -v "C:\Test Folder With Blanks":/zzz myimage jupyter lab --notebook-dir=/zzz--ip=0.0.0.0 --port=8081 --allow-root
But when I try to do the same in a Powershell script file, I get an error:
$CMD = 'docker run -p 8081:8081 -v "C:\Test Folder With Blanks":/zzz myimage jupyter lab --notebook-dir=/zzz--ip=0.0.0.0 --port=8081 --allow-root'
Invoke-Expression $CMD
docker: invalid reference format.
See 'docker run --help'.
I'm on Win10 and running Powershell in Visual Studio Code IDE.
Thanks for ideas.
First, the obligatory warning: Unless you have a command line stored as a single string somewhere and you either fully control or trust the content of the string, Invoke-Expression should generally be avoided.
You're seeing an inconsistency in how PowerShell treats compound tokens composed of directly concatenated quoted and unquoted parts.
Specifically, argument "C:\Test Folder With Blanks":/zzz is unexpectedly broken in two, i.e passed as two arguments.
The workaround is to quote the entire argument, i.e.
"C:\Test Folder With Blanks:/zzz"
Note: I'm assuming that docker doesn't actually require partial quoting in its arguments, which it shouldn't; however, there are high-profile CLIs on Windows that do, notably msiexec.
Alternatively, use an expression enclosed in (...) to compose your string; e.g.
("C:\Test Folder With Blanks" + ':/zzz')
There's no good reason to do so in this case, but it could be helpful if you need string interpolation in one part of your string ("..."), but not in another ('...').
General caveats:
Compared to cmd.exe and also POSIX-compatible shells such as bash, PowerShell has several additional metacharacters, notably # (at the start of a token), { / }, and ;. Therefore, you cannot always expect command lines written for these shells to work as-is in PowerShell.
As of PowerShell 7.2.2, passing arguments to external programs (such as docker) is fundamentally broken with respect to arguments that have embedded " characters and empty-string arguments - see this answer.
The general pattern of the inconsistency, as of PowerShell 7.2.2, is as follows:
If an argument:
starts with a quoted token - whether single- ('...') or double-quoted ("...") -
and has additional characters directly following the closing quote,
the first such character starts a separate argument.
E.g. "foo":bar / "foo"=bar / "foo"'bar' are passed as separate arguments foo and :bar / foo and =bar / foo and bar, respectively.
In other words:
You cannot compose a single string argument from a mix of quoted and unquoted / differently quoted tokens if the first token is quoted.
Conversely, it does work if the first token is unquoted, including an unquoted simple variable reference such as $HOME.
# OK: First token is unquoted.
PS> cmd /c echo foo"bar"'baz'last
foobarbazlast
# !! BROKEN: First token is quoted.
# !! Because each successive token is quoted too,
# !! each becomes its own argument.
PS> cmd /c echo 'foo'"bar"'baz'last
foo bar baz last
GitHub issue #6467 discusses this inconsistency; however, it has been closed, because the behavior is - surprisingly - considered by design.
This does not happen if the first token is unquoted; however, there are related bugs that start with unquoted tokens that similarly break arguments in two, related to their looking like named arguments to PowerShell (which is a PowerShell concept that doesn't apply when calling external programs):
GitHub issue #11646: an argument such as -foo=1,2 breaks parsing.
GitHub issue #6291: an argument such as -foo=bar.baz is broken in two at the (first) .
In my NixOS machine, I can use nix-env to query about the ghc package in two ways:
One is nix-env -f '<nixpkgs>' -qaP ghc which results in the output
ghc ghc-8.6.5
Another is nix-env -qaP ghc which results in the output
nixpkgs.ghc ghc-8.6.5
For the second case, I would like to understand why the active Nix expression has a nixpkgs root attribute.
The contents of the ~/.nix-defexpr folder and several subfolders are the following:
How is the active Nix expression assembled from the contents of ~/.nix-defexpr? Why there isn't a channels root attribute? Does the name of the nixpkgs root attribute derive from the name of the nixpkgs folder, or is it derived from the contents of the folder, perhaps from something declared in the default.nix file?
The Nix manual has some info on how .nix-defexpr is assembled:
The Nix expressions in this directory are combined into a single set,
with each file as an attribute that has the name of the file.
It doesn't mention what happens if the contents are themselves directories, though. But I found this GitHub issue that explains things a little more:
If a directory is a valid expression (i.e. has default.nix) its expression will be added to the set, otherwise it will be traversed
recursively.
Names of intermediate directories are completely ignored (i.e. do not take any part in attrpaths).
manifest.nix is recursively ignored.
So, there isn't a channels root attribute because the folder doesn't have a default.nix expression.
Ok. Then, as an experiment, I created a folder .nix-defexpr/foo with a file default.nix with contents { zzz = 4; } inside. When I execute nix-env --install -A foo.zzz I get:
error: expression does not evaluate to a derivation (or a set or list of those)
Which means that it actually found the path! The problem is that 4 is not a derivation.
But what if I create another folder .nix-defexpr/whatever and put a copy of the folder foo there? Won't there be some kind of name collision? Yes, there is:
8f792ff4f96a:~# nix-env --install -A foo.zzz
warning: name collision in input Nix expressions, skipping '/root/.nix-defexpr/whatever/foo'
Does Pandoc expose variables set on the command line (pandoc -V foo=bar) to scripts running inside the built in lua filter environment? In other words if I run:
pandoc -V foo=bar --lua-filter=myfilter.lua
...what can I put in myfilter.lua to access foo?
(Since: pandoc 2.17)
PANDOC_WRITER_OPTIONS.variables["foo"]
See https://pandoc.org/lua-filters.html#type-writeroptions
This is documented a bit in the description for the --metadata:
Like --variable, --metadata causes template variables to be set.
But unlike --variable, --metadata affects the metadata of the
underlying document (which is accessible from filters and may be
printed in some output formats) and metadata values will be escaped
when inserted into the template.
So, I think that using -M to set a variable will give you access to the variable inside your lua filter.
nix-build ... --no-out-link gives a path in the Nix store.
Is it possible to find out that path without actually building the expression ?
Is it possible to find out the dependencies and the planned build operations without building the expression ?
How could I find the answer myself ?
The Nix manual, "Building and testing" section refers to nix-build documentation, which in the last "Description" paragraph mentions it is a combination of nix-instantiate and nix-store -r.
nix-instantiate does not build. It only calculates the plan, in the form of a derivation and its closure:
$ nix-instantiate '<nixpkgs>' -A hello
warning: you did not specify '--add-root'; the result might be removed by the garbage collector
/nix/store/20bc2g6gfn44p9wk98s30pm346pmz0x9-hello-2.10.drv
However, I prefer to use nix repl to explore Nix expressions:
$ nix repl '<nixpkgs>'
Loading '<nixpkgs>'...
Added 8623 variables.
nix-repl> hello.outPath
"/nix/store/nic2bl8ry6vfyxr9717983d5b2l4sn1c-hello-2.10"
Its tab completion is very helpful when exploring expressions.
man nix-store has the answer, and in particular the --query section.
To know the output path:
nix-store -q --outputs $(nix-instanciate default.nix)
To know the build-time dependencies:
nix-store -qR --include-outputs $(nix-instanciate default.nix)
As for a build plan, the closer I get is to use the --tree flag.
Note that nix-shell exposes a $out variable too, so another possible solution to the first bullet point would be:
nix-shell --pure --run 'echo $out' some-file.nix