subtree(users/wpcarro): docking briefcase at '24f5a642
'
git-subtree-dir: users/wpcarro git-subtree-mainline:464bbcb15c
git-subtree-split:24f5a642af
Change-Id: I6105b3762b79126b3488359c95978cadb3efa789
This commit is contained in:
commit
019f8fd211
766 changed files with 175420 additions and 0 deletions
5
users/wpcarro/website/blog/content/english/caffeine.md
Normal file
5
users/wpcarro/website/blog/content/english/caffeine.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: "Caffeine"
|
||||
date: 2020-03-11T22:50:40Z
|
||||
draft: true
|
||||
---
|
|
@ -0,0 +1,280 @@
|
|||
---
|
||||
title: "Cell Phone Experiment"
|
||||
date: 2020-04-02T02:02:07Z
|
||||
draft: false
|
||||
---
|
||||
|
||||
### TL;DR
|
||||
|
||||
I will not use my cell phone during March to learn more about how much I depend
|
||||
on it.
|
||||
|
||||
### Explore/Exploit
|
||||
|
||||
Ever since I read Charles Duhigg's book, [The Power of Habit](poh), I try to
|
||||
habituate as many aspects of my life as I can.
|
||||
|
||||
Making my bed every morning is an example of a habit -- so too is flossing at
|
||||
night before bed.
|
||||
|
||||
The *exploit* axis of the [explore/exploit tradeoff](exp-exp) endows habits with
|
||||
their power. Brian Christian and Tom Griffiths explain this concept more clearly
|
||||
than I can in Chapter 2 of their exceptional book, [Algorithms to Live
|
||||
By](algos).
|
||||
|
||||
Habits are powerful, but if I overly exploit an activity, I may settle on a
|
||||
local optimum in lieu of settling on a global optimum; these are the opportunity
|
||||
costs of exploiting (i.e. habits) versus exploring (i.e. spontaneity).
|
||||
|
||||
But what if it was possible to habituate exploration?
|
||||
|
||||
### Monthly challenges
|
||||
|
||||
Every month since October 2018, I challenge myself to try something new. In the
|
||||
past, monthly challenges have been things like:
|
||||
- sign up and take Brazilian Jiu Jitsu classes
|
||||
- buy a guitar and learn [Freight Train](https://www.youtube.com/watch?v=IUK8emiWabU)
|
||||
- study Italian
|
||||
- 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.
|
||||
|
||||
This month (i.e. March) I'm challenging myself to avoid using my cell phone.
|
||||
|
||||
My parents gave me a cell phone when when I was a freshman in High School; I was
|
||||
14 years old. I am now 28, so I have been using a cell phone semi-daily for over
|
||||
a decade.
|
||||
|
||||
While I enjoy the convenience that my cell phone provides me, I am curious to
|
||||
suspend my usage to more clearly understand how much I depend on it...
|
||||
|
||||
### April
|
||||
|
||||
Now it is early April, and I completed March's challenge. So how was it?
|
||||
|
||||
Below I outline the parts of using a cell phone that I missed and the parts that
|
||||
I surprisingly did not miss. I will also mention the two times that I used my
|
||||
cell phone and why.
|
||||
|
||||
The first three things that I missed all relate to time.
|
||||
|
||||
#### Timekeeping
|
||||
|
||||
On the first day I realized that unless I was near a computer, I did not know
|
||||
what time it was.
|
||||
|
||||
I exclusively use my cell phone as my watch; I do not wear a watch. To adapt, I
|
||||
started looking for clocks around my office and while I was taking public
|
||||
transportation. Thankfully London posts the current time on the digital train
|
||||
schedules. This oriented me while I was traveling, which was also when I needed
|
||||
to know the time the most.
|
||||
|
||||
Most of the month, however, I never precisely knew what time it was.
|
||||
|
||||
#### Alarm clocks
|
||||
|
||||
While I anticipated living without an alarm clock prior to the experiment, I
|
||||
decided against buying a substitute. Prior to this month, I theorized that
|
||||
morning alarms probably disrupt the quality of my sleep. If I'm tired, shouldn't
|
||||
I keep sleeping?
|
||||
|
||||
As the month progressed and my 24 hour day morphed into a 25 hour day, I learned
|
||||
that I would prefer waking up at a set time every day and synchronize my
|
||||
schedule with the rest of my timezone.
|
||||
|
||||
I am still unsure if alarm clocks are helpful in the long-term. I would have
|
||||
slept with the curtains drawn to allow the morning sun to wake me
|
||||
up. Unfortunately, I live on the ground floor nearby a brightly shining street
|
||||
lamp that spills into my bedroom.
|
||||
|
||||
If I lived somewhere more remote (perhaps even a suburb would do) I would like
|
||||
to repeat an experiment where I live for a month without an alarm clock.
|
||||
|
||||
For now, I must return to the Temple of Chronology and supplicate until Father
|
||||
Time restores my sanity.
|
||||
|
||||
#### Timers
|
||||
|
||||
Using timers motivates me to do a bunch of short tasks like cleaning my flat for
|
||||
fifteen minutes, stretching, or reading before bed. Thankfully, I already owned
|
||||
a physical timer that I keep in my kitchen. This replaced the timer on my phone
|
||||
without disrupting my routine.
|
||||
|
||||
#### Maps
|
||||
|
||||
Speaking of being disoriented, what about living without maps software? On the
|
||||
few occasions where I traveled somewhere that was unfamiliar to me, I had to
|
||||
memorize the directions from my computer before I departed.
|
||||
|
||||
At least I didn't need to visit gas stations or museums to buy trifold tourist
|
||||
maps...
|
||||
|
||||
I once left my office mistakenly assuming that I would download the directions
|
||||
to my destination while commuting. As I awaited the office elevator, I realized
|
||||
that I had no clue where I was heading.
|
||||
|
||||
Thankfully I wasn't far from the safety, comfort, and familiarity of my desktop
|
||||
computer -- with its fatty WiFi connection. In no time I was studying Google
|
||||
Maps in my web browser and memorizing the directions.
|
||||
|
||||
Overall this was hardly an inconvenience, and I think I even enjoyed
|
||||
stress-testing my memory: a job that I so often outsource to hardware.
|
||||
|
||||
#### Rendezvouses
|
||||
|
||||
A couple of times I met friends in various parts of the city. Organizing these
|
||||
particular rendezvouses was a novel (read: anachronistic) experience. For all
|
||||
you young whippersnappers reading, take out your stone tablets and chisels. I'm
|
||||
going to explain how this works:
|
||||
|
||||
First I would tell my friends where and when to meet me. I emphasized that I
|
||||
would be quite helpless to any changes they might make to the plans once I began
|
||||
commuting, which made the commitments unusually more binding.
|
||||
|
||||
On one occasion my friend -- who is characteristically prompt, and even chides
|
||||
me for when I'm late -- was twenty minutes late for our engagement. My friend is
|
||||
German, so I figured I should do my civic duty of alerting the German embassy
|
||||
that my friend had broken German code, is obscenely late, and should therefore
|
||||
hand-in his passport and renounce his citizenship. After awhile my conscience
|
||||
advised me to reconsider.
|
||||
|
||||
It was fortunate for both of us that I did not fully understand how late he was.
|
||||
Remember: I didn't know what time it was.
|
||||
|
||||
I decided this would be a useful opportunity to test my patience, so I loitered
|
||||
for twenty minutes outside of our meeting point. He couldn't text me to tell me
|
||||
that he was late. I couldn't listen to music, call family or friends, or partake
|
||||
in any of the other rituals that modern-day loiterers observe to pass the
|
||||
time. In the end he showed up, and it was scarcely a big deal.
|
||||
|
||||
This experience made me wonder what the policy for abandoning plans is when
|
||||
someone is running late. Before smart phones, how long did people wait? Maybe
|
||||
the proper etiquette is to wait long enough for you to absolve yourself of the
|
||||
guilt of flaking in the unlikely event that your friend arrives shortly after
|
||||
you leave.
|
||||
|
||||
So... thirty minutes? I'll call my grandma tomorrow and ask her.
|
||||
|
||||
#### Boredom
|
||||
|
||||
My phone couldn't entertain me while I queued at the grocery store. Same too
|
||||
when I commuted.
|
||||
|
||||
I also found myself listening to less music than I usually do. I decided to read
|
||||
to occupy the void when I could; this helped me progress towards completing this
|
||||
year's [GoodReads challenge][gr-annual].
|
||||
|
||||
### Cheating
|
||||
|
||||
I used my phone twice during March.
|
||||
|
||||
1. Once to use my bank's mobile app to internationally transfer money from my
|
||||
U.K. account to my U.S. account. I could have used [TransferWise's][tw]
|
||||
website, but I didn't.
|
||||
2. Another time I used my phone to take pictures of an item that I wanted to
|
||||
sell on [CraigsList][cl]. I could have and perhaps should have used my laptop's
|
||||
webcam, but at the time, I didn't want to. I am accustomed to using my phone
|
||||
to take pictures, and I wanted to sell something.
|
||||
|
||||
In both of these cases, prior habits eroded my resolve to stay the course. These
|
||||
are useful reminders that habits don't distinguish between helpful and hurtful;
|
||||
they just exist.
|
||||
|
||||
In total I would estimate that I spent somewhere around fifteen minutes using
|
||||
my phone in March. While not perfect:
|
||||
|
||||
> Better a diamond with a flaw than a pebble without (Confucius)
|
||||
|
||||
### Substitution = Dilution
|
||||
|
||||
While the explicit goal of this challenge was to avoid using my cell phone for a
|
||||
month, the implicit goal was to disengage from many of the
|
||||
[nonessential][essentialism] activities that compete for my attention.
|
||||
|
||||
There were some activities that I didn't miss while living without a cell
|
||||
phone. This wasn't because I don't value these activities, but rather because I
|
||||
can adequately replace them with alternatives.
|
||||
|
||||
For texting and making phone calls, I used [Telegram][wtf-telegram]. Telegram
|
||||
helped me sustain a healthy relationship with my girlfriend while still honoring
|
||||
the constraints of the challenge.
|
||||
|
||||
While I appreciated the convenience Telegram provided, I felt that I remained
|
||||
about as [available][wtf-availability] during March as I was in February. If I
|
||||
ever experiment with drastically reducing my availability, I will be more
|
||||
explicit about my objectives.
|
||||
|
||||
### Distraction displacement (whack-a-mole)
|
||||
|
||||
Because cell phones and other electronics have conditioned my behavior, I
|
||||
habitually avoid boredom and seek entertainment. On its face this may not sound
|
||||
like a harmful practice. My generation drills the aphorism "you only live once",
|
||||
suggesting that we may want to embrace a Hedonistic lifestyle.
|
||||
|
||||
Hedonism may or may not be a wise way to play the game of Life. All I know is
|
||||
that living a life in which I am often stimulated but proportionately distracted
|
||||
appeals increasingly less to me as time progresses.
|
||||
|
||||
During March I noticed that once I freed my attention from sending/receiving
|
||||
texts, my brain quickly reassigned my attention to maintaining a vigil over the
|
||||
other social media outposts that I maintain.
|
||||
|
||||
I should also admit that I habitually checked Telegram now that it served as my
|
||||
new cell phone. Didn't see that coming...
|
||||
|
||||
In another case, once I discovered that I could use Instagram in a web browser
|
||||
instead of on my phone, I filled my newfound time and attention on
|
||||
[Instagram.com][ig] (don't click!): displacing the time that I spent on an app
|
||||
on my phone to time that I spent on a website in a web browser.
|
||||
|
||||
Holy whack-a-mole!
|
||||
|
||||
Halfway through the month, I wrote a [program to block websites][url-blocker] on
|
||||
my computer. Surprisingly this worked and forced me to more deliberately fill
|
||||
this hard-fought, foreign time with other activities.
|
||||
|
||||
### Easy come, easy go?
|
||||
|
||||
As the saying for making friends goes, "easy come, easy go", implying that
|
||||
friendships that you easily form can just as easily be destroyed.
|
||||
|
||||
Habits invert this creation/destruction relationship. In my experience "easy
|
||||
come" implies "difficult to go".
|
||||
|
||||
For example, I could easily form the habit of eating chocolate around 15:00 at
|
||||
work; curbing this habit would require more effort. When I compare this to the
|
||||
difficulty I experienced habituating a meditation practice, and how easily I
|
||||
can dislodge my meditation practice, it seems to me that the laws of habits
|
||||
dictate "easy come, difficult go; difficult come, easy go".
|
||||
|
||||
I suspect that while my cravings for using a cell phone have temporarily ceased,
|
||||
they will return shortly after I start using my cell phone. And as if nothing
|
||||
happened, I return to where I was at the end of February just before I decided
|
||||
to curb my cell phone usage.
|
||||
|
||||
Because of this, I'm planning on keeping my cell phone in my closet where I
|
||||
stored it during the month of March. As noted, enough substitutes exist for me
|
||||
to live a mostly normal life: one where I am not unnecessarily straining the
|
||||
relationships of my friends and my family. After all these are the people who
|
||||
matter most to me and those who drive me to explore new ways to improve.
|
||||
|
||||
I recognize that the "self" in self-experimentation is a misnomer. Can you truly
|
||||
conduct an [N of 1 trial][nof1]? My decisions impact the people in my life, and
|
||||
I want to thank everyone who tolerates my eccentric and oftentimes annoying
|
||||
experimentation.
|
||||
|
||||
Thank you for reading.
|
||||
|
||||
[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
|
||||
[gr-annual]: https://www.goodreads.com/user_challenges/19737920
|
||||
[cl]: http://craigslist.com
|
||||
[tw]: https://transferwise.com
|
||||
[url-blocker]: https://github.com/wpcarro/url-blocker
|
||||
[wtf-telegram]: https://telegram.org
|
||||
[wtf-availability]: https://landing.google.com/sre/sre-book/chapters/availability-table
|
||||
[essentialism]: https://www.goodreads.com/book/show/18077875-essentialism
|
||||
[ig]: https://instagram.com
|
||||
[nof1]: https://en.wikipedia.org/wiki/N_of_1_trial
|
|
@ -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?
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
```
|
58
users/wpcarro/website/blog/content/english/lets-learn-nix.md
Normal file
58
users/wpcarro/website/blog/content/english/lets-learn-nix.md
Normal 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
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: "Deploy Hugo blog with Nix"
|
||||
date: 2020-03-11T18:42:32Z
|
||||
draft: true
|
||||
---
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: "Self Hosting"
|
||||
date: 2020-03-11T22:53:56Z
|
||||
draft: true
|
||||
---
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue