Once you have your Nix package manager in place, you definitely want to have home-manager. home-manager is a tool for declaratively managing user environment using nix.
--Packages to install
--Configuration files such as ~ / .profile
, ~ / .bashrc
, ~ / config / fish
--fish, tmux, firefox, plugins
--email account
It is an excellent tool that allows you to manage various user settings declaratively in a single file.
If you put only nix and home-manager, even if you switch to a PC, it is not a dream to complete the setup with a single command. (I did that when I actually replaced my PC at work.)
For more information, see home-manager's github page or manual. As you can see, it's in English and it's long, so I'll just summarize the main points for myself.
You need a Nix package manager to use home-manager, so install Nix first.
> curl -L https://nixos.org/nix/install | sh
> nix-channel --add https://nixos.org/channels/nixpkgs-unstable nixpkgs
> nix-channel --update
You can subscribe to the channel with nixchannel --add <url> [channel-alias]
. It's like registering a repository.
To install home-manager, first subscribe to the home-manager channel.
> nix-channel --add https://github.com/nix-community/home-manager/archive/master.tar.gz home-manager
> nix-channel --update
Then you can install it by typing the following command.
> nix-shell '<home-manager>' -A install
To set up your user environment using home-manager, create ~ / .config / nixpkgs / home.nix
.
For example, the following settings install git and GNU / hello.
nix:.config/nixpkgs/home.nix
{ pkgs, ... }:
{
#This is home-Enters automatically when manager is installed
programs.home-manager.enable = true;
home.username = "hnakano";
home.stateVersion = "20.09";
#Declare the package to install here
home.packages = [
pkgs.git
pkgs.hello
];
}
Then type the following command to reflect the settings.
> home-manager switch
This configuration file is written in a proprietary language called Nix expression. To be honest, it's almost like json, so you don't have to worry too much about grammar, but I will explain the minimum grammar for those who care.
repl
There is a Nix expression repl. You can enter repl by typing nix repl
on the command line.
> nix repl
Welcome to Nix version 2.3.7. Type :? for help.
nix-repl>
Type :?
To get help with the repl command. You can exit the repl with : q
.
There are numeric, Boolean, and string types.
The string concatenation is +
.
nix-repl> 1 #interger
1
nix-repl> 3.14 #float
3.14
nix-repl> true #boolean
true
nix-repl> "hogehoge" #string
"hogehoge"
nix-repl> "hoge" + "fuga" #string concatenate
"hogefuga"
let ... in
Use let ... in
to assign a value to a variable.
Pay attention to the position of the semicolon.
nix-repl> let x = 1; y = 2; z = x + y; in z * 2
6
You can assign values only in repl without using let ... in
.
However, please note that normal Nix expression cannot be written in this way.
nix-repl> x = 3
nix-repl> y = 4
nix-repl> x + y
7
List
The list is [a b c]
. Element delimiters are single-byte spaces or line breaks.
By the way, the types do not need to match **
nix-repl> [ 1 "hoge" true ]
[ 1 "hoge" true ]
nix-repl> [
1
2
3
]
[ 1 2 3 ]
To access the elements of the list, use the built-in function builtins.elemAt
. No parentheses are required to apply the function.
nix-repl> x = [ 1 2 3 ]
nix-repl> builtins.elemAt x 0
1
nix-repl> builtins.elemAt x 1
2
Nix functions are of the form ʻarg: body. The left side of the colon is the argument. The two-argument function is ʻarg1: arg2: body
.
nix-repl> hello = x: "hello, " + x
nix-repl> hello "world"
"hello, world"
Basically Nix can only create anonymous functions.
nix-repl> x: y: x + y
«lambda @ (string):1:1»
So if you want to name the function, use the let
expression
nix-repl> let
add = x: y: x + y;
add2 = add 2; #Can be partially applied
in
add2 3 #Same as add 2 3
5
Attribute set
An Attribute set is a pair of key = value enclosed in curly braces in the form {key1 = value1; key2 = value2;}
.
A semicolon is always required at the bottom of the key = value;
pair.
You can access the value in the form x.key1
.
nix-repl> let
x = {
hoge = "hoge";
fuga = "fuga";
};
in x.hoge
"hoge"
Functions that take an attribute set as arguments can usually be defined in the form ʻarg: body`.
nix-repl> let
f = x: x.hoge + x.fuga;
in f { hoge = "hoge"; fuga = "fuga"; }
"hogefuga"
However, it can also be defined in the form {key1, key2}: body
instead.
In this form, an error will occur if the name of the argument key does not exactly match.
You can avoid this error by putting ...
in the argument, like {key, key2, ...}: body
.
nix-repl> f = { hoge, fuga }: hoge + fuga
nix-repl> let x = { hoge = "hoge"; fuga = "fuga"; }; in f x
"hogefuga"
nix-repl> let y = { hoge = 3; fuga = 4; piyo = true; }; in f y
error: anonymous function at (string):1:2 called with unexpected argument 'piyo', at (string):1:50
nix-repl> g = { hoge, ... }: "hello, " + hoge
nix-repl> let y = { hoge = "world"; fuga = 4; piyo = true; }; in g y
"hello, world"
Nix Expression grammar reference
--Official manual https://nixos.org/manual/nix/stable/#chap-writing-nix-expressions --Nix Pills (Official Blog) https://nixos.org/guides/nix-pills/basics-of-language.html
Let's read the first defined configuration file again.
nix:./config/nixpkgs/home.nix
{ pkgs, ... }:
{
#This is home-Enters automatically when manager is installed
programs.home-manager.enable = true;
home.username = "hnakano";
home.stateVersion = "20.09";
#Declare the package here
home.packages = [
pkgs.git
pkgs.hello
];
}
First, we can see that this expression is a function that takes an Attribute set with the key pkgs
as an argument.
pkgs
usually contains<nixpkgs>
that is, the Unix package collection.
{key1.key2 = value;}
is syntactic sugar for nested attribute sets, which stands for {key1 = {key2 = value;};}
.
Without syntactic sugar, this config file would look like this:
{ pkgs, ... }:
{
programs = {
home-manager = {
enable = true;
};
};
home = {
username = "hnakano";
stateVersion = "20.09";
packages = [
pkgs.git;
pkgs.hello;
];
};
}
That is, this function takes an Attribute set of {pkgs = ..; ...}
as an argument.
It is a function that returns an Attribute set of {programs = {...}; home = {...};}
.
The home-manager
command evaluates this return value and reflects the settings in the user environment.
I will try various settings using home-manager. For the contents that can be set in home-manager, refer to home-manager manual.
nix:.config/nixpkgs/home.nix
{
home.packages = with pkgs; [ nixfmt exa bat source-han-code-jp ];
programs.git = {
enable = true;
userName = "hnakano863";
userEmail = "[email protected]";
extraConfig.pull.rebase = false;
};
fonts.fontconfig.enable = true;
programs.bash = {
enable = true;
profileExtra = ''
export XDG_DATA_DIRS=$HOME/.nix-profile/share''${XDG_DATA_DIRS:+:}$XDG_DATA_DIRS
export LIBGL_ALWAYS_INDIRECT=1
export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}'):0
if [ -e $HOME/.nix-profile/etc/profile.d/nix.sh ]; then
. $HOME/.nix-profile/etc/profile.d/nix.sh;
fi
'';
initExtra = ''
if [ -z $IN_NIX_SHELL ]; then exec fish fi
'';
shellAliases = {
ls = "exa";
cat = "bat";
};
};
programs.fish = {
enable = true;
interactiveShellInit = ''
set -gx fish_user_paths $HOME/go/bin $HOME/.local/bin
'';
};
programs.tmux = {
enable = true;
clock24 = true;
keyMode = "vi";
shortcut = "a";
terminal = "screen-256color";
};
}
There are some grammatical items that I have not explained, so I will explain them.
First, in home.packages
, there is the formwith pkgs; [...]
.
This is a syntax to avoid writing pkgs.
, such as[pkgs.nixfmt pkgs.exa ...]
.
Next is the string enclosed in two single quotes that appears in programs.bash.profile Extra
etc.
This is a string of type indented string.
Indented is ignored in the indented string, which is useful for writing shell scripts.
In fact, programs.bash.profile Extra
is reflected in ~ / .profile
.
Finally, if you have programs.bash.enable = true;
, running home-manager switch
will try to replace ~ / .profile
, ~ / .bashrc
, and so on.
At this time, if an existing configuration file such as ~ / .bashrc
already exists in the user environment, the home-manager
command will fail with an error saying "I have a configuration file".
To avoid this, save the existing files in advance with mv ~ / .bashrc ~ / .bashrc.bk
.
Recommended Posts