How can I use a nix configuration when not using Nixos? - nix

So I've installed Nix on Arch linux and I'm able to run nix-env -i example, however how can I define a Nix configuration?
As I don't have any /nixos/configuration.nix file present.
Is this possible?
My goal here is to be able to define a configuration which I could then use something like nixos-rebuild switch to install and provision all the software.

I use NixOS, but I use /etc/nixos/configuration.nix to describe my system; I keep it fairly minimal and prefer not to install "user" software by editing configuration.nix.
So what I do instead is use my ~/.nixpkgs/config.nix (which I believe you also have an equivalent of even in a non-NixOS nix install? I've never actually used nix separately).
The basic structure I use is this:
{
packageOverrides = nixpkgs: with nixpkgs; rec {
mine = with pkgs; buildEnv {
name = "mine";
paths = [
# your packages here
];
};
};
}
buildEnv is a convenience function from nix that makes an "environment" package out of a bunch of others; installing the package mine depends on (and so installs) all of the things listed in paths, and also makes sure they get included in PATH and things like that.
Then I just use nix-env -riA nixos.mine to deploy changes I've made to my environment description (or to rebuild my environment following channel updates). The -r tells it to remove everything else other than mine from the new generation of my profile, which means I can (ab?)use nix-env -i some-package as a way of "temporarily" installing some-package, and if I don't decide I like it enough to actually record it in my config.nix it'll just get removed anyway next time I deploy.

You can certainly create your own configuration. For example, you can do something like this:
let
pkgs = import <nixpkgs> {};
in
{
packages = [
pkgs.vim
pkgs.gimp
];
}
That would produce a set containing an attribute called packages, containing a list of Nix packages. But, you'd need to develop a tool to build environments from this, which is part of what nix-env does. For example, the tool can use nix-env to determine what is already installed, compare that to the selected packages in the configuration, and then install/uninstall packages accordingly.
You don't have a /etc/nixos/configuration.nix because that's NixOS-specific. So while you can do as you asked, you'd have to roll your own solution.

Related

More ergonomic/elegant way to use specific version of a package in Nix?

I am trying to use specific versions of two packages:
ruby 3.0.3
postgresql 14.0.4
After hours of googling and experimenting, I came up with such a shell.nix file:
let
# stable-22.05
pkgs = import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/040c6d8374d090f46ab0e99f1f7c27a4529ecffd.tar.gz") {};
# inludes postgres 14.0.4
pgpkgs = import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/d86bcbb415938888e7f606d55c52689aec127f43.tar.gz") {};
# includes ruby 3.0.3
rubypkgs = import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/d1c3fea7ecbed758168787fe4e4a3157e52bc808.tar.gz") {};
in
pkgs.mkShell {
buildInputs = [
pgpkgs.postgresql_14
rubypkgs.ruby_3_0
];
}
(used https://lazamar.co.uk/nix-versions to find a commit)
I am wondering if there is a better way for handling my requirement?
You should not need to define or use pkgs. You can just get the mkShell function from pgpkgs (which seems like the better option since it's slightly newer than rubypkgs.
For the long term, I recommend fixing your project to work with the version of Ruby in commit d86bcbb and then just use that commit for everything, which is simpler than using multiple commits.
Another thing you should know is that you can use git to clone nixpkgs to somewhere on your computer, then use git checkout d86bcbb to check out the commit you are interested in. Then set your NIX_PATH environment variable to make it so that nixpkgs refers to that commit:
export NIX_PATH=nixpkgs=/path/to/your/nixpkgs
Now you can use import <nixpkgs> in your expressions, and if you want to try a different commit you can just use the regular git commands for changing commits, without needing to use a text editor or deal with large hashes. Also, the command nix-shell -p ruby -p postgresql uses NIX_PATH to find its derivations.

Launching IDE directly from nix-shell

I am new to NixOs and nix-shell and am still getting to know its idioms. Right now I have a Java project which I am using nix-shell via direnv to load up the build tool chain, including a jdk and bazel.
I would like the IDE - in my case ItelliJ - to use this same toolchain. My naive approach is to use a nix-shell script as follows, which is the default.nix in the root of my project, and the one picked up by direnv.
with import <nixpkgs> {};
stdenv.mkDerivation {
name = "my-project";
buildInputs = with pkgs; [
jdk11
bazel
jetbrains.idea-ultimate
];
shellHook = ''
export JAVA_HOME="${pkgs.jdk11}/lib/openjdk"
ln -s ${pkgs.jdk11}/lib/openjdk ./jdk
'';
}
I can then launch IntelliJ with the following command from the shell:
$ idea-ultimate 2>1 > /dev/null &
While it works, I have the following concerns:
Loading up the IDE into my command line shell seems really heavy, especially for the CI build.
It is going to get worse as I add other IDEs the team uses, like Eclipse.
It seems like the wrong way.
I can, of course, install these IDE packages using other Nix facilities, like home manager, which gives me the application launcher in the menu after the right config steps; however, I like directly launching the IDE from the shell to ensure the correct tool chain is in place and in correct paths.
My thought for a next step was to remove the IDE input from this default.nix and create custom nix files which include the inputs for the IDE and a launcher script to actually launch the IDE with nix-shell. My hope is that, if executed from the shell above, it will inherit its inputs, augment it with the IDE input, and then launch the IDE.
Again, my goal is to use nix to launch my IDEs, and use the packages and configs setup by the default.nix which is in the root of the project to ensure consistency.
Suggestions, including alternative approaches, are appreciated.

How to make a package that includes runtime dependencies and environment variables?

The question may not be precise, but this is what I am trying to achieve:
The puppeteer-core NPM package requires a headless browser at runtime, and I found that I could use it with the latest Chromium in Nixpkgs. My current workflow:
I have overridden the node2nix-created default.nix with override.nix by adding Chromium to buildInputs:
{pkgs ? import <nixpkgs> {
inherit system;
}, system ? builtins.currentSystem}:
let
nodePackages = import ./default.nix {
inherit pkgs system;
};
in
nodePackages // {
shell = nodePackages.shell.override {
buildInputs = [ pkgs.chromium ];
};
}
Issue nix-shell override.nix -A shell.
export CHROMIUM_PATH=$(which chromium)
Setting up Chromium in the javascript files via process.env.CHROMIUM_PATH.
This works well, and the project can be shared easily with others by creating a tarball, but they would have to set up the environment manually as well, and I also don't like Chromium being included in the build dependencies. I could have just installed it globally with Nix, but the rest of the manual steps would still be there.
I read the manuals, and getting comfortable with the language, but haven't built a derivation or a package yet, therefore I'm sure I missing something obvious.
Some of the discussions I found on the topic:
https://nixos.org/nixos/nix-pills/automatic-runtime-dependencies.html
Runtime-only dependencies #1080
https://discourse.nixos.org/t/handling-dynamic-runtime-dependencies/323

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.

Does luarocks management have "./node_modules" equivalent for projects?

In NodeJS/NPM, you can create a package.json and run npm install to install all your dependencies in a folder within your project: ./node_modules. (A project can be an app or another module/package.)
Ruby also has a "bundler" system (using a .bundle file) that keeps track of gems specific to a dir (ie project).
Does LuaRocks have similar conventions? Or is it recommeneded to install everything to /usr or $HOME?
So far I've been able to get similiar functionality, but I have to create a custom LuaRocks config file and specify --tree=my_local_lua_rocks_dir every time I want to install a rock. Granted, I can always create a bash script. The point is that it seems I'm going against a convention.
It is possible to install rocks into a directory under the current directory, using the --tree flag:
luarocks install --tree ./lua_modules lpeg
And then you have to configure your package.path and package.cpath variables in Lua (settable via LUA_PATH and LUA_CPATH environment variables) so it finds the modules installed inside it. There are several ways to do this conveniently: this tutorial explains how to do it, with more examples.
Instead of using Vert, I've decided to just edit the LuaRocks config file:
In /etc/luarocks/config.lua :
rocks_servers = {
[[http://rocks.moonscript.org/]],
[[http://luarocks.org/repositories/rocks]]
}
rocks_trees = {
[[/usr/local]],
[[./my_dir]]
}
./my_dir is relative to the pwd you're in, not to the location of the config file. Of course, change my_dir to whatever you want.
"The order of the rock_trees matters: When installing rocks, LuaRocks tries to pick a location to store the rock starting from the bottom of the list; when loading rocks in runtime, LuaRocks scans from the top of the list." From: http://luarocks.org/en/Config_file_format
Then in your .bashrc:
eval `luarocks path`
export PATH=$PATH:my_dir/bin
However, for certain commands you now have to specify the tree or it will give you a confusing error:
luarocks make --tree=my_dir

Resources