When and how should default.nix, shell.nix and release.nix be used? - nix

One of the first types of Nix expression one encounters when learning how to use the Nix package manager is default.nix; on the wonderful NixOS IRC channel I learned of the existence of shell.nix and release.nix as well.
I got the impression that - roughly -default.nix is to be used with nix-build for simply building the package, shell.nix is used with nix-shell to create an interactive environment with the package and release.nix is used with nixops in deploying the package.
Since this is likely incomplete and partially incorrect, and since this does not seem to be clearly documented, I would like a clear and precise explanation of these sorts of "standard files"; in particular, for each of these file types (as well as any other standard files I am missing), I would like to know:
What are the typical use cases for such a file? What should they not be used for?
How is this file type structured typically? What are the minimal requirements for it?
Could you show a paradigm example of such a file within its use context, i.e. with use instructions and including lines of code needed to use it in the shell or another Nix expression?
As an additional bonus question, I want to know which - if any - of these standard files should be used when installing a package into a NixOS module? How would that be done?

First of all, default.nix and shell.nix have special meanings in Nix tool, but release.nix is a convenience one.
Next, default.nix is used as a default file when running nix-build, and shell.nix is used as a default file when running nix-shell. Just like you said.
Next, default.nix isn't used only for nix-build. For example, <nixpkgs/lib/default.nix> is used as aggregator for functions, and doesn't contain derivations. So not every default.nix is supposed to be "built" (but if default.nix is an attribute set of derivations, it will be buildable, and nix-build will build all of them).
Next, nix-shell will use default.nix if no shell.nix is found.
Next, default.nix is used as default file when importing directory. So if you write x = import ./some/directory;, then ./some/directory/default.nix will be imported. That actually should explain why "nix-build ." uses default.nix.
And finally, there are two common formats for derivations in default.nix: derivation, and callPackage derivation. You can't nix-build the latter. Almost any package in nixpkgs is written in this style, see hello. But you can
nix-build -E 'with import <nixpkgs> { }; callPackage ./path/to/default.nix { }'
as a workaround. nix-shell also supports this -E argument.

As said by #danbst only default.nix and shell.nix have special meanings for the nix tooling, out of that there is no real standard and everybody is free to use what fits most their needs.
That said, it doesn't mean you cannot set your own set of rules, personally for a single derivation project I like to arrange nix files in the following manner:
default.nix: Use callpackage to import derivation.nix.
derivation.nix: nixpkgs style derivation file.
shell.nix: nix-shell file.
module.nix: NixOS module file, import default.nix.
test.nix: NixOS test file.
release.nix: Hydra jobset declaration.
We had a talk about this topic at the Tokyo NixOS meetup, an example of a such code organization can be found here.

Related

How to force Nix to "install packages" by building them locally instead of downloading a pre-built binary?

By "install packages" I mean to evaluate Nix build expressions (using nix-env, nix-shell -p, etc.) to build from source instead of using a substitute.
Also cross-posted to Unix& Linux because, as Charles Duffy pointed out, it is more on topic if it is about command-line tools or configuration. Still leaving this here because I assume forcing a package to always compile from source is possible by only using the Nix language, I just don't yet know how. (Or if it is in fact not possible, someone will point it out, and then this question does belong here.)
Either set the substitute option to false in nix.conf (the default is true) or use --option substitute false when invoking a Nix command.
nix-env --options substitute false -i hello
nix-shell --options substitute false -p hello
Might not be the droids you are looking for
As Robert Hensing (comment, chat), Henri Menke (comment), and Vladimír Čunát (comment) pointed out, this may not be the thing that you are really after.
To elaborate: I have been using the most basic Nix features confidently, but got to a point where I need to maintain and deploy a custom fork of a large application written in C, which is quite intimidating at the outset.
Tried to attack the problem the simplest way to just fetch my fork and re-build it with the new source, so I boiled it down to this question. Although, I suspect that the right direction for me is something along the lines of Nixpkgs/Create and debug packages in the NixOS Wiki.
Only re-build the package itself
Vladimír Čunát commented that "disabling substitutes makes you rebuild everything that's missing locally, even though I suspect that people asking such a question often only want to rebuild the specified package itself."
(This is probably achieved with nix-build or "just" overriding the original package but could be wrong. The latter is mention (maybe demonstrated even?) in the NixOS wiki article Development environment with nix-shell but haven't been able to read it thoroughly yet.)
Test for reproducibility
One might arrive to formulating this same question if they want to make sure that subsequent builds are deterministic. As Henri Menke comments, one should use nix-build --check for that.
The --check option is easy to miss; it's not documented in man nix-build or at nix-build in the Nix manual, but at nix-store --realize because (as man nix-build explains it):
nix-build is essentially a wrapper around nix-instantiate (to
translate a high-level Nix expression to a low-level store derivation)
and nix-store --realise (to build the store derivation) [and so] all
options not listed here are passed to nix-store --realise, except
for --arg and --attr / -A which are passed to nix-instantiate.
See detailed examples in the Nix manual at 18.1. Spot-Checking Build Determinism and the next section right after it.
The relevant parts for the substitute configuration option under the nix.conf section from the Nix manual:
Name
nix.conf — Nix configuration file
Description
Nix reads settings from two configuration files:
The system-wide configuration file sysconfdir/nix/nix.conf (i.e. /etc/nix/nix.conf on most systems), or $NIX_CONF_DIR/nix.conf if NIX_CONF_DIR is set.
The user configuration file $XDG_CONFIG_HOME/nix/nix.conf, or ~/.config/nix/nix.conf if XDG_CONFIG_HOME is not set.
You can override settings on the command line using the --option flag,
e.g. --option keep-outputs false.
The following settings are currently available:
[..]
substitute
If set to true (default), Nix will use binary substitutes if available. This option can be disabled to force building from source.
(Formerly known as use-binary-caches.)
Notes
Setting substitute to false (either with --options or in nix.conf) won't recompile the package if the command issue multiple times. That is, hello above would be compiled from source the first time, and then it will access the already present store path if the command issued again.
This is where it gets fuzzy: it is clear that no recompilation takes place because unless the package's Nix build expression doesn't change, the store output hash won't change either, making the next compilation output equivalent to the previous one, hence the action would be superfluous.
So if one would do some light hacking on a package, and just wanted to try it out locally (e.g., with nix-shell) then one would have to use -I nixpkgs=a/local/nixpkgs/dir to pick up those changes - and eventually do a recompilation? Or should one use nix-build?
See also question How to nix-build again a built store path?

Nix how to use alternative store path for CI caching

Many CI providers give you a directory whose contents are retained across builds and you can use that as a cache. Everything that is stored elsewhere is lost. This means that any artefacts that are created during a nix-build that are placed in the nix store (/nix/store) are lost. I'm trying to figure out how to convince nix to prefer that other cache directory over the global /nix/store. However the documentation is a bit lacking.
What I've tried so far:
Add file:///the/path to substituters and then nix copy --to that path. However I discovered that nix only creates some metadata files in that directory and copies the actual derivation into /nix/store. That's not what I want.
Use local?root=/the/path instead of the file:// url (btw, this syntax is not documented anywhere, I only found it in a single github issue!). That made nix copy the whole derivation to that folder, but I couldn't figure out how to convince nix-build to actually consult that store during build.
Would it be possible to use something along the lines of nix run --store ~/my-nix nixpkgs.hello -c hello --greeting 'Hi everybody!'? The installation guide points to uses of --store for such a use case, as well as some sections in the manual: 1, 2.
An example of this can be found in nix run's tests.
There are also the environment variables NIX_STORE_DIR which might be of use? It's documented in nix-shell --help.
There's also several issues in the Nix repo, here's an interesting discussion.

How to use Nix to setup a development environment?

Let's say I need PostgreSQL 9.6.3 and Ruby 2.3.1 and various other tools. I can't find a tutorial that explains what I need to do.
From the Nix manual, I seem to need to write a Nix expression to install the needed dependencies, but I can't make the leap from:
{ stdenv, fetchurl, perl }:
stdenv.mkDerivation {
name = "hello-2.1.1";
builder = ./builder.sh;
src = fetchurl {
url = ftp://ftp.nluug.nl/pub/gnu/hello/hello-2.1.1.tar.gz;
md5 = "70c9ccf9fac07f762c24f2df2290784d";
};
inherit perl;
}
to the expression that will install the proper PostgreSQL and Ruby versions. It is absolutely unclear to me where to even put the file that installs PostgreSQL and Ruby, or how to run a single file in a given directory.
Can someone provide pointers to such tutorials, or point me in the right direction?
You can use nix-shell for this. It drops you into a shell configured to the given nix expression. Initially that expression could simply be along the lines of buildInputs = [ pkgs.ruby ]; and you can develop it from that. There are a number of helpful articles online written by nix users that give more examples of using nix-shell, like this one from garbas.si
You may also find it useful to get a better idea of how nix packages work. There's a separate nixpkgs manual that covers in greater detail using nix to create package expressions. A quick skim of the 3rd section should be useful to give a bit more understanding. There's also a chapter on using nix with ruby bundler that might be useful for you. Again there are articles that give more examples of its use, such as one from stesie.github.io.
If you need postgresql actually running in your environment nix won't manage that for you; its function is solely the building and management of packages, not their activation. You could simply activate postgres manually, use the nix-shell hook, or create some other integration with nix, but I think the most robust option is to make use of the Linux distribution that's built on top of Nix - NixOS. NixOS integrates with nix packages and manages the services provided by the packages. You could create a NixOS configuration with postgres active and your development environment present. This utility from github.com/chrisfarms may also be of interest.

What are different among various dot nix files?

I am new to nixos, this is my understanding about configurations
Configuration files created by installer
/etc/nixos/configuration.nix :: The central point of system description used by nixos-rebuild
/etc/nixos/hardware-configuration.nix :: to be include in above configuration.nix
Configuration files for packages
<package>.nix on nixpkgs github :: configuration for each module (options are searchable on nixos package page)
These are what I do not fully understand
defatult.nix (any where in filesystem) :: for nix-shell like .bashrc
~/.nixpkgs/config.nix :: nix-env overrided configuration for each users
~/.config/<various>.nix :: ?? no idea
Am I understand it right?
Where can I find more information on these configuration files?
You don't call all of these files configuration files. E.g. the <package>.nix files are rather called derivations. What all these files share is the language in which they are written.
/etc/nixos/configuration.nix is indeed where you configure your system and ~/.nixpkgs/config.nix where you configure nix-env.
default.nix doesn't mean anything in particular except that this is the default file that it selected by the commands nix-build and nix-shell when you give them a directory as argument instead of a specific file. Note e.g. that the nixpkgs collection (on GitHub like you noticed already) contains a lot of such default.nix files.
To understand all of this better I advise you to read Nix-pills (that's a long series but it's worth it) and of course the NixOS, Nix and nixpkgs manuals.

Why do we still use the package keyword in Groovy / Grails?

in Java/Groovy, afaik, a package has to be defined in the corresponding folder. This results in all class files which are stored in /a/b/c start with the line package a.b.c. Is this still necessary? With regards to convention over configuration, this isn't DRY...
What kind of problems would arise when this package definition would be optional`?
While it is conventional for the directory structure to match the package structure, and certain problems arise if they don't match, it is in fact not a requirement that they match. This is also true of Java (though a lot of folks don't realize that).
Below is an example which demonstrates this.
groovydemo $ mkdir classes
groovydemo $
groovydemo $ cat src/groovy/com/demo/SomeClass.groovy
package com.somethingotherthandemo
class SomeClass {}
groovydemo $
groovydemo $ groovyc -d classes/ src/groovy/com/demo/SomeClass.groovy
groovydemo $ find classes -type f
classes/com/somethingotherthandemo/SomeClass.class
The reasons for using packages in Groovy (and Grails) are some of the same reason why they are used in Java.
Packages serve to organize classes into logical namespaces, typically by grouping collaborating classes together.
It helps avoid naming conflicts with other classes (either Java or Groovy).
In any non-trival system where you have hundreds or thousands of classes, packages provide a very useful mechanism for organization and structure.
I think what you're saying is that the package name is implied by the directory the class is in, so why do you need to state it explicity? This is only true in some cases (like Grails) where there's a convention that establishes the root of the source files (e.g. src/groovy).
But imagine I'm writing a Groovy app and have a file at /a/b/c/D.groovy, how can we tell if the root of the source files is /a and thus the package name is b.c or the root of the source files is /a/b and therefore the package name is just c? As far as I can see, we can't, so the package name needs to be stated in the source file explicitly.

Resources