Move blog into website/blog

Nest the blog work within the website directory.
This commit is contained in:
William Carroll 2020-03-20 00:46:29 +00:00
parent 54d1a0048a
commit 95e761e59b
40 changed files with 2 additions and 3 deletions

View file

@ -0,0 +1,5 @@
---
title: "Caffeine"
date: 2020-03-11T22:50:40Z
draft: true
---

View file

@ -0,0 +1,92 @@
---
title: "Cell Phone Experiment"
date: 2020-03-09T22:02:07Z
draft: true
---
### TL;DR
I will not use my cell phone during March to challenge myself and learn more
about how much I depend on my device.
### Background
Ever since I read Charles Duhigg's book, [The Power of Habit](poh), I try to
habituate as many aspects of my life that I can.
The *exploit* axis of the [explore/exploit tradeoff](exp-exp) endows habits with
their power. If you are interested in learning more about the explore/exploit
tradeoff, Brian Christian and Tom Griffiths explain this concept more clearly
than I could in Chapter 2 of their exceptional book, [Algorithms to Live
By](algos).
One pitfall of overly exploiting an activity, however, is neglecting global
optima in favor of local optima. Thus we must also explore. Is it possible to
habituate exploration? I think so.
Every month since October 2018, I commit to a monthly challenge. In the past,
monthly challenges have been things like:
- sign up and take Brazilian Jiu Jitsu lessons
- buy a guitar and learn [Freight Train by Elizabeth Cotton](https://www.youtube.com/watch?v=IUK8emiWabU)
- study Italian
- attempt to learn a handstand
Typically for an activity to qualify as a challenge, I must spend at least
fifteen minutes working on it at least five days each week. Oftentimes
challenges have concrete deliverables (e.g. playing the "Freight Train" song
from start-to-finish). Other times, with Jiu Jitsu, the challenge consists of
attending classes five days a week without any absences.
This month I'm challenging myself to avoid using my cell phone for the entire
month. I am interested in partially digitally detoxing.
My parents gave me a cell phone when when I was a freshman in High School; those
days, I was fourteen years old. I am now twenty-eight years old, which means I
have been using a cell phone semi-daily for over ten years.
While I enjoy the convenience that my cell phone provides me, I am curious to
suspend my usage aiming to more clearly understand how much I depend on it.
### What was different?
Things that I am missing:
- Alarm clock: I decided to avoid buying an alarm clock. I theorize that alarms
and caffeine may distort my reality. An excuse to sleep in? Twist my arm...
- Waking Up with Sam Harris: Thankfully, Waking Up supports web browsers, so
this was easy to replace.
- Banking with Monzo: Monzo has a web client for doing simple banking tasks. I
needed to internationally transfer GBP to my USD account.
- Spotify: I either read while taking public transport, attempted to briefly
meditate, or (most commonly) started blankly.
- Taking notes
- Timers
- Google Calendar for meeting room information
Things that I did miss:
- Phone calls: My birthday is March 5, and I wanted to talk to my family then
since I'm currently living abroad in London; I'm originally from a suburb
outside of Washington D.C.
Things that I thought I would miss but I didn't miss:
- Email: I prefer checking my emails minimally anyhow.
- Text messaging: Maybe I enjoyed this because I knew the whole time it was
temporary. I'm unsure if I'd feel this way if it was permanent.
Exploits
- Telegram native client
- Instagram's web client
### What was bad?
Not much.
### Will I use a cell phone in April?
Probably. I think this exercise removed some of the long-standing barnacles, but
some of the old habits and triggers exist. Also with web browser and native
client alternatives to mobile apps, the partial digital detox felt even more
partial.
[pod]: https://www.goodreads.com/book/show/12609433-the-power-of-habit
[exp-exp]: https://en.wikipedia.org/wiki/Multi-armed_bandit
[algos]: https://www.goodreads.com/book/show/25666050-algorithms-to-live-by

View file

@ -0,0 +1,49 @@
---
title: "Lets Learn Nix Caching"
date: 2020-03-17T18:05:38Z
draft: true
---
## TL;DR
1. I use `NixOS/nixpkgs-channels` instead of `NixOS/nixpkgs` and avoid
`nix-channel`.
## More information
- By default the Nix package manager uses cache.nixos.org as a binary cache.
- Visit status.nixos.org
- `git clone git@github.com:NixOS/nixpkgs-channels` instead of
`NixOS/nixpkgs`. The former mirrors the latter and uses Git branches to track
the published channels.
## What is a Nix channel
If you run...
```shell
$ git clone git@github.com:NixOS/nixpkgs ~/nixpkgs
$ export NIX_PATH="nixpkgs=$(realpath ~/nixpkgs)"
```
One benefit to cloning nixpkgs is that you can browse the source code on your
machine using tools like `git` and `emacs`. You can also experimentally patch
and test Nix code this way.
If any of the above appeals to you, clone `nixpkgs-channels` instead.
The Nix maintainers build and test the commits from `nixpkgs` using Hydra. Tests
include reproducibility tests, etc.
Various channels have different verification phases.
The cache at cache.nixos.org is populate the cache at cache.nixos.org.
You want to increase the likelihood that you are hitting this cache. For
example, `google-chrome` takes hours to build.
## What is a binary cache?
## What is Hydra (Nix CI)?
## What is Cachix?

View file

@ -0,0 +1,121 @@
---
title: "Lets Learn Nix: Reproducibility"
date: 2020-03-17T12:06:47Z
draft: true
---
I am dedicating this page to defining and disambiguating some terminology. I
think it is important to use these terms precisely, so it may be worthwhile to
memorize these definitions and ensure that you are clarifying the discourse
rather than muddying it.
## Terms
- repeatable build:
- reproducible build:
- deterministic build:
- pure function:
- impure function:
- idempotent function:
TODO(wpcarro): Consistently and deliberately use reproducible and
deterministic.
## Repeatable vs. Reproducible
Is NixOS reproducible? Visit [@grhmc][who-grhmc]'s website,
[r13y.com](https://r13y.com), to find out.
At the time of this writing, 1519 of 1568 (i.e. 96.9%) of the paths in the
`nixos.iso_minimal.x86_64-linux` installation image are reproducible.
## What hinders reproducibility?
Timestamps.
If package A encodes a timestamp into its build artifact, then we can
demonstrate that package A is *not reproducible* simply by building it at two
different times and doing a byte-for-byte comparison of the build artifacts.
## Does Nix protect developers against non-determinism
Yes. But not entirely. How?
## Deterministic Nix derivation
```nix
{ pkgs ? import <nixpkgs> {}, ... }:
with pkgs;
stdenv.mkDerivation {
name = "reproducible";
phases = [ "buildPhase" ];
buildPhase = "echo reproducible >$out";
}
```
## Non-deterministic Nix derivation
We can introduce some non-determinism into our build using the `date` function.
```nix
# file: /tmp/test.nix
{ pkgs ? import <nixpkgs> {}, ... }:
with pkgs;
stdenv.mkDerivation {
name = "non-reproducible";
phases = [ "buildPhase" ];
buildPhase = "date >$out";
}
```
Then run...
```shell
$ nix-build /tmp/test.nix
$ nix-build /tmp/test.nix --check --keep-failed
```
## How do you test reproducibility?
We can use `cmp` to compare files byte-for-byte. The following comparison should
fail:
```shell
$ echo foo >/tmp/a
$ echo bar >/tmp/b
$ cmp --silent /tmp/{a,b}
$ echo $?
```
And the following comparison should succeed:
```shell
$ echo hello >/tmp/a
$ echo hello >/tmp/b
$ cmp --silent /tmp/{a,b}
$ echo $?
```
## Reproducible vs. deterministic
Reproducible builds *are* deterministic builds and deterministic build
## Deterministic, Reproducible, Pure, Idempotent, oh my
- A pure function has no side-effects.
- An idempotent function can be executed more than once with the same arguments
without altering the side-effects.
- A deterministic function ensures that
## Deterministic vs. Reproducible
I can check if a build is reproducible using [these tools][wtf-repro-tools].
[wtf-repro-tools]: https://reproducible-builds.org/tools/
[who-grhmc]: https://twitter.com/grhmc

View file

@ -0,0 +1,401 @@
---
title: "Let's Learn Nix: Dotfiles"
date: 2020-03-13T22:23:02Z
draft: true
---
## Let's Learn Nix: Dotfiles
### Dependencies
Speaking of dependencies, here's what you should know before reading this tutorial.
- Basic Nix syntax: Nix 1p
What version of Nix are we using? What version of `<nixpkgs>` are we using? What
operating system are we using? So many variables...
Cartesian product of all possibilities...
TODO(wpcarro): Create a graphic of the options.
### The problems of dotfiles
How do you manage your dependencies?
You can use `stow` to install the dotfiles.
### home-manager
What we are going to write is most likely less preferable to the following
alternatives:
- using Nix home-manager
- committing your `.gitconfig` into your
In the next tutorial, we will use [home-manager][wtf-home-mgr] to replace the
functionality that we wrote.
So why bother completing this?
### Let's begin
Welcome to the first tutorial in the [Let's Learn Nix][wtf-lln] series. Today we
are going to create a Nix derivation for one of your dotfiles.
"Dotfiles" refers to a user's collection of configuration files. Typically these
files look like:
- `.vimrc`
- `.xsessionrc`
- `.bashrc`
The leading "dot" at the beginning gives dotfiles their name.
You probably have amassed a collection of dotfiles whether or not you are
aware. For example, if you use [git][wtf-git], the file `~/.gitconfig` should
exist on your machine. You can verify this with:
```shell
$ stat ~/.gitconfig
```
When I was first learning `git`, I learned to configure it using commands I
found in books and tutorials that often looked like:
```shell
$ git config user.email
```
The `~/.gitconfig` file on your machine may look something like this:
```.gitconfig
[user]
name = John Cleese
email = john@flying-circus.com
username = jcleese
[core]
editor = emacs
[web]
browser = google-chrome
[rerere]
enabled = 1
autoupdate = 1
[push]
default = matching
[color]
ui = auto
[alias]
a = add --all
ai = add -i
b = branch
cl = clone
cp = cherry-pick
d = diff
fo = fetch origin
lg = log --oneline --graph --decorate
ps = push
pb = pull --rebase
s = status
```
As I ran increasingly more `git config` commands to configure my `git`
preferences, the size of my `.gitconfig` increased, and the less likely I was to
remember which options I set to which values.
Thankfully a coworker at the time, Ryan ([@rschmukler][who-ryan]), told me that
he version-controlled his `.gitconfig` file along with his other configuration
files (e.g. `.vimrc`) in a repository he called "dotfiles".
Version-controlling your dotfiles improves upon a workflow where you have a
variety of configuration files scattered around your machine.
If you look at the above `.gitconfig`, can you spot the dependencies?
We explicitly depend `emacs` and `google-chrome`. We also *implicitly* depend on
`git`: there is not much value of having a `.gitconfig` file if you also do not
have `git` installed on your machine.
Dependencies:
- `emacs`
- `google-chrome`
Let's use Nix to generate this `.gitconfig` file. Here is what I would like our
API to be:
Let's create a file `gitconfig.nix` and build our function section-by-section:
TODO(wpcarro): Link to sections here
- options.user
- options.core
- options.web
- options.rerere
- options.push
- options.color
- options.alias
```shell
$ touch gitconfig.nix
```
### options.user
```haskell
AttrSet -> String
```
```nix
user = {
name = "John Cleese";
email = "john@flying-circus.com";
username = "jcleese";
};
```
```.gitconfig
[user]
name = John Cleese
email = john@flying-circus.com
username = jcleese
```
### options.core
```nix
core = {
editor = "${pkgs.emacs}/bin/emacs";
};
```
```.gitconfig
[core]
editor = /nix/store/<hash>-emacs-<version>/bin/emacs
```
### options.web
```nix
web.browser = "${pkgs.google-chrome}/bin/google-chrome";
```
```.gitconfig
[web]
browser = /nix/store/<hash>-google-chrome-<version>/bin/google-chrome
```
### options.rerere
```nix
rerere = {
enabled = true;
autoupdate = true;
};
```
```.gitconfig
[rerere]
enabled = 1
autoupdate = 1
```
### options.push
```nix
push.default = "matching";
```
```.gitconfig
[push]
default = matching
```
### options.color
```nix
color.ui = "auto";
```
```.gitconfig
[color]
ui = auto
```
We need to define a function named `gitconfig` that creates a Nix [derivation][wtf-derivation]:
```nix
# file: gitconfig.nix
let
# Import the <nixpkgs> package repository.
pkgs = import <nixpkgs> {};
# Stringify the attribute set, `xs`, as a multilined string formatted as "<key> = <value>".
# See attrsets.nix for more functions that work with attribute sets.
encodeAttrSet = xs: lib.concatStringsSep "\n" (lib.mapAttrsToList (k: v: "${k} = ${v}") xs);
# Define out function name `gitconfig` that accepts an `options` argument.
gitconfig = options: pkgs.stdenv.mkDerivation {
# The gitconfig file that Nix builds will be located /nix/store/some-hash-gitconfig.
name = "gitconfig";
src = pkgs.writeTextFile ".gitconfig" ''
[user]
name = ${options.user.name}
email = ${options.user.email}
username = ${options.user.username}
[core]
editor = ${options.core.editor}
[web]
editor = ${options.web.browser}
[rerere]
enabled = ${if options.rerere.enabled "1" else "0"}
autoupdate = ${if options.rerere.autoupdate "1" else "0"}
[push]
default = ${options.push.default}
[color]
ui = ${options.color.ui}
[alias]
${encodeAttrSet options.aliases}
'';
buildPhase = ''
${pkgs.coreutils}/bin/cp $src $out
'';
installPhase = ''
${pkgs.coreutils}/bin/ln -s $out ~/.gitconfig
'';
};
} in gitconfig {
user = {
name = "John Cleese";
email = "john@flying-circus.com";
username = "jcleese";
};
core = {
editor = "${pkgs.emacs}/bin/emacs";
};
web.browser = "${pkgs.google-chrome}/bin/google-chrome";
rerere = {
enabled = true;
autoupdate = true;
};
push.default = "matching";
color.ui = "auto";
aliases = {
a = "add --all";
ai = "add -i";
b = "branch";
cl = "clone";
cp = "cherry-pick";
d = "diff";
fo = "fetch origin";
lg = "log --oneline --graph --decorate";
ps = "push";
pb = "pull --rebase";
s = "status";
};
}
```
### options.alias
We want to write a function that accepts an attribute set and returns a
string. While Nix is a dynamically typed programming language, thinking in types
helps me clarify what I'm trying to write.
```haskell
encodeAttrSet :: AttrSet -> String
```
I prefer using a Haskell-inspired syntax for describing type signatures. Even if
you haven't written Haskell before, you may find the syntax intuitive.
Here is a non comprehensive, but demonstrative list of example type signatures:
- `[String]`: A list of strings (i.e. `[ "cogito" "ergo" "sum" ]`)
- `AttrSet`: A nix attribute set (i.e. `{ name = "John Cleese"; age = 80; }`).
- `add :: Integer -> Integer -> Integer`: A function named `add` that accepts
two integers and returns an integer.
Specifically, we want to make sure that when we call:
```nix
encodeAttrSet {
a = "add --all";
b = "branch";
}
```
...it returns a string that looks like this:
```.gitconfig
a = "add --all"
b = "branch"
```
TODO(wpcarro): @tazjin's nix-1p mentions this. Link to it.
Nix has useful functions scattered all over the place:
- `lib.nix`
- `list.nix`
- `lib.attrSet`
But I cannot recall exactly which functions we will need to write
`encodeAttrSet`. In these cases, I do the following:
1. Run `nix repl`.
2. Browse the Nix source code.
Google "nix attribute sets" and find the Github link to `attrsets.nix`.
You should consider repeating this search but instead of searching for
"attribute sets" search for "lists" and "strings". That is how I found the
functions needed to write `encodeAttrSet`. Let's return to our `nix repl`.
Load the nixpkgs set:
```nix
nix-repl> :l <nixpkgs>
Added 11484 variables.
```
Define a test input called `attrs`:
```nix
nix-repl> attrs = { fname = "John"; lname = "Cleese"; }
```
Map the attribute set into `[String]` using `lib.mapAttrsToList`:
```nix
nix-repl> lib.mapAttrsToList (k: v: "${k} = ${toString v}") attrs
[ "fname = John" "lname = Cleese" ]
```
Now join the `[String]` together using `lib.concatStringsSep`:
```nix
nix-repl> lib.concatStringsSep "\n" (lib.mapAttrsToList (k: v: "${k} = ${v}") attrs)
"fname = John\nlname = Cleese"
```
Now let's use this to define our function `encodeAttrSet`:
```nix
# file: gitconfig.nix
encodeAttrSet = xs: lib.concatStringsSep "\n" (lib.mapAttrsToList (k: v: "${k} = ${v}") xs);
```
### Using nixpkgs search
[Nixpkgs search][wtf-nixpkgs-search].
### Conclusion
We learned how to help ourselves.
- Where does `emacs` exist? What about `google-chrome`? [nixpkgs search][wtf-nixpkgs-search]
- Verify that I have it? [nix REPL][using-nix-repl]
We used Nix to create our first derivation.
[wtf-lln]: /lets-learn-nix
[wtf-git]: https://git-scm.com/
[wtf-derivation]: https://nixos.org/nixos/nix-pills/our-first-derivation.html
[wtf-nixpkgs-search]: https://nixos.org/nixos/packages.html?channel=nixos-19.09
[using-nix-repl]: /using-the-nix-repl
[wtf-home-mgr]: https://github.com/rycee/home-manager
[who-ryan]: https://twitter.com/rschmukler

View file

@ -0,0 +1,41 @@
---
title: "Lets Learn Nix: Tutorial Reproducibility"
date: 2020-03-17T18:34:58Z
draft: true
---
## Install Nix
Link to nixos page.
## The rest
Start with this...
```shell
$ mkdir ~/lets-learn-nix
$ cd ~/lets-learn-nix
```
...done. Copy the following and paste it into a file name `shell.nix`.
```nix
# file: shell.nix
let
pkgs = import (builtins.fetchGit {
url = "https://github.com/NixOS/nixpkgs-channels";
ref = "refs/heads/nixos-19.09";
}) {}
in pkgs.mkShell {
buildInputs = with pkgs; [
git
];
NIX_PATH = "nixpkgs=${pkgs}";
};
```
...then...
```shell
$ nix-shell
```

View file

@ -0,0 +1,58 @@
---
title: "Lets Learn Nix"
date: 2020-03-13T21:50:47Z
draft: false
---
## Background
[Nix][wtf-nix] may be the most useful tool that I use. I consider it as valuable
as [Git][wtf-git] or [Emacs][wtf-emacs]. My friend, David ([@dmjio][who-dmjio]),
first introduced me to Nix when we worked together at a Haskell startup in
NYC. Before this, I had been managing my system configuration using software
that I wrote -- first in Bash, then in Python, then in Golang.
It took me awhile to understand Nix. I left the NYC startup, joined Google, and
relocated to London. Here I met another Nix-enlightened monk, Vincent
([@tazjin][who-tazjin]), who patiently taught me enough Nix to become
self-reliant and productive.
Many resources exist to learn Nix; the Nix community on IRC continues to help me
and others effectively use Nix. I'm creating this series to write the tutorials
that I would have found useful when I started learning Nix. If you are just
beginning your Nix journey, I hope these tutorials help you.
## Goals
I aim to make each tutorial in the "Let's Learn Nix" series:
- Actionable: Readers will be writing code.
- Digestible: Readers should be able to finish each tutorial in fifteen minutes.
- Reproducible: Readers should expect the output of their code to match what
these tutorials claim they should see.
## About the author
My name is William ([@wpcarro][who-wpcarro]). My three favorite tools are Git,
Emacs, and Nix. I am an American expat currently working at Google in
London. While during the day I primarily write Java, Python, and TypeScript, I
prefer functional programming. I use Nix to deploy software and manage the
multiple machines across which I work.
## Let's Begin
Before we get started, Nix is a programming language. To familiarize yourself
with the syntax, semantics, and idioms, consider reading this brief [Nix One
Pager][nix-1p]. I recommend keeping it around as a reference.
When I was first learning Nix, I wanted to use it to manage my dotfiles. Our
first tutorial will help you get started: [Let's Learn Nix:
Dotfiles][lln-dotfiles]
[wtf-nix]: https://nixos.org
[wtf-git]: https://git-scm.com
[wtf-emacs]: https://www.gnu.org/software/emacs
[who-dmjio]: https://twitter.com/dmjio
[who-tazjin]: https://twitter.com/tazjin
[who-wpcarro]: https://twitter.com/wpcarro
[lln-dotfiles]: /lets-learn-nix-dotfiles
[nix-1p]: https://github.com/tazjin/nix-1p

View file

@ -0,0 +1,5 @@
---
title: "Deploy Hugo blog with Nix"
date: 2020-03-11T18:42:32Z
draft: true
---

View file

@ -0,0 +1,6 @@
---
title: "Self Hosting"
date: 2020-03-11T22:53:56Z
draft: true
---