musicmatzes blog

linux

So I promised I will explain my vim setup in this part of the series. And of course, I will do this.

The requirements

The requirements are fairly easy here. I wanted to be able to use YouCompleteMe with vim, so I need a vim with Python support enabled. So, I absolutely need the configurable vim package from the NixOS package tree and I clearly must override it. And when doing this step, I can remove all the stuff from the vim package I do not need.

Another requirement was that I can replace vim with neovim. I've not done this yet, but I guess it should be fairly easy.

Because not all vim plugins are in the NixOS packages, I need to be able to build my own packages outside of the NixOS package tree and pack them into my store as well.

And, because vim needs to know all these plugins, I must be able to override the runtimepath variable in the vim configuration, the vimrc. So, I need to be able to compile the vimrc out of the package definition as well.

The setup

The directory setup here is fairly easy. I have my normal configuration folder whereas I created a folder vim inside the pkgs folder:

config/nixos/ | +– ./pkgs/ | +– vim.nix +– vim | +– override.nix +– pkgPlugins.nix +– plugins.nix +– vimrc/ | +– colorscheme.vim +– filetypes.vim +– ... +– vimrc.nix

Let me elaborate what is located where here.

vim.nix

The top-level file for the vim packaging. This file is actually included in my machine-specific configuration or in the pkgs/basePackages.nix file, so my vim is always installed on every system. The latter is the way I want to do this, so I have the same vim on all systems.

This file returns a list.

vim/override.nix

This file simply contains the overridden vim package.

This file returns a package / derivation.

vim/pkgPlugins.nix

This file contains the already packaged plugins. I do not have to compile them, as they are already in the NixOS package tree, which makes certain things simple but others more complex, we will see why.

This file returns a list.

vim/plugins.nix

Self-packaged plugins. Period.

This file returns a list.

vim/vimrc.nix

This file uses all files in pkgs/vim/vimrc/*.vim and compiles them into one giant string and writes this one as vimrc file to the store. Actually, there is a pkgs/vim/vimrc/plugins.nix file in the directory which compiles pkgs/vim/vimrc/plugins/*.vim files into a string and returns that string, which simply gets included in the vimrc. I did this for abstraction, so the configuration for each file lives into the appropriate subdirectory.

The How

Lets start with the easy parts here first. To override vim, you don't really have to do much things. What you have to do can be explained best with the appropriate nix file:

Override vim

{ pkgs, lib, vimrc }:

let vim = lib.overrideDerivation pkgs.vimconfigurable (o: { aclSupport = false; cscopeSupport = true; darwinSupport = false; fontsetSupport = true; ftNixSupport = true; gpmSupport = true; hangulinputSupport = false; luaSupport = true; multibyteSupport = true; mzschemeSupport = true; netbeansSupport = false; nlsSupport = false; perlSupport = false; pythonSupport = true; rubySupport = true; sniffSupport = false; tclSupport = false; ximSupport = false; xsmpSupport = false; xsmpinteractSupport = false;

postInstall = (o.postInstall or “”) + '' ln -sf “${vimrc}” “$out/share/vim/vimrc” ''; }); in vim

Of course, you have to make sure that this is the only occurance of vim in your package setup. And if you install vim in a user environment, it will override this as well, so be warned!

So I ripped out everything I don't need here, which is for example tcl support. I don't even know what tcl is, actually.

You also need to override the postInstall hook to ensure you link the vimrc to the appropriate path. The vimrc file must be passed to this function, as you can see in the first line.

Packaged plugins

The second thing which is fairly easy is the file for the plugins which are already in the NixOS package repository. What I do here is simple:

{ stdenv , pkgs }:

[ pkgs.vimPlugins.youcompleteme # pkgs.vimPlugins. # ... ]

And yes, it is that simple. I will not share my entire config files here, of course. You don't need to know what kind of plugins I use in my vim setup!

More plugins!

Now comes the more difficult part. I actually copied these definitins from aszlig:

{ stdenv , pkgs , lib , writeTextFile , writeText , buildEnv , fetchgit , vim_configurable }:

with stdenv;

let

# ... here were some things I did not need

mkVimPlugins = plugins: buildEnv { name = “vim-plugins”; paths = with lib; mapAttrsToList (const id) plugins; ignoreCollisions = true; postBuild = '' find -L “$out” -mindepth 1 -maxdepth 1 -type f -delete ''; };

pluginDeps = { };

plugins = mkVimPlugins (pluginDeps // {

vimvim-fugitive = fetchgit { url = “https://github.com/tpope/vim-fugitive"; rev = “”; sha256 = “”; };

# ...

});

in [plugins]

As you can see, this file is a bit longer than the previous ones. I only inserted the fugitive plugin for posting here, obviousely. So how does this work? Each plugin gets fetched with git (for fetching from vimscripts or other methods of fetching, look at aszligs repo, this file, actually). After it was fetched from git, it is inserted in a set which is afterwards fed to the mkVimPlugins function, which adds all the plugins to one package. All plugin pathes are added to the package then. Why you need the ignoreCollisions = true; line... I'm not sure but I guess it ensures that two plugins can have files with same names. I'm also not sure about the postBuild hook.

But that's how it is supposed to work. It returns a list of plugins, then.

Lets build a vimrc!

Yes, I actually compile my vimrc out of nix expressions. That's not that hard, it is actually string concatenation, because I do write .vim files.

{ stdenv, writeText, additionalRTP }:

let

generic = builtins.readFile ./vimrc/general.vim; # ... statusline = builtins.readFile ./vimrc/statusline.vim; # ...

plugins = import ./vimrc/plugins.nix;

in

writeText “vimrc” '' ${generic}

set runtimepath+=${additionalRTP} set runtimepath+=${additionalRTP}/after set runtimepath+=${additionalRTP}/share/vim-plugins

${statusline}

${plugins} ''

That's really easy: I read the files which contain the vim configurations (general configuration, statusline, etc) and put them all together.

What I add as well: The additional runtime path. This is actually required because when installing vim packages which are not in the package tree of NixOS by now, vim cannot find these. When adding the additional runtime path here, I tell vim to look in these directories as well, ensuring that the plugins can be found.


The last point is obviousely one point I have to clean up, because I guess there should be a better way how to do this. As you might notice when setting up your vim configuration on NixOS, there is also an plugin manager for vim you can use from within NixOS/the nix packages. It gives you lazy loading of vim plugins and all these nice things you want to have. I'm not sure how this fits into the way how NixOS packages vim plugins, I guess I have to dig around here a bit.

Anyhow, it works. On my testing machine, which is an rather old machine (not that old, but also not the new shit, you know) vim starts up in about 1 second. This is obviousely way to much for a machine I want to use for developing software, but for this machine it is okay.

Maybe this will get better after cleaning up the setup, I'm not sure.


In the next part of the series, I will explain my bash(rc) setup, which is handled by nix, of course. Maybe I can also elaborate on my vim setup, if I managed to clean up the mentioned parts. tags: #linux #nixos

In the last part of the series I described what my requirements for a NixOS installation are and why I wanted to switch to it (and KDE).

In this part I describe how I installed my second machine (a Toshiba Notebook) with NixOS and how I got some things running.

The machine

I had NixOS installed on a virtual machine in the first place and I already had it on the mentioned Toshiba Notebook. But this installation was removed in favour of a complete reinstall (including disk formatting and everything). So this is actually a installation from scratch, whereas I kept the configuration files.

The machine I installed NixOS on is a Toshiba Notebook, a Toshiba Satellite PRO S300L.

Machine Data:

  • Intel Core 2 Duo Processor @ 2,00 GHz
  • 3 GB RAM
  • 160 GB HDD
  • Mobile Intel GMA 4500MHD Graphics
  • 15,4” WXGA TFT Display

Yes, it is an old machine, but that does not matter.

The Installation

The installation was really basic. I actually followed the NixOS installation guide pretty much.

After booting the live image, I formatted the disk to have approx. 75GB for the root partition and the rest (which was another approx. 75GB) for /home. I did that because I want to play with this machine, so a big root partition is important for me at this point. For a productive installation on this machine I would've used only 50GB, but not less. The Nix package manager actually needs more disk space for the packages as other package managers, but that's part of the approach and won't change in future, I guess. Anyhow, 75GB is not that much nowadays!

I formatted both partitions with ext4. Pretty basic stuff here, no encryption or something, no LVM, actually.

After this stuff was done, I copied the configuration file from my backup stick to /etc/nixos/configuration.nix, including all the parts I outsourced into .nix modules and fired up a nixos-install. It build my complete system, which I was able to boot afterwards!

Now, how's that, Archlinuxers? It actually build my entire system including boot loader, mount points, services and desktop! I can actually use this piece of hardware now! I can use it productively!

That's my sellings point No. 1 of NixOS! You don't have to mess around anymore!

The KDE desktop.

I did some small configurations for the KDE desktop. Actually, I bound ALT-j, ATL-j, ALT-k and ALT-L and so on, to have some basic vi-like key bindings.

I also added some desktop widgets, but that's not of a big deal as well.

Here are some screenshots:

Blank KDE

Dirty KDE

Nothing interesting, huh? It's just a basic KDE desktop, of course!


So, in the next part I will elaborate a bit on my configuration setup. Maybe I will explain a bit of the syntax of the Nix expression language. I will clearly elaborate on the appraoch and maybe show a way how to build another system out of the already provided parts of my configuration.

Stay tuned!

tags: #linux #nixos

In the last part of the series I descripted what I did to install KDE on the machine and promised to explain the configuration setup in this article.

The KDE was removed since, as I read some comments from people raging against Kontact/KMail/Akonadi and that it is bloat which does not work. So, I'm back at i3 and the “old” setup. Anyways, the configuration setup did not change, and I will explain it in this part of the series.

Kontact or no Kontact

So, Akonadi, KMail, Kontact and the whole stuff does not work. I've heard that from several people at reddit and in several IRC channels. So I'm back at my old setup, including

  • offlineimap / msmtp for mailing services
  • mutt as mailreader (was: Kmail)
  • remind as calendar (was: KOrganizer)
  • wyrd as calendar interface (was: KOrganizer)
  • taskwarrior as task tool (was: KOrganizer)
  • abook as address book (was: KAdressbook)

The point is, that I must get this tools to get working with eachother properly to have something like Kontact. And I will do so.

But, of course, this is another problem and I will explain it in another blog post, maybe.

The configuration setup

That's the part you're interested in most, I guess. So here we go. I've already described the problem, I have several machines, which have some parts of configuration which is same on every machine, but some parts differ.

My approach is simple. I have several subsets of configuration I can include into eachother to build a complete configuration. My folder structure looks like this:

~/config/ | +– nixos/ | +– fs/ +– nixpkgs/ +– pkgs/ +– services/ +– users/

in ./nixpkgs/ I simply symlinked the ~/.nixpkgs/config.nix for version controlling purposes (~/config is a git repository on my machines).

So, I have several sets of configuration sorted by kind of configuration.

fs

The ./fs/ subdirectory contains file system configurations for each machine. Of course, these parts cannot be re-used by other machines most of the time, but I keep them in a special subdirectory to keep my setup clean and modular.

A file ./fs/some.nix looks like this:

{ ... }: { fileSystems.“/home” = { device = “/dev/sda2”; fsType = “ext4”; options = “nosuid,nodev,relatime”; }; }

for example.

pkgs

In the ./pkgs/ subdirectory, there are package sets defined. Namingly:

./pkgs/ | +– basePackages.nix +– desktopPackages.nix +– devPackages.nix

by now. Each of these files look like so:

pkgs: [ pkgs.mosh pkgs.tmux ... ]

for example.

services

A file in ./services/ defines one service. I can include a service file for simply “installing” the services.

My ./service/ file for redshift looks like this, for example:

{ services.redshift = { enable = true; latitude = “48.059402”; longitude = “8.464087”; temperature = { day = 5500; night = 3700; }; }; }

Simple stuff.

users

And last, but not least: ./users/. I don't think I have to explain this one, it looks like the service or file system definitions.

The machine configuration

What's more important and interesting, is the actual machine configuration. The machine configuration is a single file which lives in my ~/config/nixos/ folder and is named like the host.

So, nox.nix, which is the configuration file for my testing machine, looks literally like this:

{ config, pkgs, ... }:

let configDir = /home/m/config/nixos; in

{ imports = [ # Base configuration “${configDir}/base-configuration.nix”

# Users “${configDir}/users/m.nix”

# Services “${configDir}/services/synergyClient.nix” “${configDir}/services/x.i3.nix” “${configDir}/services/redshift.nix” “${configDir}/services/networkmanager.nix” ];

# Define on which hard drive you want to install Grub. boot.loader.grub.device = “/dev/sda”;

networking.hostName = “nox”;

environment.systemPackages = let basePkgs = import “${configDir}/pkgs/basePackages.nix” pkgs; devPkgs = import “${configDir}/pkgs/devPackages.nix” pkgs; desktopPkgs = import “${configDir}/pkgs/desktopPackages.nix” pkgs; in basePkgs ++ devPkgs ++ desktopPkgs;

}

That's the whole deal. You may notice, that there is a base-configuration.nix, I include in this file. This is a very generic default configuration for each machine. It simply defines the following stuff:

  • use grub2, but not where to install it
  • system language
  • default shell (bash for me)
  • timezone
  • enable “sudo”

So this is really just basic stuff each machine has to be configured to.

After linking the /etc/nixos/configuration.nix to the appropriate file in the configuration directory, nixos can be rebuild and everything just works ™.

Feel free to copy the described setup and adjust so it fits your needs! Feel also free to ask me questions about it.


In the next article of this series, I will explain my vim setup including the plugin setup. Be prepared, it will be awesome to manage all you vim plugins with the Nix package manager!

Stay tuned! tags: #linux #nixos

As you might have noticed, I'm about to switch to NixOS, the purely functional Linux distribution ™. Here are some toughts on Racket on NixOS.

First, why Racket? Well, my blog here is written using frog, the frozen blog tool which is written in Racket . It actually works really well for me and was not that much effort to setup – I'd recommend it to everyone.

But this isn't about frog, this is about racket. So, I need Racket for my blog. But I also like Racket, I played with it some time ago and it is a neat language, really!

Because of my switch to NixOS I wanted to try whether I can compile my blog on NixOS, so I installed Racket on my NixOS-testing machine. And you know what is awesome?

It. Just. Worked.

When installing racket, the racket language distribution ships everything you need. It ships the racket interpreter, it ships DrRacket, the Racket-IDE, the REPL, the package manager for racket. I was able to install frog and compile my blog in 3 steps.

  1. Install racket
  2. Install frog using the racket package manager
  3. Compile the blog

Well, you actually do not use the nix package manager when doing the upper steps, which is, of course, impure. But I wanted to focus on whether it works or not here, not on purity. Of course it would be much better to be able to install frog via the nix package manager, keeping everything in the nix store. But that's not possible (yet), I guess. tags: #linux #nixos #nix #blog

I love minimalism. I had my prompt long time just beeing a simple status indicator and a pipe, everything which was not that important was ripped out.

At some point, I decided that I need at least the time in my prompt, but I wanted it to be on the right side. I managed to do it. And now, as I have more machines, I need to put the hostname in the prompt. I also added a shell-level indicator in the prompt, a “How many jobs are in the background” indicator was also added some time ago.

This post wants to elaborate how this all was achived while keeping the prompt itself as minimal as possible. At least from my point of view.

Requirements

So first, the requirements:

  • Indicators
    • Did the last command work?
    • How many background jobs do you have?
    • How many shell levels are there?
  • What's the current hostname?
  • What's the time?
  • Where am I?

Also, the bash shouldn't flatter around. I want to have my commands in one column, straight down the line.

The prompt

So, that's what my prompt looks like:

my prompt

As you can see, my hostname is one the left but almost everything else is on the right. Well, there's actually really much on the left!

First, there is the hostname. I managed to get the hostname into a box which is always 8 characters long. So longer host names will fit in there as well and don't break the pipe bar at the end of the left side of the prompt.

Also, the hostname will be green whenever the last command succeeded, turning into red if the last command failed.

After the hostname we have the pipe, which is simply the delimiter between my hostname and my commands. Well, not quite. It also doubles itself in a subshell, tribles itself in a sub-subshell and so on.

On the right side there is another pipe, but this one flutters. After that, we have another two delimiters which could be removed, but I keep them. Then there is the current branch whenever I'm inside a git directory, the current working directory the number of jobs and the time.

Howto

To achive this, you need to write a bit of bash code into your .bashrc, that's all:

#
# ~/.bashrc
#

printfnchr() {
    for i in `seq 1 $1`; do echo -ne "$2"; done
}

shlvl() {
    # I'm always on shell level 4 here, login, xserver, terminal, bash
    # so subtract 3 to get 1 in a normal (non-nested) shell
    echo $((SHLVL - 3))
}

PS1=$'$(if [[ "$?" == "0" ]];then echo "\[\033[32m\]"; else echo "\[\033[31m\]"; fi) $(printf "%8s" "($HOSTNAME)")\e[0m $(printfnchr $(shlvl) "\u2502") '
PS2=$'\[\033[32m\] $(printf "%8s" "($HOSTNAME)") #>\e[0m \u2502 '

rightpromptstring() {
    local tmp=$?
    local dirty=$([[ $(git diff --shortstat 2>/dev/null | tail -n 1) != "" ]] &&
        echo " *")
    local g=$([[ $(git branch 2>/dev/null) ]] &&
        echo " ($(git describe --all | sed 's/^[a-zA-Z]*\///')) ")
    local p=$(pwd | sed "s:^$HOME:~:" | rev | cut -d/ -f 1 | rev)
    local j=$(jobs | wc -l)
    local d=$(date +%H:%M)

    local r=$(echo -n "\u2502 \033[1;30m<<$dirty$g$p [$j] [$d]\033[0m")

    local rl=${#r}
    local t=$(tput cols)
    let "p = $t - $rl + 22"
    printf -v sp "%*s" $p ' '
    echo -ne "$sp$r\r"
    return $tmp
}

PROMPT_COMMAND=rightpromptstring

It is not as complicated as it seems and I'm sure there's room for optimization here and there, but for me it works and it is fast.

Of course, the printfnchr function and also the shlvl function could have been placed right in the PS1 variable, but I want to keep them, maybe I can reuse them later!

The rightpromptstring function is a beast, I know. This would be my first point if I had to optimize this whole thing, but I don't need to, so there is no need to.


I won't go into detail how things work, I assume you know bash. Anyways, feel free to ask me questions about this!


Edit:

To have the pipe character also when logged in via SSH, you have to modify the shlvl function like this:

shlvl() {
    # I'm always on shell level 4 here, login, xserver, terminal, bash
    # so subtract 3 to get 1 in a normal (non-nested) shell
    if [ -z "$SSH_CLIENT" ]
    then
        echo $((SHLVL - 3))
    else
        echo $SHLVL
    fi
}

tags: #linux #bash

This will be a series of blog posts about my experience when switching to NixOS, the Purely Functional Linux Distribution.

It will cover everything: The successes, the issues, the problems, everything you can imagine, including my personal NixOS configuration, so you can learn how to get your feet wet with this blog series.

But, of course, this is not a tutorial on how to write Nix or how to use NixOS. This is an experience report.

The Why

So, why did I switch or do I want to switch? I'm a Archlinux user for more than 7 years now. Archlinux is a great distribution, you can tweak every single bit to fit your needs perfectly. It is truly awesome. But there is a problem with it, I don't want to have anymore: You can really easily break things. You can break your packages by upgrading a version of a library. You can pollute your package database by installing something and shortly afterwards removing it, but forgetting to remove the dependencies it pulled in. You have no option to actually tweak packages. You want emacs? Okay, here is emacs. You want it with GTK3 instead of GTK2? Then, compileit yourself. (I picked emacs as example here because that's the one example on the NixOS page, there is certainly a package for emacs with GTK3 in Archlinux)!

Another big selling point for me is, that NixOS comes with either the stability of Debian, if you want it to, but you can be bleeding-edge like Archlinux if you want to. It's in your hands with NixOS!

Of course, in NixOS, you only have one configuration file for all the things!

Configure all the things!

The How

So, I started playing around with NixOS in a virtual machine. I started with a minimal configuration which is shipped with the system. Of course, I read a lot of blog articles beforehand, so I almost knew what I did. Well, at least I thought, I knew it.

There are great resources online. Well, there are not that much resources around, but at least the ones that are there are really good. My starting point, of course, was the NixOS homepage, the NixOS wiki, but also the great blogging series Nix Pills which explains the Nix language.

What was also worth looking at is the real world NixOS Dotfiles page, where links to dotfiles of NixOS people are collected. Mine are not up there, because I tend to keep my dotfiles private, so you won't find them there. But you find them here!

The requirements

My requirements for NixOS should be listed before I go into detail how I managed to get things done.

Configuration files

So, first, I wanted to be able to track my configurations with git. I track all my configurations with git, as this enables me to mess around with them without actually losing them/information/knowledge/bla. I think you get that point.

Well, that was not much of an issue, actually. I just created a new folder in my dotfiles directory and linked the global NixOS configuration file to it:

mkdir config/nixos
sudo cp /etc/nixos/configuration.nix config/nixos/
sudo chown $USER config/nixos/configuration.nix
sudo mv /etc/nixos/configuration.nix /etc/nixos/configuration.nix.bkp
sudo ln -s config/nixos/configuration.nix /etc/nixos/configuration.nix

As you can see, I backuped the configuration before overriding it, just to be safe here.

Well, this actually works out really well. But! There is a but!

When installing a new machine, you actually cannot do this, because your NixOS installation doesn't know of /home yet (as it is not mounted at this point). To work around this, you simply use the /etc/nixos/confuiguration.nix file until you have set up the basic system!


I also wanted the configuration files to be shareable between several machines, which required me to split them up into several parts. I already described this in another blog post!

KDE!

Well, packages. As I described in the other blog post mentioned above, I have several sets of configuration which I merge into eachother to compile the machine-specific configuration out of several parts then. This works really well and I use it every day!

One big thing I wanted to have was KDE. Yes, me, the Archlinux-i3-minimalistic-terminal-only-loving guy tries KDE. Why? Well, that's another topic!

Turned out that KDE works really good for me! I tweaked some shortcuts, so I'm able to do “tiling” with it (but not with this ugly “Tiling” script for KWin, actually!) so it works really well for me and I really like it.

But there also were some problems, I will tell you later on.

Services

For the services department: I want to be able to run a gitolite instance, I already run a ssh server, synergy (client) and redshift. I did not try the synergy client on my latest install, but beforehand it worked, so I assume it still works. Redshift and ssh work, so that's none of an issue.

What does not work is gitolite. I don't know why, yet, but I will do some further investigation on this.

Overall requirements

Well, one big requirement for me is that things just work. I did not write “work out of the box”, because this requirement was already destroyed when this blog article was written. I don't want to mess around with things every now and then – I want them to work, so I can be productive in things I actually want to do.

So, that's also the reason why I wanted a switch to KDE. I want to use the Kontact suite, including KOrganizer, KMail, KAddressbook and not mutt with abook anymore, which works, but is not that great IMHO. I mean, mutt, yeah! It is awesome and fast and everything. But I cannot do contact managing, scheduling, etc with it. As an email reader it is the best piece of software I ever used and in combination with vim, it becomes even more awesome! But it does not integrate with other tools like an adressbook or day planner.

Also, all these things can integrate my Android phone, which is awesome. I did not try it yet, though.


So, that's enough for the first part. In the next part of the series, I will describe my steps from zero to a basic system and how I installed the configurations and things. Maybe the post will also cover my first problem with NixOS.

Stay tuned!

tags: #linux #nixos

I finally made my first steps with NixOS! I started to thnik about how to set up a multi-machine-multi-purpose configuration environment a few days ago, when I wasn't able to sleep half of the night.

And, surprisingly, it works! So here is what I've done...

The idea

My idae was to have one setup which can be combined for every machine I have. So, it must fit:

  • My (future) desktop machine, which will have mutliple drives and multiple monitors. It will be a backup server for my other machines as well. It will be a development/gaming (as little gaming as I do – I still do it)/everything machine.
  • My current main machine: my Thinkpad. It is my current development machine as well as my machine for my university stuff etc.
  • My old notebook, which I play with (in manner of trying out nix configurations). I created the setup on this machine, as it already runs NixOS).
  • My old desktop computer, which is my “home-server” at the moment, mainly for my music and for storage.
  • Eventually for a root server I will have at any time in the future – who knows?

The problem

I had several problems with that. None of these machines will have the same setup, none of them need all packages and hell none of these machines will have the same services running. But all of them will have packages from a specific set of packages. Some of these machines will have the same services with the same configurations. So, I created a matrix of packages and one of services.

Packages

(Well, lets leak my new host names here as well...)

|           | Package-Set   | base  | dev   | desktop   | server    |
| Machine   |               |       |       |           |           |
| --------- | ------------- | ----- | ----- | --------- | --------- |
| lucy      |               | x     | x     | x         | x         |
| nyu       |               | x     | x     | x         |           |
| nox       |               | x     |       | x         |           |
| light     |               | x     |       |           | x         |

Explanation:

  • Hostnames, retreived from “Elfenlied” and “Deathnote” (nox is the opposite from “lumos” from Harry Potter)
    • “lucy” will be my tower machine
    • “nyu” will be my thinkpad
    • “nox” will be (and already is) my second notebook
    • “light” will be my home server
  • Packages
    • “base” is just the basic stuff, like “awk”, “vim”, “coreutils”, htop, etc
    • “dev” is my development stuff, so vim, gdb, git, cmake, make, valgrind, ruby, python, haskell, lua, etc.
    • “desktop” is everything graphical, so a browser, email client, irc client, etc.
    • “server” is everything which a server needs, so things like htop and other utilities

Maybe I will create even more package sets for music, music modifying (tags for example), music creation, movies, gaming, etc. But these are the basic sets I actually created.

As you can see, all hosts will get the basic package set. All desktop machines and notebooks will get the desktop set and just lucy and light will get the server set. Development will be on my current and my future main machine, but not on nox.

Services

When it comes to services, there are also some stuff each hosts needs and others don't:

|           | Service-Type  | X | synergyClient | sshServer | printing  |
| Machine   |               |   |               |           |           |
| --------- | ------------- | - | ------------- | --------- | --------- |
| lucy      |               | x |               |           | x         |
| nyu       |               | x | x             | x         | x         |
| nox       |               | x | x             | x         |           |
| light     |               |   |               | x         |           |

Explanation:

  • “X” is the x server including my i3 setup and so on
  • “synergyClient” is the synergy configuration for the client
  • “sshServer” – nothing to explain here, I assume
  • “printing” – nothing to explain here as well...

Of course, lucy won't have the ssh server enabled (maybe it will, but I'm rather sure I won't need it on lucy). It will be the synergy server, so it doesn't need a synergy client configuration as well.

Filesystem

I already mentioned that lucy will be a storage server as well as my main machine. I'm currently thinking about a 2 * 2 TiB configuration for the host itself but attaching 2 * 1 TiB and 1 * 2 TiB external USB storage as well. This would make “light” outdated, as this is my storage machine by now, but I will continue using it to play around with, especially with NixOps maybe.

So, I have a different filesystem configuration for each host. But that's not a problem, as the next section shows...

The Solution

Of course, this was not everything. More services, more package sets and so on will follow, but they can be attached to my current setup really easily.

So, how did I do it? First, I want to thank “Lethalman” from the NixOS IRC channel, he helped me a lot!

So, I have a base configuration file, which looks like this:

{ config, pkgs, ... }:

{
  imports = [ # Include the results of the hardware scan.
    /etc/nixos/hardware-configuration.nix
  ];

  # Use the GRUB 2 boot loader.
  boot.loader.grub.enable = true;
  boot.loader.grub.version = 2;

  networking.firewall = {
    enable = true;
    allowedUDPPorts = [ ... ];
  };

  # Select internationalisation properties.
  i18n = {
    consoleFont = "lat9w-16";
    consoleKeyMap = "de";
    defaultLocale = "de_DE.UTF-8";
  };

  users.defaultUserShell = "/var/run/current-system/sw/bin/fish";

  # Define a user account. Don't forget to set a password with ‘passwd’.
  users.extraUsers.m = {
    name = "m";
    group = "users";
    uid = 1000;
    createHome = true;
    home = "/home/m";
    extraGroups = [ "wheel" "audio" "video" "power" ];
    shell = "/var/run/current-system/sw/bin/fish";
    openssh.authorizedKeys.keys = [ ... ];
  };

  time.timeZone = "Europe/Berlin";
}

(sadly, the fish shell does not work yet and I don't know why).

As you can see, the grub configuration is just partly set, I did not mention on which drive grub shall be installed. Of course, this follows in the host-specific configuration file:

{ config, pkgs, ... }:

let
  configDir = /home/m/config/nixos;
in

{
  imports = [
    # Base configuration
    "${configDir}/base-configuration.nix"

    # Filesystem additions
    "${configDir}/fs/tmpfs.nix"

    # Services
    "${configDir}/services/synergyClient.nix"
    "${configDir}/services/x.nix"
    "${configDir}/services/sshServer.nix"
    "${configDir}/services/printing.nix"
  ];

  # Define on which hard drive you want to install Grub.
  boot.loader.grub.device = "/dev/sda";

  networking.hostName = "nox";
  networking.wireless.enable = true;

  nixpkgs.config = {
    allowUnfree = true;

  # Overrides for chromium, as stated in http://nixos.org/wiki/Enable_Browser_Plugins
    chromium = {
      enablePepperFlash = true; # Chromium removed support for Mozilla (NPAPI) plugins so Adobe Flash no longer works
        enablePepperPDF = true;
    };
  };

  environment.systemPackages = let
    basePkgs    = import "${configDir}/pkgs/basePackages.nix" pkgs;
    devPkgs     = import "${configDir}/pkgs/devPackages.nix" pkgs;
    desktopPkgs = import "${configDir}/pkgs/desktopPackages.nix" pkgs;
  in
    pkgs.lib.attrValues (basePkgs // devPkgs // desktopPkgs);

}

In this file, which is the host configuration for “nox”, I put grub on “/dev/sda”, included some service configuration files and imported some package sets as well as I did some more host-specific configuration.

The service files would look like this:

{
  # Enable the X11 windowing system.
  services.xserver = {
    enable = true;
    layout = "de";
    xkbOptions = "eurosign:e";

    # Display manager configuration
    displayManager.slim.enable = true;

    # Enable the i3 window manager.
    windowManager.i3.enable = true;
    windowManager.default = "i3";
  };
}

for the X-Server configuration. The package files look like this:

pkgs: {
  inherit (pkgs)
  acpid
  acpitool
  bashCompletion
  ...
  zip
  ;
}

And it works like a real charm!

Even more beneficial...

I can actually put this in a git repository. I actually already did this! I have a git repository on the host which will be named “nyu” after the port to NixOS. This git repository contains all my dotfiles. At the moment, I run Archlinux (without nix) on this machine, but I will keep the dotfiles repo, of course, and this enables me to just get the git repository and start using the already modified dotfiles.

More hosts can now be added really easily, as I just have to write one file for them, including everything I need from the other files and add some custom flags and configurations if I want. This file gets then symlinked from /etc/nixos/configuration.nix and I can run nixos-rebuild switch and I'm ready – setup for the machine and dotfiles are present and I can start using it! Awesome!

If you have suggestions how to improve this setup, let me know. If this article helped you with your setup, let me know as well!

tags: #linux #nixos

I own a second notebook (my old one) which currently runs Debian stable. I use it for skype only, as I don't want this proprietary software on my main machine. Recently, I deinstalled a lot of crap which comes with Debian per default (in the Gnome version). I deinstalled Libreoffice. I deinstalled Gimp. I deinstalled similar software nobody needs (on a skype-only machine).

Suprisingly I deinstalled network-manager as well. I don't know how this could happen! Now, how to reinstall the network-manager if you cannot access the internet? Well, if you did not reboot, it might work. But I did! It's really simple: Just go to the Debian-packages website and download the package. Then, transfer it to the appropriate machine and install it with

sudo dpkg -i package

Well, you can only do that if you have another machine where you can download the package. If you don't have such a machine, you should ask a friend or so! If you didn't run

sudo apt-get autoremove

The package may be remaining in the cache of apt-get. You have to google around where this cache is, but the procedure should be the same, if you found the package.

tags: #linux #debian

I switched to i3 recently and therefor reconfigured my whole system in manner of apperance. I really like it now, as it uses grey as basic color. Everything is grey: My terminal (xterm, bash), my editor (vim), my IRC client (irssi), my music player (ncmpcpp). But what I like most by far, is my prompt.

Bash it to the right

I always hated the flutter of my bash prompt when diving into directories:

~ $ cd foo ~/foo & cd bar ~/foo/bar $ cd ~ $

But now, I finally reconfigured it to be in a straigt line:

:> | cd foo :> | cd bar :> | cd

And the path is now on the right side (I can't show it in the example, unfortunately).

There is not much magic in it... but let me show you:

The magic

The PS1 variable is the one shelter for the prompt. I configured it to be just

:> |

but if the last command failed, it uses the sad smilie:

:< |

(you can do this with Unicode smilies as well!) There is not much magic in it. The pipe symbol is a Unicode character (\u2502) for me, so I get a straight line without gaps between the lines.

The real magic comes now! There is also a bash variable for a command which gets executed for a prompt. And I abuse this variable a little bit. But first, we have to write the command (actually a bash function):

rightpromptstring() { local tmp=$? local dirty=$([[ $(git diff —shortstat 2>/dev/null | tail -n 1) != “” ]] && echo “ “) local g=$([[ $(git branch 2>/dev/null) ]] && echo “ ($(git name-rev HEAD | cut -d ” “ -f 2)) “) local p=$(pwd | sed “s:^$HOME:~:“) local j=$(jobs | wc -l) local d=$(date +%H:%M) local r=$(echo -n “\u2502 \033[1;30m<<$dirty$g$p [$j] [$d]\033[0m”) local rl=${#r} local t=$(tput cols) let “p = $t – $rl” printf -v sp “%s” $p ' ' echo -ne “$sp$r\r” return $tmp }

So, what happens in here? The first line is for saving the return value of the previous command. We need it to be returned lateron, as the smilie from PS1 won't work if we don't return it.

The next few lines do a bit of git magic, to include the current branch and a asterisk if the repository is “dirty”. The variable p gets the path, but if I'm in my home directory, it gets replaced by the tilde. The j variable gets the number of jobs in the bash, as I always want this to be printed somewhere. The d gets the current time.

The r variable now gets the string which represents the right prompt. It also gets the pipe character (actually the Unicode character \u2502) and some color stuff. Then, the rl variable gets the length of the string in r. The t variable gets the number of colums, which is required for printing spaces until we are at the right side (the printf part prints spaces to the variable sp). Then, the spaces and the right prompt get printed. And then simply a \r for carriage-return.

Afterwards we return the stored exit code of the application which just exited and that's it.

Now, just set the prompt command variable:

PROMTP_COMMAND=rightpromptstring

And that's it.

I know, the rightpromptstring function is a bit ugly and I bet it can be improved, but it works very good for me! Feel free to send me patches!

tags: #bash #programming #linux

When dealing with Linux and Open source, you notice Canonical and Ubuntu very quickly, as a lot of people suggest Ubuntu as beginner distribution for switching to linux.

I already made some statements about what I think about this. I do not like Ubuntu neither Canonical or Mark Shuttleworth. But that's not the point why I think Ubuntu is a problem.

Yes, I think Ubuntu is a problem for the open source community.

Why is Ubuntu a problem?

Ubuntu is a problem from my perspective, because they're trying to do something different. They do not follow the Community, they try to do their own thing. The first approch into another direction was the integration of the amazon-search in their desktop. The second one was Mir.

The problem is not, that they want to be inovative. I even think that it is really good to be inovative, just look at docker! But they're doing something wrong, all the time! They do not learn from their mistakes! One big mistake was Unity. The Unity desktop environment simply sucks. It is optimized for small netbooks, which have a small screen – but it uses way too much resources and there are already well-established alternatives which are way better – LXDE and Xfce!

... and the community?

Now, it is not only that Ubuntu is a problem. The community around Ubuntu is a problem, too! I don't want to offend anybody, but the Ubuntu community is a really big community and they still tell outstanding people that Ubuntu is a very good beginner distribution when switching to linux. It is not. It is crap for beginners.

If one of you out there want to do a simple experiment, if you have the ability: Take a Windows user and give him an Ubuntu whateverversion with Unity and another one with Ubuntu and Gnome installed. Tell them to write a Document with the contents of the wikipedia page on Canonical and then install gimp (don't know, is it preinstalled? If yes, some other random software which is not installed...). Don't tell them that they have to compete! I would bet the one with Gnome is faster!

tags: #linux #ubuntu