<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Tony Finn - Personal Blog</title>
    <subtitle>Personal blog of a professional developer, covering self-hosting, Nix, Rust and other topics</subtitle>
    <link rel="self" type="application/atom+xml" href="https://tonyfinn.com/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://tonyfinn.com"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2024-10-14T00:00:00+00:00</updated>
    <id>https://tonyfinn.com/atom.xml</id>
    <entry xml:lang="en">
        <title>Jujutsu (jj), a git compatible VCS</title>
        <published>2024-10-14T00:00:00+00:00</published>
        <updated>2024-10-14T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://tonyfinn.com/blog/jj/"/>
        <id>https://tonyfinn.com/blog/jj/</id>
        
        <summary type="html">&lt;p&gt;It&#x27;s quite a common opinion that git (while a big improvement on
what came before) still has plenty of rough edges, particularly
with regards to the user interface. At the same time, there&#x27;s
also a significant barrier to entry for a new version control
system with all the tooling that&#x27;s built up around git over
the years, particularly if you want to try it in your workplace
without migrating the entire company.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;martinvonz&#x2F;jj&quot;&gt;jj&lt;&#x2F;a&gt; is one of the latest round of git-compatible version control
systems which allows you to have a better experience locally,
without having to abandon everything that depends on git. I&#x27;ve
been trying it out now for about two months, and this post shares
some of my thoughts.&lt;&#x2F;p&gt;</summary>
        
    </entry>
    <entry xml:lang="en">
        <title>Building Arch Packages With Nix</title>
        <published>2023-01-23T00:00:00+00:00</published>
        <updated>2023-01-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://tonyfinn.com/blog/arch-packages-with-nix/"/>
        <id>https://tonyfinn.com/blog/arch-packages-with-nix/</id>
        
        <summary type="html">&lt;p&gt;In recent months I&#x27;ve been building more and more of my packages with Nix.
However, most of my personal systems are still running Arch. While NixOS
is making headways there and is probably the eventual destination for all
my systems, I&#x27;m not interested in migrating all my personal infrastructure
all at once.&lt;&#x2F;p&gt;
&lt;p&gt;Instead, what I really want to do is having my Nix tooling output Arch
packages that I can install on those systems in this transitional period.
After some experimentation, I got it working for one of my packages, this
blog, and this post details the steps it took.&lt;&#x2F;p&gt;</summary>
        
    </entry>
    <entry xml:lang="en">
        <title>Runnable Flakes (Nix From First Principles: Flake Edition #9)</title>
        <published>2022-11-10T00:00:00+00:00</published>
        <updated>2022-11-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://tonyfinn.com/blog/nix-from-first-principles-flake-edition/nix-9-runnable-flakes/"/>
        <id>https://tonyfinn.com/blog/nix-from-first-principles-flake-edition/nix-9-runnable-flakes/</id>
        
        <summary type="html">&lt;p&gt;In the last two parts, I covered using flakes for two different types of output:
&lt;a href=&quot;https:&#x2F;&#x2F;tonyfinn.com&#x2F;blog&#x2F;nix-from-first-principles-flake-edition&#x2F;nix-7-what-about-flakes-then&#x2F;&quot;&gt;packages&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;tonyfinn.com&#x2F;blog&#x2F;nix-from-first-principles-flake-edition&#x2F;nix-8-flakes-and-developer-environments&#x2F;&quot;&gt;developer environments&lt;&#x2F;a&gt;. This time I&#x27;ll cover a
third type of output - runnable commands. These are what power the &lt;code&gt;nix run&lt;&#x2F;code&gt;
command that you&#x27;ve seen a few times throughout the series, and now you will
find out how to get this functionality for your own flakes.&lt;&#x2F;p&gt;</summary>
        
    </entry>
    <entry xml:lang="en">
        <title>Flakes and Developer Environments (Nix From First Principles: Flake Edition #8)</title>
        <published>2022-11-07T00:00:00+00:00</published>
        <updated>2022-11-07T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://tonyfinn.com/blog/nix-from-first-principles-flake-edition/nix-8-flakes-and-developer-environments/"/>
        <id>https://tonyfinn.com/blog/nix-from-first-principles-flake-edition/nix-8-flakes-and-developer-environments/</id>
        
        <summary type="html">&lt;p&gt;While packages are the most common type of item you&#x27;ll find contained in flakes,
another type of item is a &lt;em&gt;development shell&lt;&#x2F;em&gt;. This is an environment that you can
enter with the &lt;code&gt;nix develop&lt;&#x2F;code&gt; command. By default, each package will provide a development
shell which is the build environment used to build it. By running just &lt;code&gt;nix develop&lt;&#x2F;code&gt;
without specifying which shell is wanted, &lt;code&gt;nix&lt;&#x2F;code&gt; will put you in a &lt;code&gt;bash&lt;&#x2F;code&gt; shell with the
environment from the default package.&lt;&#x2F;p&gt;
&lt;p&gt;However, sometimes you may wish to set up additional tools in a development environment,
for example you may have scripts written in Python and want to have Python available as
for a developer to use, yet you do not want to include Python as a dependency in your built
package. Or you might want to set some environment variables so that logging is set to
debug mode in your development environment.&lt;&#x2F;p&gt;
&lt;p&gt;You can customise the &lt;code&gt;nix develop&lt;&#x2F;code&gt; environment with the &lt;code&gt;devShells&lt;&#x2F;code&gt; attribute set in a
flake.&amp;hellip;
&lt;&#x2F;p&gt;
</summary>
        
    </entry>
    <entry xml:lang="en">
        <title>What about flakes then? (Nix From First Principles: Flake Edition #7)</title>
        <published>2022-11-06T00:00:00+00:00</published>
        <updated>2022-11-06T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://tonyfinn.com/blog/nix-from-first-principles-flake-edition/nix-7-what-about-flakes-then/"/>
        <id>https://tonyfinn.com/blog/nix-from-first-principles-flake-edition/nix-7-what-about-flakes-then/</id>
        
        <summary type="html">&lt;p&gt;One of the big new concepts in Nix is the &lt;code&gt;flake&lt;&#x2F;code&gt;, which is a new standard
format for nix projects to declare all their outputs. At the beginning of
this series, I mentioned them as being one of the major components of modern
Nix, and now this series has introduced enough of a foundation it&#x27;s time
to explain flakes themselves.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-a-flake&quot;&gt;What is a flake?&lt;&#x2F;h2&gt;
&lt;aside class=&quot;hide-from-preview&quot;&gt;
&lt;h3 id=&quot;why-the-name-flake&quot;&gt;Why the name &#x27;flake&#x27;?&lt;&#x2F;h3&gt;
&lt;p&gt;Nix&#x27;s logo is a snow flake. Nix itself means snow in Latin. So Nix flakes
are a pun on snow flakes.&lt;&#x2F;p&gt;
&lt;&#x2F;aside&gt;
&lt;p&gt;A &lt;code&gt;flake&lt;&#x2F;code&gt; is a standard format for describing a collection of Nix resources.
These resources can be packages, of the type described in previous posts,
intended to be used to install some software to your system. There&#x27;s also a
number of other types of resources that can be exposed by the flake which
we&#x27;ll cover in later posts. Some examples of these are:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;developer environment descriptions&lt;&#x2F;li&gt;
&lt;li&gt;modules for configuring NixOS systems&lt;&#x2F;li&gt;
&lt;li&gt;runnable commands&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;By standardising a format to list all these outputs (compared to the ad-hoc
files this series has been using until now), Nix allows a number of higher level
tools to operate on these resources, like the &lt;code&gt;nix profile install&lt;&#x2F;code&gt; and &lt;code&gt;nix run&lt;&#x2F;code&gt;
commands that have been shown in earlier parts.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, the development of the flake based tooling allowed the Nix team
to resolve some pain points with the older generation of tooling, such
as making the process of recording versions for reproducibility more ergonomic with
lock files, or making better ways to identify newer versions of the same
package to allow tools to manage updates.&lt;&#x2F;p&gt;</summary>
        
    </entry>
    <entry xml:lang="en">
        <title>Nixpkgs - How Not to Reinvent the Wheel (Nix From First Principles: Flake Edition #6)</title>
        <published>2022-10-12T00:00:00+00:00</published>
        <updated>2022-10-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://tonyfinn.com/blog/nix-from-first-principles-flake-edition/nix-6-nixpkgs-not-reinventing-the-wheel/"/>
        <id>https://tonyfinn.com/blog/nix-from-first-principles-flake-edition/nix-6-nixpkgs-not-reinventing-the-wheel/</id>
        
        <summary type="html">&lt;p&gt;In the last section I discussed creating your first derivation, which
allows you to make a first nix package. As you might have noticed, the
default execution environment is incredibly barebones, to the point that
you needed to include such fundamental tools as &lt;code&gt;chmod&lt;&#x2F;code&gt; and &lt;code&gt;cp&lt;&#x2F;code&gt;. If that
process had to be repeated by every Nix user, it would be very inconvenient.
Luckily, there is nixpkgs, which provides a number of packages that the
community has already built, along with the standard environment which
includes a number of tools to use in building your own. You may remember
installing some of these packages in &lt;a href=&quot;https:&#x2F;&#x2F;tonyfinn.com&#x2F;blog&#x2F;nix-from-first-principles-flake-edition&#x2F;nix-3-package-manager&#x2F;&quot;&gt;part 3&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;</summary>
        
    </entry>
    <entry xml:lang="en">
        <title>Overview (Nix From First Principles: Flake Edition #1)</title>
        <published>2022-10-05T00:00:00+00:00</published>
        <updated>2022-10-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://tonyfinn.com/blog/nix-from-first-principles-flake-edition/nix-1-nix-guide-overview/"/>
        <id>https://tonyfinn.com/blog/nix-from-first-principles-flake-edition/nix-1-nix-guide-overview/</id>
        
        <summary type="html">&lt;p&gt;One technology that I&#x27;d been hearing more and more over the last two years has been
Nix, in its various forms. The big draws I&#x27;ve heard about include declarative,
portable, cross lang dependency specification, and the ability to have a config file
declare the entire state of a system without storing huge docker container artifacts
for every permutation.&lt;&#x2F;p&gt;
&lt;p&gt;Actually learning Nix though felt much harder than it needed to be. The biggest problem
is that the documentation you need is often fragmented among the different subprojects,
and also the transition that Nix is in at the moment from the current standard methods
of &lt;code&gt;default.nix&lt;&#x2F;code&gt;, &lt;code&gt;configuration.nix&lt;&#x2F;code&gt; and &lt;code&gt;shell.nix&lt;&#x2F;code&gt; to a new world of &lt;code&gt;flakes&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;As an outsider looking in, the flake world felt kind of in limbo at the moment
where anyone I talked to indicated that flakes fix so many of the problems with
current nix, but also they&#x27;re still officially experimental so the official documentation
declines to mention flakes.&lt;&#x2F;p&gt;
&lt;p&gt;After spending a fair amount of time understanding Nix for myself, I&#x27;ve decided to write my own guide
which explains it from scratch in a world using only the new Nix features,
with the &lt;code&gt;nix&lt;&#x2F;code&gt; CLI and flakes for the use cases I want from Nix. Credit
to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ianthehenry.com&#x2F;posts&#x2F;how-to-learn-nix&#x2F;&quot;&gt;ianthehenry&lt;&#x2F;a&gt; for his guide on Nix focused on the &quot;old world&quot; approach, and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;xeiaso.net&#x2F;blog&#x2F;nix-flakes-1-2022-02-21&quot;&gt;Xe Iaso&lt;&#x2F;a&gt;
for explaining flakes. The information included in this guide
is largely from synthesising their blogs and the official documentation.&lt;&#x2F;p&gt;
&lt;p&gt;This first post will describe the major parts of the Nix ecosystem.&lt;&#x2F;p&gt;</summary>
        
    </entry>
    <entry xml:lang="en">
        <title>Installation (Nix From First Principles: Flake Edition #2)</title>
        <published>2022-10-05T00:00:00+00:00</published>
        <updated>2022-10-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://tonyfinn.com/blog/nix-from-first-principles-flake-edition/nix-2-installation/"/>
        <id>https://tonyfinn.com/blog/nix-from-first-principles-flake-edition/nix-2-installation/</id>
        
        <summary type="html">&lt;p&gt;Nix can be installed on Linux or Mac systems. If you&#x27;re using the Nix based Linux
distribution, NixOS, then you&#x27;ll already have it installed. Otherwise the official
nix website provides &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;nixos.org&#x2F;download.html#download-nix&quot;&gt;the most up to date installation steps&lt;&#x2F;a&gt;, which
at the time of writing are&lt;&#x2F;p&gt;
&lt;p&gt;Linux:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;sh&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;lt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -L https:&#x2F;&#x2F;nixos.org&#x2F;nix&#x2F;install) --daemon&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Mac:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;sh&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;lt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -L https:&#x2F;&#x2F;nixos.org&#x2F;nix&#x2F;install)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Windows (run in WSL):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;sh&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;lt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -L https:&#x2F;&#x2F;nixos.org&#x2F;nix&#x2F;install) --no-daemon&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</summary>
        
    </entry>
    <entry xml:lang="en">
        <title>Nix Package Manager CLI (Nix From First Principles: Flake Edition #3)</title>
        <published>2022-10-05T00:00:00+00:00</published>
        <updated>2022-10-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://tonyfinn.com/blog/nix-from-first-principles-flake-edition/nix-3-package-manager/"/>
        <id>https://tonyfinn.com/blog/nix-from-first-principles-flake-edition/nix-3-package-manager/</id>
        
        <summary type="html">&lt;p&gt;The foundational part of Nix is the Nix package manager. This is a tool that
allows you to install packages. The &quot;first layer&quot; of Nix usage is to use this
tool to install packages. The Nix package manager, similar to projects like
os-rpmtree (used in Fedora Silverblue) or snapper (used in snap based Linux distros),
will allow you to easily revert package installs or updates if something goes wrong.&lt;&#x2F;p&gt;
&lt;p&gt;This post covers the basics of using the nix package manager at the command
line - while most users use nix through more advanced workflows, the basics
explained here will be useful in understanding those workflows, as well as
for users who want to dip their toes into Nix by treating it like a more
traditional package manager to start out.&lt;&#x2F;p&gt;</summary>
        
    </entry>
    <entry xml:lang="en">
        <title>Just Enough Nixlang (Nix From First Principles: Flake Edition #4)</title>
        <published>2022-10-05T00:00:00+00:00</published>
        <updated>2022-10-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://tonyfinn.com/blog/nix-from-first-principles-flake-edition/nix-4-just-enough-nixlang/"/>
        <id>https://tonyfinn.com/blog/nix-from-first-principles-flake-edition/nix-4-just-enough-nixlang/</id>
        
        <summary type="html">&lt;p&gt;This is a crash course in Nix&#x27;s language, which I&#x27;ll also sometimes call Nixlang
from here on, to avoid confusing it with the Nix package manager. For more detailed
instructions see &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;nixos.org&#x2F;manual&#x2F;nix&#x2F;stable&#x2F;language&#x2F;index.html&quot;&gt;the manual&lt;&#x2F;a&gt;. The Nix language is used heavily
within Nix, for defining packages, environments, runnable commands and library
functions.&lt;&#x2F;p&gt;
&lt;p&gt;Nix&#x27;s language is expression oriented. This means everything, including up to
the level of an entire program, has an output value. It will be most familiar
if you have experimented with functional langages such as Haskell, but it is
less complicated than those languages, so you don&#x27;t need to have mastered one
to start.&lt;&#x2F;p&gt;
&lt;p&gt;To start experimenting with it, you can run the &lt;code&gt;nix repl&lt;&#x2F;code&gt;
command which will let you type in Nix expressions and see the output.&lt;&#x2F;p&gt;</summary>
        
    </entry>
    <entry xml:lang="en">
        <title>Derivations (Nix From First Principles: Flake Edition #5)</title>
        <published>2022-10-05T00:00:00+00:00</published>
        <updated>2022-10-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://tonyfinn.com/blog/nix-from-first-principles-flake-edition/nix-5-derivation-intro/"/>
        <id>https://tonyfinn.com/blog/nix-from-first-principles-flake-edition/nix-5-derivation-intro/</id>
        
        <summary type="html">&lt;p&gt;So, time to explain the nix derivation. A Nix &lt;code&gt;derivation&lt;&#x2F;code&gt; is a special
type of &lt;code&gt;set&lt;&#x2F;code&gt; created from the &lt;code&gt;derivation&lt;&#x2F;code&gt; function which describes
how to obtain and build a package. The Nix package manger will then evaluate
this derivation, and use the result to copy the built package into the Nix
store, which is effectively a folder with all locally Nix built or installed
packages in it. The subfolders are hashes derived from the inputs to the
expression that built the stored packages.&lt;&#x2F;p&gt;</summary>
        
    </entry>
    <entry xml:lang="en">
        <title>Preserve - Jellyfin Music Client</title>
        <published>2021-01-31T00:00:00+00:00</published>
        <updated>2021-01-31T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://tonyfinn.com/preserve/"/>
        <id>https://tonyfinn.com/preserve/</id>
        
        <summary type="html">&lt;div class=&quot;hide-from-preview&quot;&gt;
In the last few months, I&#x27;ve moved away from using Spotify and back to using my own music collection, largely
driven by tracks which I include in my playlists disappearing off the service due to licensing issues. Moving fully
back to local media has left to issues keeping my library in sync across devices, so I&#x27;ve begun using Jellyfin,
an open source media server to store my collection and make it available to all my devices. However, the default
web interface in Jellyfin did not provide the same efficiency I liked from Clementine, my music player I used locally.
&lt;p&gt;Much like foobar2000, Clementine has a very efficient interface for the way in which I tend to listen to music - i.e.
rapidly creating a playlist of disparate tracks via search, listening to it for a few days or weeks, then making
a new collection. The same is not true for Jellyfin&#x27;s web interface (and wasn&#x27;t true for Spotify either). So I built my
own client to replicate that experience.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;preserve&quot;&gt;Preserve&lt;&#x2F;h2&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gitlab.com&#x2F;tonyfinn&#x2F;preserve&quot;&gt;Preserve&lt;&#x2F;a&gt; is a web based media player frontend to a jellyfin server. It aims to
replicate the experience of using players like foobar2000 or Clementine with its two panel design allowing you to quickly
search tracks and assemble&#x2F;order a playlist how you like, including full keyboard controls. It&#x27;s fully open source, under GPLv2+.&lt;&#x2F;p&gt;
&lt;p&gt;Since it is a jellyfin client, you will first need to host
your music using a Jellyfin server, but once that is done you can use Preserve in your browser at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;preserveplayer.com&quot;&gt;preserveplayer.com&lt;&#x2F;a&gt;
or install a desktop client from the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gitlab.com&#x2F;tonyfinn&#x2F;preserve&#x2F;-&#x2F;releases&quot;&gt;Preserve Gitlab releases&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;a href=&quot;&#x2F;preserve&#x2F;preserve-v0.5.3-720p.png&quot;&gt;
    &lt;picture&gt;
        &lt;source srcset=&quot;&#x2F;preserve&#x2F;preserve-v0.5.3-360p.avif?cache=20241013&quot; type=&quot;image&#x2F;avif&quot;&gt;
        &lt;source srcset=&quot;&#x2F;preserve&#x2F;preserve-v0.5.3-360p.webp?cache=20241013&quot; type=&quot;image&#x2F;webp&quot;&gt;
        &lt;img src=&quot;&#x2F;preserve&#x2F;preserve-v0.5.3-360p.png?cache=20241013&quot; alt=&quot;Preserve v0.5.3 Screenshot&quot; width=&quot;640&quot; height=&quot;360&quot;&gt;
    &lt;&#x2F;picture&gt;
&lt;&#x2F;a&gt;
&lt;figcaption&gt;Preserve v0.5.3&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;</summary>
        
    </entry>
    <entry xml:lang="en">
        <title>Home Server Part 1, Requirements and Hardware</title>
        <published>2019-09-07T00:00:00+00:00</published>
        <updated>2019-09-07T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://tonyfinn.com/blog/home-server-reqs/"/>
        <id>https://tonyfinn.com/blog/home-server-reqs/</id>
        
        <content type="html" xml:base="https://tonyfinn.com/blog/home-server-reqs/">&lt;p&gt;Having recently built a new gaming desktop, I still had enough components that
weren&#x27;t reused to decide what to do with them. I&#x27;d also been meaning to build
some sort of server setup for a while, so it proved a good opportunity to
convert my old desktop into a server. In the coming weeks, I&#x27;ll post a couple
more posts detailing my software setup but for now I&#x27;ll go over my goals and
hardware.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;requirements&quot;&gt;Requirements&lt;&#x2F;h2&gt;
&lt;p&gt;So what did I need a home server for anyway?&lt;&#x2F;p&gt;
&lt;h3 id=&quot;file-sync&quot;&gt;File sync&lt;&#x2F;h3&gt;
&lt;p&gt;I&#x27;ve used a number of solutions for this over the years. Dropbox had been my
goto but late last year &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.linuxuprising.com&#x2F;2018&#x2F;08&#x2F;dropbox-client-will-only-support-ext4.html%3E&quot;&gt;they dropped support for filesystems other than
ext4&lt;&#x2F;a&gt;
which was a wake up call to investigate other options. While they&#x27;ve since
relented, it was during this time I discovered
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;syncthing.net&quot;&gt;Syncthing&lt;&#x2F;a&gt; which took my interest. As someone who
likes to have control over their data, its nature as a P2P tool appealed to
me. This meant that my data no longer had to leave servers I control for sync.&lt;&#x2F;p&gt;
&lt;p&gt;This was especially relevant because of my setup for password management. I&#x27;ve
never been entirely happy entrusting my passwords to a third party service
like LastPass, but wanted the benefits of a password manager. This meant that
I used a keepass database in Dropbox for syncing passwords between devices, on
the grounds that someone would have to both breach Dropbox and break KeePass&#x27;s
encryption to obtain my passwords. But I still wasn&#x27;t entirely happy having my
passwords on a cloud service. In addition, the Android experience just was not
there, as the best I could do was open the dropbox copy in KeePassDroid which
was a one way export and occasionally expired meaning I&#x27;d have to log in again
to access the passwords again. It also ruled out using a password manager
password on Dropbox itself.&lt;&#x2F;p&gt;
&lt;p&gt;Syncthing ended up being a very useful tool to replace Dropbox, and I&#x27;d tried
it out with a couple of use cases. I moved my password database sync to there,
and my RPG rulebook PDFs. However, there was one area it fell down, and that
was syncing between my desktop and my tablet for files which both modified,
such as my password database.&lt;&#x2F;p&gt;
&lt;p&gt;Because it was P2P and had no persistent host, to sync my password database
required my tablet to be awake and my desktop to be on at the same time, which
was a rare occurence. As such my password database ended up getting out of
sync and having merge conflicts which need to be resolved. I tried using my
phone as a always-on sync host for that folder which worked a bit, but it
would often take a while to sync because of the phone being asleep or killing
the syncthing app when low on resources.&lt;&#x2F;p&gt;
&lt;p&gt;This meant that I needed an always-on host to ensure that all devices had
somewhere to sync that would keep changes from getting too divergent. I could
just run syncthing on my VPS, but that puts me back with the Dropbox scenario
of having to entrust someone else (linode) with my password database. And as
my VPS was internet facing, the risk of compromise is much higher.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;home-streaming&quot;&gt;Home streaming&lt;&#x2F;h3&gt;
&lt;p&gt;I have a variety of content I&#x27;ve ripped from physical media or stripped DRM,
as well as from sources like Bandcamp artists that simply aren&#x27;t on streaming
services over the years. Sometimes I would like to watch or listen this away
from my desktop such as on my tablet which doesn&#x27;t have the capacity to store
much. This meant when I wanted to watch some movies in bed for the evening
that were not available on any of my subscribed streaming services, I had to
copy them manually onto my device each time. Which usually meant I didn&#x27;t
watch them over whatever was on Netflix at the time.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;backups&quot;&gt;Backups&lt;&#x2F;h3&gt;
&lt;p&gt;My backup strategy over the years has been varying levels of existent. Most
recently it has consisted of putting code into private gitlab repos and other
highly important files into Dropbox. This protected me against hard drive
failure for the covered content, but there was other content (Twitch stream
archives, aforementioned ripped movies) which was just too large to
economically store in Dropbox. Also as people would be rushing to mention on a
similar post, Dropbox is not really a backup - it&#x27;s online and if compromised,
someone could encrypt my Dropbox files with ransomware in the event of a
breach and the client would dutifully overwrite my local copies.&lt;&#x2F;p&gt;
&lt;p&gt;The other issue was that I wanted something easier to restore. While I could
get back to a working system without anything too major lost in the event of a
hard drive failure or similar, when actually put to the test it was a painful
experience. While I did get back to a working system, the time spent restoring
applications, their configs, games with mods etc. left a lot to be desired.
All this content could be pulled back from the internet, but I wanted
something a bit more &quot;restore from backup, be back like nothing happened&quot;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;fun&quot;&gt;Fun&lt;&#x2F;h3&gt;
&lt;p&gt;While this whole project may not be most people&#x27;s idea of fun, but it&#x27;d let me
play around with technologies that I didn&#x27;t often use, which I always find
interesting.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;hardware-setup&quot;&gt;Hardware Setup&lt;&#x2F;h2&gt;
&lt;p&gt;As previously mentioned, I had built a new gaming desktop so most of the
hardware for this actually are parts from my previous desktop. So my system
composed of the i5-4670k, 16gb of DDR3 RAM and gigabyte z87 motherboard used
in my old system. In addition, when it was my gaming system, the storage setup
was a bit of a mess. It had started out simply enough with a 256GB SSD + 2TB
HDD, but as it was serving part time duty as a file server already, it had
grown to 2 SSDs (a 256 gb 840 Pro and 1TB 850 Pro). 2x2TB HDDs and 2x4TB HDDs
(All WD blue drives). Most of these were formatted with NTFS as that worked
best for drives shared between Linux and Windows. Also, when I upgraded my GPU
to a GTX 1080, I actually had to remove most of the drive bays to fit the GPU,
with the result that one of the SSDs was just loose in the case.&lt;&#x2F;p&gt;
&lt;p&gt;As it turns out, having a wall of HDDs in your gaming desktop is not great for
airflow.&lt;&#x2F;p&gt;
&lt;p&gt;So the plan was the new gaming desktop is much simpler from a storage
perspective. It has a new 1TB 970 Pro SSD for the Windows&#x2F;boot drive, as
that&#x27;s where X-Plane 11 lives and is the most IO-heavy use, and the 1TB 850
Pro also went to the new build to be my Linux root drive.&lt;&#x2F;p&gt;
&lt;p&gt;Everything else stayed in the old build. In addition, moving the gtx1080 to my
new system let me put the drive trays back in. So now the system has the 840
Pro SSD as the boot&#x2F;OS drive, and 2x2TB + 2x4TB of hard drives for
storage.&lt;&#x2F;p&gt;
&lt;p&gt;While it had been used as my gaming desktop, the i5-4670k had been overclocked
up to 4.3ghz, but as part of this setup that was reversed for reasons of heat
and power consumption - the server uses weren&#x27;t demanding enough to require
the overclock to stay, as this had mostly been done for the purposes of
running X-Plane 11 at an acceptable framerate.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Screenshot testing with Rust</title>
        <published>2018-12-18T00:00:00+00:00</published>
        <updated>2018-12-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://tonyfinn.com/blog/rust-screenshot-testing/"/>
        <id>https://tonyfinn.com/blog/rust-screenshot-testing/</id>
        
        <summary type="html">&lt;h2 id=&quot;intro&quot;&gt;Intro&lt;&#x2F;h2&gt;
&lt;p&gt;This is a follow on from my previous blog post about capturing screenshots with Rust + OpenGL. While the previous article
most revolved around the process of actually capturing the rendered pixel data for my OpenGL application, this time around
I will focus on the process of actually validating the screenshots.&lt;&#x2F;p&gt;</summary>
        
    </entry>
    <entry xml:lang="en">
        <title>Capturing screenshots with Rust + OpenGL</title>
        <published>2018-12-15T00:00:00+00:00</published>
        <updated>2018-12-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://tonyfinn.com/blog/opengl-rust-screenshots/"/>
        <id>https://tonyfinn.com/blog/opengl-rust-screenshots/</id>
        
        <summary type="html">&lt;h2 id=&quot;intro&quot;&gt;Intro&lt;&#x2F;h2&gt;
&lt;p&gt;One ongoing area of side projects for me has been game development. It&#x27;s an area which
I&#x27;ve often found interesting, and while the only games I&#x27;ve completed so far have
been small games for Ludum Dare with the deadline hanging over, I&#x27;ve often had a few
larger side projects running around.&lt;&#x2F;p&gt;
&lt;p&gt;In general for these side projects, I tend to write a lot of the lower level code myself,
mostly because it&#x27;s something that I enjoy learning about. Part of this means that I can&#x27;t
just rely on the framework or engine rendering my game correctly, and instead need some way
to test it. Unit tests clearly aren&#x27;t enough here, while they can verify that I&#x27;m
calling the functions I expect, they really can&#x27;t verify that this results in something
cohesive being rendered to the screen.&lt;&#x2F;p&gt;
&lt;p&gt;Inspired by tools that exist in my day job of web development &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;percy.io&#x2F;&quot;&gt;like Percy&lt;&#x2F;a&gt;,
I decided to take the approach of comparing screenshots taken to reference screenshots.&lt;&#x2F;p&gt;
&lt;p&gt;For some reason, I was under the impression that &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.factorio.com&#x2F;&quot;&gt;Factorio&lt;&#x2F;a&gt; had
used a similar approach and detailed it in one of their FFF blogs, but when researching for this blog
post, I was unable to track this down. They certainly perform &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=erYjMMBXy7A&quot;&gt;integration testing&lt;&#x2F;a&gt;
but it appears screenshots are not involved.&lt;&#x2F;p&gt;</summary>
        
    </entry>
</feed>
