diary at Telent Netowrks

First steps in NixOS#

Mon, 15 Jun 2015 15:10:01 +0000

According to the mtime of /nix on this laptop I've been running NixOS since February, so I should be past "first steps" by now, really. But I decided last week to switch to the Nix package collection on my work Mac as well, and that has prompted me to learn how to package some of the stuff I use that isn't already available.

(tl;dr - It's here: https://github.com/telent/nix-local/ )

Item zero was to find a way of keeping local packages alongside the real nixpkgs collection without a permanently divergent fork of the nixpkgs repo. The approach I eventually decided on was to use packageOverrides to augment the upstream package list with my own packages in an entirely separate repo. See https://github.com/telent/nix-local/blob/master/README.md#installation for details

With that out of the way, the fist thing I needed to package is vault which is a quite neat program for generating secure passwords given a master secret and a service name - i.e. you can have per-service passwords for each site you use without having to store the passwords anywhere.

It's Javascript/NPM. NPM is a bad fit for Nix because as explained by Sander van der Burg it does dependency management as well as building, and its model of dependencies (semver, in theory) is considerably more lax than the Nix model. So we use npm2nix to produce nix expressions for all its dependencies from `package.json`

$ git clone git@github.com:jcoglan/vault
$ git co 0.3.0
$ `nix-build '<nixpkgs>' -A npm2nix`/bin/npm2nix package.json node-packages.generated.nix

then we copy the generated files into our nix-local repo.

$ mkdir -p ~/nix-local/vault/
$ cp node-packages.generated.nix default.nix ~/nix-local/vault/

The generated default.nix then needed significant manual editing:

deps = (filter (v: nixType v == "derivation") (attrValues nodePackages))

Finally the package can be installed with nix-env -iA nixpkgs.vault or nix-env -i nodejs-vault. I don't know which of these is stylistically preferable, but in this case they both have exactly the same effect. As far as I know.

Regaining my compojure#

Thu, 19 Feb 2015 11:16:22 +0000

Picking up $secret_project which I put down in November to do Sledge and Yablog, I find that the routing of http requests is a horrendous mess based on substring matching and ad hoc argument parsing, and would really benefit from some Compojure

(Now, that is, that I've actually got my head around how Compojure works)

Because I'm using Hiccup to compose pages out of parts, I thought it would be neat if I could return hiccup page bodies directly as responses so that they get uniformly topped and tailed and turned into response maps. Turns out to be fairly straightforward:

  1. define a type for the hiccup response
  2. extend the compojure.response/Renderable protocol to deal with the new type

(deftype Hiccupage [body])
 
(defn page-surround [page]
  (let [head [:head
              [:link {:rel "stylesheet" :type "text/css"
                      :href "/static/default.css"}]
              [:script {:src "/static/stuff.js"}]
              [:title "Hey you"]]]
    (into head (.body page))))
 
(extend-protocol compojure.response/Renderable
  Hiccupage
  (render [page req]
    {:status  200
     :headers {"Content-Type" "text/html; charset=utf-8"}
     :body   (hiccup.page/html5 (page-surround page))}))

Now we can return Hiccupage (hiccup page? geddit? I'm still looking for a better name, yes) objects directly from our routes

(defroutes app
    (GET "/hello/:name" [name] 
	 (Hiccupage.
	  [[:h1 "hello"]
	   [:p "hello " name]
	   [:p "This is text. I like text"]]))
  ...
  )

Yet another blog engine#

Mon, 16 Feb 2015 22:35:11 +0000

Yablog is the unimaginatively named "Yet Another Blog engine" and is what's now behind the blog at ww.telent.net - mostly because every third attempt to post with my-way ended up with having to relearn out how all the baroque git hooks worked.

It was supposed to be a two-hour Tuesday morning hack, but it's now almost the following Tuesday morning as I did not anticipate that

This entry is mostly just a placeholder to check the new posting process works, but do check out Instaparse if you haven't used it already.

The Invisible AUDIO element#

Thu, 22 Jan 2015 19:26:47 +0000

I said this morning that I was going to replace the browser-native audio controls with something which looks (approximately, at least) consistent everywhere. There's another couple of reasons for wanting to revisit the way we render the audio element

The nice thing about Om application state is that it's also a perfectly ordinary Clojure atom and we can call add-watch on it to have a perfectly ordinary Clojure(Script) function called whenever it changes. So what we're going to do is

Lucene, you don't do your Daddy's will#

Thu, 22 Jan 2015 07:10:54 +0000

I'm only showing you pictures of the new Sledge UI as a stopgap, as it will shortly be replaced with the new new Sledge UI.

I Am Keeping: the way we allow search refining. Each search you request (either by typing something in or by clicking an artist or title name) is turned into one of those little yellow label things and then you can remove it again just by clicking the 'x' (I stole this idiom from the amazon ec2 console ui, but it's also what the gmail composer does when you type addresses into the to/from lines).

I Am Losing: the link to 'view play queue'. Rather than a 'tabs' metaphor, we will have an 'expand' button in the player area at the bottom which causes the queue to roll up and overlay the search results.

Also To Go: the browser-native audio controls, which are getting replaced with something that is consistent across browsers.

But the bigger reason for writing: already gone, the Lucene interface for storing the music database. I started working on having Sledge monitor its music folders for additions/deletions, and realised just how hard it is to persuade Lucene to search for an exact match on a particular field with no ambiguity or helpful tokenising - which is necessary when you want to delete the record for a file that's not in the filesytsem any more. So now we're using a flat file and EDN and doing our own tokenising into a bunch of maps that are created at load time. It's actually faster too, but I don't think that's anything to do with Lucene, more with it being the second stab at the problem.

This has now taken substantially more than one weekend and it's still not done. Damn scope creep.