Jekyll2021-12-01T22:30:33+01:00https://alphahydrae.com/feed.xmlAlphaHydraeTales of a programmerThere is a GitHub page listing your account’s SSH public keys2021-12-01T22:22:06+01:002021-12-01T22:22:06+01:00https://alphahydrae.com/2021/12/there-is-a-github-page-listing-your-account-s-ssh-public-keys<p>Visit <code class="language-plaintext highlighter-rouge">https://github.com/<your-username>.keys</code> to see your SSH public keys.</p>
<p>For example, here’s <a href="https://github.com/torvalds.keys">Linus Torvalds’s GitHub
key</a>.</p>
<blockquote>
<p>I happened upon this information while reading the documentation of
<a href="https://www.ansible.com">Ansible</a>’s <a href="https://docs.ansible.com/ansible/latest/collections/ansible/posix/authorized_key_module.html#parameter-key">POSIX authorized key
module</a>.</p>
</blockquote>Visit https://github.com/<your-username>.keys to see your SSH public keys.A java function that lists an object’s field names2021-08-17T08:07:46+02:002021-08-17T08:07:46+02:00https://alphahydrae.com/2021/08/a-java-function-that-lists-an-object-s-field-names<p>In order to make some assertions in a Java project’s automated test suite, I
needed to get the list of private, protected and public members of an object.</p>
<p>Using
<a href="https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/lang/Class.html#getDeclaredFields()"><code class="language-plaintext highlighter-rouge">Class#getDeclaredFieldNames()</code></a>,
you can easily get a class’s
<a href="https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/lang/reflect/Field.html"><code class="language-plaintext highlighter-rouge">Field</code></a>s,
an example of <a href="https://www.baeldung.com/java-reflection">reflection in Java</a>:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Class</span><span class="o"><?></span> <span class="n">someClass</span> <span class="o">=</span> <span class="n">someObject</span><span class="o">.</span><span class="na">getClass</span><span class="o">();</span>
<span class="nc">Field</span><span class="o">[]</span> <span class="n">declaredFields</span> <span class="o">=</span> <span class="n">someClass</span><span class="o">.</span><span class="na">getDeclaredFields</span><span class="o">();</span>
</code></pre></div></div>
<p>For our purposes, we’ll get that as a
<a href="https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/util/stream/package-summary.html">stream</a>:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Stream</span><span class="o"><</span><span class="nc">Field</span><span class="o">></span> <span class="n">declaredFields</span> <span class="o">=</span> <span class="nc">Arrays</span><span class="o">.</span><span class="na">stream</span><span class="o">(</span>
<span class="n">someClass</span><span class="o">.</span><span class="na">getDeclaredFields</span><span class="o">()</span>
<span class="o">);</span>
</code></pre></div></div>
<p>Unfortunately, this only returns the class’s direct fields. It doesn’t include
fields from parent classes. But we can do that with a <a href="https://en.wikipedia.org/wiki/Recursion_(computer_science)">recursive
function</a>:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">package</span> <span class="nn">com.alphahydrae.example</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.lang.reflect.Field</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.Arrays</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.stream.Stream</span><span class="o">;</span>
<span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="nc">FieldUtils</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="nc">Stream</span><span class="o"><</span><span class="nc">Field</span><span class="o">></span> <span class="nf">streamFields</span><span class="o">(</span>
<span class="nc">Class</span><span class="o"><?></span> <span class="n">currentClass</span>
<span class="o">)</span> <span class="o">{</span>
<span class="c1">// The stop condition for the recursive function: when we</span>
<span class="c1">// run out of parent classes, return an empty stream.</span>
<span class="k">if</span> <span class="o">(</span><span class="n">currentClass</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="nc">Stream</span><span class="o">.</span><span class="na">empty</span><span class="o">();</span>
<span class="o">}</span>
<span class="c1">// Return the stream of the parent class's fields</span>
<span class="c1">// concatenated to the current class's.</span>
<span class="k">return</span> <span class="nc">Stream</span><span class="o">.</span><span class="na">concat</span><span class="o">(</span>
<span class="n">streamFields</span><span class="o">(</span><span class="n">currentClass</span><span class="o">.</span><span class="na">getSuperclass</span><span class="o">()),</span>
<span class="nc">Arrays</span><span class="o">.</span><span class="na">stream</span><span class="o">(</span><span class="n">currentClass</span><span class="o">.</span><span class="na">getDeclaredFields</span><span class="o">())</span>
<span class="o">);</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="nf">FieldUtils</span><span class="o">()</span> <span class="o">{}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Using the functional powers granted to us by streams, we can easily:</p>
<ul>
<li>Filter out the fields we don’t want (in this case I did not want static fields
to be listed);</li>
<li>Get the names of the fields.</li>
</ul>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// ...</span>
<span class="kn">import</span> <span class="nn">java.lang.reflect.Modifier</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.List</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.stream.Collectors</span><span class="o">;</span>
<span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="nc">FieldUtils</span> <span class="o">{</span>
<span class="c1">// ...</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="nc">List</span><span class="o"><</span><span class="nc">String</span><span class="o">></span> <span class="nf">getDeclaredFieldNames</span><span class="o">(</span>
<span class="nc">Object</span> <span class="n">object</span>
<span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="nf">getFields</span><span class="o">(</span><span class="n">object</span><span class="o">.</span><span class="na">getClass</span><span class="o">())</span>
<span class="c1">// Filter out static fields.</span>
<span class="o">.</span><span class="na">filter</span><span class="o">(</span><span class="n">field</span> <span class="o">-></span>
<span class="o">!</span><span class="nc">Modifier</span><span class="o">.</span><span class="na">isStatic</span><span class="o">(</span><span class="n">field</span><span class="o">.</span><span class="na">getModifiers</span><span class="o">()))</span>
<span class="c1">// Get the names.</span>
<span class="o">.</span><span class="na">map</span><span class="o">(</span><span class="nl">Field:</span><span class="o">:</span><span class="n">getName</span><span class="o">)</span>
<span class="c1">// Collect them into a list.</span>
<span class="o">.</span><span class="na">collect</span><span class="o">(</span><span class="nc">Collectors</span><span class="o">.</span><span class="na">toList</span><span class="o">());</span>
<span class="o">}</span>
<span class="c1">// ...</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Done.</p>
<p>Here’s how you could use it:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// PersonDto.java</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">PersonDto</span> <span class="o">{</span>
<span class="kd">public</span> <span class="nc">String</span> <span class="n">firstName</span><span class="o">;</span>
<span class="kd">public</span> <span class="nc">String</span> <span class="n">lastName</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">// EmployeeDto.java</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">EmployeeDto</span> <span class="kd">extends</span> <span class="nc">PersonDto</span> <span class="o">{</span>
<span class="kd">public</span> <span class="nc">String</span> <span class="n">employeeNo</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">// EmployeeDtoTests.java</span>
<span class="kn">import</span> <span class="nn">static</span> <span class="n">org</span><span class="o">.</span><span class="na">hamcrest</span><span class="o">.</span><span class="na">MatcherAssert</span><span class="o">.</span><span class="na">assertThat</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">static</span> <span class="n">org</span><span class="o">.</span><span class="na">hamcrest</span><span class="o">.</span><span class="na">Matchers</span><span class="o">.</span><span class="na">containsInAnyOrder</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.junit.jupiter.api.Test</span><span class="o">;</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">EmployeeDtoTests</span> <span class="o">{</span>
<span class="nd">@Test</span>
<span class="kt">void</span> <span class="nf">employeeDtoFieldsHaveNotChanged</span><span class="o">()</span> <span class="o">{</span>
<span class="n">assertThat</span><span class="o">(</span>
<span class="nc">FieldUtils</span><span class="o">.</span><span class="na">getDeclaredFieldNames</span><span class="o">(</span><span class="k">new</span> <span class="nc">EmployeeDto</span><span class="o">()),</span>
<span class="n">containsInAnyOrder</span><span class="o">(</span>
<span class="s">"firstName"</span><span class="o">,</span>
<span class="s">"lastName"</span><span class="o">,</span>
<span class="s">"employeeNo"</span>
<span class="o">)</span>
<span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>In order to make some assertions in a Java project’s automated test suite, I needed to get the list of private, protected and public members of an object.How to make an Elixir module alias itself2021-03-12T20:40:21+01:002021-03-12T20:40:21+01:00https://alphahydrae.com/2021/03/how-to-make-an-elixir-module-alias-itself<p>Elixir modules are generally named with a hierarchical structure separated by
dots:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">defmodule</span> <span class="no">MyProject</span><span class="o">.</span><span class="no">Thing</span> <span class="k">do</span>
<span class="c1"># ...</span>
<span class="k">end</span>
</code></pre></div></div>
<p>This is just a convention and provides no special functionality. Like <a href="http://erlang.org/doc/reference_manual/modules.html">Erlang
modules</a>, <a href="https://elixir-lang.org/getting-started/modules-and-functions.html">Elixir modules</a> are just atoms,
prefixed with <code class="language-plaintext highlighter-rouge">"Elixir."</code>:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">Atom</span><span class="o">.</span><span class="n">to_string</span><span class="p">(</span><span class="no">List</span><span class="p">)</span> <span class="c1"># "Elixir.List"</span>
<span class="ss">:"Elixir.List"</span> <span class="c1"># List</span>
<span class="no">Atom</span><span class="o">.</span><span class="n">to_string</span><span class="p">(</span><span class="no">MyProject</span><span class="o">.</span><span class="no">Thing</span><span class="p">)</span> <span class="c1"># "Elixir.MyProject.Thing"</span>
</code></pre></div></div>
<p>You can reference an Elixir module by its full name but that’s rather verbose
and repetitive, especially in its own implementation. Here’s an example with an
<a href="https://elixir-lang.org/getting-started/structs.html">Elixir struct</a> and a function that manipulate it:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">defmodule</span> <span class="no">MyProject</span><span class="o">.</span><span class="no">Thing</span> <span class="k">do</span>
<span class="k">defstruct</span> <span class="p">[</span><span class="ss">:name</span><span class="p">,</span> <span class="ss">value:</span> <span class="mi">0</span><span class="p">]</span>
<span class="k">def</span> <span class="n">awesome</span><span class="p">(%</span><span class="no">MyProject</span><span class="o">.</span><span class="no">Thing</span><span class="p">{</span><span class="ss">name:</span> <span class="n">name</span><span class="p">}</span> <span class="o">=</span> <span class="n">thing</span><span class="p">)</span> <span class="k">do</span>
<span class="p">%</span><span class="no">MyProject</span><span class="o">.</span><span class="no">Thing</span><span class="p">{</span><span class="n">thing</span> <span class="o">|</span> <span class="ss">name:</span> <span class="s2">"Awesome </span><span class="si">#{</span><span class="n">name</span><span class="si">}</span><span class="s2">"</span><span class="p">}</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<!-- more -->
<h2 id="using-__module__">Using <code class="language-plaintext highlighter-rouge">__MODULE__</code></h2>
<p>One way to avoid the repetition of the module name is to use <a href="https://hexdocs.pm/elixir/Kernel.SpecialForms.html#__MODULE__/0">the <code class="language-plaintext highlighter-rouge">__MODULE__/0</code>
macro from <code class="language-plaintext highlighter-rouge">Kernel.SpecialForms</code></a>. It returns the current
module name as an atom:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">defmodule</span> <span class="no">MyProject</span><span class="o">.</span><span class="no">Thing</span> <span class="k">do</span>
<span class="k">defstruct</span> <span class="p">[</span><span class="ss">:name</span><span class="p">,</span> <span class="ss">value:</span> <span class="mi">0</span><span class="p">]</span>
<span class="k">def</span> <span class="n">awesome</span><span class="p">(%</span><span class="bp">__MODULE__</span><span class="p">{</span><span class="ss">name:</span> <span class="n">name</span><span class="p">}</span> <span class="o">=</span> <span class="n">thing</span><span class="p">)</span> <span class="k">do</span>
<span class="p">%</span><span class="bp">__MODULE__</span><span class="p">{</span><span class="n">thing</span> <span class="o">|</span> <span class="ss">name:</span> <span class="s2">"Awesome </span><span class="si">#{</span><span class="n">name</span><span class="si">}</span><span class="s2">"</span><span class="p">}</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Although the module name is no longer repeated, this may not be the most
readable version.</p>
<h2 id="using-an-alias">Using an alias</h2>
<p>Another way to avoid too much repetition is to use <a href="https://elixir-lang.org/getting-started/alias-require-and-import.html#alias">an alias</a>:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">defmodule</span> <span class="no">MyProject</span><span class="o">.</span><span class="no">Thing</span> <span class="k">do</span>
<span class="k">defstruct</span> <span class="p">[</span><span class="ss">:name</span><span class="p">,</span> <span class="ss">value:</span> <span class="mi">0</span><span class="p">]</span>
<span class="n">alias</span> <span class="no">MyProject</span><span class="o">.</span><span class="no">Thing</span><span class="p">,</span> <span class="ss">as:</span> <span class="no">Thing</span>
<span class="k">def</span> <span class="n">awesome</span><span class="p">(%</span><span class="no">Thing</span><span class="p">{</span><span class="ss">name:</span> <span class="n">name</span><span class="p">}</span> <span class="o">=</span> <span class="n">thing</span><span class="p">)</span> <span class="k">do</span>
<span class="p">%</span><span class="no">Thing</span><span class="p">{</span><span class="n">thing</span> <span class="o">|</span> <span class="ss">name:</span> <span class="s2">"Awesome </span><span class="si">#{</span><span class="n">name</span><span class="si">}</span><span class="s2">"</span><span class="p">}</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>This is a bit more readable.</p>
<p>Since aliases are often used as shortcuts for the last part of the module name
like this, it is the default behavior if you don’t specify a name:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># These two aliases are equivalent:</span>
<span class="n">alias</span> <span class="no">MyProject</span><span class="o">.</span><span class="no">Thing</span>
<span class="n">alias</span> <span class="no">MyProject</span><span class="o">.</span><span class="no">Thing</span><span class="p">,</span> <span class="ss">as:</span> <span class="no">Thing</span>
</code></pre></div></div>
<p>You can also alias an Elixir module to whatever name you want if you prefer:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">alias</span> <span class="no">MyProject</span><span class="o">.</span><span class="no">Thing</span><span class="p">,</span> <span class="ss">as:</span> <span class="no">Foo</span>
</code></pre></div></div>
<h2 id="making-a-module-alias-itself">Making a module alias itself</h2>
<p>Ok, so an alias is good, but the solution above still makes you repeat the full
module name twice. However, you can combine it with <code class="language-plaintext highlighter-rouge">__MODULE__</code> and get the
best of both worlds:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">defmodule</span> <span class="no">MyProject</span><span class="o">.</span><span class="no">Thing</span> <span class="k">do</span>
<span class="k">defstruct</span> <span class="p">[</span><span class="ss">:name</span><span class="p">,</span> <span class="ss">value:</span> <span class="mi">0</span><span class="p">]</span>
<span class="n">alias</span> <span class="bp">__MODULE__</span>
<span class="k">def</span> <span class="n">awesome</span><span class="p">(%</span><span class="no">Thing</span><span class="p">{</span><span class="ss">name:</span> <span class="n">name</span><span class="p">}</span> <span class="o">=</span> <span class="n">thing</span><span class="p">)</span> <span class="k">do</span>
<span class="p">%</span><span class="no">Thing</span><span class="p">{</span><span class="n">thing</span> <span class="o">|</span> <span class="ss">name:</span> <span class="s2">"Awesome </span><span class="si">#{</span><span class="n">name</span><span class="si">}</span><span class="s2">"</span><span class="p">}</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>This way you both avoid the repetition of the full name <em>and</em> can use the more
readable <code class="language-plaintext highlighter-rouge">Thing</code> instead of <code class="language-plaintext highlighter-rouge">__MODULE__</code> in the rest of the code.</p>
<h2 id="credits">Credits</h2>
<p><a href="https://pragprog.com/titles/lhelph/functional-web-development-with-elixir-otp-and-phoenix/"><img class="float-right w-full ml-3 mb-3 sm:w-1/2 sm:-mt-12" src="/assets/books/functional-web-development-with-elixir-otp-and-phoenix.jpg" /></a></p>
<p>I learned this while reading chapter 2 of <a href="https://pragprog.com/titles/lhelph/functional-web-development-with-elixir-otp-and-phoenix/"><em>Functional Web Development with
Elixir, OTP, and Phoenix, Rethink the Modern Web App</em> by Lance Halvorsen</a>.</p>Elixir modules are generally named with a hierarchical structure separated by dots:asdf, one version manager to rule them all2021-03-06T21:32:17+01:002021-03-06T21:32:17+01:00https://alphahydrae.com/2021/03/one-version-manager-to-rule-them-all<p><a href="https://asdf-vm.com">asdf</a> is an extendable version manager with support for <a href="https://www.ruby-lang.org">Ruby</a>,
<a href="https://nodejs.org">Node.js</a>, <a href="https://elixir-lang.org">Elixir</a>, <a href="https://www.erlang.org">Erlang</a>, <a href="https://www.python.org">Python</a>,
<a href="https://www.rust-lang.org">Rust</a>, <a href="https://asdf-vm.com/#/plugins-all?id=plugin-list">and more</a>.</p>
<p>When you regularly work on multiple projects using the same programming
language, Node.js for example, you might need different versions of the language
for different projects. One project might require version 14, currently the
latest stable version, while another project might still be using version 10.
It’s a pain to install all these versions yourself and manage your <a href="https://en.wikipedia.org/wiki/PATH_(variable)">PATH</a>,
especially if you work with multiple programming languages on a daily basis.</p>
<!-- more -->
<p><a href="https://rvm.io">rvm</a> was the first programming language version manager I used back when I
was doing a lot of <a href="https://rubyonrails.org">Ruby on Rails</a>. Then I switched to <a href="https://github.com/rbenv/rbenv">rbenv</a>
because it seemed simpler and used less dark shell magic. <a href="https://github.com/nvm-sh/nvm">nvm</a> and
<a href="https://github.com/nodenv/nodenv">nodenv</a> are similar tools for Node.js. I have also used the latter.</p>
<p>When I started playing with Elixir, I discovered <a href="https://asdf-vm.com">asdf</a>, a version manager
capable of installing and managing multiple versions of both <a href="https://elixir-lang.org">Elixir</a>
and <a href="https://www.erlang.org">Erlang</a>, but also Ruby and Node.js which I am still using
regularly. Not only that, it’s a plugin-based version manager with plugins for
practically every programming language.</p>
<h2 id="i-need-to-get-me-some-of-that">I need to get me some of that!</h2>
<p>You can <a href="https://asdf-vm.com/#/core-manage-asdf">install asdf</a> with Aptitude on Linux or with
<a href="https://brew.sh">Homebrew</a> on macOS:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Install dependencies</span>
<span class="nv">$></span> brew <span class="nb">install </span>coreutils curl git
<span class="c"># Install asdf itself</span>
<span class="nv">$></span> brew <span class="nb">install </span>asdf
</code></pre></div></div>
<blockquote>
<p>On Windows, it should work in the <a href="https://docs.microsoft.com/en-us/windows/wsl/about">Windows Subsystem for Linux (WSL)</a>.</p>
</blockquote>
<p>You also need to add it to your shell by adding this line to your shell
configuration file, for example <code class="language-plaintext highlighter-rouge">.zshrc</code> or <code class="language-plaintext highlighter-rouge">.bash_profile</code>:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">.</span> <span class="si">$(</span>brew <span class="nt">--prefix</span> asdf<span class="si">)</span>/asdf.sh
</code></pre></div></div>
<p>Restart your shell for this change to take effect.</p>
<p>You can now use asdf. The first thing you need to do is install a plugin for
your favorite programming language, for example <a href="https://github.com/asdf-vm/asdf-nodejs">the Node.js
plugin</a>:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$></span> asdf plugin add nodejs
</code></pre></div></div>
<blockquote>
<p>A plugin might require additional setup. For example, this plugin requires you
to <a href="https://github.com/asdf-vm/asdf-nodejs#install">import the Node.js release team’s OpenPGP keys</a> to
ensure the authenticity of downloaded Node.js releases.</p>
</blockquote>
<p>Once installed, the plugin allows you to list the available versions for the
language:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$></span> asdf list all nodejs
...
14.0.0
...
14.16.0
15.0.0
...
15.11.0
</code></pre></div></div>
<p>You can install whatever versions you want:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$> asdf install nodejs 14.16.0
$> asdf install nodejs 15.11.0
</code></pre></div></div>
<p>You can change the version of a language used in the current shell like this:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$></span> asdf shell nodejs 15.11.0
<span class="nv">$></span> node <span class="nt">--version</span>
v15.11.0
<span class="nv">$></span> asdf shell nodejs 14.16.0
<span class="nv">$></span> node <span class="nt">--version</span>
v14.16.0
</code></pre></div></div>
<p>This will only last until you close that shell. But you can also set the default
global version for your user so that it persists for any new shell:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$></span> asdf global nodejs 14.16.0
</code></pre></div></div>
<p>This actually just puts a line in your <code class="language-plaintext highlighter-rouge">~/.tool-versions</code> file:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$></span> <span class="nb">cat</span> ~/.tool-versions
nodejs 14.16.0
</code></pre></div></div>
<p>You can put a similar file in one of your projects if it uses a different
version than the others:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$></span> node <span class="nt">--version</span>
v14.16.0
<span class="nv">$></span> <span class="nb">echo</span> <span class="s2">"nodejs 15.11.0"</span> <span class="o">></span> ~/path/to/project/.tool-versions
<span class="nv">$></span> <span class="nb">cd</span> ~/path/to/project
<span class="nv">$></span> node <span class="nt">--version</span>
v15.11.0
</code></pre></div></div>
<blockquote>
<p>As another example, you can check <a href="https://github.com/AlphaHydrae/blog/blob/main/.tool-versions">the <code class="language-plaintext highlighter-rouge">.tool-versions</code> file in this blog’s
repository</a>.</p>
</blockquote>
<p>You can also use an environment variable to set the current version. The name of
the variable depends on which plugin you’re using. For example, the variable for
the Node.js plugin is <code class="language-plaintext highlighter-rouge">ASDF_NODEJS_VERSION</code>:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$></span> node <span class="nt">--version</span>
v14.16.0
<span class="nv">$></span> <span class="nv">ASDF_NODEJS_VERSION</span><span class="o">=</span>15.11.0 node <span class="nt">--version</span>
v15.11.0
</code></pre></div></div>
<h2 id="what-sorcery-is-this">What sorcery is this?</h2>
<p>Check your <a href="https://en.wikipedia.org/wiki/PATH_(variable)">PATH</a> and notice that the <code class="language-plaintext highlighter-rouge">~/.asdf/shims</code> directory has been
prepended to it:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$></span> <span class="nb">echo</span> <span class="nv">$PATH</span>
/Users/alice/.asdf/shims:...
</code></pre></div></div>
<p>When you install a Node.js version with asdf, it will put a <code class="language-plaintext highlighter-rouge">node</code> executable
for Node.js in <a href="https://asdf-vm.com/#/core-manage-versions?id=shims">the shims directory</a>. This executable isn’t actually
Node.js. You can see this by displaying its contents:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$></span> <span class="nb">cat</span> ~/.asdf/shims/node
<span class="nb">exec</span> /usr/local/bin/asdf <span class="nb">exec</span> <span class="s2">"node"</span> <span class="s2">"</span><span class="nv">$@</span><span class="s2">"</span>
</code></pre></div></div>
<p>The shim is here to “intercept” the execution of Node.js (since the shims
directory should be the first thing in your PATH), and to instead call asdf with
the language used and any additional arguments.</p>
<p>asdf will select the correct version of Node.js to run depending on your various
<code class="language-plaintext highlighter-rouge">.tool-versions</code> file and the <code class="language-plaintext highlighter-rouge">ASDF_NODEJS_VERSION</code> environment variable, and
call the corresponding Node.js executable somewhere in the <code class="language-plaintext highlighter-rouge">~/.asdf/installs</code>
directory (for example, the executable for version 14.16.0 of Node.js is at
<code class="language-plaintext highlighter-rouge">~/.asdf/installs/nodejs/14.16.0/bin/node</code>).</p>
<blockquote>
<p>Other related commands such as <code class="language-plaintext highlighter-rouge">npm</code> and any global Node.js package you might
install will also have corresponding scripts in the shims directory.</p>
</blockquote>
<p>Shims is how many programming language version managers work. The previously
mentionned rbenv and nodenv <a href="https://github.com/rbenv/rbenv#understanding-shims">work the same way</a>.</p>
<p>This simple PATH-based mechanism makes it easy to programmaticaly use
asdf-managed versions of languages from a script. Simply put the shims directory
in the PATH and set the correct environment variable to the desired version.
Here’s an example from an <a href="https://www.ansible.com">Ansible</a> playbook:</p>
<div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="pi">>-</span>
<span class="s">Execute a script with an asdf-managed</span>
<span class="s">version of Node.js</span>
<span class="c1"># Switch to a user who has asdf installed.</span>
<span class="na">become</span><span class="pi">:</span> <span class="no">true</span>
<span class="na">become_user</span><span class="pi">:</span> <span class="s">alice</span>
<span class="c1"># Run the script.</span>
<span class="na">command</span><span class="pi">:</span> <span class="s2">"</span><span class="s">node</span><span class="nv"> </span><span class="s">/path/to/script.js"</span>
<span class="na">environment</span><span class="pi">:</span>
<span class="c1"># Use a specific version of Node.js.</span>
<span class="na">ANSIBLE_NODEJS_VERSION</span><span class="pi">:</span> <span class="s">14.16.0</span>
<span class="c1"># Put the shims directory in the PATH.</span>
<span class="na">PATH</span><span class="pi">:</span> <span class="s2">"</span><span class="s">/home/alice/.asdf/shims:{{</span><span class="nv"> </span><span class="s">ansible_env.PATH</span><span class="nv"> </span><span class="s">}}"</span>
</code></pre></div></div>
<p>Go forth and install all the versions.</p>asdf is an extendable version manager with support for Ruby, Node.js, Elixir, Erlang, Python, Rust, and more.A JavaScript function that recursively resolves promises2021-02-25T21:34:43+01:002021-02-25T21:34:43+01:00https://alphahydrae.com/2021/02/a-javascript-function-that-recursively-resolves-promises<p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function">Async/await</a> is awesome because it enables asynchronous,
promise-based behavior to be written in a cleaner, more imperative-looking
style:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">async</span> <span class="kd">function</span> <span class="nx">computeAsyncStuff</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">foo</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">computeFoo</span><span class="p">();</span>
<span class="kd">const</span> <span class="nx">bar</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">computeBar</span><span class="p">();</span>
<span class="k">return</span> <span class="nx">foo</span> <span class="o">+</span> <span class="nx">bar</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Want to run things in parallel? Piece of cake, with a nice <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment">destructuring
assignment</a> as a bonus:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">async</span> <span class="kd">function</span> <span class="nx">computeAsyncStuffInParallel</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">[</span> <span class="nx">foo</span><span class="p">,</span> <span class="nx">bar</span> <span class="p">]</span> <span class="o">=</span> <span class="k">await</span> <span class="nb">Promise</span><span class="p">.</span><span class="nx">all</span><span class="p">([</span>
<span class="nx">computeFoo</span><span class="p">(),</span>
<span class="nx">computeBar</span><span class="p">()</span>
<span class="p">]);</span>
<span class="k">return</span> <span class="nx">foo</span> <span class="o">+</span> <span class="nx">bar</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>But… <em>oh no</em>, it doesn’t work with objects:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">async</span> <span class="kd">function</span> <span class="nx">computeAsyncObject</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">foo</span><span class="p">,</span> <span class="nx">bar</span> <span class="p">}</span> <span class="o">=</span> <span class="k">await</span> <span class="p">{</span>
<span class="na">foo</span><span class="p">:</span> <span class="nx">computeFoo</span><span class="p">(),</span>
<span class="na">bar</span><span class="p">:</span> <span class="nx">computeBar</span><span class="p">()</span>
<span class="p">};</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">foo</span><span class="p">);</span> <span class="c1">// Promise { ... }</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">bar</span><span class="p">);</span> <span class="c1">// Promise { ... }</span>
<span class="k">return</span> <span class="nx">foo</span> <span class="o">+</span> <span class="nx">bar</span><span class="p">;</span> <span class="c1">// '[object Promise][object Promise]'</span>
<span class="p">}</span>
</code></pre></div></div>
<!-- more -->
<p>So I wrote a small function to resolve nested structures of plain arrays and
objects:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">async</span> <span class="kd">function</span> <span class="nx">resolve</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Await the value in case it's a promise.</span>
<span class="kd">const</span> <span class="nx">resolved</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">value</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">isPlainObject</span><span class="p">(</span><span class="nx">resolved</span><span class="p">))</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">entries</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">entries</span><span class="p">(</span><span class="nx">resolved</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">resolvedEntries</span> <span class="o">=</span> <span class="nx">entries</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span>
<span class="c1">// Recursively resolve object values.</span>
<span class="k">async</span> <span class="p">([</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">value</span> <span class="p">])</span> <span class="o">=></span> <span class="p">[</span> <span class="nx">key</span><span class="p">,</span> <span class="k">await</span> <span class="nx">resolve</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="p">]</span>
<span class="p">);</span>
<span class="k">return</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">fromEntries</span><span class="p">(</span>
<span class="k">await</span> <span class="nb">Promise</span><span class="p">.</span><span class="nx">all</span><span class="p">(</span><span class="nx">resolvedEntries</span><span class="p">)</span>
<span class="p">);</span>
<span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nb">Array</span><span class="p">.</span><span class="nx">isArray</span><span class="p">(</span><span class="nx">resolved</span><span class="p">))</span> <span class="p">{</span>
<span class="c1">// Recursively resolve array values.</span>
<span class="k">return</span> <span class="nb">Promise</span><span class="p">.</span><span class="nx">all</span><span class="p">(</span><span class="nx">resolved</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">resolve</span><span class="p">));</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">resolved</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nx">isPlainObject</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">typeof</span> <span class="nx">value</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">object</span><span class="dl">'</span> <span class="o">&&</span>
<span class="nx">value</span> <span class="o">!==</span> <span class="kc">null</span> <span class="o">&&</span>
<span class="nx">value</span><span class="p">.</span><span class="kd">constructor</span> <span class="o">===</span> <span class="nb">Object</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Now you can do this:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">async</span> <span class="kd">function</span> <span class="nx">computeAsyncObject</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">foo</span><span class="p">,</span> <span class="nx">bar</span> <span class="p">}</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">resolve</span><span class="p">({</span>
<span class="na">foo</span><span class="p">:</span> <span class="nx">computeFoo</span><span class="p">(),</span>
<span class="na">bar</span><span class="p">:</span> <span class="nx">computeBar</span><span class="p">()</span>
<span class="p">});</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">foo</span><span class="p">);</span> <span class="c1">// 14</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">bar</span><span class="p">);</span> <span class="c1">// 28</span>
<span class="k">return</span> <span class="nx">foo</span> <span class="o">+</span> <span class="nx">bar</span><span class="p">;</span> <span class="c1">// 42</span>
<span class="p">}</span>
</code></pre></div></div>
<p>You can even do this with arbitrarily nested structures as long as they’re only
arrays and plain objects:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">async</span> <span class="kd">function</span> <span class="nx">computeAsyncStructure</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">foo</span><span class="p">,</span> <span class="na">bar</span><span class="p">:</span> <span class="p">[</span> <span class="nx">baz</span><span class="p">,</span> <span class="nx">qux</span> <span class="p">]</span> <span class="p">}</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">resolve</span><span class="p">({</span>
<span class="na">foo</span><span class="p">:</span> <span class="nx">computeFoo</span><span class="p">(),</span>
<span class="na">bar</span><span class="p">:</span> <span class="nb">Promise</span><span class="p">.</span><span class="nx">resolve</span><span class="p">([</span>
<span class="nx">computeBaz</span><span class="p">(),</span>
<span class="nx">computeQux</span><span class="p">()</span>
<span class="p">])</span>
<span class="p">});</span>
<span class="k">return</span> <span class="nx">foo</span> <span class="o">+</span> <span class="nx">baz</span> <span class="o">+</span> <span class="nx">qux</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>If you like <a href="https://lodash.com">Lodash</a>, here’s another version taking advantage of its
utility functions:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="p">{</span>
<span class="nx">isArray</span><span class="p">,</span>
<span class="nx">isPlainObject</span><span class="p">,</span>
<span class="nx">zipObject</span>
<span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">lodash</span><span class="dl">'</span><span class="p">);</span>
<span class="k">async</span> <span class="kd">function</span> <span class="nx">resolve</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Await the value in case it's a promise.</span>
<span class="kd">const</span> <span class="nx">resolved</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">value</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">isPlainObject</span><span class="p">(</span><span class="nx">resolved</span><span class="p">))</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">keys</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">keys</span><span class="p">(</span><span class="nx">resolved</span><span class="p">);</span>
<span class="c1">// Recursively resolve object values.</span>
<span class="kd">const</span> <span class="nx">resolvedValues</span> <span class="o">=</span> <span class="k">await</span> <span class="nb">Promise</span><span class="p">.</span><span class="nx">all</span><span class="p">(</span>
<span class="nb">Object</span><span class="p">.</span><span class="nx">values</span><span class="p">(</span><span class="nx">resolved</span><span class="p">).</span><span class="nx">map</span><span class="p">(</span><span class="nx">resolve</span><span class="p">)</span>
<span class="p">);</span>
<span class="k">return</span> <span class="nx">zipObject</span><span class="p">(</span><span class="nx">keys</span><span class="p">,</span> <span class="nx">resolvedValues</span><span class="p">);</span>
<span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">isArray</span><span class="p">(</span><span class="nx">resolved</span><span class="p">))</span> <span class="p">{</span>
<span class="c1">// Recursively resolve array values.</span>
<span class="k">return</span> <span class="nb">Promise</span><span class="p">.</span><span class="nx">all</span><span class="p">(</span><span class="nx">resolved</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">resolve</span><span class="p">));</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">resolved</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The world awaits.</p>Async/await is awesome because it enables asynchronous, promise-based behavior to be written in a cleaner, more imperative-looking style:How to check which Git branches contain a commit2021-02-14T15:42:39+01:002021-02-14T15:42:39+01:00https://alphahydrae.com/2021/02/how-to-check-which-git-branches-contain-a-commit<p>The <a href="https://git-scm.com/docs/git-branch#Documentation/git-branch.txt---containsltcommitgt"><code class="language-plaintext highlighter-rouge">--contains</code> option of the <code class="language-plaintext highlighter-rouge">git branch</code> command</a> will
list branches which contain the specified commit, in the same format as when
running <code class="language-plaintext highlighter-rouge">git branch</code> or <code class="language-plaintext highlighter-rouge">git branch --list</code>:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$></span> git branch <span class="nt">--contains</span> aa82193
<span class="k">*</span> some-branch
master
</code></pre></div></div>
<p>This output indicates that both the <code class="language-plaintext highlighter-rouge">some-branch</code> branch and the <code class="language-plaintext highlighter-rouge">master</code> branch
contain commit <code class="language-plaintext highlighter-rouge">aa82193</code> (and that <code class="language-plaintext highlighter-rouge">some-branch</code> is the current branch).</p>
<blockquote>
<p>There is an inverse option, <a href="https://git-scm.com/docs/git-branch#Documentation/git-branch.txt---no-containsltcommitgt">the <code class="language-plaintext highlighter-rouge">--no-contains</code>
option</a>, which will only list branches that don’t
contain the specified commit.</p>
</blockquote>The --contains option of the git branch command will list branches which contain the specified commit, in the same format as when running git branch or git branch --list:How to display an image protected by header-based authentication2021-02-12T20:02:36+01:002021-02-12T20:02:36+01:00https://alphahydrae.com/2021/02/how-to-display-an-image-protected-by-header-based-authentication<p>I recently had to work with an API that serves images protected by header-based
authentication. You have to send a <a href="https://tools.ietf.org/html/rfc6750">bearer token</a> in the
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization"><code class="language-plaintext highlighter-rouge">Authorization</code> header</a> for all requests, including
images. How do you display such an image in a web page?</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><img</span> <span class="na">src=</span><span class="s">'https://api.example.com/secret-image.png'</span> <span class="nt">/></span>
</code></pre></div></div>
<p>This won’t work because an <code class="language-plaintext highlighter-rouge"><img></code> tag cannot send a custom header. You’ll
probably get some flavor of <a href="https://httpstatuses.com/401"><code class="language-plaintext highlighter-rouge">401 Unauthorized</code></a> error. It would be
trivial to make it work if authentication was based on an URL query parameter or
a cookie, but it’s not as easy with a header.</p>
<!-- more -->
<h2 id="fetch-the-image">Fetch the image</h2>
<p>You’ll have to make the HTTP call to get the image yourself so you can send that
header. For example, you could do this using the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch API</a>:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">fetchWithAuthentication</span><span class="p">(</span><span class="nx">url</span><span class="p">,</span> <span class="nx">authToken</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">headers</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Headers</span><span class="p">();</span>
<span class="nx">headers</span><span class="p">.</span><span class="kd">set</span><span class="p">(</span><span class="dl">'</span><span class="s1">Authorization</span><span class="dl">'</span><span class="p">,</span> <span class="s2">`Bearer </span><span class="p">${</span><span class="nx">authToken</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
<span class="k">return</span> <span class="nx">fetch</span><span class="p">(</span><span class="nx">url</span><span class="p">,</span> <span class="p">{</span> <span class="nx">headers</span> <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The fetch response contains binary data, for example PNG data. You need to
insert this data into the DOM somehow.</p>
<h2 id="embed-the-image-with-a-base64-data-url">Embed the image with a Base64 data URL</h2>
<p>My first attempt was to <a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Using_images#embedding_an_image_via_data_url">embed the image</a> using a <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs">data
URL</a>. I used <a href="https://stackoverflow.com/a/11562550">this function I found on Stack
Overflow</a> to perform the binary-to-<a href="https://en.wikipedia.org/wiki/Base64">Base64</a>
conversion:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">arrayBufferToBase64</span><span class="p">(</span><span class="nx">buffer</span><span class="p">:</span> <span class="nb">ArrayBuffer</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">btoa</span><span class="p">(</span><span class="nb">String</span><span class="p">.</span><span class="nx">fromCharCode</span><span class="p">(...</span><span class="k">new</span> <span class="nb">Uint8Array</span><span class="p">(</span><span class="nx">buffer</span><span class="p">)));</span>
<span class="p">}</span>
</code></pre></div></div>
<p>You can use <a href="https://developer.mozilla.org/en-US/docs/Web/API/Body/arrayBuffer">the <code class="language-plaintext highlighter-rouge">arrayBuffer</code> method</a> of the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Response">fetch
<code class="language-plaintext highlighter-rouge">Response</code></a> to get the array buffer to pass to the Base64
conversion function, then build a properly formatted data URL and use it as the
source of the image:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">async</span> <span class="kd">function</span> <span class="nx">displayProtectedImage</span><span class="p">(</span>
<span class="nx">imageId</span><span class="p">,</span> <span class="nx">imageUrl</span><span class="p">,</span> <span class="nx">authToken</span>
<span class="p">)</span> <span class="p">{</span>
<span class="c1">// Fetch the image.</span>
<span class="kd">const</span> <span class="nx">response</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">fetchWithAuthentication</span><span class="p">(</span>
<span class="nx">imageUrl</span><span class="p">,</span> <span class="nx">authToken</span>
<span class="p">);</span>
<span class="c1">// Convert the data to Base64 and build a data URL.</span>
<span class="kd">const</span> <span class="nx">binaryData</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">response</span><span class="p">.</span><span class="nx">arrayBuffer</span><span class="p">();</span>
<span class="kd">const</span> <span class="nx">base64</span> <span class="o">=</span> <span class="nx">arrayBufferToBase64</span><span class="p">(</span><span class="nx">binaryData</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">dataUrl</span> <span class="o">=</span> <span class="s2">`data:image/png;base64,</span><span class="p">${</span><span class="nx">base64</span><span class="p">}</span><span class="s2">`</span><span class="p">;</span>
<span class="c1">// Update the source of the image.</span>
<span class="kd">const</span> <span class="nx">imageElement</span> <span class="o">=</span> <span class="nx">getElementById</span><span class="p">(</span><span class="nx">imageId</span><span class="p">);</span>
<span class="nx">imageElement</span><span class="p">.</span><span class="nx">src</span> <span class="o">=</span> <span class="nx">dataUrl</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Here’s how to use it:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">imageId</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">some-image</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">imageUrl</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">https://api.example.com/secret-image.png</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">authToken</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">changeme</span><span class="dl">'</span><span class="p">;</span>
<span class="nx">displayProtectedImage</span><span class="p">(</span><span class="nx">imageId</span><span class="p">,</span> <span class="nx">imageUrl</span><span class="p">,</span> <span class="nx">authToken</span><span class="p">);</span>
</code></pre></div></div>
<p>Yay!</p>
<h3 id="so-slow">So slow…</h3>
<p>It works but I ran into an issue: if you try to display several images like this
at the same time and they are large enough, converting all this binary data to
Base64 will slow down your UI.</p>
<p>This is because JavaScript in the browser runs on a <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop">single-threaded event
loop</a>. Since your JavaScript runs in the same thread as the UI, any
sufficiently heavy calculation will temporary block everything, making your site
feel unresponsive. (I recommend Philip Roberts’ excellent video <a href="https://youtu.be/8aGhZQkoFbQ"><em>What the heck
is an event loop anyway?</em></a> if you want to learn more about
this topic.)</p>
<p>Maybe a <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers">web worker</a> could be a solution to make sure this work is
done in a separate thread, but I did not try going down that path.</p>
<h2 id="use-an-object-url">Use an object URL</h2>
<p>In the end, I used the <a href="https://developer.mozilla.org/en-US/docs/Web/API/URL">URL Web API</a>, specifically <a href="https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL">its
<code class="language-plaintext highlighter-rouge">createObjectURL</code> function</a>. If you have a blob of
binary data, you can pass it to this function to create a <code class="language-plaintext highlighter-rouge">blob:</code> URL that
points to this data in memory:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">URL</span><span class="p">.</span><span class="nx">createObjectURL</span><span class="p">(</span><span class="nx">blob</span><span class="p">);</span>
<span class="c1">// blob:http://example.com/e88f2e72-94c6-4f79-a40d-fc6749ce</span>
</code></pre></div></div>
<p>If your blob contains image data, you can use this new URL as the source of an
<code class="language-plaintext highlighter-rouge"><img></code> tag. The advantage of this technique compared to constructing a data URL
is that you do not have to process the image data at all. This blob URL is
simply a pointer to the existing data in memory, with no extra computation
required. The data is stored in the <a href="https://w3c.github.io/FileAPI/#BlobURLStore">blob URL store</a>, a feature
of the <a href="https://developer.mozilla.org/en-US/docs/Web/API/File">File API</a>.</p>
<p>You can get the data of a fetch <code class="language-plaintext highlighter-rouge">Response</code> as a blob by using <a href="https://developer.mozilla.org/en-US/docs/Web/API/Body/blob">its <code class="language-plaintext highlighter-rouge">blob</code>
function</a>. Let’s rewrite the <code class="language-plaintext highlighter-rouge">displayProtectedImage</code> function to
take advantage of object URLs:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">async</span> <span class="kd">function</span> <span class="nx">displayProtectedImage</span><span class="p">(</span>
<span class="nx">imageId</span><span class="p">,</span> <span class="nx">imageUrl</span><span class="p">,</span> <span class="nx">authToken</span>
<span class="p">)</span> <span class="p">{</span>
<span class="c1">// Fetch the image.</span>
<span class="kd">const</span> <span class="nx">response</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">fetchWithAuthentication</span><span class="p">(</span>
<span class="nx">imageUrl</span><span class="p">,</span> <span class="nx">authToken</span>
<span class="p">);</span>
<span class="c1">// Create an object URL from the data.</span>
<span class="kd">const</span> <span class="nx">blob</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">response</span><span class="p">.</span><span class="nx">blob</span><span class="p">();</span>
<span class="kd">const</span> <span class="nx">objectUrl</span> <span class="o">=</span> <span class="nx">URL</span><span class="p">.</span><span class="nx">createObjectURL</span><span class="p">(</span><span class="nx">blob</span><span class="p">);</span>
<span class="c1">// Update the source of the image.</span>
<span class="kd">const</span> <span class="nx">imageElement</span> <span class="o">=</span> <span class="nx">getElementById</span><span class="p">(</span><span class="nx">imageId</span><span class="p">);</span>
<span class="nx">imageElement</span><span class="p">.</span><span class="nx">src</span> <span class="o">=</span> <span class="nx">objectUrl</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>You can use it the same way as the previous version:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">imageId</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">some-image</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">imageUrl</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">https://api.example.com/secret-image.png</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">authToken</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">changeme</span><span class="dl">'</span><span class="p">;</span>
<span class="nx">displayProtectedImage</span><span class="p">(</span><span class="nx">imageId</span><span class="p">,</span> <span class="nx">imageUrl</span><span class="p">,</span> <span class="nx">authToken</span><span class="p">);</span>
</code></pre></div></div>
<h2 id="collect-the-garbage">Collect the garbage</h2>
<p>The memory referenced by object URLs is released automatically when the document
is unloaded. However, if you’re writing a single page application with no page
refresh or if you generally care about memory consumption and performance, you
should let the browser know when this memory can be released by calling <a href="https://developer.mozilla.org/en-US/docs/Web/API/URL/revokeObjectURL">the
<code class="language-plaintext highlighter-rouge">revokeObjectURL</code> function</a>:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">URL</span><span class="p">.</span><span class="nx">revokeObjectURL</span><span class="p">(</span><span class="nx">someObjectUrl</span><span class="p">);</span>
</code></pre></div></div>
<p>In the case of an image, it’s easy to do it automatically as soon as the image
is done loading by using its <code class="language-plaintext highlighter-rouge">onload</code> callback. Once the image is displayed, the
object URL and the referenced data are no longer needed:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">imageElement</span><span class="p">.</span><span class="nx">src</span> <span class="o">=</span> <span class="nx">objectUrl</span><span class="p">;</span>
<span class="nx">imageElement</span><span class="p">.</span><span class="nx">onload</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="nx">URL</span><span class="p">.</span><span class="nx">revokeObjectUrl</span><span class="p">(</span><span class="nx">objectUrl</span><span class="p">);</span>
</code></pre></div></div>
<p>Here’s an updated <code class="language-plaintext highlighter-rouge">displayProtectedImage</code> function that does this:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">async</span> <span class="kd">function</span> <span class="nx">displayProtectedImage</span><span class="p">(</span>
<span class="nx">imageId</span><span class="p">,</span> <span class="nx">imageUrl</span><span class="p">,</span> <span class="nx">authToken</span>
<span class="p">)</span> <span class="p">{</span>
<span class="c1">// Fetch the image.</span>
<span class="kd">const</span> <span class="nx">response</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">fetchWithAuthentication</span><span class="p">(</span>
<span class="nx">imageUrl</span><span class="p">,</span> <span class="nx">authToken</span>
<span class="p">);</span>
<span class="c1">// Create an object URL from the data.</span>
<span class="kd">const</span> <span class="nx">blob</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">response</span><span class="p">.</span><span class="nx">blob</span><span class="p">();</span>
<span class="kd">const</span> <span class="nx">objectUrl</span> <span class="o">=</span> <span class="nx">URL</span><span class="p">.</span><span class="nx">createObjectURL</span><span class="p">(</span><span class="nx">blob</span><span class="p">);</span>
<span class="c1">// Update the source of the image.</span>
<span class="kd">const</span> <span class="nx">imageElement</span> <span class="o">=</span> <span class="nx">getElementById</span><span class="p">(</span><span class="nx">imageId</span><span class="p">);</span>
<span class="nx">imageElement</span><span class="p">.</span><span class="nx">src</span> <span class="o">=</span> <span class="nx">objectUrl</span><span class="p">;</span>
<span class="nx">imageElement</span><span class="p">.</span><span class="nx">onload</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="nx">URL</span><span class="p">.</span><span class="nx">revokeObjectUrl</span><span class="p">(</span><span class="nx">objectUrl</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>May your UI remain swift.</p>I recently had to work with an API that serves images protected by header-based authentication. You have to send a bearer token in the Authorization header for all requests, including images. How do you display such an image in a web page?How to run PostgreSQL 13 on Travis CI2021-02-11T21:51:47+01:002021-02-11T21:51:47+01:00https://alphahydrae.com/2021/02/how-to-run-postgresql-13-on-travis-ci<p><a href="https://travis-ci.org">Travis CI</a> is a continuous integration platform for open source. I
use it for all my open source projects that have an automated test suite (here’s
<a href="https://travis-ci.org/github/AlphaHydrae/gitload/builds">an example</a>). Read about the <a href="https://docs.travis-ci.com/user/for-beginners">core
concepts</a> and <a href="https://docs.travis-ci.com/user/tutorial/">the tutorial</a> if you
want to know more.</p>
<p>It supports <a href="https://www.postgresql.org">PostgreSQL</a> as a database for your tests.
Unfortunately, according to the documentation at the time of writing, the
default integration is with PostgreSQL 9.2, a version that is no longer under
active development since November 2017. Versions 10 and later are also not as
well supported in that they require additional configuration to avoid <a href="https://travis-ci.community/t/services-for-postgresql-11-and-12-fail-to-start-assertion-failed-on-job-for-postgresql-11-main-service/7069">this
error</a>:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>travis_setup_postgresql 13
Starting PostgreSQL v13
Assertion failed on job <span class="k">for </span>postgresql@13-main.service.
<span class="nb">sudo </span>systemctl start postgresql@13-main
</code></pre></div></div>
<p>Let’s see about fixing that.</p>
<!-- more -->
<p>The default PostgreSQL integration is enabled by adding the <code class="language-plaintext highlighter-rouge">postgresql</code> service
to your <code class="language-plaintext highlighter-rouge">.travis-ci.yml</code> file:</p>
<div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">services</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s">postgresql</span>
</code></pre></div></div>
<p>The documentation indicates what to do if you want to <a href="https://docs.travis-ci.com/user/database-setup/#using-a-different-postgresql-version">use a different
version</a>:</p>
<ul>
<li>Specify the version of the PostgreSQL addon.</li>
<li>Install the appropriate APT package.</li>
<li>Set the <code class="language-plaintext highlighter-rouge">PGPORT</code> environment variable to use a different port.</li>
</ul>
<p>Here’s the configuration fragment for PostgreSQL 13:</p>
<div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">addons</span><span class="pi">:</span>
<span class="na">postgresql</span><span class="pi">:</span> <span class="m">13</span>
<span class="na">apt</span><span class="pi">:</span>
<span class="na">packages</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s">postgresql-13</span>
<span class="na">env</span><span class="pi">:</span>
<span class="na">global</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s">PGPORT=5433</span>
</code></pre></div></div>
<p>The documentation states that you can use the <code class="language-plaintext highlighter-rouge">postgres</code> user with a blank
password to access the PostgreSQL database. However when you’re not using the
default PostgreSQL version, that’s a lie (like the cake). You might get the
following error:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>psql: error: FATAL:
Peer authentication failed for user "postgres"
</code></pre></div></div>
<p><a href="https://github.com/travis-ci/travis-ci/issues/9624">You have to update the configuration
yourself</a>. For example, you can
modify <a href="https://www.postgresql.org/docs/13/auth-pg-hba-conf.html">the <code class="language-plaintext highlighter-rouge">pg_hba.conf</code> file</a> to use the <code class="language-plaintext highlighter-rouge">trust</code>
authentication method for local connections. That way you won’t have to supply a
password at all:</p>
<div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">before_install</span><span class="pi">:</span>
<span class="c1"># Use trust instead of peer authentication:</span>
<span class="pi">-</span> <span class="pi">>-</span>
<span class="s">sudo sed -i</span>
<span class="s">-e '/local.*peer/s/postgres/all/'</span>
<span class="s">-e 's/peer\|md5/trust/g'</span>
<span class="s">/etc/postgresql/13/main/pg_hba.conf</span>
<span class="c1"># Restart the PostgreSQL service:</span>
<span class="pi">-</span> <span class="s">sudo service postgresql@13-main restart</span>
</code></pre></div></div>
<p>Finally, you can create your test database like you would with the default
PostgreSQL integration. You just have to specify the same custom port as the
<code class="language-plaintext highlighter-rouge">PGPORT</code> environment variable:</p>
<div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">before_script</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s">sudo psql -p 5433 -U postgres -c 'create database my-app;'</span>
</code></pre></div></div>
<p>Here’s a full sample configuration for a hypothetical Node.js application:</p>
<div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">language</span><span class="pi">:</span> <span class="s">node_js</span>
<span class="na">node_js</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s1">'</span><span class="s">10'</span>
<span class="pi">-</span> <span class="s1">'</span><span class="s">12'</span>
<span class="pi">-</span> <span class="s1">'</span><span class="s">14'</span>
<span class="na">addons</span><span class="pi">:</span>
<span class="c1"># Use a different PostgreSQL version than the default:</span>
<span class="na">postgresql</span><span class="pi">:</span> <span class="m">13</span>
<span class="na">apt</span><span class="pi">:</span>
<span class="na">update</span><span class="pi">:</span> <span class="no">true</span>
<span class="na">packages</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s">postgresql-13</span>
<span class="pi">-</span> <span class="s">postgresql-13-postgis-3</span>
<span class="na">services</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s">postgresql</span>
<span class="na">env</span><span class="pi">:</span>
<span class="na">global</span><span class="pi">:</span>
<span class="c1"># A different port must be used when not using the</span>
<span class="c1"># default PostgreSQL:</span>
<span class="pi">-</span> <span class="s">PGPORT=5433</span>
<span class="na">jobs</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s">NODE_ENV=test DB_PORT=5433 DB_USERNAME=postgres</span>
<span class="na">before_install</span><span class="pi">:</span>
<span class="c1"># Use trust instead of peer authentication:</span>
<span class="pi">-</span> <span class="pi">>-</span>
<span class="s">sudo sed -i</span>
<span class="s">-e '/local.*peer/s/postgres/all/'</span>
<span class="s">-e 's/peer\|md5/trust/g'</span>
<span class="s">/etc/postgresql/13/main/pg_hba.conf</span>
<span class="c1"># Restart the PostgreSQL service:</span>
<span class="pi">-</span> <span class="s">sudo service postgresql@13-main restart</span>
<span class="na">before_script</span><span class="pi">:</span>
<span class="c1"># Create the test database:</span>
<span class="pi">-</span> <span class="s">sudo psql -p 5433 -U postgres -c 'create database my-app;'</span>
</code></pre></div></div>Travis CI is a continuous integration platform for open source. I use it for all my open source projects that have an automated test suite (here’s an example). Read about the core concepts and the tutorial if you want to know more.How to export PostgreSQL data to a JSON file2021-02-10T20:00:15+01:002021-02-10T20:00:15+01:00https://alphahydrae.com/2021/02/how-to-export-postgresql-data-to-a-json-file<p>You know this data sitting in a PostgreSQL database that you have always wanted
to export to a JSON file?</p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="o">*</span>
<span class="k">FROM</span> <span class="n">people</span>
<span class="k">WHERE</span> <span class="n">meaning_of_life</span> <span class="o">=</span> <span class="mi">42</span><span class="p">;</span>
<span class="c1">-- id | name | meaning_of_life</span>
<span class="c1">-- ----+-------+-----------------</span>
<span class="c1">-- 1 | Alice | 42</span>
<span class="c1">-- 2 | Bob | 42</span>
<span class="c1">-- (2 rows)</span>
</code></pre></div></div>
<!-- more -->
<p>Because PostgreSQL is awesome, it <a href="https://www.postgresql.org/docs/13/datatype-json.html">supports JSON</a> and has <a href="https://www.postgresql.org/docs/13/functions-json.html">a
lot of cool functions to work with JSON</a>. Let’s start
by converting those rows to JSON objects using the <code class="language-plaintext highlighter-rouge">row_to_json</code> function:</p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="n">row_to_json</span><span class="p">(</span><span class="n">people</span><span class="p">)</span>
<span class="k">FROM</span> <span class="n">people</span>
<span class="k">WHERE</span> <span class="n">meaning_of_life</span> <span class="o">=</span> <span class="mi">42</span><span class="p">;</span>
<span class="c1">-- row_to_json</span>
<span class="c1">-- ----------------------------------------------</span>
<span class="c1">-- {"id":1,"name":"Alice","meaning_of_life":42}</span>
<span class="c1">-- {"id":2,"name":"Bob","meaning_of_life":42}</span>
<span class="c1">-- (2 rows)</span>
</code></pre></div></div>
<p>You can now aggregate these rows into a JSON array with the <code class="language-plaintext highlighter-rouge">json_agg</code>
<a href="https://www.postgresql.org/docs/13/functions-aggregate.html">aggregation-function</a>:</p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="n">json_agg</span><span class="p">(</span><span class="n">row_to_json</span><span class="p">(</span><span class="n">people</span><span class="p">))</span>
<span class="k">FROM</span> <span class="n">people</span>
<span class="k">WHERE</span> <span class="n">meaning_of_life</span> <span class="o">=</span> <span class="mi">42</span><span class="p">;</span>
<span class="c1">-- Note: the result is represented on two lines here</span>
<span class="c1">-- for readability, but it's really one long line of</span>
<span class="c1">-- JSON in a single row:</span>
<span class="c1">-- json_agg</span>
<span class="c1">-- ------------------------------------------------</span>
<span class="c1">-- [{"id":1,"name":"Alice","meaning_of_life":42},</span>
<span class="c1">-- {"id":2,"name":"Bob","meaning_of_life":42}]</span>
<span class="c1">-- (1 row)</span>
</code></pre></div></div>
<p>Finally, convert this data to text and dump it to a file using <a href="https://www.postgresql.org/docs/13/sql-copy.html">the <code class="language-plaintext highlighter-rouge">COPY</code>
command</a>:</p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">COPY</span> <span class="p">(</span>
<span class="k">SELECT</span> <span class="n">json_agg</span><span class="p">(</span><span class="n">row_to_json</span><span class="p">(</span><span class="n">people</span><span class="p">))</span> <span class="p">::</span> <span class="nb">text</span>
<span class="k">FROM</span> <span class="n">people</span>
<span class="k">WHERE</span> <span class="n">meaning_of_life</span> <span class="o">=</span> <span class="mi">42</span><span class="p">;</span>
<span class="p">)</span> <span class="k">to</span> <span class="s1">'/path/to/some/file.json'</span><span class="p">;</span>
</code></pre></div></div>
<p>And your JSON file is ready:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Note: again, the contents of the file are represented</span>
<span class="c"># on two lines here, but there's only one line in it.</span>
<span class="nv">$></span> <span class="nb">cat</span> /path/to/some/file.json
<span class="o">[{</span><span class="s2">"id"</span>:1,<span class="s2">"name"</span>:<span class="s2">"Alice"</span>,<span class="s2">"meaning_of_life"</span>:42<span class="o">}</span>,
<span class="o">{</span><span class="s2">"id"</span>:2,<span class="s2">"name"</span>:<span class="s2">"Bob"</span>,<span class="s2">"meaning_of_life"</span>:42<span class="o">}]</span>
</code></pre></div></div>
<p>Easy as pie.</p>
<blockquote>
<p>Note that you can convert multiple rows into a JSON array with just
<code class="language-plaintext highlighter-rouge">json_agg</code>, without using <code class="language-plaintext highlighter-rouge">row_to_json</code>, but for some reason converting that
array to text will introduce line breaks into the resulting text, and the
<code class="language-plaintext highlighter-rouge">COPY</code> command will serialize those line breaks into literal <code class="language-plaintext highlighter-rouge">\n</code> characters
instead of actual line breaks.</p>
<p>To my knowledge there isn’t a configurable JSON stringification mechanism in
PostgreSQL. It would be nice to have a function equivalent to
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify"><code class="language-plaintext highlighter-rouge">JSON.stringify</code></a> that allows you to specify what kind
of whitespace you want.</p>
</blockquote>You know this data sitting in a PostgreSQL database that you have always wanted to export to a JSON file?How to create a temporary directory in a shell script2021-02-06T14:11:43+01:002021-02-06T14:11:43+01:00https://alphahydrae.com/2021/02/how-to-create-a-temporary-directory-in-a-shell-script<p>Sometimes when you write a shell script, you need to temporarily save files
somewhere, temporarily clone a Git repo, etc. This temporary data should be
deleted once the script has completed.</p>
<!-- more -->
<h2 id="create-a-temporary-directory">Create a temporary directory</h2>
<p>You can use <a href="https://linux.die.net/man/1/mktemp">the <code class="language-plaintext highlighter-rouge">mktemp</code> command</a> to create a temporary file or
directory in the appropriate location depending on the operating system:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$></span> <span class="nb">mktemp</span> <span class="nt">-d</span> <span class="nt">-t</span> my-script
/var/folders/a0/8alqx_yap8dl30000ap/T/my-script.J3Fv0NWl
</code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">-d</code> option creates a directory instead of a file (the default).</p>
<p>The <code class="language-plaintext highlighter-rouge">-t <prefix></code> option specifies a prefix so that your temporary directory is
named after your script and with a random suffix. It will be created in your
operating system’s standard location for temporary files (defined by <a href="https://en.wikipedia.org/wiki/TMPDIR">the
<code class="language-plaintext highlighter-rouge">$TMPDIR</code> environment variable</a>).</p>
<p>The directory is created with mode <code class="language-plaintext highlighter-rouge">0700</code> by default, meaning it should only be
accessible by you:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$></span> <span class="nb">ls</span> <span class="nt">-la</span> <span class="s2">"</span><span class="nv">$tmp_dir</span><span class="s2">"</span>
total 0
drwx------ 2 you your-group 64 Feb 6 17:19 <span class="nb">.</span>
drwx------@ 98 you your-group 3136 Feb 6 17:19 ..
</code></pre></div></div>
<p>You can store this temporary directory in a variable:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">tmp_dir</span><span class="o">=</span><span class="si">$(</span> <span class="nb">mktemp</span> <span class="nt">-d</span> <span class="nt">-t</span> my-script <span class="si">)</span>
</code></pre></div></div>
<h2 id="define-a-cleanup-function">Define a cleanup function</h2>
<p>This function will clean up the temporary directory, making sure it exists first
(in case the <code class="language-plaintext highlighter-rouge">mktemp</code> command failed):</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>clean_up<span class="o">()</span> <span class="o">{</span>
<span class="nb">test</span> <span class="nt">-d</span> <span class="s2">"</span><span class="nv">$tmp_dir</span><span class="s2">"</span> <span class="o">&&</span> <span class="nb">rm</span> <span class="nt">-fr</span> <span class="s2">"</span><span class="nv">$tmp_dir</span><span class="s2">"</span>
<span class="o">}</span>
</code></pre></div></div>
<h2 id="automatically-clean-up-on-exit">Automatically clean up on exit</h2>
<p>You don’t want to call this cleanup function manually. Your script could fail
before it is completed. It could receive a signal and exit.</p>
<p>However, you can use <a href="https://man7.org/linux/man-pages/man1/trap.1p.html">Bash’s built-in <code class="language-plaintext highlighter-rouge">trap</code> command</a> to catch the <code class="language-plaintext highlighter-rouge">EXIT</code>
pseudo-signal. Your script will receive this signal when it closes, whether
successfully, unsuccessfully or due to an interrupt (e.g. the user hitting
<code class="language-plaintext highlighter-rouge">Ctrl-C</code>).</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">trap</span> <span class="s2">"clean_up </span><span class="nv">$tmp_dir</span><span class="s2">"</span> EXIT
</code></pre></div></div>
<h2 id="do-the-magic">Do the magic</h2>
<p>You can now write the rest of your script and put whatever you want in the
temporary directory, safe in the knowledge that it will be automatically cleaned
up at the end.</p>
<p>Here’s the complete version:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/usr/bin/env bash</span>
clean_up<span class="o">()</span> <span class="o">{</span>
<span class="nb">test</span> <span class="nt">-d</span> <span class="s2">"</span><span class="nv">$tmp_dir</span><span class="s2">"</span> <span class="o">&&</span> <span class="nb">rm</span> <span class="nt">-fr</span> <span class="s2">"</span><span class="nv">$tmp_dir</span><span class="s2">"</span>
<span class="o">}</span>
<span class="nv">tmp_dir</span><span class="o">=</span><span class="si">$(</span> <span class="nb">mktemp</span> <span class="nt">-d</span> <span class="nt">-t</span> my-script <span class="si">)</span>
<span class="nb">trap</span> <span class="s2">"clean_up </span><span class="nv">$tmp_dir</span><span class="s2">"</span> EXIT
<span class="nb">echo </span>Do the magic...
</code></pre></div></div>Sometimes when you write a shell script, you need to temporarily save files somewhere, temporarily clone a Git repo, etc. This temporary data should be deleted once the script has completed.