← Home

Using Nix to set up my new Mac

I recently started working with a new client that uses Microsoft Teams. It’s such a resource hog that I was unable to be on calls and do some programming at the same time on my 2015 13" Macbook Pro (16GB RAM), so I decided to upgrade to the latest 13" Macbook Pro which with 32GB of RAM, and 10th gen Intel processor. All-in-all, it’s got around twice the single threaded performance, and twice as many CPU cores, so it’s just about fast enough.

My work mostly involves using infrastructure as code to build repeatable processes, and I’m attracted to having that same capability on my desktop computer. I’ve been keeping my “dotfiles” configuration at [0] for a while, but I hadn’t got a list of the various programs that I’ve added to the system using brew or added manually to my path, so I knew I’d lose a few programs during the move.

In my work, I move around a lot between programming languages and tools, and I’m always trying something out. This sometimes leaves me with a bunch of random programs around my disk, so a lot of the stuff that’s lying around is stuff I can live without.

I saw some posts about NixOS [1] and found the idea of defining the operating system configuration in code very appealing, especially being able to roll back easily, and to create throwaway shells.

I sometimes use Docker for throwaway shells, but it’s a hassle to mount volumes in and out of the container, and it can be quite tedious. I also resent the amount of RAM and CPU that Docker uses, and Brew was very slow on my old Mac, so I was looking for some extra speed there too.

When I first looked around Nix, I didn’t quite get the ecosystem. The Nix package manager seems focussed on local environments, and there isn’t much of a concept of an overall base system in the documentation. It turns out that I was looking for [2] to be able to configure my Mac in a similar way to NixOS.

I was able to find most of the packages I needed in Nix by using the command line search (nix search <x>) and to list some of the stuff I was going to migrate on my old Mac with brew list.

The first problem I came to was converting various examples of how to configure vim, fortunately, the community was very helpful. I nipped on to the chat at [3] and [4] gave me a few pointers that got me unstuck.

With a few more pointers from [5] and a browse of [6] I was able to get my own configuration up and running with no brew on my Mac at all.

The workflow is simple, search for missing packages with nix search <name>, then add it to the darwin-configuration.nix file, then run darwin-rebuild switch to update the system and use the new configuration.

The key things I needed help with were packaging vim plugins that weren’t already in Nix’s package list (coverage and easygrep), and installing some global python packages - answers can be found in the config below. I’m using it day-to-day now, the latest version will always be over at [7]

{ config, pkgs, ... }:

let

  coverage = pkgs.vimUtils.buildVimPlugin {
    name = "vim-coverage";
    src = pkgs.fetchFromGitHub {
      owner = "ruanyl";
      repo = "coverage.vim";
      rev = "1d4cd01e1e99d567b640004a8122be8105046921";
      sha256 = "1vr6ylppwd61rj0l7m6xb0scrld91wgqm0bvnxs54b20vjbqcsap";
    };
  };

  easygrep = pkgs.vimUtils.buildVimPlugin {
    name = "vim-easygrep";
    src = pkgs.fetchFromGitHub {
      owner = "dkprice";
      repo = "vim-easygrep";
      rev = "d0c36a77cc63c22648e792796b1815b44164653a";
      sha256 = "0y2p5mz0d5fhg6n68lhfhl8p4mlwkb82q337c22djs4w5zyzggbc";
    };
  };

  python-with-global-packages = pkgs.python3.withPackages(ps: with ps; [
    pip
    botocore
  ]);

in

{
  environment.variables = { EDITOR = "vim"; };

  # List packages installed in system profile. To search by name, run:
  # $ nix-env -qaP | grep wget
  environment.systemPackages =
    [
      python-with-global-packages
      pkgs.asciinema
      pkgs.awscli
      pkgs.docker
      pkgs.fzf
      pkgs.git
      pkgs.gitAndTools.gh
      pkgs.gnupg
      pkgs.go
      pkgs.gopass
      pkgs.graphviz
      pkgs.htop
      pkgs.hugo
      pkgs.jq
      pkgs.lynx
      pkgs.musescore
      pkgs.nmap
      pkgs.nodejs
      pkgs.nodePackages.typescript
      pkgs.nodePackages.serverless
      pkgs.ripgrep
      pkgs.terraform
      pkgs.tmux
      pkgs.tree
      pkgs.unzip
      pkgs.vscode
      pkgs.wget
      pkgs.yarn
      pkgs.zip
      (
	 pkgs.neovim.override {
	    vimAlias = true;
	    configure = {
	      packages.myPlugins = with pkgs.vimPlugins; {
		start = [
		  vim-go
		  vim-lastplace
		  vim-nix
		  coc-nvim
		  coc-tsserver # neoclide/coc-tsserver
		  coc-yaml
		  coc-json
		  nerdcommenter #preservim/nerdcommenter
		  ctrlp #ctrlpvim/ctrlp.vim
		  vim-sleuth #tpope/vim-sleuth
		  vim-surround #tpope/vim-surround
		  vim-test #janko/vim-test
		  coverage #ruanyl/coverage.vim
		  ultisnips #SirVer/ultisnips
		  vim-snippets #honza/vim-snippets
		  easygrep #dkprice/vim-easygrep
		];
		opt = [];
	      };
	      customRC = builtins.readFile ./../dotfiles/.vimrc;
	  };
	}
      )
    ];

  # Create /etc/bashrc that loads the nix-darwin environment.
  programs.zsh.enable = true;  # default shell on catalina

  # Used for backwards compatibility, please read the changelog before changing.
  system.stateVersion = 4;

  nixpkgs.config.allowUnfree = true;
}