<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>y|sndr blog - Alot of stuff about alot of stuff</title>
    <link href="https://blog.ysndr.de/atom.xml" rel="self" />
    <link href="https://blog.ysndr.de" />
    <id>https://blog.ysndr.de/atom.xml</id>
    <author>
        <name>Yannik Sander</name>
        <email>contact@ysndr.de</email>
    </author>
    <updated>2021-12-12T00:00:00Z</updated>
    <entry>
    <title>Rust as a platform for IoT</title>
    <link href="https://blog.ysndr.de/posts/essays/2021-12-12-rust-for-iot/index.html" />
    <id>https://blog.ysndr.de/posts/essays/2021-12-12-rust-for-iot/index.html</id>
    <published>2021-12-12T00:00:00Z</published>
    <updated>2021-12-12T00:00:00Z</updated>
    <summary type="html"><![CDATA[<div class="uk-alert-primary note box y-fill-horizontal" data-header="Background">
<div class="header">
<div>
<span class="las la-pencil-alt"></span>
<div class="badge">
<p>NOTE</p>
</div>
</div>
<div>
<p>
Background
</p>
</div>
</div>
<p>
This essay was written as part of the ID2012 Ubiquitous Computing Course at KTH Royal Institute of Technology Stockholm.
</p>
<p>
The task was to produce an analytic overview of a topic in the domain of Ubiquitous Computing or IoT. I chose Rust’s application for IoT out of my personal interest in Rust and previous experiences diving into IoT and specifically embedded devices using Rust.
</p>
<p>
The essay was finished and handed in by <strong>May 2021</strong> and reviewing the field today already shows some minor changes. Therefore be warned, the field is evolving quickly and might look better depending on when you will read this.
</p>
<p>
If you want to support my work or reach out feel free under the emails below:
</p>
<p>
<strong>Yannik Sander</strong> (yannik@kth.se / contact@ysndr.de)
</p>
<p>
<em>If you want to use this article, please consult me first. A PDF version is available <a href="../rust-for-iot/Sander_Rust-for-IoT.pdf">here</a></em>
</p>
</div>
<h1 class="y-header" id="introduction">
<span>Introduction</span><a href="#introduction" class="anchor las la-anchor" title="introduction"></a>
</h1>
<p>
The IoT and Ubiquitous Computing already makes for a large share of software being written today. To prove secure writing such software should be ergonomic while staying performant and efficient, the potential for human error should be minimized.
</p>
<p>
Rust is a young programming language with a lot of promises, including being a viable platform for IoT of Ubiquitous computing. This essay will introduce Ubiquitous Computing and IoT, then, draw a picture of the current Rust ecosystem relevant for these fields and finally analyze how well this ecosystem can provide for the demands of the field.
</p>
<h2 class="y-header" id="ubiquitous-computing-and-iot">
<span>Ubiquitous Computing and IoT</span><a href="#ubiquitous-computing-and-iot" class="anchor las la-anchor" title="ubiquitous-computing-and-iot"></a>
</h2>
<h3 class="y-header" id="introduction-to-the-character-of-ubiquitous-computing">
<span>Introduction to the character of ubiquitous computing</span><a href="#introduction-to-the-character-of-ubiquitous-computing" class="anchor las la-anchor" title="introduction-to-the-character-of-ubiquitous-computing"></a>
</h3>
<p>
The notion of Ubiquitous Computing, often and in the following simply referred to as <strong>Ubicomp</strong>, has been established by Mark Weiser in his 1991 paper envisioning “The Computer for the 21st Century”<span class="citation" data-cites="weiser_computer_nodate"><span class="citation" data-cites="weiser_computer_nodate">[1]</span></span>. In a time where computing was visible, immobile and rear compared to today’s standards, Weiser spoke of a “disappearance” of technology. Surely, he did not speak about a decrease in computing, but the opposite. The disappearance was about the obvious presence of said technology. Weiser predicted a world where computing is omnipresent – <em>ubiquitous</em> – “weaved into everyday life.” On the one hand, it was about the mobility of computers, i.e. being able to take computing everywhere. Yet, this doesn’t cover it completely! Indeed, it was the unintrusive enhancement of people’s life that defined Ubicomp.
</p>
<p>
In the modern day, Ubicomp has become an important part of human-computer interaction (HCI) implementation and research. Especially being aware of the user’s context and acting upon that is an important aspect of Ubicomp relevant to HCI and carrying numerous opportunities for future advancements in computing <span class="citation" data-cites="dey_distributed_2002"><span class="citation" data-cites="dey_distributed_2002">[2]</span></span>. There have been great developments in technology since Weiser formulated the concept of Ubicomp that enable many of his ideas. Poppe et.al. <span class="citation" data-cites="poppe_evaluating_2007"><span class="citation" data-cites="poppe_evaluating_2007">[3]</span></span> pointed out critical developments in this regard.:
</p>
<h4 class="y-header" id="context-awareness-and-pro-activeness">
<span>Context Awareness and Pro-Activeness</span><a href="#context-awareness-and-pro-activeness" class="anchor las la-anchor" title="context-awareness-and-pro-activeness"></a>
</h4>
<p>
Multitudes of sensors both owned (or even worn) by the user or present in the public domain allow the greater possibility to take user context into account. This includes classifying user’s actions, emotions, health and location and allows them to provide services related to that. This might be sports tracking e.g. analytics and recommendations in tennis <span class="citation" data-cites="sharma_wearable_2017"><span class="citation" data-cites="sharma_wearable_2017">[4]</span></span> or granting access to public transport without any interaction, enabled by face detection <span class="citation" data-cites="li_you_2019"><span class="citation" data-cites="li_you_2019">[5]</span></span>. Further, context awareness empowers services to be gradually more proactive, likewise reducing the amount of interaction required by a user, although “mixed-initiative” is said to be more appropriate to HCI. Siri <span class="citation" data-cites="noauthor_use_nodate"><span class="citation" data-cites="noauthor_use_nodate">[6]</span></span> and Google Assistant <span class="citation" data-cites="noauthor_google_nodate"><span class="citation" data-cites="noauthor_google_nodate">[7]</span></span> are examples of such context-sensitive, mixed-initiative services. They provide information when they are queried by a user, most notably facilitating non-physical interaction with distributed devices (i.e. through voice commands handled by a supported client device). They might also present information on their own, based on context and need.
</p>
<h4 class="y-header" id="adaptability">
<span>Adaptability</span><a href="#adaptability" class="anchor las la-anchor" title="adaptability"></a>
</h4>
<p>
<em>Need</em> is interesting on its own. It might mean external factors such as emergency warnings, but often employs a different concept important to Ubiquitous computing, namely, <em>adaptability</em>. Evers et.al.<span class="citation" data-cites="evers_user_2014"><span class="citation" data-cites="evers_user_2014">[8]</span></span> claim that “future computing systems must adjust to the user’s situations, habits, and intentions.” Pro-activeness, as mentioned above, is much more useful, if not only useful, if it supports and anticipates the user’s intentions and develops with their behaviour. As such, it’s imperative to not only collect user context but also user feedback on the actions anticipated.
</p>
<h4 class="y-header" id="intelligence">
<span>Intelligence</span><a href="#intelligence" class="anchor las la-anchor" title="intelligence"></a>
</h4>
<p>
Tangential to the ability to learn from user feedback is the perceived intelligence of a Ubiquitous system. As humans, we are used to expecting decent levels of intelligence in natural interaction with each other. In effect, to be perceived as a <em>natural</em> part of one’s environment, rather than being a tool, ubiquitous technology needs to show intelligence too. Adaptivity and pro-activeness, as discussed before, are some aspects of this. Additionally one might ask for additional criteria such as an ability to reflect and anticipate consequences, improve their behaviour and show diverse strategies as well as <em>natural</em> social competence.
</p>
<p>
Speaking of intelligence, one can discern different types of intelligence by the agent that shows it. Things or machines that display intelligence are typically considered robots. User software becomes a (software) agent or softbot. While softbots (for instance the aforementioned personal agents) can already be integrated into the environment and provide non-physical interaction, going a step further one can also separately distinguish smart environments. These are often referred to as implementations of ambient intelligence. We see intelligence embedded into objects in our environment <span class="citation" data-cites="cook_ambient_2009"><span class="citation" data-cites="cook_ambient_2009">[9]</span></span> such as appliances, thermostats and similar devices. Research might go even further exploring rooms, that sense the user’s presence, can store and prepare different states for different users <span class="citation" data-cites="eliasson_secure_nodate"><span class="citation" data-cites="eliasson_secure_nodate">[10, p. 21]</span></span> and be augmented virtually <span class="citation" data-cites="weiser_computer_nodate"><span class="citation" data-cites="weiser_computer_nodate">[1]</span></span>.
</p>
<p>
In fact, augmented reality was also envisioned by Weiser <span class="citation" data-cites="weiser_computer_nodate"><span class="citation" data-cites="weiser_computer_nodate">[1]</span></span> as part of a ubiquitously computing future. Several projects are pushing the idea of AR implemented in projects of varying comfort in form of the Google Glasses and Microsoft Holo Lens or smartphone-based solutions like Google Lens.
</p>
<h4 class="y-header" id="summary-of-the-dimensions-of-ubicomp">
<span>Summary of the Dimensions of Ubicomp</span><a href="#summary-of-the-dimensions-of-ubicomp" class="anchor las la-anchor" title="summary-of-the-dimensions-of-ubicomp"></a>
</h4>
<p>
Summarizing the nature of Ubiquitous computing one can distinguish advances on <!-- three --> different dimensions. First, implementations of Ubicomp might have varying <em>distance</em> to the user. It can be public domain face detection based access control, or intelligent rooms. Closer to the user there are wearables or smart fabrics. In recent days project like Neuralink <span class="citation" data-cites="pisarchik_novel_2019"><span class="citation" data-cites="pisarchik_novel_2019">[11]</span></span> picture a future with even closer integration of computing. Second, different grades of <em>artificial intelligence</em> are shown. Systems that interact close to the user are supposed to do so naturally, i.e. intelligently. The less direct the interaction the less the requirement for pro-activeness, talking about face detection as an example. Weiser himself coined another dimension, namely <em>size</em>:
</p>
<blockquote>
<p>
“Inch scale, foot scale and yard scale devices.”
</p>
</blockquote>
<p>
Computing nowadays can be as big or bigger than smart screens, down to tablet and smartphone/smartwatch size. Yet, even smaller computing is present in our environment. Credit cards, contactless keys, or glucose meters are examples of such smaller and certainly much more transparent areas of computation with medical devices reaching even greater records in smallness.
</p>
<p>
So far, Ubicomp has been mainly described as a form of HCI, providing ways for users to interact more or less directly with a greater service. Ubicomp itself while popular in academics (listing more than 1.5M search results on Google Scholar<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>) hasn’t become nearly as present in the industry and everyday life as a term. Possibly due to its nature being more of a concept without clear and concrete borders as seen above. Instead, the term <em>Internet of Things</em> (IoT) experienced a phase of ubiquity in industry and consumer electronics. What is IoT then?
</p>
<h3 class="y-header" id="the-internet-of-things">
<span>The Internet of Things</span><a href="#the-internet-of-things" class="anchor las la-anchor" title="the-internet-of-things"></a>
</h3>
<p>
While Ubicomp as a concept seems to concentrate more on the connection with humans and the possibilities it offers to them, IoT has a greater impact as a marketing term for connected devices. In a way, it’s a more practical term than Ubicomp. Yet, that does not mean it is a more concrete one. Applications of IoT include Home Automatization, Smart Cities, Media Consumption and Transportation to name a few many of which are also part of Ubicomp. The difference to Ubicomp is that IoT describes <em>actual</em> systems/networks of devices that work together and communicate, as well as their protocols and standards.
</p>
<p>
As shown in an article in <em>Business Horizons</em> <span class="citation" data-cites="lee_internet_2015"><span class="citation" data-cites="lee_internet_2015">[12]</span></span> numerous artefacts are part of the IoT. It is the nature of a system that qualifies it as part of <em>the</em> IoT. Data is produced at one end by wirelessly connected sensors, send over a network, processed by specific middleware running <em>in the cloud</em> and driving IoT based applications.
</p>
<p>
Only considering consumer applications the market for IoT is enormous. Home automation for example has evolved rapidly over the last years, with multiple applications by competing vendors reaching from lighting overheating to property security and more. The great interest in this market led to a substantial fragmentation of the market on nearly every layer of IoT. In the pursuit of standard multiple communication protocols evolved. Nowadays, Zigbee, Z-Wave, Bluetooth LE and WiFi are the dominant standards to build networks<span class="citation" data-cites="elhadi_comparative_2018"><span class="citation" data-cites="elhadi_comparative_2018">[13]</span></span>. Yet, device protocols often remain largely incompatible still.
</p>
<p>
If building on open standards, the entrance to IoT has become quite simple. Hubs provide an interface to compatible connected devices or connect them to cloud-based services. Yet there is little standardization around the interaction between different devices’ specially if coming from different vendors.
</p>
<p>
Looking at industrial contexts, an apparent difference is the predominance of sensors at the bottom of the network becomes apparent. IIoT is characterized by a multitude of wirelessly connected actuators and sensors <span class="citation" data-cites="foukalas_dependable_2019"><span class="citation" data-cites="foukalas_dependable_2019">[14]</span></span>. Unsurprisingly, IIoT generates a lot of data, which needs to be stored and processes or analyzed<span class="citation" data-cites="noauthor_what_nodate"><span class="citation" data-cites="noauthor_what_nodate">[15]</span></span>. This fact strongly motivates cloud computing or even more immediate processing at the <em>edge of the network</em>. <span class="citation" data-cites="noauthor_real-time_nodate"><span class="citation" data-cites="noauthor_real-time_nodate">[16]</span></span>. Additionally, the uniqueness of many applications implies that there are even incompatibilities between systems than in the consumer market.
</p>
<p>
To summarize, IoT consists of three main elements each of which can vary in complexity based on the application as crystallized by Jayavardhana Gubbi in a 2013 paper <span class="citation" data-cites="gubbi_internet_2013"><span class="citation" data-cites="gubbi_internet_2013">[17]</span></span>.
</p>
<ol type="1">
<li>
<strong>Hardware</strong> is the common term for sensors, actuators and communication drivers
</li>
<li>
<strong>Middleware</strong> provides intermediate analytics and data storage
</li>
<li>
<strong>Presentation</strong> conveys the findings to the end-user
</li>
</ol>
<p>
One might additionally include <strong>Software</strong>, especially protocols, in the list. In the following, this essay focuses on software related to the first two points.
</p>
<h2 class="y-header" id="rust">
<span>Rust</span><a href="#rust" class="anchor las la-anchor" title="rust"></a>
</h2>
<p>
Rust is a relatively modern programming language that was first introduced in 2010 by Mozilla as a basis for their experimental browser engine Servo<span class="citation" data-cites="graydon_project_nodate"><span class="citation" data-cites="graydon_project_nodate">[18]</span></span> parts of which are now driving the Firefox Browser<span class="citation" data-cites="noauthor_quantum_nodate"><span class="citation" data-cites="noauthor_quantum_nodate">[19]</span></span>. Its trifecta of speed, safety and concurrency caught peoples interest early on. Since the beginning rust strived to provide greater safety through an advanced type system. By design, Rust disallows concurrent mutable access to the same data. Instead, it employs the concepts of data <em>ownership</em> and <em>borrowing</em>. At compile-time, Rust can resolve how long references are used and when they are cleared up. In effect, (modern) Rust does not implement a garbage collector. This and the fact that it is compiled to native code through LLVM put it in the same category as other unmanaged languages such as C/C++ and account for Rust’s performance. The first stable version of Rust was released in 2015<span class="citation" data-cites="noauthor_rustreleasesmd_nodate"><span class="citation" data-cites="noauthor_rustreleasesmd_nodate">[20]</span></span>. Since then public interest grew starkly, due to its promises.
</p>
<p>
By now, Rust has been voted the “most-loved” language since 2016 by developers on StackOverflows yearly survey <span class="citation" data-cites="noauthor_stack_nodate"><span class="citation" data-cites="noauthor_stack_nodate">[21]</span></span>. Its today’s most convincing features are summarized by Jake Goulding<span class="citation" data-cites="goulding_what_2020"><span class="citation" data-cites="goulding_what_2020">[22]</span></span> in a blog post from January 2020. Firstly, its versatile and ergonomic type system enables very practical safety measures, for example, replacing <code>null</code> pointers for more expressive and safe <code>Option&lt;T&gt;</code> types and enforcing the handling of errors through a <code>Result&lt;Error, T&gt;</code>. Additionally, these are also examples of Rust’s capability of algebraic data types. The aforementioned garbage collection model – or the lack thereof – is as well highly appreciated by users of the language as it decreases the applications memory footprint dramatically. The possibility of <em>safe</em> direct memory access has likewise driven Rust to be an aspiring candidate for embedded{@} devices as well as recently becoming an officially supported option for Linux kernel module development<span class="citation" data-cites="noauthor_rust_nodate-2"><span class="citation" data-cites="noauthor_rust_nodate-2">[23]</span></span>, not at last because sticking to Rust’s compiler enforced rules drastically reduces the possibility of segfaults. Segfaults, typically occurring when accessing invalid memory, are by default prevented by Rust’s memory design.
</p>
<p>
Additionally to the language design, Rust has built a thriving ecosystem. Its standard build tool and package manager Cargo<span class="citation" data-cites="noauthor_introduction_nodate"><span class="citation" data-cites="noauthor_introduction_nodate">[24]</span></span> is the pivoting point of this ecosystem. Using cargo one can easily manage dependencies, config feature flags, run tests and much more. It also offers great extensibility through custom commands and built-in integrability with IDEs <span class="citation" data-cites="noauthor_external_nodate"><span class="citation" data-cites="noauthor_external_nodate">[25]</span></span>. Cargo links in and provides tools for publishing libraries on its package library <a href="https://crates.io">crates.io</a><span class="citation" data-cites="noauthor_cratesio_nodate"><span class="citation" data-cites="noauthor_cratesio_nodate">[26]</span></span>. These libraries referred to as <em>crates</em> are considered to be one of Rust’s most important features on their own. Traditional languages such as C/C++ do not have any standard package manager, libraries are typically installed as precompiled binaries that need to be linked at compile time or runtime in case of shared objects. This requires the developer to include header files that are only resolved using a basic preprocessor, install these libraries separately and track/require them using third party tooling with little control over the actual version being used leaving many security issues to be dealt with by the user of the software and OS maintainers. C++ recently added support for modules<span class="citation" data-cites="corob-msft_overview_nodate"><span class="citation" data-cites="corob-msft_overview_nodate">[27]</span></span> solving some problems related to header files but remains fragmented in general. Rust got inspired by more modern and ergonomic solutions of more recent languages such as NPM<span class="citation" data-cites="noauthor_npm_nodate"><span class="citation" data-cites="noauthor_npm_nodate">[28]</span></span>.
</p>
<h1 class="y-header" id="the-rust-ecosystem-for-iot">
<span>The Rust Ecosystem for IoT</span><a href="#the-rust-ecosystem-for-iot" class="anchor las la-anchor" title="the-rust-ecosystem-for-iot"></a>
</h1>
<p>
In the introduction, Rust’s ecosystem was outlined. Focusing on IoT one needs to take a deeper look into the accompanying tools and libraries. This essay will introduce key technologies and concepts that enable the development of IoT devices and related edge computing.
</p>
<p>
When speaking of IoT ARM is by far the leading manufacturer of Chipsets used at the edge of the IoT<span class="citation" data-cites="noauthor_who_2020"><span class="citation" data-cites="noauthor_who_2020">[29]</span></span> and embedded devices such as sensors. As such, to be a viable option to cover the IoT space as a language, support for ARM-based processors is imperative! Hence special focus will lie on ARM support in Rust.
</p>
<h2 class="y-header" id="rust-on-microcontrollers">
<span>Rust on Microcontrollers</span><a href="#rust-on-microcontrollers" class="anchor las la-anchor" title="rust-on-microcontrollers"></a>
</h2>
<h3 class="y-header" id="tools">
<span>Tools</span><a href="#tools" class="anchor las la-anchor" title="tools"></a>
</h3>
<p>
A major component of the ecosystem of a programming language are tools that simplify or automate the development processes. These processes can become highly complex even for rather simple projects. For instance programming, a common microchip, requires a debugger, a connector to the on-chip debugger and the programmer and the build tool to work together. The latter also needs to be configured for the programmed chip. Several tools that have been developed try to shrink the associated learning curve and strive to allow for greater productivity quicker.
</p>
<p>
Being based on LLVM Rust supports a multitude of platforms <span class="citation" data-cites="noauthor_platform_nodate"><span class="citation" data-cites="noauthor_platform_nodate">[30]</span></span> including many ARM platforms. Cargo complements this by offering an interface to cross-compile to foreign architectures. Additionally, rustup<span class="citation" data-cites="noauthor_introduction_nodate-2"><span class="citation" data-cites="noauthor_introduction_nodate-2">[31]</span></span> provides an interface to easily acquire toolchains for these architectures and simplifies keeping track of the fast-paced releases of the Rust language. Combining these tools, cross<span class="citation" data-cites="noauthor_rust-embeddedcross_2021"><span class="citation" data-cites="noauthor_rust-embeddedcross_2021">[32]</span></span> has been developed by the rust-embedded working group which uses isolated docker containers to minimize the efforts required and possible failures of setting up a development environment by providing a managed prepackaged solution. With this running and testing code for different architectures becomes as easy as
</p>
<div class="y-fill-horizontal">
<div id="cb1" class="sourceCode">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> cross test <span class="dt">\</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  <span class="at">--target</span> mips64-unknown-linux-gnuabi64</span></code></pre>
</div>
</div>
<p>
Targeting microcontrollers, in particular, the knurling project <span class="citation" data-cites="noauthor_knurling-rs_nodate"><span class="citation" data-cites="noauthor_knurling-rs_nodate">[33]</span></span> develops tools that make embedded development more seamless. <code>probe-run</code> is a project that integrates downloading binaries to controllers, and running code, as well as connecting debuggers with cargo and can therefore be easily integrated with IDE’s. <code>defmt</code> significantly reduces resource overhead of logging on microchips and has been found to offer a highly integrated debug process <span class="citation" data-cites="noauthor_using_nodate"><span class="citation" data-cites="noauthor_using_nodate">[34]</span></span>.
</p>
<h3 class="y-header" id="abstraction-layers">
<span>Abstraction layers</span><a href="#abstraction-layers" class="anchor las la-anchor" title="abstraction-layers"></a>
</h3>
<p>
Speaking about abstraction layers one must first understand why they are needed. Programming microcontrollers is flooded with hardware-level interaction, unsurprisingly. While rust is capable of doing these accesses, in many cases <em>some</em> of Rusts safety measures need to be disabled. While more is possible in these <code>unsafe</code> environments, obviously one strives to reduce the use of <code>unsafe</code>. Besides safety, ergonomics and compatibility are more reasons to ask for abstractions. Rust is known for its capabilities to bring these virtues to its users in other areas already due to expressive Generics and its trait system. In the context of embedded programming, this has enabled people to create various levels of abstractions on top of the lowest levels of interaction with the hardware.
</p>
<h4 class="y-header" id="accessing-the-hardware">
<span>Accessing the hardware</span><a href="#accessing-the-hardware" class="anchor las la-anchor" title="accessing-the-hardware"></a>
</h4>
<p>
Peripherals on microcontrollers are configured through so-called memory-mapped registers. Manipulating the state of these registers changes how the external connectors to the chip behave, whether they are inputs or outputs, digital or analogue. Also, internal structures can be controlled this way, e.g. timers can be set and reacted upon. Unfortunately, there is no common interface to these registers not only due to the number of different manufacturers but also different chip design and application.
</p>
<p>
While configuration and layout differ, it does not do so undocumented. In fact for long SVD files <span class="citation" data-cites="noauthor_svd_nodate"><span class="citation" data-cites="noauthor_svd_nodate">[35]</span></span> are being made available by manufacturers describing the chip layout formally. In Rust, this is made use of to create so-called <em>peripheral access crates</em> (PAC). Using a <code>svd2rust</code> <span class="citation" data-cites="noauthor_rust-embeddedsvd2rust_2021"><span class="citation" data-cites="noauthor_rust-embeddedsvd2rust_2021">[36]</span></span> one can <em>generate</em> a rust library that implements a <strong>safe interface</strong> to all of the specified registers including context-based functions, such as being able to write or read from pins, or start timers using a method rather than setting bits manually.
</p>
<h4 class="y-header" id="abstracting-hardware-functions">
<span>Abstracting hardware functions</span><a href="#abstracting-hardware-functions" class="anchor las la-anchor" title="abstracting-hardware-functions"></a>
</h4>
<p>
PACs do a great job making raw hardware accessible by Rust in an automated and safe way. Building on top of this, one might perform standard operations such as communicating to peripherals connect to USB, enable timers and so on. While building this functionality from the ground up based on peripheral access, a safer and more portable solution is building on a shared abstraction. Such an abstraction is provided by the <code>embedded_hal</code><span class="citation" data-cites="noauthor_embedded_hal_nodate"><span class="citation" data-cites="noauthor_embedded_hal_nodate">[37]</span></span> crate.
</p>
<p>
The functionality provided by <code>embedded_hal</code> fulfils some important requirements:
</p>
<ol type="1">
<li>
It is independent of any specific chip
</li>
<li>
Does not make restricting assumptions about how it is used on a specific chip
</li>
<li>
Provides low-cost abstractions that are compassable into higher-order abstractions (note that <code>embedded_hal</code> is still a <em>very</em> low-level abstraction)
</li>
<li>
Stemming from the previous point: Offers sufficient freedom and capabilities to base device-independent drivers upon.
</li>
</ol>
<p>
Note, that <code>embedded_hal</code> does not implement most of the functionality, but defines interfaces that are eventually implemented for a specific chip or family of devices.
</p>
<h4 class="y-header" id="section">
<span><!--Building on specific devices--></span><a href="#section" class="anchor las la-anchor" title="section"></a>
</h4>
<p>
<!--Device Support-->
</p>
<h3 class="y-header" id="drivers">
<span>Drivers</span><a href="#drivers" class="anchor las la-anchor" title="drivers"></a>
</h3>
<p>
Apart from accessing mere hardware, the most important aspect of embedded development is, as in non-embedded scenarios, processing data, and providing functionality. In the context of IoT data is typically produced by the periphery, and communicated over some network channel, it is still the <em>internet</em> of things. Enabling this, one finds themselves at a gap. So far, the discussed abstractions merely provide hardware access. Yet, communication, in particular, requires conformity to often complex protocols (i.e. IEEE802.11/WLAN<span class="citation" data-cites="noauthor_ieee_2018"><span class="citation" data-cites="noauthor_ieee_2018">[38]</span></span>). Implementations for these protocols readily exist in C, less so in Rust, often because the modems are using more niche platforms, to begin with. Instead of reimplementing the existing C <!--might come--> implementation for those modems, Rust focuses on offloading this functionality. <!--expensive--> Offloading means to employ a second chip running a firmware that drives a communication module and exposing the data access through a firmware specific (serial) interface. Drivers have been implemented for all sorts of such devices and often make use of the aforementioned <code>embedded_hal</code> to be usable from any host device.
</p>
<p>
While serial protocols such as USB, RS232 or i2C can be part of a HAL, data protocols like AT<span class="citation" data-cites="noauthor_hayes_2021"><span class="citation" data-cites="noauthor_hayes_2021">[39]</span></span> are implemented separately. Crates like <code>atat</code><span class="citation" data-cites="noauthor_blackbirdhqatat_2021"><span class="citation" data-cites="noauthor_blackbirdhqatat_2021">[40]</span></span> transparently offer access to these protocols. Building on that, driver crates for popular networking modems are already available. With IoT in mind, we can find drivers for cellular access<span class="citation" data-cites="noauthor_blackbirdhqublox-cellular-rs_2021"><span class="citation" data-cites="noauthor_blackbirdhqublox-cellular-rs_2021">[41]</span></span> or short-range networks<span class="citation" data-cites="noauthor_blackbirdhqublox-short-range-rs_2021"><span class="citation" data-cites="noauthor_blackbirdhqublox-short-range-rs_2021">[42]</span></span> that connect to u-blox<span class="citation" data-cites="noauthor_u-blox_nodate"><span class="citation" data-cites="noauthor_u-blox_nodate">[43]</span></span> devices. The drogue IoT project <span class="citation" data-cites="noauthor_drogue_nodate"><span class="citation" data-cites="noauthor_drogue_nodate">[44]</span></span> not only brings support for common network standards like WiFi or LoRaWAN but also abstracts these to a transparent network interface, such that from Rust each of these network gateways can be used the same way providing TCP/UDP sockets. Building on this network abstraction the project also implements an MQTT and HTTP client.
</p>
<h3 class="y-header" id="notable-mentions">
<span>Notable Mentions</span><a href="#notable-mentions" class="anchor las la-anchor" title="notable-mentions"></a>
</h3>
<p>
LoRaWAN<span class="citation" data-cites="noauthor_what_nodate"><span class="citation" data-cites="noauthor_what_nodate">[15]</span></span> is known for its application as the basis for IoT. Especially The Things Network<span class="citation" data-cites="noauthor_things_nodate"><span class="citation" data-cites="noauthor_things_nodate">[45]</span></span> plays a major role in pushing LoRa by providing a shared infrastructure that is energy efficient, yet reliant, open and secure. Incidentally, crates to create clients to this network already exist.
</p>
<h2 class="y-header" id="leaving-microcontrollers">
<span>Leaving Microcontrollers</span><a href="#leaving-microcontrollers" class="anchor las la-anchor" title="leaving-microcontrollers"></a>
</h2>
<p>
At this point, Rust’s support for microcontrollers was comprehensively presented… Although a lot of the IoT is implemented on the smallest of processors, often one has more resources to spare. Devices that could be described as “raspberry pi sized,” can run a supported operating system (e.g. GNU/Linux) on a higher architecture, such as <code>aarch64</code>. Consequently, they profit from full Rust-Support. These offer more versatile tools and capabilities to connect to complex technologies such as Bluetooth, or processing greater amounts of data, such as camera feeds.
</p>
<h2 class="y-header" id="rust-on-the-edge">
<span>Rust on the Edge</span><a href="#rust-on-the-edge" class="anchor las la-anchor" title="rust-on-the-edge"></a>
</h2>
<p>
In recent years WebAssembly <span class="citation" data-cites="noauthor_webassembly_nodate"><span class="citation" data-cites="noauthor_webassembly_nodate">[46]</span></span> (WASM) has been growing as an OS-independent platform, meant to run programs in web-browsers at near-native speed in secure sandboxes. Rust as a language has been pushing this development forward, by language support and tooling. Not only have the three biggest freestanding WASM runtimes adopted Rust as their implementing language<span class="citation" data-cites="noauthor_wasmeriowasmer_2021"><span class="citation" data-cites="noauthor_wasmeriowasmer_2021">[49]</span></span>, but also there have evolved standard tools to integrate WASM into your JavaScript Codebase <span class="citation" data-cites="noauthor_rustwasmwasm-pack_2021"><span class="citation" data-cites="noauthor_rustwasmwasm-pack_2021">[50]</span></span> and library support to narrow the gap between the Rust/WASM world and the JavaScript runtime<span class="citation" data-cites="noauthor_rustwasmwasm-bindgen_2021"><span class="citation" data-cites="noauthor_rustwasmwasm-bindgen_2021">[51]</span></span>.
</p>
<p>
Companies like <em>fastly</em> and <em>Cloudflare</em> have developed services that facilitate this platform to offer easy entrance to Edge Computing. Cloudflare Workers <span class="citation" data-cites="noauthor_cloudflare_nodate"><span class="citation" data-cites="noauthor_cloudflare_nodate">[52]</span></span> offers the infrastructure for reliable functions on the web that can act as an ingress point for IoT devices. Workers run code compiled to WebAssembly which makes them a ready target for Rust.
</p>
<h1 class="y-header" id="rust-as-a-platform">
<span>Rust as a platform</span><a href="#rust-as-a-platform" class="anchor las la-anchor" title="rust-as-a-platform"></a>
</h1>
<p>
In the previous section, a multitude of applications and capabilities of the Rust Language has been presented. While the ecosystem is large, it is important to also analyze it with an eye on qualitative factors to come up with a convincing conclusion about the usability of Rust as a Platform for IoT today. As rust is still evolving, many things will still improve. This essay aims to summarize the current developments and make an educated guess where Rust is heading.
</p>
<h2 class="y-header" id="today">
<span>Today</span><a href="#today" class="anchor las la-anchor" title="today"></a>
</h2>
<p>
Rust is known for assessing its performance in many areas publicly in the form of “are we X yet” websites<span class="citation" data-cites="noauthor_areweyet_nodate"><span class="citation" data-cites="noauthor_areweyet_nodate">[54]</span></span>. Unfortunately, for the domain of embedded/IoT, the community has not yet started such a project. Yet, as that form has proven very informative, this essay will adopt a similar approach.
</p>
<dl>
<dt>
++
</dt>
<dd>
Rust has stable and mature support. You can use Rust for this
</dd>
<dt>
+
</dt>
<dd>
Rust offers some support/development. Think twice.
</dd>
<dt>
±
</dt>
<dd>
Ideas are there but little has evolved from it.
</dd>
<dt>
-
</dt>
<dd>
Close to nothing has been developed. You are on your own, not recommended to use Rust here.
</dd>
</dl>
<h3 class="y-header" id="the-good">
<span>The good</span><a href="#the-good" class="anchor las la-anchor" title="the-good"></a>
</h3>
<p>
In some regards, rust can already shine, although it might need some polish in some places. Especially the strong features of Rust, tooling and performance, can shine too in the IoT context.
</p>
<h4 class="y-header" id="performance-and-ergonomics">
<span>Performance and Ergonomics (++)</span><a href="#performance-and-ergonomics" class="anchor las la-anchor" title="performance-and-ergonomics"></a>
</h4>
<p>
One of the strongest points to make about Rust is probably its performance. This does not mean solely its runtime performance but also its development process.
</p>
<p>
Rust is often hailed for the high-level elements that make it look and act like a general-purpose language in many regards. At the same time, it embraces the concept of “Zero-Cost Abstractions” that let it produce highly optimized code without accepting drawbacks on its high-level features.
</p>
<p>
Yet in areas where every byte counts, with rust one, has to trust on the optimizer to produce sufficiently small binaries. Which becomes harder given how easy it is to add dependencies to a project. Projects exist to help monitor the size of binaries but the main problem remains.
</p>
<p>
Looking at it in another way, given how high-level rust can be, memory accesses are not as obvious as they are with C. Clearly, this can cause unexpected problems in performance, especially on microcontrollers with limited memory speeds.
</p>
<h4 class="y-header" id="tools-1">
<span>Tools (++)</span><a href="#tools-1" class="anchor las la-anchor" title="tools-1"></a>
</h4>
<p>
Rust is known for its great tooling. This doesn’t stop in the world of embedded systems and IoT. For one, Rust is pioneering the world of WebAssembly. Additionally, the entry into Embedded systems is made greatly easier given the rust tooling.
</p>
<p>
As we saw with the abstractions above, embedded Rust does not exclude the possibility to use cargo and its package management. In fact, it even provides a measure to tell whether a library can run on embedded devices or not, precisely as long as it does not use the standard library that is built on top of specific operating systems. Such crates are marked as <code>#[no_std]</code>. It doesn’t stop there. We saw projects automatizing the whole process of downloading binaries and running/debugging them through standard cargo invocations that integrate well with IDEs.
</p>
<p>
Of course, not everything is perfect in this regard area yet. As a lot of Rust’s tooling is automatized, as a user one faces a rather high-level view of the process. While this can be desirable, it reduces the account one has to tell what parts are causing errors. Also, due to abstraction over multiple interfaces, the functionality provided might be less than what would theoretically be possible using those tools directly, at which point using Rust might become more of a burden as configuring these tools to fit Rust might not be trivial in every case.
</p>
<p>
A similar thing can be said about Rust for Edge Computing using WebAssembly. We have seen it as the driving language for modern runtimes and offering rich library support<span class="citation" data-cites="noauthor_webassembly_nodate-1"><span class="citation" data-cites="noauthor_webassembly_nodate-1">[55]</span></span>. As such given its tools, it is easy to integrate them into existing platforms or important in the domain of Edge Computing write high performant workers in it.
</p>
<h4 class="y-header" id="frameworks-and-libraries">
<span>Frameworks and Libraries (+)</span><a href="#frameworks-and-libraries" class="anchor las la-anchor" title="frameworks-and-libraries"></a>
</h4>
<p>
The presentation shed light on some of the most influential projects. While on the WASM front Rust has already developed a mature environment. In the space of embedded devices, libraries while bringing support for many devices, do not enjoy the same kinds of maturity and maintenance.
</p>
<p>
The <code>embedded-hal</code> is a great leap toward a unified API on microcontrollers and is already heavily used. Yet, many projects have implemented drivers independently or base on incompatible versions. Drivers are generally added more as an implementation to tick the boxes for a specific use case and therefore do usually not cover the available functionality.
</p>
<p>
<code>drogue-wifi</code> for instance implements a driver for the WiFi breakout board ESP8266. Yet, while the target chip is capable of a whole range of functionality, the driver only implements a limited subset of that such that it fits the drogue project. More extensive support would be desirable to use rust more ergonomically and ease the development.
</p>
<h3 class="y-header" id="the-bad">
<span>The bad</span><a href="#the-bad" class="anchor las la-anchor" title="the-bad"></a>
</h3>
<p>
As a comparatively young language, especially compared to its contenders in the embedded world, naturally, Rust has a set of drawbacks mainly connected to its development pace and lack of maturity and experience in the industry.
</p>
<h4 class="y-header" id="documentation">
<span>Documentation (+/±)</span><a href="#documentation" class="anchor las la-anchor" title="documentation"></a>
</h4>
<p>
Generally, Rust is known for its great documentation. There is even specialized tooling around it. Rustdoc<span class="citation" data-cites="noauthor_what_nodate-2"><span class="citation" data-cites="noauthor_what_nodate-2">[56]</span></span> is the standard tool to generate documentation from rust source code. Docs.rs<span class="citation" data-cites="noauthor_docsrs_nodate"><span class="citation" data-cites="noauthor_docsrs_nodate">[57]</span></span> adds to this hosting documentation for the whole crates.io index of packages. The fact that all documentation is entangled this tightly is a major win to the whole community and aids development dramatically.
</p>
<p>
Rust has also evolved the mdBook<span class="citation" data-cites="noauthor_mdbook_nodate"><span class="citation" data-cites="noauthor_mdbook_nodate">[58]</span></span> tool. It is used throughout the rust community to assemble more high-level documentation and tutorials. For embedded the rust Community has published multiple of these books that aim to introduce programming Rust for low power hardware. Unfortunately, while covering the basics, once diverting from these or using newer technologies the amount of documentation is very sparse. At that point, it is mostly up to the developer of certain libraries to provide decent documentation. Yet, often development is faster than documentation, leading to outdated tutorials and examples. Additionally, many parts of the rust ecosystem are still mostly documented through blog posts. Although this is certainly not a bad thing in itself, as it shows that the interest is big, it is difficult to tell the recency or relevance of such articles. Likewise, there is little being written about how different projects are supposed to work together.
</p>
<h4 class="y-header" id="stability">
<span>Stability (±)</span><a href="#stability" class="anchor las la-anchor" title="stability"></a>
</h4>
<p>
As mentioned earlier, incompatibility especially at the abstraction level can be a problem. Indeed, <code>embedded-hal</code> is still considered unstable and while sticking to a semantic versioning protocol, must still be considered to break existing code without previous warning. Consequently, this means that the whole ecosystem around it is at most as stable as the abstraction layer they built upon. In reality, most libraries are yet to be considered incidental, meaning they were built to fit a need of someone at some time and are therefore not actively maintained or feature complete.
</p>
<p>
A few projects trying to build a stable foundation for certain functional units, such as the IoT network/cloud project <code>drogue</code>. Still, the interfaces that come to existence due to these projects aim foremost for internal compatibility.
</p>
<h4 class="y-header" id="framework-interoperability">
<span>Framework Interoperability (±)</span><a href="#framework-interoperability" class="anchor las la-anchor" title="framework-interoperability"></a>
</h4>
<p>
Extending on the internal compatibility, it would be desirable to have projects interoperate cleanly. The aforementioned stability issues and fragmented ecosystem can often not be equalized by the overarching abstraction layer.
</p>
<p>
Moreover, documentation to integrate one library within the other is often hard to find as well. RTIC<span class="citation" data-cites="noauthor_preface_nodate"><span class="citation" data-cites="noauthor_preface_nodate">[59]</span></span> for example promises to provide a framework that works concurrently by managing interrupts and resources. Yet, it brings in a very different way to set up projects that complicate how to get started with the whole system especially as examples are scarce here too.
</p>
<h3 class="y-header" id="the-ugly">
<span>The ugly</span><a href="#the-ugly" class="anchor las la-anchor" title="the-ugly"></a>
</h3>
<p>
Lastly, some tasks are so far virtually impossible to achieve with Rust or require a lot of work to be invested by the user.
</p>
<h4 class="y-header" id="arm--">
<span><del>ARM</del> (-)</span><a href="#arm--" class="anchor las la-anchor" title="arm--"></a>
</h4>
<p>
We have seen that on ARM Rust offers great support. Indeed the stm32-rs group, for example, tries to provide embedded-has implementations for all chips manufactured by STM. Other ARM vendors have similar good support.
</p>
<p>
It is once one asks to write software for other architectures. First, they are limited by support for these architectures of the LLVM backend. The popular IoT platform Arduino for instance runs on AVR based chips which require a fork of LLVM to be programmed for In Rust. Extensa, the architecture employed by the ESP8266/ESP32 chips also requires additional care. These reasons drive the current disinterest in writing software for these chips (as it is not possible or difficult) which in turn affects the motivation to bring support for the platforms to Rust in the first place.
</p>
<table>
<caption>
Summary of Rust’s ecosystem today
</caption>
<thead>
<tr class="header">
<th>
Ecosystem element
</th>
<th>
Maturity
</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>
Performance and Ergonomics
</td>
<td>
++
</td>
</tr>
<tr class="even">
<td>
Tools
</td>
<td>
++
</td>
</tr>
<tr class="odd">
<td>
Frameworks and Libraries
</td>
<td>
+
</td>
</tr>
<tr class="even">
<td>
Documentation (Rust)
</td>
<td>
+
</td>
</tr>
<tr class="odd">
<td>
Documentation (Libraries)
</td>
<td>
±
</td>
</tr>
<tr class="even">
<td>
Stability
</td>
<td>
±
</td>
</tr>
<tr class="odd">
<td>
Framework Interoperability
</td>
<td>
±
</td>
</tr>
<tr class="even">
<td>
Architecture Support (not ARM)
</td>
<td>
-
</td>
</tr>
</tbody>
</table>
<h2 class="y-header" id="in-the-future">
<span>In the future</span><a href="#in-the-future" class="anchor las la-anchor" title="in-the-future"></a>
</h2>
<p>
Today, Rust’s ecosystem is not all roses. A lot of things are missing still. Yet, observing the community fundamental steps are being taken. Looking at the future there are a few clear indicators that Rust will become a growing influence for not and ubiquitous computing.
</p>
<h3 class="y-header" id="rust-foundation">
<span>Rust Foundation</span><a href="#rust-foundation" class="anchor las la-anchor" title="rust-foundation"></a>
</h3>
<p>
More generically, the advent of the Rust Foundation <span class="citation" data-cites="noauthor_laying_nodate"><span class="citation" data-cites="noauthor_laying_nodate">[60]</span></span> will eventually also benefit the embedded section of the language. With greater structural organization and backing from industry-leading companies such as Google and Amazon, Microsoft, Huawei and Facebook, Rust manifests itself as a credible choice.
</p>
<h3 class="y-header" id="embedded-wg">
<span>Embedded-WG</span><a href="#embedded-wg" class="anchor las la-anchor" title="embedded-wg"></a>
</h3>
<p>
The embedded working group has been mentioned throughout this essay. They have proven themselves as the originators of remarkable work that has brought rust a long way. Its projects will for sure continue to improve the experience of embedded development in Rust.
</p>
<h3 class="y-header" id="ferrous">
<span>Ferrous</span><a href="#ferrous" class="anchor las la-anchor" title="ferrous"></a>
</h3>
<p>
Ferrous Systems, the leading force behind the excellent knurling project, is committed to further invest in Rusts embedded future. Ferrous already contributes to the Rust Open Source community in many ways, and with knurling still being a young project, its influence in the embedded world is still to be expanded.
</p>
<h3 class="y-header" id="librariestools">
<span>Libraries/Tools</span><a href="#librariestools" class="anchor las la-anchor" title="librariestools"></a>
</h3>
<p>
Finally, with more companies and individuals committing to Rust as their language of choice, albeit its current pitfalls will eventually populate the language with more helpful libraries and tools. Especially, once fundamental libraries such as the <code>embedded-hal</code> a point of stability, libraries building on these are expected to follow.
</p>
<p>
Taking into account WebAssembly, we see that with its adoption in all major browsers and the stabilization of its specification, WASM is there to stay. Rust has been influencing its development a lot until today
</p>
<h1 class="y-header" id="conclusion">
<span>Conclusion</span><a href="#conclusion" class="anchor las la-anchor" title="conclusion"></a>
</h1>
<p>
Throughout this essay, the domain of Ubiquitous Computing and IoT has been described in detail. Building on that the programming language Rust has been closely examined on its capabilities to fulfil the needs of this field. We have seen which infrastructure drives Rust’s support of embedded programming, how WebAssembly enables Rust to play a leading role as a language to implement functions on the Edge. Apart from this descriptive part, we put the available ecosystem into perspective, pointing out its strengths and current weaknesses.
</p>
<p>
Finally, we can conclude that Rust is perfectly capable of doing specific tasks, in the area of Embedded Computing and more so on higher levels of the Internet of Things, such as lightweight computing on the edge and the implementation of backend services. Yet, it shows that Rust is a fairly recent language. As such parts of its ecosystem, relevant to IoT, are still evolving, lack even some significant foundations and are far from stable. For early adopters and the generally curious Rust still offers the foundations on which one can build their own solutions, albeit without providing the maturity of decades of development. On the bright side, we see several companies like Drogue, Ferrous Systems and other independent groups, doing exactly that. Crucial foundations are in active development and promise a brighter future for Rust.
</p>
<p>
Condensing this essay into one sentence
</p>
<blockquote>
<p>
Rust shows the potential to become the IoT platform of choice in the future, providing speed, ergonomics and safety, but does not show the maturity to be readily used as such without thorough consideration.
</p>
</blockquote>
<p>
… Wow! You made it until here. Thank you a lot for your time and interest. If you have any thoughts about this post after all, please feel free to reach out to me.
</p>
<h1 class="y-header" id="references">
<span>References</span><a href="#references" class="anchor las la-anchor" title="references"></a>
</h1>
<section class="footnotes" role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote">
<p>
May 4th, 2021<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a>
</p>
</li>
</ol>
</section>
<div class="box y-fill-horizontal info">
<div class="header">
<div>
<span class="las la-book"></span>
<div class="badge">
References
</div>
</div>
</div>
<div id="refs" class="references csl-bib-body" role="doc-bibliography">
<div id="ref-weiser_computer_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[1] </div><div class="csl-right-inline">M. Weiser, <span>“The <span>Computer</span> for the 21st <span>Century</span>,”</span> p. 8.</div>
</div>
<div id="ref-dey_distributed_2002" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[2] </div><div class="csl-right-inline">A. Dey, J. Mankoff, G. Abowd, and S. Carter, <span>“Distributed mediation of ambiguous context in aware environments,”</span> in <em>Proceedings of the 15th annual <span>ACM</span> symposium on <span>User</span> interface software and technology</em>, Oct. 2002, pp. 121–130. doi: <a href="https://doi.org/10.1145/571985.572003">10.1145/571985.572003</a>.</div>
</div>
<div id="ref-poppe_evaluating_2007" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[3] </div><div class="csl-right-inline">R. Poppe, R. Rienks, and B. van Dijk, <span>“Evaluating the <span>Future</span> of <span>HCI</span>: <span>Challenges</span> for the <span>Evaluation</span> of <span>Emerging Applications</span>,”</span> in <em>Artifical <span>Intelligence</span> for <span>Human Computing</span></em>, 2007, pp. 234–250. doi: <a href="https://doi.org/10.1007/978-3-540-72348-6_12">10.1007/978-3-540-72348-6_12</a>.</div>
</div>
<div id="ref-sharma_wearable_2017" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[4] </div><div class="csl-right-inline">M. Sharma, R. Srivastava, A. Anand, D. Prakash, and L. Kaligounder, <span>“Wearable motion sensor based phasic analysis of tennis serve for performance feedback,”</span> in <em>2017 <span>IEEE International Conference</span> on <span>Acoustics</span>, <span>Speech</span> and <span>Signal Processing</span> (<span>ICASSP</span>)</em>, Mar. 2017, pp. 5945–5949. doi: <a href="https://doi.org/10.1109/ICASSP.2017.7953297">10.1109/ICASSP.2017.7953297</a>.</div>
</div>
<div id="ref-li_you_2019" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[5] </div><div class="csl-right-inline">T. Li, <span>“You will soon be able to pay your subway fare with your face in <span>China</span>,”</span> Mar. 13, 2019. <a href="https://www.scmp.com/tech/innovation/article/3001306/you-can-soon-pay-your-subway-ride-scanning-your-face-china">https://www.scmp.com/tech/innovation/article/3001306/you-can-soon-pay-your-subway-ride-scanning-your-face-china</a> (accessed May 04, 2021).</div>
</div>
<div id="ref-noauthor_use_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[6] </div><div class="csl-right-inline"><span>“Use <span>Siri</span> on all your <span>Apple</span> devices.”</span> <a href="https://support.apple.com/en-us/HT204389">https://support.apple.com/en-us/HT204389</a> (accessed May 04, 2021).</div>
</div>
<div id="ref-noauthor_google_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[7] </div><div class="csl-right-inline"><span>“Google <span>Assistant</span>.”</span> <a href="https://developers.google.com/assistant">https://developers.google.com/assistant</a> (accessed May 04, 2021).</div>
</div>
<div id="ref-evers_user_2014" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[8] </div><div class="csl-right-inline">C. Evers, R. Kniewel, K. Geihs, and L. Schmidt, <span>“The user in the loop: <span>Enabling</span> user participation for self-adaptive applications,”</span> <em>Future Generation Computer Systems</em>, vol. 34, pp. 110–123, May 2014, doi: <a href="https://doi.org/10.1016/j.future.2013.12.010">10.1016/j.future.2013.12.010</a>.</div>
</div>
<div id="ref-cook_ambient_2009" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[9] </div><div class="csl-right-inline">D. J. Cook, J. C. Augusto, and V. R. Jakkula, <span>“Ambient intelligence: <span>Technologies</span>, applications, and opportunities,”</span> <em>Pervasive and Mobile Computing</em>, vol. 5, no. 4, pp. 277–298, Aug. 2009, doi: <a href="https://doi.org/10.1016/j.pmcj.2009.04.001">10.1016/j.pmcj.2009.04.001</a>.</div>
</div>
<div id="ref-eliasson_secure_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[10] </div><div class="csl-right-inline">E. Eliasson, <span>“Secure <span>Internet Telephony</span>: <span>Design</span>, <span>Implementation</span>, and <span>Performance Measurements</span>,”</span> p. 80.</div>
</div>
<div id="ref-pisarchik_novel_2019" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[11] </div><div class="csl-right-inline">A. N. Pisarchik, V. A. Maksimenko, and A. E. Hramov, <span>“From <span>Novel Technology</span> to <span>Novel Applications</span>: <span>Comment</span> on <span>‘<span>An Integrated Brain-Machine Interface Platform With Thousands</span> of <span>Channels</span>’</span> by <span>Elon Musk</span> and <span>Neuralink</span>,”</span> <em>Journal of Medical Internet Research</em>, vol. 21, no. 10, p. e16356, Oct. 2019, doi: <a href="https://doi.org/10.2196/16356">10.2196/16356</a>.</div>
</div>
<div id="ref-lee_internet_2015" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[12] </div><div class="csl-right-inline">I. Lee and K. Lee, <span>“The <span>Internet</span> of <span>Things</span> (<span>IoT</span>): <span>Applications</span>, investments, and challenges for enterprises,”</span> <em>Business Horizons</em>, vol. 58, no. 4, pp. 431–440, Jul. 2015, doi: <a href="https://doi.org/10.1016/j.bushor.2015.03.008">10.1016/j.bushor.2015.03.008</a>.</div>
</div>
<div id="ref-elhadi_comparative_2018" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[13] </div><div class="csl-right-inline">S. Elhadi, A. Marzak, N. Sael, and S. Merzouk, <span>“Comparative <span>Study</span> of <span>IoT Protocols</span>,”</span> <span>Social Science Research Network</span>, <span>Rochester, NY</span>, SSRN Scholarly Paper ID 3186315, May 2018. doi: <a href="https://doi.org/10.2139/ssrn.3186315">10.2139/ssrn.3186315</a>.</div>
</div>
<div id="ref-foukalas_dependable_2019" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[14] </div><div class="csl-right-inline">F. Foukalas, P. Pop, F. Theoleyre, C. A. Boano, and C. Buratti, <span>“Dependable <span>Wireless Industrial IoT Networks</span>: <span>Recent Advances</span> and <span>Open Challenges</span>,”</span> in <em>2019 <span>IEEE European Test Symposium</span> (<span>ETS</span>)</em>, May 2019, pp. 1–10. doi: <a href="https://doi.org/10.1109/ETS.2019.8791551">10.1109/ETS.2019.8791551</a>.</div>
</div>
<div id="ref-noauthor_what_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[15] </div><div class="csl-right-inline"><span>“What <span>Edge Computing Means</span> for <span>Infrastructure</span> and <span>Operations Leaders</span>.”</span> <a href="https:////www.gartner.com/smarterwithgartner/what-edge-computing-means-for-infrastructure-and-operations-leaders/">//www.gartner.com/smarterwithgartner/what-edge-computing-means-for-infrastructure-and-operations-leaders/</a> (accessed May 06, 2021).</div>
</div>
<div id="ref-noauthor_real-time_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[16] </div><div class="csl-right-inline"><span>“Real-<span>Time Distributed Computing</span> at <span>Network Edges</span> for <span>Large Scale Industrial IoT Networks</span>.”</span> <a href="https://ieeexplore.ieee.org/abstract/document/8495797?casa_token=CHZD9tpi9_cAAAAA:saG8dFLJX9KMntLMllGoBLn5JZWpOs8cAv0sJu9oPZINmQ3qzV5ecEDQzByUTTupjNtl_MkOfRc">https://ieeexplore.ieee.org/abstract/document/8495797?casa_token=CHZD9tpi9_cAAAAA:saG8dFLJX9KMntLMllGoBLn5JZWpOs8cAv0sJu9oPZINmQ3qzV5ecEDQzByUTTupjNtl_MkOfRc</a> (accessed May 04, 2021).</div>
</div>
<div id="ref-gubbi_internet_2013" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[17] </div><div class="csl-right-inline">J. Gubbi, R. Buyya, S. Marusic, and M. Palaniswami, <span>“Internet of <span>Things</span> (<span>IoT</span>): <span>A</span> vision, architectural elements, and future directions,”</span> <em>Future Generation Computer Systems</em>, vol. 29, no. 7, pp. 1645–1660, Sep. 2013, doi: <a href="https://doi.org/10.1016/j.future.2013.01.010">10.1016/j.future.2013.01.010</a>.</div>
</div>
<div id="ref-graydon_project_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[18] </div><div class="csl-right-inline">graydon, <span>“Project <span>Servo</span>.”</span> Available: <a href="http://venge.net/graydon/talks/intro-talk-2.pdf">http://venge.net/graydon/talks/intro-talk-2.pdf</a></div>
</div>
<div id="ref-noauthor_quantum_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[19] </div><div class="csl-right-inline"><span>“Quantum - <span>MozillaWiki</span>.”</span> <a href="https://wiki.mozilla.org/Quantum">https://wiki.mozilla.org/Quantum</a> (accessed May 13, 2021).</div>
</div>
<div id="ref-noauthor_rustreleasesmd_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[20] </div><div class="csl-right-inline"><span>“Rust/<span>RELEASES</span>.md at master · rust-lang/rust.”</span> <a href="https://github.com/rust-lang/rust/blob/master/RELEASES.md">https://github.com/rust-lang/rust/blob/master/RELEASES.md</a> (accessed May 13, 2021).</div>
</div>
<div id="ref-noauthor_stack_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[21] </div><div class="csl-right-inline"><span>“Stack <span>Overflow Developer Survey</span> 2020.”</span> <a href="https://insights.stackoverflow.com/survey/2020/?utm_source=social-share&amp;utm_medium=social&amp;utm_campaign=dev-survey-2020">https://insights.stackoverflow.com/survey/2020/?utm_source=social-share&amp;utm_medium=social&amp;utm_campaign=dev-survey-2020</a> (accessed May 03, 2021).</div>
</div>
<div id="ref-goulding_what_2020" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[22] </div><div class="csl-right-inline">J. Goulding, <span>“What is <span>Rust</span> and why is it so popular?”</span> Jan. 20, 2020. <a href="https://stackoverflow.blog/2020/01/20/what-is-rust-and-why-is-it-so-popular/">https://stackoverflow.blog/2020/01/20/what-is-rust-and-why-is-it-so-popular/</a> (accessed May 13, 2021).</div>
</div>
<div id="ref-noauthor_rust_nodate-2" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[23] </div><div class="csl-right-inline"><span>“Rust in the <span>Linux</span> kernel.”</span> <a href="https://security.googleblog.com/2021/04/rust-in-linux-kernel.html">https://security.googleblog.com/2021/04/rust-in-linux-kernel.html</a> (accessed May 04, 2021).</div>
</div>
<div id="ref-noauthor_introduction_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[24] </div><div class="csl-right-inline"><span>“Introduction - <span>Discovery</span>.”</span> <a href="https://docs.rust-embedded.org/discovery/">https://docs.rust-embedded.org/discovery/</a> (accessed May 04, 2021).</div>
</div>
<div id="ref-noauthor_external_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[25] </div><div class="csl-right-inline"><span>“External <span>Tools</span> - <span>The Cargo Book</span>.”</span> <a href="https://doc.rust-lang.org/cargo/reference/external-tools.html">https://doc.rust-lang.org/cargo/reference/external-tools.html</a> (accessed May 13, 2021).</div>
</div>
<div id="ref-noauthor_cratesio_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[26] </div><div class="csl-right-inline"><span>“Crates.io: <span>Rust Package Registry</span>.”</span> <a href="https://crates.io/">https://crates.io/</a> (accessed May 05, 2021).</div>
</div>
<div id="ref-corob-msft_overview_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[27] </div><div class="csl-right-inline">corob-msft, <span>“Overview of modules in <span>C</span>++.”</span> <a href="https://docs.microsoft.com/en-us/cpp/cpp/modules-cpp">https://docs.microsoft.com/en-us/cpp/cpp/modules-cpp</a> (accessed May 05, 2021).</div>
</div>
<div id="ref-noauthor_npm_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[28] </div><div class="csl-right-inline"><span>“Npm.”</span> <a href="https://www.npmjs.com/">https://www.npmjs.com/</a> (accessed May 05, 2021).</div>
</div>
<div id="ref-noauthor_who_2020" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[29] </div><div class="csl-right-inline"><span>“Who is the <span>World</span>’s <span>Leading IoT Chipmaker</span>?”</span> Sep. 13, 2020. <a href="https://www.nanalyze.com/2020/09/worlds-leading-iot-chipmaker/">https://www.nanalyze.com/2020/09/worlds-leading-iot-chipmaker/</a> (accessed May 05, 2021).</div>
</div>
<div id="ref-noauthor_platform_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[30] </div><div class="csl-right-inline"><span>“Platform <span>Support</span> - <span>The</span> rustc book.”</span> <a href="https://doc.rust-lang.org/nightly/rustc/platform-support.html">https://doc.rust-lang.org/nightly/rustc/platform-support.html</a> (accessed May 05, 2021).</div>
</div>
<div id="ref-noauthor_introduction_nodate-2" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[31] </div><div class="csl-right-inline"><span>“Introduction - <span>The</span> rustup book.”</span> <a href="https://rust-lang.github.io/rustup/">https://rust-lang.github.io/rustup/</a> (accessed May 06, 2021).</div>
</div>
<div id="ref-noauthor_rust-embeddedcross_2021" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[32] </div><div class="csl-right-inline"><em>Rust-embedded/cross</em>. <span>Rust Embedded</span>, 2021. Accessed: May 13, 2021. [Online]. Available: <a href="https://github.com/rust-embedded/cross">https://github.com/rust-embedded/cross</a></div>
</div>
<div id="ref-noauthor_knurling-rs_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[33] </div><div class="csl-right-inline"><span>“Knurling-rs.”</span> <a href="https://knurling.ferrous-systems.com/">https://knurling.ferrous-systems.com/</a> (accessed May 13, 2021).</div>
</div>
<div id="ref-noauthor_using_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[34] </div><div class="csl-right-inline"><span>“Using <span>GDB</span> and defmt to debug embedded programs.”</span> <a href="https://ferrous-systems.com/blog/gdb-and-defmt/">https://ferrous-systems.com/blog/gdb-and-defmt/</a> (accessed May 06, 2021).</div>
</div>
<div id="ref-noauthor_svd_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[35] </div><div class="csl-right-inline"><span>“<span>SVD Description</span> (*.svd) <span>Format</span>.”</span> <a href="https://www.keil.com/pack/doc/CMSIS/SVD/html/svd_Format_pg.html">https://www.keil.com/pack/doc/CMSIS/SVD/html/svd_Format_pg.html</a> (accessed May 06, 2021).</div>
</div>
<div id="ref-noauthor_rust-embeddedsvd2rust_2021" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[36] </div><div class="csl-right-inline"><em>Rust-embedded/Svd2rust</em>. <span>Rust Embedded</span>, 2021. Accessed: May 13, 2021. [Online]. Available: <a href="https://github.com/rust-embedded/svd2rust">https://github.com/rust-embedded/svd2rust</a></div>
</div>
<div id="ref-noauthor_embedded_hal_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[37] </div><div class="csl-right-inline"><span>“Embedded_hal - <span>Rust</span>.”</span> <a href="https://docs.rs/embedded-hal/0.2.5/embedded_hal/index.html">https://docs.rs/embedded-hal/0.2.5/embedded_hal/index.html</a> (accessed May 06, 2021).</div>
</div>
<div id="ref-noauthor_ieee_2018" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[38] </div><div class="csl-right-inline"><span>“<span>IEEE Standard</span> for <span>Information</span> technology–<span>Telecommunications</span> and information exchange between systems <span>Local</span> and metropolitan area network–<span>Specific</span> requirements <span>Part</span> 11: <span>Wireless LAN Medium Access Control</span> (<span>MAC</span>) and <span>Physical Layer</span> (<span>PHY</span>) <span>Specifications Amendment</span> 5: <span>Preassociation Discovery</span>,”</span> <em>IEEE Std 802.11aq-2018 (Amendment to IEEE Std 802.11-2016 as amended by IEEE Std 802.11ai-2016, IEEE Std 802.11ah-2016, IEEE Std 802.11aj-2018, and IEEE Std 802.11ak-2018)</em>, pp. 1–69, Aug. 2018, doi: <a href="https://doi.org/10.1109/IEEESTD.2018.8457463">10.1109/IEEESTD.2018.8457463</a>.</div>
</div>
<div id="ref-noauthor_hayes_2021" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[39] </div><div class="csl-right-inline"><span>“Hayes command set,”</span> <em>Wikipedia</em>. May 04, 2021. Accessed: May 06, 2021. [Online]. Available: <a href="https://en.wikipedia.org/w/index.php?title=Hayes_command_set&amp;oldid=1021310741">https://en.wikipedia.org/w/index.php?title=Hayes_command_set&amp;oldid=1021310741</a></div>
</div>
<div id="ref-noauthor_blackbirdhqatat_2021" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[40] </div><div class="csl-right-inline"><em><span>BlackbirdHQ</span>/atat</em>. <span>Blackbird</span>, 2021. Accessed: May 13, 2021. [Online]. Available: <a href="https://github.com/BlackbirdHQ/atat">https://github.com/BlackbirdHQ/atat</a></div>
</div>
<div id="ref-noauthor_blackbirdhqublox-cellular-rs_2021" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[41] </div><div class="csl-right-inline"><em><span>BlackbirdHQ</span>/ublox-cellular-rs</em>. <span>Blackbird</span>, 2021. Accessed: May 06, 2021. [Online]. Available: <a href="https://github.com/BlackbirdHQ/ublox-cellular-rs">https://github.com/BlackbirdHQ/ublox-cellular-rs</a></div>
</div>
<div id="ref-noauthor_blackbirdhqublox-short-range-rs_2021" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[42] </div><div class="csl-right-inline"><em><span>BlackbirdHQ</span>/ublox-short-range-rs</em>. <span>Blackbird</span>, 2021. Accessed: May 06, 2021. [Online]. Available: <a href="https://github.com/BlackbirdHQ/ublox-short-range-rs">https://github.com/BlackbirdHQ/ublox-short-range-rs</a></div>
</div>
<div id="ref-noauthor_u-blox_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[43] </div><div class="csl-right-inline"><span>“U-blox.”</span> <a href="https://www.u-blox.com/en">https://www.u-blox.com/en</a> (accessed May 06, 2021).</div>
</div>
<div id="ref-noauthor_drogue_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[44] </div><div class="csl-right-inline"><span>“Drogue <span>IoT</span>.”</span> <a href="https://github.com/drogue-iot">https://github.com/drogue-iot</a> (accessed May 13, 2021).</div>
</div>
<div id="ref-noauthor_things_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[45] </div><div class="csl-right-inline"><span>“The <span>Things Network</span>.”</span> <a href="https://thethingsnetwork.org/">https://thethingsnetwork.org/</a> (accessed May 06, 2021).</div>
</div>
<div id="ref-noauthor_webassembly_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[46] </div><div class="csl-right-inline"><span>“<span>WebAssembly</span>.”</span> <a href="https://webassembly.org/">https://webassembly.org/</a> (accessed May 10, 2021).</div>
</div>
<div id="ref-noauthor_wasmeriowasmer_2021" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[47] </div><div class="csl-right-inline"><em>Wasmerio/wasmer</em>. <span>Wasmer</span>, 2021. Accessed: May 13, 2021. [Online]. Available: <a href="https://github.com/wasmerio/wasmer">https://github.com/wasmerio/wasmer</a></div>
</div>
<div id="ref-noauthor_bytecodealliancewasmtime_2021" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[48] </div><div class="csl-right-inline"><em>Bytecodealliance/wasmtime</em>. <span>Bytecode Alliance</span>, 2021. Accessed: May 13, 2021. [Online]. Available: <a href="https://github.com/bytecodealliance/wasmtime">https://github.com/bytecodealliance/wasmtime</a></div>
</div>
<div id="ref-noauthor_bytecodealliancelucet_2021" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[49] </div><div class="csl-right-inline"><em>Bytecodealliance/lucet</em>. <span>Bytecode Alliance</span>, 2021. Accessed: May 13, 2021. [Online]. Available: <a href="https://github.com/bytecodealliance/lucet">https://github.com/bytecodealliance/lucet</a></div>
</div>
<div id="ref-noauthor_rustwasmwasm-pack_2021" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[50] </div><div class="csl-right-inline"><em>Rustwasm/wasm-pack</em>. <span>Rust and WebAssembly</span>, 2021. Accessed: May 13, 2021. [Online]. Available: <a href="https://github.com/rustwasm/wasm-pack">https://github.com/rustwasm/wasm-pack</a></div>
</div>
<div id="ref-noauthor_rustwasmwasm-bindgen_2021" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[51] </div><div class="csl-right-inline"><em>Rustwasm/wasm-bindgen</em>. <span>Rust and WebAssembly</span>, 2021. Accessed: May 13, 2021. [Online]. Available: <a href="https://github.com/rustwasm/wasm-bindgen">https://github.com/rustwasm/wasm-bindgen</a></div>
</div>
<div id="ref-noauthor_cloudflare_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[52] </div><div class="csl-right-inline"><span>“Cloudflare <span>Workers</span>®.”</span> <a href="https://workers.cloudflare.com/">https://workers.cloudflare.com/</a> (accessed May 10, 2021).</div>
</div>
<div id="ref-noauthor_areweyet_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[53] </div><div class="csl-right-inline"><span>“Areweyet - <span>MozillaWiki</span>.”</span> <a href="https://wiki.mozilla.org/Areweyet">https://wiki.mozilla.org/Areweyet</a> (accessed May 13, 2021).</div>
</div>
<div id="ref-noauthor_are_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[54] </div><div class="csl-right-inline"><span>“Are we web yet? <span>Yes</span>, and it’s freaking fast!”</span> <a href="https://www.arewewebyet.org/">https://www.arewewebyet.org/</a> (accessed May 13, 2021).</div>
</div>
<div id="ref-noauthor_webassembly_nodate-1" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[55] </div><div class="csl-right-inline"><span>“<span>WebAssembly</span> » <span>AWWY</span>?”</span> <a href="https://www.arewewebyet.org/topics/webassembly/">https://www.arewewebyet.org/topics/webassembly/</a> (accessed May 10, 2021).</div>
</div>
<div id="ref-noauthor_what_nodate-2" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[56] </div><div class="csl-right-inline"><span>“What is rustdoc? - <span>The</span> rustdoc book.”</span> <a href="https://doc.rust-lang.org/rustdoc/index.html">https://doc.rust-lang.org/rustdoc/index.html</a> (accessed May 10, 2021).</div>
</div>
<div id="ref-noauthor_docsrs_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[57] </div><div class="csl-right-inline"><span>“Docs.rs.”</span> <a href="https://docs.rs/">https://docs.rs/</a> (accessed May 10, 2021).</div>
</div>
<div id="ref-noauthor_mdbook_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[58] </div><div class="csl-right-inline"><span>“<span class="nocase">mdBook</span> - <span class="nocase">mdBook Documentation</span>.”</span> <a href="https://rust-lang.github.io/mdBook/">https://rust-lang.github.io/mdBook/</a> (accessed May 10, 2021).</div>
</div>
<div id="ref-noauthor_preface_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[59] </div><div class="csl-right-inline"><span>“Preface - <span class="nocase">Real-Time Interrupt-driven Concurrency</span>.”</span> <a href="https://rtic.rs/0.5/book/en/">https://rtic.rs/0.5/book/en/</a> (accessed May 10, 2021).</div>
</div>
<div id="ref-noauthor_laying_nodate" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[60] </div><div class="csl-right-inline"><span>“Laying the foundation for <span>Rust</span>’s future | <span>Rust Blog</span>.”</span> <a href="https://blog.rust-lang.org/2020/08/18/laying-the-foundation-for-rusts-future.html">https://blog.rust-lang.org/2020/08/18/laying-the-foundation-for-rusts-future.html</a> (accessed May 03, 2021).</div>
</div>
</div>
</div>]]></summary>
</entry>
<entry>
    <title>Hooking up with Git</title>
    <link href="https://blog.ysndr.de/posts/code/2021-12-02-git-hooks/index.html" />
    <id>https://blog.ysndr.de/posts/code/2021-12-02-git-hooks/index.html</id>
    <published>2021-12-02T00:00:00Z</published>
    <updated>2021-12-02T00:00:00Z</updated>
    <summary type="html"><![CDATA[<h1 class="y-header" id="git-hooks">
<span>Git hooks</span><a href="#git-hooks" class="anchor las la-anchor" title="git-hooks"></a>
</h1>
<p>
Git hooks are very useful in theory e.g. to enforce style guidelines of code being pushed or doing arbitrary cleanup/analysis in response to various git events. Yet, if you are using nix, the way git hooks are set up and managed goes against the ideas of Nix.
</p>
<p>
The presented approach does not solve the underlying issue of mutability but makes git-hooks more trackable and easily appliable.
</p>
<div class="uk-alert-primary note box y-fill-horizontal" data-header="Flake">
<div class="header">
<div>
<span class="las la-pencil-alt"></span>
<div class="badge">
<p>NOTE</p>
</div>
</div>
<div>
<p>
Flake
</p>
</div>
</div>
<p>
An up-to-date version of the presented approach can be <a href="https://github.com/ysndr/nix-git-hooks">found on GitHub</a>.
</p>
<p>
Please file issues or PRs if you like the project and want to contribute.
</p>
</div>
<h1 class="y-header" id="the-big-picture">
<span>The big picture</span><a href="#the-big-picture" class="anchor las la-anchor" title="the-big-picture"></a>
</h1>
<p>
Let me present a full-fledged example first, the functions are individually posted down in the <a href="#appendix">appendix</a>.
</p>
<div class="y-fill-horizontal">
<div id="cb1" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="bu">let</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>    <span class="ex">installGitHooks</span> = hookTypes:</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>        <span class="bu">let</span> <span class="va">mkHook</span> <span class="op">=</span> <span class="va">type</span><span class="op">:</span> <span class="va">hooks</span><span class="op">:</span> {</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>        <span class="ex">hook</span> = pkgs.writeShellScript type</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>        <span class="st">&#39;&#39;</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>            <span class="cf">for</span> hook <span class="kw">in</span> <span class="va">${pkgs</span><span class="er">.symlinkJoin { name = &quot;${type</span><span class="va">}</span>-git-hooks<span class="st">&quot;; paths = hooks; }}/bin/*; do</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="st">            </span><span class="va">$hook</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="st">            RESULT=</span><span class="va">$?</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="st">            if [ </span><span class="va">$RESULT</span><span class="st"> != 0 ]; then</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="st">                echo &quot;</span><span class="va">$hook</span> returned non-zero: <span class="va">$RESULT</span>, abort operation<span class="st">&quot;</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="st">            exit </span><span class="va">$RESULT</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a><span class="st">            fi</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a><span class="st">            done</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a><span class="st">            echo &quot;</span><span class="va">$INSTALLED_GIT_HOOKS</span> <span class="va">$type</span><span class="st">&quot;</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a><span class="st">            exit 0</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a><span class="st">        &#39;&#39;;</span></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a><span class="st">        inherit type;</span></span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a><span class="st">        };</span></span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a><span class="st">        installHookScript = { type, hook }: &#39;&#39;</span></span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a><span class="st">            if [[ -e .git/hooks/</span><span class="va">${type}</span><span class="st"> ]]; then</span></span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a><span class="st">                echo &quot;</span>Warn: <span class="va">${type}</span> hook already present, skipping<span class="st">&quot;</span></span>
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a><span class="st">            else</span></span>
<span id="cb1-24"><a href="#cb1-24" aria-hidden="true" tabindex="-1"></a><span class="st">                ln -s </span><span class="va">${hook}</span><span class="st"> </span><span class="va">$PWD</span><span class="st">/.git/hooks/</span><span class="va">${type}</span></span>
<span id="cb1-25"><a href="#cb1-25" aria-hidden="true" tabindex="-1"></a><span class="st">                INSTALLED_GIT_HOOKS+=(</span><span class="va">${type}</span><span class="st">)</span></span>
<span id="cb1-26"><a href="#cb1-26" aria-hidden="true" tabindex="-1"></a><span class="st">            fi</span></span>
<span id="cb1-27"><a href="#cb1-27" aria-hidden="true" tabindex="-1"></a><span class="st">        &#39;&#39;;</span></span>
<span id="cb1-28"><a href="#cb1-28" aria-hidden="true" tabindex="-1"></a><span class="st">        in</span></span>
<span id="cb1-29"><a href="#cb1-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-30"><a href="#cb1-30" aria-hidden="true" tabindex="-1"></a><span class="st">        pkgs.writeShellScriptBin &quot;</span>install-git-hooks<span class="st">&quot; </span></span>
<span id="cb1-31"><a href="#cb1-31" aria-hidden="true" tabindex="-1"></a><span class="st">        &#39;&#39;</span></span>
<span id="cb1-32"><a href="#cb1-32" aria-hidden="true" tabindex="-1"></a><span class="st">            if [[ ! -d .git ]] || [[ ! -f flake.nix ]]; then</span></span>
<span id="cb1-33"><a href="#cb1-33" aria-hidden="true" tabindex="-1"></a><span class="st">                echo &quot;</span>Invocate <span class="dt">\`</span>nix develop<span class="dt">\`</span> from the project root directory.<span class="st">&quot;</span></span>
<span id="cb1-34"><a href="#cb1-34" aria-hidden="true" tabindex="-1"></a><span class="st">                exit 1</span></span>
<span id="cb1-35"><a href="#cb1-35" aria-hidden="true" tabindex="-1"></a><span class="st">            fi</span></span>
<span id="cb1-36"><a href="#cb1-36" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-37"><a href="#cb1-37" aria-hidden="true" tabindex="-1"></a><span class="st">            if [[ -e .git/hooks/nix-installed-hooks ]]; then</span></span>
<span id="cb1-38"><a href="#cb1-38" aria-hidden="true" tabindex="-1"></a><span class="st">                echo &quot;</span>Hooks already installed, reinstalling<span class="st">&quot;</span></span>
<span id="cb1-39"><a href="#cb1-39" aria-hidden="true" tabindex="-1"></a><span class="st">                </span><span class="va">${uninstallGitHooks}</span><span class="st">/bin/</span><span class="va">${uninstallGitHooks</span><span class="er">.name</span><span class="va">}</span></span>
<span id="cb1-40"><a href="#cb1-40" aria-hidden="true" tabindex="-1"></a><span class="st">            fi</span></span>
<span id="cb1-41"><a href="#cb1-41" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-42"><a href="#cb1-42" aria-hidden="true" tabindex="-1"></a><span class="st">            mkdir -p ./.git/hooks</span></span>
<span id="cb1-43"><a href="#cb1-43" aria-hidden="true" tabindex="-1"></a><span class="st">            </span></span>
<span id="cb1-44"><a href="#cb1-44" aria-hidden="true" tabindex="-1"></a><span class="st">            </span><span class="va">${pkgs</span><span class="er">.lib.concatStringsSep &quot;\n&quot; (pkgs.lib.mapAttrsToList (type: hooks: installHookScript (mkHook type hooks)) hookTypes )</span><span class="va">}</span></span>
<span id="cb1-45"><a href="#cb1-45" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-46"><a href="#cb1-46" aria-hidden="true" tabindex="-1"></a><span class="st">            echo &quot;</span>Installed git hooks: <span class="va">$INSTALLED_GIT_HOOKS</span><span class="st">&quot;</span></span>
<span id="cb1-47"><a href="#cb1-47" aria-hidden="true" tabindex="-1"></a><span class="st">            printf &quot;</span>%s<span class="dt">\n</span><span class="st">&quot; &quot;&#39;&#39;</span><span class="va">${INSTALLED_GIT_HOOKS</span><span class="op">[@]</span><span class="va">}</span><span class="st">&quot; &gt; .git/hooks/nix-installed-hooks</span></span>
<span id="cb1-48"><a href="#cb1-48" aria-hidden="true" tabindex="-1"></a><span class="st">        &#39;&#39;;</span></span>
<span id="cb1-49"><a href="#cb1-49" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-50"><a href="#cb1-50" aria-hidden="true" tabindex="-1"></a><span class="st">    uninstallGitHooks = pkgs.writeShellScriptBin &quot;</span>uninstall-git-hooks<span class="st">&quot; </span></span>
<span id="cb1-51"><a href="#cb1-51" aria-hidden="true" tabindex="-1"></a><span class="st">        &#39;&#39;</span></span>
<span id="cb1-52"><a href="#cb1-52" aria-hidden="true" tabindex="-1"></a><span class="st">            if [[ ! -e &quot;</span><span class="va">$PWD</span>/.git/hooks/nix-installed-hooks<span class="st">&quot; ]]; then</span></span>
<span id="cb1-53"><a href="#cb1-53" aria-hidden="true" tabindex="-1"></a><span class="st">            echo &quot;</span>Error: could find list of installed hooks.<span class="st">&quot;</span></span>
<span id="cb1-54"><a href="#cb1-54" aria-hidden="true" tabindex="-1"></a><span class="st">            exit 1</span></span>
<span id="cb1-55"><a href="#cb1-55" aria-hidden="true" tabindex="-1"></a><span class="st">            fi</span></span>
<span id="cb1-56"><a href="#cb1-56" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-57"><a href="#cb1-57" aria-hidden="true" tabindex="-1"></a><span class="st">            while read -r hook</span></span>
<span id="cb1-58"><a href="#cb1-58" aria-hidden="true" tabindex="-1"></a><span class="st">            do</span></span>
<span id="cb1-59"><a href="#cb1-59" aria-hidden="true" tabindex="-1"></a><span class="st">            echo &quot;</span>Uninstalling <span class="va">$hook</span><span class="st">&quot;</span></span>
<span id="cb1-60"><a href="#cb1-60" aria-hidden="true" tabindex="-1"></a><span class="st">            rm &quot;</span><span class="va">$PWD</span>/.git/hooks/<span class="va">$hook</span><span class="st">&quot;</span></span>
<span id="cb1-61"><a href="#cb1-61" aria-hidden="true" tabindex="-1"></a><span class="st">            done &lt; &quot;</span><span class="va">$PWD</span>/.git/hooks/nix-installed-hooks<span class="st">&quot;</span></span>
<span id="cb1-62"><a href="#cb1-62" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-63"><a href="#cb1-63" aria-hidden="true" tabindex="-1"></a><span class="st">            rm &quot;</span><span class="va">$PWD</span>/.git/hooks/nix-installed-hooks<span class="st">&quot;</span></span>
<span id="cb1-64"><a href="#cb1-64" aria-hidden="true" tabindex="-1"></a><span class="st">        &#39;&#39;;</span></span>
<span id="cb1-65"><a href="#cb1-65" aria-hidden="true" tabindex="-1"></a><span class="st">    </span></span>
<span id="cb1-66"><a href="#cb1-66" aria-hidden="true" tabindex="-1"></a><span class="st">    rustFormatHook = pkgs.writeShellScriptBin &quot;</span>check-rust-format-hook<span class="st">&quot;</span></span>
<span id="cb1-67"><a href="#cb1-67" aria-hidden="true" tabindex="-1"></a><span class="st">        &#39;&#39;</span></span>
<span id="cb1-68"><a href="#cb1-68" aria-hidden="true" tabindex="-1"></a><span class="st">            </span><span class="va">${pkgs</span><span class="er">.rustfmt</span><span class="va">}</span><span class="st">/bin/rustfmt --check</span></span>
<span id="cb1-69"><a href="#cb1-69" aria-hidden="true" tabindex="-1"></a><span class="st">            RESULT=</span><span class="va">$?</span></span>
<span id="cb1-70"><a href="#cb1-70" aria-hidden="true" tabindex="-1"></a><span class="st">            [ </span><span class="va">$RESULT</span><span class="st"> != 0 ] &amp;&amp; echo &quot;</span>Please run <span class="dt">\`</span>cargo fmt<span class="dt">\`</span> before<span class="st">&quot;</span></span>
<span id="cb1-71"><a href="#cb1-71" aria-hidden="true" tabindex="-1"></a><span class="st">            exit </span><span class="va">$RESULT</span></span>
<span id="cb1-72"><a href="#cb1-72" aria-hidden="true" tabindex="-1"></a><span class="st">        &#39;&#39;;</span></span>
<span id="cb1-73"><a href="#cb1-73" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-74"><a href="#cb1-74" aria-hidden="true" tabindex="-1"></a><span class="st">    hookInstaller =  installGitHooks { pre-commit = [rustFormatHook]; } </span></span>
<span id="cb1-75"><a href="#cb1-75" aria-hidden="true" tabindex="-1"></a><span class="st">in </span></span>
<span id="cb1-76"><a href="#cb1-76" aria-hidden="true" tabindex="-1"></a><span class="st">    pkgs.mkShell {</span></span>
<span id="cb1-77"><a href="#cb1-77" aria-hidden="true" tabindex="-1"></a><span class="st">        packages = [ (installGitHooks { pre-commit = [rustFormatHook];) } uninstallGitHooks ];</span></span>
<span id="cb1-78"><a href="#cb1-78" aria-hidden="true" tabindex="-1"></a><span class="st">        inputsFrom = [ ];</span></span>
<span id="cb1-79"><a href="#cb1-79" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-80"><a href="#cb1-80" aria-hidden="true" tabindex="-1"></a><span class="st">        shellHook = &#39;&#39;</span></span>
<span id="cb1-81"><a href="#cb1-81" aria-hidden="true" tabindex="-1"></a><span class="st">            echo &quot;</span>=== Development shell ===<span class="st">&quot;</span></span>
<span id="cb1-82"><a href="#cb1-82" aria-hidden="true" tabindex="-1"></a><span class="st">            echo &quot;</span>Info: Git hooks can be installed using <span class="dt">\`</span>install-git-hooks<span class="dt">\`</span><span class="st">&quot;</span></span>
<span id="cb1-83"><a href="#cb1-83" aria-hidden="true" tabindex="-1"></a><span class="st">            # or run </span><span class="kw">`</span><span class="ex">install-git-hooks</span><span class="kw">`</span><span class="st"> automatically</span></span>
<span id="cb1-84"><a href="#cb1-84" aria-hidden="true" tabindex="-1"></a><span class="st">        &#39;&#39;;</span></span>
<span id="cb1-85"><a href="#cb1-85" aria-hidden="true" tabindex="-1"></a><span class="st">    };</span></span></code></pre>
</div>
</div>
<h1 class="y-header" id="explanation">
<span>Explanation</span><a href="#explanation" class="anchor las la-anchor" title="explanation"></a>
</h1>
<p>
The above code defines functions to build installation and uninstallation commands for git hooks.
</p>
<p>
To run a hook, create a derivation with the hook (or hooks) for one event located in the <code>bin/</code> folder, i.e. using. <code>writeShellScriptBin</code> :
</p>
<div class="y-fill-horizontal">
<div id="cb2" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="ex">rustFormatHook</span> = pkgs.writeShellScriptBin <span class="st">&quot;check-rust-format-hook&quot;</span> <span class="st">&#39;&#39;</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>    <span class="va">${pkgs</span><span class="er">.rustfmt</span><span class="va">}</span><span class="ex">/bin/rustfmt</span> <span class="at">--check</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="st">&#39;&#39;</span><span class="kw">;</span></span></code></pre>
</div>
</div>
<p>
Then create a <code>hookInstaller</code> by adding the derivation to a list of hooks for a specific event type:
</p>
<div class="y-fill-horizontal">
<div id="cb3" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ex">hookInstaller</span> =  installGitHooks { pre-commit = [rustFormatHook]<span class="kw">;</span> <span class="er">}</span> </span></code></pre>
</div>
</div>
<p>
This will run all commands under <code>${rustFormatHook}/bin/*</code> for <code>pre-commit</code> events.
</p>
<p>
The event types can be arbitrary but have to comply with <a href="https://git-scm.com/docs/githooks">actual git hooks</a> to be run.
</p>
<p>
Finally, add the installer (and optionally the uninstall-command) to your dev shell as input programs. You can choose to automatically run the installer at entrance to the shell as a <code>shellHook</code> or manually by the user.
</p>
<div class="y-fill-horizontal">
<div id="cb4" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ex">pkgs.mkShell</span> {</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>    <span class="ex">packages</span> = [ hookInstaller uninstallGitHooks ]<span class="kw">;</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>    <span class="ex">inputsFrom</span> = [ ]<span class="kw">;</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>    <span class="ex">shellHook</span> = <span class="st">&#39;&#39;</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>        <span class="bu">echo</span> <span class="st">&quot;=== Development shell ===&quot;</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>        <span class="bu">echo</span> <span class="st">&quot;Info: Git hooks can be installed using </span><span class="dt">\`</span><span class="st">install-git-hooks</span><span class="dt">\`</span><span class="st">&quot;</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>        <span class="co"># or run `install-git-hooks` automatically</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>    <span class="st">&#39;&#39;</span><span class="kw">;</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="er">}</span><span class="kw">;</span></span></code></pre>
</div>
</div>
<h1 class="y-header" id="clarification">
<span>Clarification</span><a href="#clarification" class="anchor las la-anchor" title="clarification"></a>
</h1>
<p>
I am aware that there is <a href="https://github.com/cachix/pre-commit-hooks.nix">much more advanced tools</a> available with more advanced configuration systems etc. Yet, this approach is nix-native and sufficiently flexible for simple hook setups. It does still require you to write all hooks yourself but this way they can be tracked with nix and in theory make use of programs not even populated to the final environment.
</p>
<p>
Nonetheless, this might be of interest for someone and if so thanks for reading.
</p>
<h1 class="y-header" id="appendix">
<span>Appendix</span><a href="#appendix" class="anchor las la-anchor" title="appendix"></a>
</h1>
<p>
Copy the respective functions here to include them into your project or checkout the <a href="https://github.com/ysndr/nix-git-hooks">repository on GitHub</a> avoid copy-pasting and receive upstream bugfixes. ## Installer
</p>
<div class="y-fill-horizontal">
<div id="cb5" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="ex">installGitHooks</span> = hookTypes:</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>    <span class="bu">let</span> <span class="va">mkHook</span> <span class="op">=</span> <span class="va">type</span><span class="op">:</span> <span class="va">hooks</span><span class="op">:</span> {</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>    <span class="ex">hook</span> = pkgs.writeShellScript type</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>    <span class="st">&#39;&#39;</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>        <span class="cf">for</span> hook <span class="kw">in</span> <span class="va">${pkgs</span><span class="er">.symlinkJoin { name = &quot;${type</span><span class="va">}</span>-git-hooks<span class="st">&quot;; paths = hooks; }}/bin/*; do</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="st">        </span><span class="va">$hook</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="st">        RESULT=</span><span class="va">$?</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a><span class="st">        if [ </span><span class="va">$RESULT</span><span class="st"> != 0 ]; then</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a><span class="st">            echo &quot;</span><span class="va">$hook</span> returned non-zero: <span class="va">$RESULT</span>, abort operation<span class="st">&quot;</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a><span class="st">        exit </span><span class="va">$RESULT</span></span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a><span class="st">        fi</span></span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a><span class="st">        done</span></span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a><span class="st">        echo &quot;</span><span class="va">$INSTALLED_GIT_HOOKS</span> <span class="va">$type</span><span class="st">&quot;</span></span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a><span class="st">        exit 0</span></span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a><span class="st">    &#39;&#39;;</span></span>
<span id="cb5-16"><a href="#cb5-16" aria-hidden="true" tabindex="-1"></a><span class="st">    inherit type;</span></span>
<span id="cb5-17"><a href="#cb5-17" aria-hidden="true" tabindex="-1"></a><span class="st">    };</span></span>
<span id="cb5-18"><a href="#cb5-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-19"><a href="#cb5-19" aria-hidden="true" tabindex="-1"></a><span class="st">    installHookScript = { type, hook }: &#39;&#39;</span></span>
<span id="cb5-20"><a href="#cb5-20" aria-hidden="true" tabindex="-1"></a><span class="st">        if [[ -e .git/hooks/</span><span class="va">${type}</span><span class="st"> ]]; then</span></span>
<span id="cb5-21"><a href="#cb5-21" aria-hidden="true" tabindex="-1"></a><span class="st">            echo &quot;</span>Warn: <span class="va">${type}</span> hook already present, skipping<span class="st">&quot;</span></span>
<span id="cb5-22"><a href="#cb5-22" aria-hidden="true" tabindex="-1"></a><span class="st">        else</span></span>
<span id="cb5-23"><a href="#cb5-23" aria-hidden="true" tabindex="-1"></a><span class="st">            ln -s </span><span class="va">${hook}</span><span class="st"> </span><span class="va">$PWD</span><span class="st">/.git/hooks/</span><span class="va">${type}</span></span>
<span id="cb5-24"><a href="#cb5-24" aria-hidden="true" tabindex="-1"></a><span class="st">            INSTALLED_GIT_HOOKS+=(</span><span class="va">${type}</span><span class="st">)</span></span>
<span id="cb5-25"><a href="#cb5-25" aria-hidden="true" tabindex="-1"></a><span class="st">        fi</span></span>
<span id="cb5-26"><a href="#cb5-26" aria-hidden="true" tabindex="-1"></a><span class="st">    &#39;&#39;;</span></span>
<span id="cb5-27"><a href="#cb5-27" aria-hidden="true" tabindex="-1"></a><span class="st">    in</span></span>
<span id="cb5-28"><a href="#cb5-28" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-29"><a href="#cb5-29" aria-hidden="true" tabindex="-1"></a><span class="st">    pkgs.writeShellScriptBin &quot;</span>install-git-hooks<span class="st">&quot; </span></span>
<span id="cb5-30"><a href="#cb5-30" aria-hidden="true" tabindex="-1"></a><span class="st">    &#39;&#39;</span></span>
<span id="cb5-31"><a href="#cb5-31" aria-hidden="true" tabindex="-1"></a><span class="st">        if [[ ! -d .git ]] || [[ ! -f flake.nix ]]; then</span></span>
<span id="cb5-32"><a href="#cb5-32" aria-hidden="true" tabindex="-1"></a><span class="st">            echo &quot;</span>Invocate <span class="dt">\`</span>nix develop<span class="dt">\`</span> from the project root directory.<span class="st">&quot;</span></span>
<span id="cb5-33"><a href="#cb5-33" aria-hidden="true" tabindex="-1"></a><span class="st">            exit 1</span></span>
<span id="cb5-34"><a href="#cb5-34" aria-hidden="true" tabindex="-1"></a><span class="st">        fi</span></span>
<span id="cb5-35"><a href="#cb5-35" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-36"><a href="#cb5-36" aria-hidden="true" tabindex="-1"></a><span class="st">        if [[ -e .git/hooks/nix-installed-hooks ]]; then</span></span>
<span id="cb5-37"><a href="#cb5-37" aria-hidden="true" tabindex="-1"></a><span class="st">            echo &quot;</span>Hooks already installed, reinstalling<span class="st">&quot;</span></span>
<span id="cb5-38"><a href="#cb5-38" aria-hidden="true" tabindex="-1"></a><span class="st">            </span><span class="va">${uninstallGitHooks}</span><span class="st">/bin/</span><span class="va">${uninstallGitHooks</span><span class="er">.name</span><span class="va">}</span></span>
<span id="cb5-39"><a href="#cb5-39" aria-hidden="true" tabindex="-1"></a><span class="st">        fi</span></span>
<span id="cb5-40"><a href="#cb5-40" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-41"><a href="#cb5-41" aria-hidden="true" tabindex="-1"></a><span class="st">        mkdir -p ./.git/hooks</span></span>
<span id="cb5-42"><a href="#cb5-42" aria-hidden="true" tabindex="-1"></a><span class="st">        </span></span>
<span id="cb5-43"><a href="#cb5-43" aria-hidden="true" tabindex="-1"></a><span class="st">        </span><span class="va">${pkgs</span><span class="er">.lib.concatStringsSep &quot;\n&quot; (pkgs.lib.mapAttrsToList (type: hooks: installHookScript (mkHook type hooks)) hookTypes )</span><span class="va">}</span></span>
<span id="cb5-44"><a href="#cb5-44" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-45"><a href="#cb5-45" aria-hidden="true" tabindex="-1"></a><span class="st">        echo &quot;</span>Installed git hooks: <span class="va">$INSTALLED_GIT_HOOKS</span><span class="st">&quot;</span></span>
<span id="cb5-46"><a href="#cb5-46" aria-hidden="true" tabindex="-1"></a><span class="st">        printf &quot;</span>%s<span class="dt">\n</span><span class="st">&quot; &quot;&#39;&#39;</span><span class="va">${INSTALLED_GIT_HOOKS</span><span class="op">[@]</span><span class="va">}</span><span class="st">&quot; &gt; .git/hooks/nix-installed-hooks</span></span>
<span id="cb5-47"><a href="#cb5-47" aria-hidden="true" tabindex="-1"></a><span class="st">    &#39;&#39;;</span></span></code></pre>
</div>
</div>
<h2 class="y-header" id="uninstaller">
<span>Uninstaller</span><a href="#uninstaller" class="anchor las la-anchor" title="uninstaller"></a>
</h2>
<div class="y-fill-horizontal">
<div id="cb6" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="ex">uninstallGitHooks</span> = pkgs.writeShellScriptBin <span class="st">&quot;uninstall-git-hooks&quot;</span> </span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>    <span class="st">&#39;&#39;</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>        <span class="cf">if</span> <span class="kw">[[</span> <span class="ot">!</span> <span class="ot">-e</span> <span class="st">&quot;</span><span class="va">$PWD</span><span class="st">/.git/hooks/nix-installed-hooks&quot;</span> <span class="kw">]];</span> <span class="cf">then</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>        <span class="bu">echo</span> <span class="st">&quot;Error: could find list of installed hooks.&quot;</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>        <span class="bu">exit</span> 1</span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>        <span class="cf">fi</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>        <span class="cf">while</span> <span class="bu">read</span> <span class="at">-r</span> <span class="va">hook</span></span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>        <span class="cf">do</span></span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a>        <span class="bu">echo</span> <span class="st">&quot;Uninstalling </span><span class="va">$hook</span><span class="st">&quot;</span></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a>        <span class="fu">rm</span> <span class="st">&quot;</span><span class="va">$PWD</span><span class="st">/.git/hooks/</span><span class="va">$hook</span><span class="st">&quot;</span></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a>        <span class="cf">done</span> <span class="op">&lt;</span> <span class="st">&quot;</span><span class="va">$PWD</span><span class="st">/.git/hooks/nix-installed-hooks&quot;</span></span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a>        <span class="fu">rm</span> <span class="st">&quot;</span><span class="va">$PWD</span><span class="st">/.git/hooks/nix-installed-hooks&quot;</span></span>
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a>    <span class="st">&#39;&#39;</span><span class="kw">;</span></span></code></pre>
</div>
</div>]]></summary>
</entry>
<entry>
    <title>One too many shell</title>
    <link href="https://blog.ysndr.de/posts/guides/2021-12-01-nix-shells/index.html" />
    <id>https://blog.ysndr.de/posts/guides/2021-12-01-nix-shells/index.html</id>
    <published>2021-12-01T00:00:00Z</published>
    <updated>2021-12-01T00:00:00Z</updated>
    <summary type="html"><![CDATA[<h1 class="y-header" id="a-new-nix-command">
<span>A new Nix command</span><a href="#a-new-nix-command" class="anchor las la-anchor" title="a-new-nix-command"></a>
</h1>
<p>
This post follows the <a href="https://discourse.nixos.org/t/nix-2-4-released/15822">release</a> of Nix 2.4, which among many other things introduced an all new (experimental) <code>nix</code> command along with the <a href="../internals/2021-01-01-flake-ification">previously discussed</a> flake feature.
</p>
<p>
The <code>nix</code> command aims to collect most common commands such as <code>nix-build</code>, <code>nix-copy-closure</code>, <code>nix-env</code>, … as subcommands of one common program. Unsurprisingly, this does not spare <code>nix-shell</code>.
</p>
<p>
Yet, unlike some of the other commands which received a more or less one-to-one replacement it is not so easy with <code>nix-shell</code>. This command was actually broken up into multiple commands with different semantics: <code>nix shell</code>, <code>nix develop</code> and <code>nix run</code>. Yet, depending on what you used <code>nix-shell</code> for in the past the new commands may not exactly do what you would expect. Indeed, they happen to cause quite some <a href="https://www.reddit.com/r/NixOS/comments/r15hx4/nix_shell_vs_nix_develop/">confusion</a> already. Most notably, while <code>nix-shell</code> invoked without any other flags previously set up the build environment of a derivation (which could be somewhat abused to define general development environments) that is <em>not</em> what <code>nix shell</code> will do…
</p>
<h1 class="y-header" id="what-the-shell">
<span>What the shell…<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a></span><a href="#what-the-shell" class="anchor las la-anchor" title="what-the-shell"></a>
</h1>
<p>
Yes, but from the start…
</p>
<p>
If you are here just for the commands you can read the tl;dr for <a href="#tldr-nix-develop"><code>nix develop</code></a>, <a href="#tldr-nix-shell"><code>nix shell</code></a>, or <a href="#tldr-nix-run"><code>nix run</code></a> directly or jump to the <a href="#notes-and-resources">notes</a> section.
</p>
<h2 class="y-header" id="development-shells-nix-shell-derivation">
<span>Development shells (<code>nix-shell [DERIVATION]</code>)</span><a href="#development-shells-nix-shell-derivation" class="anchor las la-anchor" title="development-shells-nix-shell-derivation"></a>
</h2>
<p>
Development shells using the new <code>nix</code> command are now created with <code>nix develop</code>.
</p>
<p>
That command is a more focused version with additional tools for development. It is meant to be used with flakes but supports standalone derivations using the <code>-f</code> flag. How to use it then and what will it do?
</p>
<h3 class="y-header" id="a-development-aid">
<span>A development aid</span><a href="#a-development-aid" class="anchor las la-anchor" title="a-development-aid"></a>
</h3>
<p>
The intended use of <code>nix develop</code> is to recreate build environments for single packages. That is, you call <code>nix develop nixpkgs#hello</code> and are dropped into a shell that is as close as possible to the nix builder environment.
</p>
<p>
<em>“yes,.. and?”</em>
</p>
<p>
This allows you to build a package step by step, or better phase by phase, meaning that in particular the build instructions used by nix can be reused for development purposes. Thus, we can use nix without needing to repeatedly go through full build processes, including wasteful copying, configuring, etc.
</p>
<p>
To make this process even easier, <code>nix develop</code> now comes with special arguments to run those phases directly.
</p>
<div id="tldr-nix-develop" class="uk-alert-primary note box y-fill-horizontal" data-header="tl;dr">
<div class="header">
<div>
<span class="las la-pencil-alt"></span>
<div class="badge">
<p>NOTE</p>
</div>
</div>
<div>
<p>
tl;dr
</p>
</div>
</div>
<p>
<code>nix develop</code> creates a shell with <em>all <code>buildInputs</code></em> and environment variables of a derivation loaded and <code>shellHook</code>s executed.
</p>
<p>
This allows to <em>run phases</em> individually in the shell using <code>$ unpackPhase</code>, <code>$ configurePhase</code> <code>$ buildPhase</code>, etc.
</p>
<p>
…or directly using <code>nix develop --&lt;PHASE&gt;</code> or <code>nix develop --phase PHASE</code> (for non-standard phases).
</p>
<p>
…or run an arbitrary command in the shell using <code>nix develop --command COMMAND [ARGS…]</code>
</p>
<p>
<strong>Why should you use this?</strong>
</p>
<p>
It is most useful for locally developed packages.
</p>
<p>
Use it to set up the environment using e.g. the <code>configurePhase</code> and perform the subsequent development using <code>build</code> and <code>check</code> phases. If your workflow includes things that are not part of a phase use <code>nix develop --command</code>
</p>
</div>
<p>
In essence, this is exactly what <code>nix-shell</code> was intended for!
</p>
<div class="uk-alert-warning warning box y-fill-horizontal" data-header="">
<div class="header">
<div>
<span class="las la-exclamation-circle"></span>
<div class="badge">
<p>WARN</p>
</div>
</div>
<div>

</div>
</div>
<p>
A slight annoyance with phases arises when the targeted derivation overrides standard phases, i.e. <code>{unpack,configure,build,install}Phase</code>s. As the default implementation in nix’s <code>stdenv</code> is done as functions, an internal use of <code>runHook</code> will give precedence to those functions over the overridden phases stored as environment variables.
</p>
<p>
<strong>Solution</strong>
</p>
<p>
Enter a shell using <code>nix develop</code> and run the overridden phases using <code>eval $buildPhase</code> or <code>--command eval ‘$buildPhase’</code>.
</p>
</div>
<p>
Practically, <code>nix-shell</code> was also used for another purpose; reproducible development environments.
</p>
<h3 class="y-header" id="development-environments">
<span>Development environments</span><a href="#development-environments" class="anchor las la-anchor" title="development-environments"></a>
</h3>
<p>
Particularly useful combined with tools like <a href="https://direnv.net/"><code>direnv</code></a>, one can leverage the fact that the resulting shell of <del><code>nix-shell</code></del> <code>nix develop</code> includes all declared <code>buildInputs</code> and environment variables to put together an environment with all sorts of dependencies and development tools available. Importantly, nix will also ensure all <code>setupHook</code>s are run when the shell is opened allowing for some impure setup to happen.
</p>
<div class="uk-alert-success help box y-fill-horizontal">
<p>
A helpful tool to achieve this is <code>mkShell</code>. This function provides an easy interface to collect packages for an environment.
</p>
<div class="y-fill-horizontal">
<div id="cb1" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ex">pkgs.mkShell</span> = {</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  <span class="co"># a list of packages to add to the shell environment</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  <span class="ex">packages</span> <span class="pp">?</span> [ ]</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="ex">,</span> <span class="co"># propagate all the inputs from the given derivations</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>  <span class="ex">inputsFrom</span> <span class="pp">?</span> [ ]</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="ex">,</span> buildInputs <span class="pp">?</span> [ ]</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="ex">,</span> nativeBuildInputs <span class="pp">?</span> [ ]</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="ex">,</span> propagatedBuildInputs <span class="pp">?</span> [ ]</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="ex">,</span> propagatedNativeBuildInputs <span class="pp">?</span> [ ]</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="ex">,</span> ...</span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="er">}</span><span class="ex">:</span> ...</span></code></pre>
</div>
</div>
<p>
<em>All extra attributes unknown to <code>mkDerivation</code> are applied as env variables.</em>
</p>
<p>
You can provide a <code>shellHook</code> to run commands whenever you enter the shell
</p>
</div>
<p>
Being closely connected to flakes, <code>nix develop</code> supports loading a flake’s development shell directly if a <code>devShell</code> output is defined.
</p>
<div class="uk-alert-success help box y-fill-horizontal" data-header="Example" data-caption="(Adapted from my previous [post](../internals/2021-01-01-flake-ification.md)). ">
<div class="header">
<div>
<span class="las la-life-ring"></span>
<div class="badge">
<p>HELP</p>
</div>
</div>
<div>
<p>
Example
</p>
</div>
</div>
<div class="y-fill-horizontal">
<div id="cb2" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">{</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>  <span class="ex">description</span> = <span class="st">&quot;Flake utils demo&quot;</span><span class="kw">;</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>  <span class="ex">inputs.nixpkgs.url</span> = <span class="st">&quot;github:nixos/nixpkgs&quot;</span><span class="kw">;</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>  <span class="ex">inputs.flake-utils.url</span> = <span class="st">&quot;github:numtide/flake-utils&quot;</span><span class="kw">;</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>  <span class="ex">outputs</span> = { self, nixpkgs, flake-utils }:</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>    <span class="bu">let</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>    <span class="er">in</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>      <span class="ex">flake-utils.lib.eachDefaultSystem</span> <span class="er">(</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>        <span class="ex">system:</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>          <span class="bu">let</span></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>            <span class="ex">pkgs</span><span class="st">&#39; = import nixpkgs { inherit system; };</span></span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a><span class="st">          in</span></span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a><span class="st">            rec {</span></span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a><span class="st">              packages = { myPackage = ... }; # packages defined here</span></span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a><span class="st">              devShell  = pkgs&#39;</span><span class="ex">.mkShell</span> = {</span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a>                <span class="co"># a list of packages to add to the shell environment</span></span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a>                <span class="ex">packages</span> <span class="pp">?</span> [ jq ]</span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a>                <span class="ex">,</span> <span class="co"># propagate all the inputs from the given derivations</span></span>
<span id="cb2-21"><a href="#cb2-21" aria-hidden="true" tabindex="-1"></a>                  <span class="co"># this adds all the tools that can build myPackage to the environment</span></span>
<span id="cb2-22"><a href="#cb2-22" aria-hidden="true" tabindex="-1"></a>                <span class="ex">inputsFrom</span> <span class="pp">?</span> [ pacakges.myPackage ]</span>
<span id="cb2-23"><a href="#cb2-23" aria-hidden="true" tabindex="-1"></a>              <span class="er">}</span><span class="kw">;</span></span>
<span id="cb2-24"><a href="#cb2-24" aria-hidden="true" tabindex="-1"></a>            <span class="er">}</span></span>
<span id="cb2-25"><a href="#cb2-25" aria-hidden="true" tabindex="-1"></a>      <span class="kw">);</span></span>
<span id="cb2-26"><a href="#cb2-26" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span></code></pre>
</div>
</div>
<div class="caption">
<p>
(Adapted from my previous <a href="../internals/2021-01-01-flake-ification.md">post</a>).
</p>
</div>
</div>
<h2 class="y-header" id="temporary-programs">
<span>Temporary Programs</span><a href="#temporary-programs" class="anchor las la-anchor" title="temporary-programs"></a>
</h2>
<p>
The fact that nix is built on the idea of the nix store from which user environments are created by cherry-picking the desired packages may raise the question, whether we may be able to amend our current environment imperatively<a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>. And in fact, we can. It is possible to add software to a user’s profile by imperatively by the means of <del><code>nix-env -iA</code></del> or nowadays <code>nix profile install</code>.
</p>
<div class="uk-alert-warning warning box y-fill-horizontal" data-header="">
<div class="header">
<div>
<span class="las la-exclamation-circle"></span>
<div class="badge">
<p>WARN</p>
</div>
</div>
<div>

</div>
</div>
<p>
Beware that <code>nix profile</code> is incompatible with <code>nix-env</code> and therefore (today) also with <code>home-manager</code>.
</p>
</div>
<p>
Yet, we also know that installing software this way is <em>not the Nix way</em> of doing things.
</p>
<p>
For the times when we <em>do</em> want to have some program at our disposal, either to try it out, use a different version or just needing it only temporarily, there should be a way to get this without going through the effort of adding it to your <code>configuration.nix</code>, <code>home.nix</code>, project <code>default.nix</code>, etc. and rebuilding your environment. In these cases, traditional distributions reach back to installing software or relying on containerization (i.e. docker). In Nix, while you could install the piece of software, the aforementioned usage of the nix store allows making software available temporarily without installing it.
</p>
<p>
This is what <code>nix-shell -p &lt;package+&gt;</code> is used for. <code>nix-shell</code> will retrieve the desired packages and open a shell with these packages mixed in.
</p>
<div class="uk-alert-success help box y-fill-horizontal" data-header="Example">
<div class="header">
<div>
<span class="las la-life-ring"></span>
<div class="badge">
<p>HELP</p>
</div>
</div>
<div>
<p>
Example
</p>
</div>
</div>
<p>
Given you need to quickly convert some <code>asciidoc</code> to HTML usually the response of your terminal will be
</p>
<pre><code>$ asciidoc -b html5 manual.adoc
zsh: command not found: asciidoc</code></pre>
<p>
While you could go and add asciidoc to your configuration you might need it just once. In that case we can make use of <code>nix-shell</code>:
</p>
<pre><code>$ nix-shell -p asciidoc
[nix-shell] $ asciidoc -b html5 manual.adoc</code></pre>
<p>
This should now just work. Likewise, this works with almost anything available to install through <code>nixpkgs</code>.
</p>
</div>
<div class="info box y-fill-horizontal" data-header="Under the hood">
<div class="header">
<div>
<span class="las la-info"></span>
<div class="badge">
<p>INFO</p>
</div>
</div>
<div>
<p>
Under the hood
</p>
</div>
</div>
<p>
Internally, what happens when <code>nix-shell -p asciidoc</code> is called is that nix constructs a derivation with the programs as <code>buildInputs</code> and popularizes them through the same mechanism described above.
</p>
<p>
In this case the derivation shell’ed into is:
</p>
<pre><code>with import &lt;nixpkgs&gt; { }; (pkgs.runCommandCC or pkgs.runCommand) &quot;shell&quot; { buildInputs = [ (asciidoc) ]; } &quot;&quot;</code></pre>
<p>
Note that instead of derivations you can also add expressions as the <code>-p</code> argument as these are just plugged in, i.e.:
</p>
<pre><code>$ nix-shell -p &quot;import ./some.nix {}&quot; </code></pre>
</div>
<p>
But this is not about <code>nix-shell</code>…
</p>
<p>
Nix 2.4 allows the same thing using <code>nix shell</code> now focussing on flakes.
</p>
<p>
With <code>nix shell</code> any output of a flake can be added to the environment by running
</p>
<pre><code>$ nix shell nixpkgs#asciidoc</code></pre>
<p>
<em>Here, nix strictly expects a <a href="../internals/2021-01-01-flake-ification/#flake-reference-conventions">flake URL</a>.</em>
</p>
<p>
Like <code>nix-shell</code> this command supports multiple arguments.
</p>
<div id="tldr-nix-shell" class="uk-alert-primary note box y-fill-horizontal" data-header="tl;dr">
<div class="header">
<div>
<span class="las la-pencil-alt"></span>
<div class="badge">
<p>NOTE</p>
</div>
</div>
<div>
<p>
tl;dr
</p>
</div>
</div>
<p>
<code>nix shell</code> creates a shell from the <em>specified inputs</em>.
</p>
<p>
This is useful to install temporary software
</p>
<p>
…from a <a href="../../internals/2021-01-01-flake-ification/#flake-reference-conventions">flake specifier</a>.
</p>
<p>
…from a <code>*.nix</code> file/arbitrary expression using <code>--impure --expr EXPR</code> flags
</p>
<p>
<strong>Why should you use this?</strong>
</p>
<p>
The strong point about Nix is its declarative way to manage installations. Software that is used constantly can and should be packaged by the respective tool, be it a system configuration, home configuration.
</p>
<p>
For project development tools one can use development shells as discussed above.
</p>
<p>
Yet, sometimes a program or library is needed temporarily only, or once in a different version etc. In these cases programs can be loaded into the shell using <code>nix shell</code>. Derivations from this kind command are eventually garbage collected and removed from the nix store, so they do not use up dist space unnecessarily.
</p>
</div>
<div class="uk-alert-warning warning box y-fill-horizontal" data-header="">
<div class="header">
<div>
<span class="las la-exclamation-circle"></span>
<div class="badge">
<p>WARN</p>
</div>
</div>
<div>

</div>
</div>
<p>
Notably, not mentioned here is the use of <code>nix shell</code> to load <code>FANCYLANGUAGE</code> with <code>FANCYLANGUAGEPACKAGES</code>. Sadly, this hits the limits of the new command. See the section about <code>shellHook</code>s <a href="#shell-hooks">below</a>.
</p>
</div>
<h2 class="y-header" id="run-scripts">
<span>Run scripts</span><a href="#run-scripts" class="anchor las la-anchor" title="run-scripts"></a>
</h2>
<p>
Apart from dropping into development shells, <code>nix-shell</code> can also be used to run commands and programs from derivation not currently installed to the user’s profile. This is it can build a shell as before and run a command inside transparently.
</p>
<p>
We discussed the use of <code>nix-shell --command COMMAND ARGS</code> above, where we would run a command from within the build environment of a derivation. Similarly, we may want to just run a program provided by a derivation. For this <code>nix-shell</code> provided the <code>--run</code> argument
</p>
<div class="info box y-fill-horizontal" data-header="&quot;`--command`&quot; vs &quot;`run`&quot;">
<div class="header">
<div>
<span class="las la-info"></span>
<div class="badge">
<p>INFO</p>
</div>
</div>
<div>
<p>
“<code>–command</code>” vs “<code>run</code>”
</p>
</div>
</div>
<p>
As a development aid, <code>--command</code> is interactive, meaning among other things, that <em>if a command fails or is interrupted by the user, the user is dropped into the shell with the build environment loaded</em>.
</p>
<p>
This behavior translates into an invocation using the <code>-p PROGRAM</code> argument as well as seen in the following box.
</p>
<div class="y-fill-horizontal">
<div id="cb8" class="sourceCode">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> asciidoc </span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="ex">zsh:</span> command not found: asciidoc</span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix-shell <span class="at">-p</span> asciidoc <span class="at">--command</span> asciidoc</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="ex">Man</span> page:     asciidoc <span class="at">--help</span> manpage</span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a><span class="ex">Syntax:</span>       asciidoc <span class="at">--help</span> syntax</span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> asciidoc <span class="co"># still available as were in the build shell with asciidoc present</span></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a><span class="ex">Man</span> page:     asciidoc <span class="at">--help</span> manpage</span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a><span class="ex">Syntax:</span>       asciidoc <span class="at">--help</span> syntax</span></code></pre>
</div>
</div>
<p>
<code>--run</code> runs non-interactive and closes the shell after the command returns
</p>
<div class="y-fill-horizontal">
<div id="cb9" class="sourceCode">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> asciidoc </span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="ex">zsh:</span> command not found: asciidoc</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix-shell <span class="at">-p</span> asciidoc <span class="at">--run</span> asciidoc</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a><span class="ex">Man</span> page:     asciidoc <span class="at">--help</span> manpage</span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a><span class="ex">Syntax:</span>       asciidoc <span class="at">--help</span> syntax</span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> asciidoc <span class="co"># not available anymore</span></span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a><span class="ex">zsh:</span> command not found: asciidoc</span></code></pre>
</div>
</div>
</div>
<h3 class="y-header" id="nix-shell--c">
<span><code>nix shell -c</code></span><a href="#nix-shell--c" class="anchor las la-anchor" title="nix-shell--c"></a>
</h3>
<p>
As the functions of <code>nix-shell DERIVATION</code> and <code>nix-shell -p DERIVATION</code> were separated, the new tools come with new clearer semantics.
</p>
<p>
The generic <code>nix-shell --run</code> function is now <code>nix shell -c</code>. Given an installable, nix allows to run any command in an environment where the installable is present. Note that this command is run in a non-interactive shell. The shell is dropped as the command ends.
</p>
<div class="info box y-fill-horizontal">
<p>
The above example using the new command would look like this:
</p>
<pre><code>$ nix shell nixpkgs#asciidoc -c asciidoc</code></pre>
</div>
<h3 class="y-header" id="nix-run">
<span><code>nix run</code></span><a href="#nix-run" class="anchor las la-anchor" title="nix-run"></a>
</h3>
<p>
Yet, <code>nix shell -c</code> will still require to type the name of the executed program. As for most programs this command is the same as the derivation name e.g. <code>nix shell nixpkgs#asciidoc -c asciidoc</code> another command was introduced named <code>nix run</code>. With <code>nix run</code> the previous command can be run as <code>nix run nixpkgs#asciidoc</code>.
</p>
<p>
Naturally, the functionality of <code>nix run</code> goes further and as is the case for many other new commands mainly concerns flakes. Next to <code>packages</code>, <code>nixosModules</code> and others, flakes can now also define <code>apps</code>. Written as records with two fields -<code>type</code> (currently, necessarily <code>app</code>) and <code>program</code> (an executable path) - these apps can be run directly using <code>nix run</code>.
</p>
<p>
This app definition
</p>
<div class="y-fill-horizontal">
<div id="cb11" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="ex">...</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="ex">outputs</span> = {self}: {</span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>  <span class="ex">...</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>  <span class="ex">apps.x86_64-linux.watch</span> = {</span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>    <span class="bu">type</span> = <span class="st">&quot;app&quot;</span><span class="kw">;</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>    <span class="ex">program</span> = <span class="st">&quot;</span><span class="va">${generator</span><span class="er">-watch</span><span class="va">}</span><span class="st">&quot;</span><span class="kw">;</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>  <span class="er">}</span><span class="kw">;</span></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a><span class="er">}</span></span></code></pre>
</div>
</div>
<p>
… could be used to watch and build this blogs source directly using <code>nix run .#watch</code>, given <code>generator-watch</code> is a script in the nix store. Note that <em><code>program</code> only accepts paths</em> in the store and <em>no default arguments</em>.
</p>
<p>
If an attribute to <code>nix run</code> is not found as an app, nix will look up a <code>program</code> using this key instead and execute <code>programs.${&lt;program&gt;}/bin/&lt;program&gt;</code> instead.
</p>
<div id="tldr-nix-run" class="uk-alert-primary note box y-fill-horizontal" data-header="tl;dr">
<div class="header">
<div>
<span class="las la-pencil-alt"></span>
<div class="badge">
<p>NOTE</p>
</div>
</div>
<div>
<p>
tl;dr
</p>
</div>
</div>
<p>
The new <code>nix</code> command comes with a new way to run programs not installed in your system for an even greater “run and forget” experience.
</p>
<p>
With <code>nix shell DERIVATION+ -c COMMAND</code>
</p>
<p>
… run any command in an environment with all specified <code>DERIVATION</code>s present (again consider the <a href="#shell-hooks">section about <code>shellHook</code>s</a>)
</p>
<p>
With <code>nix run INSTALLABLE</code> you can
</p>
<p>
… run scripts defined in a flake under the <code>apps</code> output
</p>
<p>
… run the executables of any derivation as long as it is located in <code>bin/INSTALLABLE</code> of the derivation with the attribute name <code>INSTALLABLE</code>
</p>
</div>
<h2 class="y-header" id="shell-interpreter-usrbinenv-nix-shell">
<span>Shell interpreter <code>#!/usr/bin/env nix-shell</code></span><a href="#shell-interpreter-usrbinenv-nix-shell" class="anchor las la-anchor" title="shell-interpreter-usrbinenv-nix-shell"></a>
</h2>
<p>
Lastly, a useful feature of <code>nix-shell</code> is its usage as a shell interpreter. What that means is that <code>nix-shell</code> can be used to dynamically fetch dependencies for a script file and execute the file in that context. Shell interpreters are defined using a special syntax at the start of script files.
</p>
<div class="info box y-fill-horizontal" data-header="Shebang Interpreter Line">
<div class="header">
<div>
<span class="las la-info"></span>
<div class="badge">
<p>INFO</p>
</div>
</div>
<div>
<p>
Shebang Interpreter Line
</p>
</div>
</div>
<p>
Bash, Zsh and other shells interpret a first line starting with <code>#!</code> as an interpreter instruction. This way, instead of running a file using e.g. bash or python explicitly, we can write <code>#!/usr/bin/env python</code> to instruct the shell to use python to execute the file.
</p>
<div class="y-fill-horizontal">
<div id="cb12" class="sourceCode" data-caption="file.py">
<pre class="sourceCode python"><code class="sourceCode python"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="co">#!/usr/bin/env python</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a><span class="co"># file.py</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="st">&quot;hello&quot;</span>)</span></code></pre>
</div>
</div>
<p>
Here <code>$ python file.py</code> would be equivalent to <code>./file.py</code>, given the user has permission to execute the file.
</p>
</div>
<p>
The <code>nix-shell</code> command can be used to use nix to provide the actual interpreter using
</p>
<div class="y-fill-horizontal">
<div id="cb13" class="sourceCode">
<pre class="sourceCode .bash"><code class="sourceCode bash"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="co">#! /usr/bin/env nix-shell</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="co">#! nix-shell -i real-interpreter -p packages</span></span></code></pre>
</div>
</div>
<p>
Therefore, the above example would therefore continue to work even without python installed, if defined as
</p>
<div class="y-fill-horizontal">
<div id="cb14" class="sourceCode" data-caption="file.py">
<pre class="sourceCode python"><code class="sourceCode python"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="co">#! /usr/bin/env nix-shell</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="co">#! nix-shell -i python -p python3</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="st">&quot;hello&quot;</span>)</span></code></pre>
</div>
</div>
<div class="uk-alert-warning warning box y-fill-horizontal">
<p>
As it stands this function does not <a href="https://github.com/NixOS/nix/pull/5189">yet</a> have a replacement.
</p>
</div>
<h1 class="y-header" id="notes-and-resources">
<span>Notes and Resources</span><a href="#notes-and-resources" class="anchor las la-anchor" title="notes-and-resources"></a>
</h1>
<h2 class="y-header" id="to-flake-or-not-to-flake">
<span>To flake or not to flake</span><a href="#to-flake-or-not-to-flake" class="anchor las la-anchor" title="to-flake-or-not-to-flake"></a>
</h2>
<p>
Most of the new nix commands are designed in a flake first way. Most notably <code>nix {shell,develop,run}</code> expect <a href="../internals/2021-01-01-flake-ification/#flake-reference-conventions">flake URLs</a> as argument. Traditional <code>*.nix</code> files can be used with the <code>--expr</code> argument all commands support. As flake mode imposes greater purity strictness, imports have to happen with the <code>--impure</code> flag given:
</p>
<div class="y-fill-horizontal">
<div id="cb15" class="sourceCode">
<pre class="sourceCode sh"><code class="sourceCode bash"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix shell <span class="at">--impure</span> <span class="at">--expr</span> <span class="st">&quot;import my.nix {}&quot;</span></span></code></pre>
</div>
</div>
<h2 class="y-header" id="shell-hooks">
<span>A word about <code>shellHook</code>s</span><a href="#shell-hooks" class="anchor las la-anchor" title="shell-hooks"></a>
</h2>
<p>
While shell hooks were previously introduced as a means to run certain commands to set up a development shell with <code>nix develop</code> and <code>nix-shell</code>, they find use in other places. Concretely, neither <code>nix run</code> nor <code>nix shell</code> are running these hooks. This is even though their <code>nix-shell</code> equivalent does so.
</p>
<p>
What that means is that <code>nix shell</code> cannot be used to load e.g. a Python environment with packages directly as python modules use the <code>shellHook</code> to set up the <code>PYTHONPATH</code>. The same goes for Perl and other ecosystems with similar principles. This means
</p>
<pre><code>nix shell nixpkgs#{python,python3Packages.numpy}</code></pre>
<p>
and
</p>
<pre><code>nix-shell -p python python3Packages.numpy</code></pre>
<p>
Do not evaluate to the same thing.
</p>
<p>
Instead, one needs to work around with custom expressions or <code>mkShell</code>s passed to nix develop.
</p>
<h3 class="y-header" id="workarounds">
<span>Workarounds</span><a href="#workarounds" class="anchor las la-anchor" title="workarounds"></a>
</h3>
<p>
For Python in particular we can use <code>python3.withPackages</code> to build an ad-hoc derivation with the paths set up correctly:
</p>
<pre><code>nix shell --impure --expr &quot;with import &lt;nixpkgs&gt; {}; python.withPackages (pkgs: with pkgs; [ prettytable ])&quot; </code></pre>
<p>
This might work as well with other language ecosystems
</p>
<p>
Alternatively, we can (ab)use <code>nix develop</code> by passing it a <code>devShell</code>:
</p>
<pre><code>nix develop --impure --expr &quot;with import &lt;nixpkgs&gt; {}; pkgs.mkShell { packages = [python3 python3Packages.numpy ];}&quot; </code></pre>
<p>
Both approaches work to some degree but are clunky (i.e. <em>not improving UX as promised</em>) and rely on the supposed-to-be-superseded channels.
</p>
<h2 class="y-header" id="the-second-hardest-problem">
<span>The second-hardest problem</span><a href="#the-second-hardest-problem" class="anchor las la-anchor" title="the-second-hardest-problem"></a>
</h2>
<p>
Picking up the confusion mentioned in the beginning, there is another problem with <code>nix shell</code>… naming. Being so closely named to its <em>semantically different</em> predecessor, it is impossible to query google for meaningful, targeted results. This is a pain for newcomers and more experienced nix’ers alike. And indeed, there is a heated <a href="https://github.com/NixOS/nix/issues/4715">discussion</a> on renaming the shell command. Yet, until that is resolved, I hope this guide helps to understand the differences a bit better.
</p>
<p>
<em>newnixshellguide</em>
</p>
<h1 class="y-header" id="appendix">
<span>Appendix</span><a href="#appendix" class="anchor las la-anchor" title="appendix"></a>
</h1>
<h2 class="y-header" id="summary-table">
<span>Summary table</span><a href="#summary-table" class="anchor las la-anchor" title="summary-table"></a>
</h2>
<table>
<colgroup>
<col style="width: 20%" />
<col style="width: 20%" />
<col style="width: 20%" />
<col style="width: 20%" />
<col style="width: 20%" />
</colgroup>
<thead>
<tr class="header">
<th>
/
</th>
<th>
<code>nix-shell</code>
</th>
<th>
<code>nix develop</code>
</th>
<th>
<code>nix shell</code>
</th>
<th>
<code>nix run</code>
</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>
<strong>runs <code>shellHook</code>s</strong>
</td>
<td>
yes
</td>
<td>
yes
</td>
<td>
no
</td>
<td>
no
</td>
</tr>
<tr class="even">
<td>
<strong>use as interpreter</strong>
</td>
<td>
yes
</td>
<td>
no
</td>
<td>
no
</td>
<td>
no
</td>
</tr>
<tr class="odd">
<td>
<strong>supports flakes</strong>
</td>
<td>
no
</td>
<td>
yes
</td>
<td>
yes
</td>
<td>
only
</td>
</tr>
<tr class="even">
<td>
<strong>evaluate nix file</strong>
</td>
<td>
yes
</td>
<td>
with <code>--impure</code>, <code>-f</code> or <code>--expr</code>
</td>
<td>
with <code>--impure</code>, <code>-f</code> or <code>--expr</code>
</td>
<td>
with <code>--impure</code>, <code>-f</code> or <code>--expr</code>
</td>
</tr>
<tr class="odd">
<td>
<strong>modifies environment</strong>
</td>
<td>
<code>PATH</code>, attributes mk<code>mkDerivation</code> and changes by <code>shellHooks</code>
</td>
<td>
<code>PATH</code>, attributes mk<code>mkDerivation</code> and changes by <code>shellHooks</code>
</td>
<td>
<code>PATH</code>
</td>
<td>
<em>nothing</em>
</td>
</tr>
</tbody>
</table>
<section class="footnotes" role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote">
<p>
Seemingly, no-one has given any thought about google’ability of the new commands… google <strong>“newnixshellguide”</strong> to find this post in the meantime<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a>
</p>
</li>
<li id="fn2" role="doc-endnote">
<p>
Functional purists, please bear with me here<a href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a>
</p>
</li>
</ol>
</section>]]></summary>
</entry>
<entry>
    <title>The Rust Build System</title>
    <link href="https://blog.ysndr.de/posts/essays/2021-04-30-the-rust-build-system/index.html" />
    <id>https://blog.ysndr.de/posts/essays/2021-04-30-the-rust-build-system/index.html</id>
    <published>2021-04-30T00:00:00Z</published>
    <updated>2021-04-30T00:00:00Z</updated>
    <summary type="html"><![CDATA[<div class="uk-alert-primary note box y-fill-horizontal" data-header="Background and Acknowledgement">
<div class="header">
<div>
<span class="las la-pencil-alt"></span>
<div class="badge">
<p>NOTE</p>
</div>
</div>
<div>
<p>
Background and Acknowledgement
</p>
</div>
</div>
<p>
This essay was part of the DD2482 DevOps Course at KTH <a href="https://github.com/kth/devops-course">(open on github)</a>.
</p>
<p>
The aim was to present a topic of our interest in 2000 ± 5% words. We chose the rust build system out of interest in the language and to learn about the difficulties and implications of managing a reasonably big open source project such as the Rust Programming language.
</p>
<p>
While researching about and writing this essay, the general lack of definite and up-to-date information about the topic drove our motivation to assemble this snapshot which is supposed to cover all important steps given the word restrictions.
</p>
<p>
This essay is the product of a pair project by:
</p>
<ul>
<li>
<strong>Aron Hansen Berggren</strong> (aronber@kth.se)
</li>
<li>
and <strong>Yannik Sander</strong> (yannik@kth.se / contact@ysndr.de)
</li>
</ul>
<p>
<em>If you want to use this article, please consult either of us. A PDF version is available <a href="../the-rust-build-system/Sander-Berggren_The-Rust-Build-System.pdf">here</a></em>
</p>
</div>
<h1 class="y-header" id="introduction">
<span>Introduction</span><a href="#introduction" class="anchor las la-anchor" title="introduction"></a>
</h1>
<p>
There is a lot of talk about how DevOps supposedly solves all your problems when developing software, from the features planned to how they are used in production and everything between. Even open-source projects are expected to follow DevOps principles these days. The Rust programming language is no exception.<br /> But how does DevOps Scale for projects as massive as rust, an advanced programming language which compiles to every mainstream platform with tooling, documentation and hundreds of contributors? This is what will be explored and explained in the upcoming sections.
</p>
<p>
We start by explaining what we are looking at, before diving into the tools that ensure this project’s integrity.
</p>
<h2 class="y-header" id="what-is-rust">
<span>What is Rust</span><a href="#what-is-rust" class="anchor las la-anchor" title="what-is-rust"></a>
</h2>
<p>
According to the official Rust language website<span class="citation" data-cites="RustProgrammingLanguage"><span class="citation" data-cites="RustProgrammingLanguage">[1]</span></span>, Rust is a low-level programming language that focuses on performance, reliability and productivity. It extends these in the following ways:
</p>
<ul>
<li>
<p>
Performance:<br /> Memory efficient without any garbage collector or run-time.
</p>
</li>
<li>
<p>
Reliability:<br /> Extensive type system and ownership models to guarantee memory and thread safety at compile time.
</p>
</li>
<li>
<p>
Productivity:<br /> The tooling for working with rust such as documentation, build tools and compiler errors are feature-complete and reliable.
</p>
</li>
</ul>
<p>
These points together with a strong type-system and its expansive ecosystem are pointed out as the reasons for Rust being voted as the most loved programming language 4 years in a row in the yearly surveys by Stack Overflow<span class="citation" data-cites="gouldingWhatRustWhy2020"><span class="citation" data-cites="gouldingWhatRustWhy2020">[2]</span></span>.
</p>
<h2 class="y-header" id="what-is-a-ci">
<span>What is a “CI”</span><a href="#what-is-a-ci" class="anchor las la-anchor" title="what-is-a-ci"></a>
</h2>
<p>
A CI, or Continuous Integration, takes some input and performs a set of steps to output some product at the end. This often includes code reviews, automated tests, code compilation, packaging of compiled code and further validation of the packages before publishing.
</p>
<figure>
<img src="../the-rust-build-system/1619420761_screenshot.png" id="fig:rust_ci" class="align-center" alt="Figure 1: CI pipelines are run by different events, depicted are the standard tests for Rust PR’s." />
<figcaption aria-hidden="true">
Figure 1: CI pipelines are run by different events, depicted are the standard tests for Rust PR’s.
</figcaption>
</figure>
<p>
Throughout this process, one of the most important aspects is to monitor these results and act on that feedback.<span class="citation" data-cites="ImportanceDevOpsPipeline2020 katzEssentialStepsBuilding"><span class="citation" data-cites="ImportanceDevOpsPipeline2020 katzEssentialStepsBuilding">[3], [4]</span></span>
</p>
<h1 class="y-header" id="the-rabbit-hole-rust-build-ci">
<span>The <del>Rabbit Hole</del> Rust Build CI</span><a href="#the-rabbit-hole-rust-build-ci" class="anchor las la-anchor" title="the-rabbit-hole-rust-build-ci"></a>
</h1>
<p>
This section presents the specifics of the Rust project’s build process. We strive to present a comprehensive picture of the most important pieces, as the overall process would not get a fair representation in this limited scope. We will focus on how Rust facilitates the <strong>bors</strong> bot and its development pattern while also introducing the social interactions bot <strong>triagebot</strong>.
</p>
<h2 class="y-header" id="sec:triagebot">
<span>Triagebot</span><a href="#sec:triagebot" class="anchor las la-anchor" title="sec:triagebot"></a>
</h2>
<p>
The Triagebot can be summarised as the people and issues managing bot of the Rust development process. Its documentation<span class="citation" data-cites="TriagebotRustForge"><span class="citation" data-cites="TriagebotRustForge">[5]</span></span> explains how it achieves this:<br /> It is the instantiator of tags on issues by being invoked by its GitHub name, “<span class="citation" data-cites="rustbot"><strong>rustbot?</strong></span>” It also makes it easy to ping teams within the Rust organisation, for example, the documentation maintainers by tracking more than just people and issues. This makes it easier for the teams to assist without those in need of help knowing whom directly to contact, as well as for the teams to find issues that need their attention.
</p>
<h2 class="y-header" id="developing-with-bors">
<span>Developing with bors</span><a href="#developing-with-bors" class="anchor las la-anchor" title="developing-with-bors"></a>
</h2>
<p>
Inspecting the <code>rust-lang/rust</code><a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a> repository two things become apparent:
</p>
<p>
First, none of the main branches shows any trace of being a <em>development branch</em>. On the contrary, their naming (<code>stable, beta, master</code>) rather suggests a connection with the release. Secondly, supporting the first insight, the commit history appears very automated as well. Many commits are structured as follows:
</p>
<blockquote>
<p>
<code>Auto merge of #84353 - estebank:as-ref-mir, r=davidtwco</code>
</p>
</blockquote>
<p>
Under closer inspection these commits become apparent as <strong>merge-commits</strong>, merging a set of changes into the master branch. All of these commits are merged by bors and refer to PR.
</p>
<p>
We see: bors automates the merging of PR. Indeed <em>none</em> of the commits made directly onto the master branch are by any other committer than bors.
</p>
<p>
Yet, where do these commits come from and more importantly are they even verified?
</p>
<h3 class="y-header" id="the-pull-request">
<span>The Pull Request</span><a href="#the-pull-request" class="anchor las la-anchor" title="the-pull-request"></a>
</h3>
<p>
When opening a Pull Request (PR) on the rust repository, if you did not ask for any specific reviewer, the <strong>rust-highfive</strong> bot assigns a rust team member to it. This affects the assignee on GitHub as well as leaving a comment picked up by triagebot.
</p>
<p>
A GitHub Action <code>pr</code> will test the code on three major platforms (Windows and two Linux systems with different toolchains).
</p>
<p>
If if the action succeeds and a maintainer reviewed your code they might comment in one of the following ways:
</p>
<ul>
<li>
<p>
<code>r+</code> In bors terms this is equivalent to pressing the green “Merge” button and comes with the same responsibility
</p>
</li>
<li>
<p>
Mark the PR as rollup target. Note; We will cover rollups in depth after going through bors’ workflow below.
</p>
</li>
<li>
<p>
Instruct the author to do changes
</p>
</li>
<li>
<p>
<code>r? <span class="citation" data-cites="username"><strong>username?</strong></span></code> Ask for another review
</p>
</li>
</ul>
<p>
In case of the first action (<code>r+</code>) we see bors commenting with something like:
</p>
<blockquote>
<p>
⌛ Testing commit f43ee8e with merge e888a57…
</p>
</blockquote>
<p>
This, given the tests run successfully and the change is approved, will cause bors to merge the PR.
</p>
<h3 class="y-header" id="sec:playground">
<span>A bot’s playground</span><a href="#sec:playground" class="anchor las la-anchor" title="sec:playground"></a>
</h3>
<p>
The whole CI of the rust project is managed in a fork of the main repository. That fork lives in <code>rust-lang-ci/rust</code><a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>. It ensures that the main repository, especially its master branch, always builds without failure. Interactions with this repository are indirect and managed by bors. The two main branches that are of interest are <code>auto</code> and <code>try</code> both of which trigger GitHub Actions workflows with the same name as defined in the repository.<span class="citation" data-cites="RustlangRustCI"><span class="citation" data-cites="RustlangRustCI">[6]</span></span>
</p>
<p>
When a maintainer approves a change (i.e. by commenting with <code>r+</code>) bors takes the changes and force-pushes them to the <code>auto</code> branch. Changes on this branch subsequently trigger the GitHub Actions system.
</p>
<h4 class="y-header" id="sec:auto">
<span>The <code>auto</code> Action</span><a href="#sec:auto" class="anchor las la-anchor" title="sec:auto"></a>
</h4>
<p>
The <code>auto</code> action is the heart of rust’s CI build process. It builds and tests the rust compiler on all 57 supported platforms<span class="citation" data-cites="RustCIMoving"><span class="citation" data-cites="RustCIMoving">[7]</span></span>. Most of the action sets up the CI environment including connecting to a compiler cache for intermediate built dependencies <strong><a href="#fn3" class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a>sccache</strong> and initializing the repository by pulling all related submodules.
</p>
<p>
Once this is done the actual build will be executed. On available platforms this is run natively. All other platforms are cross-compiled using a custom docker image.
</p>
<p>
Finally, assuming the build succeeded the produced artefacts are pushed to an S3 object storage<a href="#fn4" class="footnote-ref" id="fnref4" role="doc-noteref"><sup>4</sup></a>.
</p>
<p>
Unsurprisingly, as the build and tests need to succeed for such a large number of targets, a full CI run on <code>auto</code> takes <em>two-and-a-half to three hours</em><span class="citation" data-cites="RustlangciRust"><span class="citation" data-cites="RustlangciRust">[8]</span></span>. The whole CI runs on custom machines owned by the rust projects<span class="citation" data-cites="CustomGitHubActions"><span class="citation" data-cites="CustomGitHubActions">[9]</span></span>. This means they are always available for bors, but only in a limited capacity. The extension of this is that it is not possible to run more than eight <code>auto</code> builds per day and thus at most eight PRs are merged every day!
</p>
<p>
The very curious reader might ask themselves now how this system is supposed to facilitate a CI workflow incorporating <em>regular</em> automated testing. In part, this is where the second action comes into play.
</p>
<h4 class="y-header" id="the-try-action">
<span>The <code>try</code> Action</span><a href="#the-try-action" class="anchor las la-anchor" title="the-try-action"></a>
</h4>
<p>
The <code>try</code> action, like <code>auto</code> is triggered by pushes made by bors targeting the <code>try</code> branch.
</p>
<p>
This action is structurally equivalent to the one described before. The major difference shows when looking at the build targets. Instead of 57 targets it only runs for <em>x86_64 Linux</em>, for it is the most widely available target. It allows a maintainer to get an idea of whether the change introduced by a PR will build as in contrast to the <code>pr</code> action this one build the complete rust toolchain including all tests.
</p>
<p>
With <code>try</code> and <code>auto</code> in mind one might wonder:
</p>
<blockquote>
<p>
<em>“Will all changes trigger a full build and test on 50+ platforms? Is that not pretty wasteful for simple changes such as correcting missspellings?”</em>
</p>
</blockquote>
<p>
It is and that brings us back to the PR process from before.
</p>
<h3 class="y-header" id="rollups">
<span>Rollups</span><a href="#rollups" class="anchor las la-anchor" title="rollups"></a>
</h3>
<p>
In Section <a href="#sec:auto" data-reference-type="ref" data-reference="sec:auto">2.2.2.1</a> a maximum number of 8 PR’s per day limit was exposed. However, documentation changes and other small fixes that do not impose any notable risk to the pipeline can be bundled. These bundled PR’s are known as a <em>rollup</em><span class="citation" data-cites="RollupProcedureRust"><span class="citation" data-cites="RollupProcedureRust">[10]</span></span>.
</p>
<p>
A rollup is initiated by a maintainer through bors’ web interface <a href="#fn5" class="footnote-ref" id="fnref5" role="doc-noteref"><sup>5</sup></a>. It shows mergeability and the associated risk for open PRs and lets the maintainer select a group of PRs that will be queued for bors to push them onto the CI’s <code>auto</code> branch. This causes them to be tested collectively thus saving resources.
</p>
<h2 class="y-header" id="the-green-master">
<span>The Green Master</span><a href="#the-green-master" class="anchor las la-anchor" title="the-green-master"></a>
</h2>
<div class="epigraph box y-fill-horizontal">
<p>
“<strong>The Not Rocket Science Rule Of Software Engineering</strong>:<br /> automatically maintain a repository of code that always passes all the tests”
</p>
<p>
— <span class="upright">Graydon Hoare</span>, founder of Rust
</p>
</div>
<p>
As stated previously, successfully running/testing on causes bors to commit these changes back to master. As the auto branch is always the latest master this ensures that the main repository is always <em>green</em>.<br /> Yet, not everything on the rust repository is the rust compiler! There are some custom tools that might fail to build but do not influence the compiler. These breakages should not fail the tests. Therefore when the CI merges changes into master it runs its final action <code>master</code> which collects information about which tools succeeded to build and publishes them to the toolstate repository<a href="#fn6" class="footnote-ref" id="fnref6" role="doc-noteref"><sup>6</sup></a>.
</p>
<h2 class="y-header" id="action-or-lack-there-off">
<span>Action! Or lack there off</span><a href="#action-or-lack-there-off" class="anchor las la-anchor" title="action-or-lack-there-off"></a>
</h2>
<p>
The Rust CI is running on the GitHub Actions platform<span class="citation" data-cites="RustCIMoving"><span class="citation" data-cites="RustCIMoving">[7]</span></span>, but what is it? One engineer, Jonas Hecht describes GitHub Actions in a blog post<span class="citation" data-cites="StopRewritingPipelines2021"><span class="citation" data-cites="StopRewritingPipelines2021">[11]</span></span> as the next generation CI/CD. He goes further to explain why: CI/CD has been available as file configurations for a good while now, but GitHub Actions takes it one step further with the easily accessible pre-built actions available to everyone on GitHub. He describes them as the missing Lego™ blocks for building a complete CI/CD pipeline, with close to single click interactions with code analysis and deployment tools as examples.<br /> Yet, analysing the actions file<span class="citation" data-cites="RustlangRusta"><span class="citation" data-cites="RustlangRusta">[12]</span></span> we see that there are not any GitHub Actions ran by the Rust CI. The Rust project does not need more features for their build pipeline as they have built custom tooling for the necessary parts instead, sacrificing DevOps velocity offered by this available platform to push for higher build-pipe throughput, reliability and security.
</p>
<h1 class="y-header" id="wrap-up">
<span>Wrap Up</span><a href="#wrap-up" class="anchor las la-anchor" title="wrap-up"></a>
</h1>
<p>
Having escaped the wonderland of rust, what did we learn?
</p>
<p>
The most unique feature of the rust project might be that most of its CI, although running through GitHub PRs, is mostly independent. First of all, it’s run in its own repository, whose master is a bot. Secondly, all the interactions with the CI happen through commands sent to a bot either in form of comments or its web interface. This extends into this bot bors performing all the heavy lifting merging PRs. And finally, although running on GitHub’s infrastructure, the actual actions are entirely implemented as part of the project.
</p>
<p>
These features constitute a unique integration of custom tooling and GitHub and make rust one of the most extraordinary open-source projects.
</p>
<section class="footnotes" role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote">
<p>
<a href="https://github.com/rust-lang/rust" class="uri">https://github.com/rust-lang/rust</a><a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a>
</p>
</li>
<li id="fn2" role="doc-endnote">
<p>
<a href="https://github.com/rust-lang-ci/rust" class="uri">https://github.com/rust-lang-ci/rust</a><a href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a>
</p>
</li>
<li id="fn3" role="doc-endnote">
<p>
<a href="https://github.com/mozilla/sccache" class="uri">https://github.com/mozilla/sccache</a><a href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a>
</p>
</li>
<li id="fn4" role="doc-endnote">
<p>
<a href="https://aws.amazon.com/s3/" class="uri">https://aws.amazon.com/s3/</a><a href="#fnref4" class="footnote-back" role="doc-backlink">↩︎</a>
</p>
</li>
<li id="fn5" role="doc-endnote">
<p>
<a href="https://bors.rust-lang.org/queue/rust" class="uri">https://bors.rust-lang.org/queue/rust</a><a href="#fnref5" class="footnote-back" role="doc-backlink">↩︎</a>
</p>
</li>
<li id="fn6" role="doc-endnote">
<p>
Toolstate of the latest build available under: <a href="https://rust-lang-nursery.github.io/rust-toolstate/" class="uri">https://rust-lang-nursery.github.io/rust-toolstate/</a><a href="#fnref6" class="footnote-back" role="doc-backlink">↩︎</a>
</p>
</li>
</ol>
</section>
<div class="box y-fill-horizontal info">
<div class="header">
<div>
<span class="las la-book"></span>
<div class="badge">
References
</div>
</div>
</div>
<div id="refs" class="references csl-bib-body" role="doc-bibliography">
<div id="ref-RustProgrammingLanguage" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[1] </div><div class="csl-right-inline"><span>“Rust <span>Programming Language</span>.”</span> Accessed: Apr. 14, 2021. [Online]. Available: <a href="https://www.rust-lang.org/">https://www.rust-lang.org/</a></div>
</div>
<div id="ref-gouldingWhatRustWhy2020" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[2] </div><div class="csl-right-inline">J. Goulding, <span>“What is <span>Rust</span> and why is it so popular?”</span> <em>Stack Overflow Blog</em>. <a href="https://stackoverflow.blog/2020/01/20/what-is-rust-and-why-is-it-so-popular/">https://stackoverflow.blog/2020/01/20/what-is-rust-and-why-is-it-so-popular/</a>, Jan. 2020.</div>
</div>
<div id="ref-ImportanceDevOpsPipeline2020" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[3] </div><div class="csl-right-inline"><span>“The <span>Importance</span> of the <span>DevOps Pipeline</span> + <span>How</span> to <span>Build</span>,”</span> <em>phoenixNAP Blog</em>. <a href="https://phoenixnap.com/blog/devops-pipeline">https://phoenixnap.com/blog/devops-pipeline</a>, Jul. 2020.</div>
</div>
<div id="ref-katzEssentialStepsBuilding" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[4] </div><div class="csl-right-inline">E. Katz, <span>“The essential steps to building your own <span>DevOps</span> pipeline.”</span> <a href="https://blog.exigence.io/build-devops-pipeline">https://blog.exigence.io/build-devops-pipeline</a>.</div>
</div>
<div id="ref-TriagebotRustForge" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[5] </div><div class="csl-right-inline"><span>“Triagebot - <span>Rust Forge</span>.”</span> Accessed: Apr. 19, 2021. [Online]. Available: <a href="https://forge.rust-lang.org/platforms/zulip/triagebot.html">https://forge.rust-lang.org/platforms/zulip/triagebot.html</a></div>
</div>
<div id="ref-RustlangRustCI" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[6] </div><div class="csl-right-inline"><span>“Rust-lang/rust <span>CI</span> - <span>Rust Forge</span>.”</span> Accessed: Apr. 14, 2021. [Online]. Available: <a href="https://forge.rust-lang.org/infra/docs/rustc-ci.html#which-branches-we-test">https://forge.rust-lang.org/infra/docs/rustc-ci.html#which-branches-we-test</a></div>
</div>
<div id="ref-RustCIMoving" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[7] </div><div class="csl-right-inline"><span>“Rust’s <span>CI</span> is moving to <span>GitHub Actions</span> | <span>Inside Rust Blog</span>.”</span> Accessed: Apr. 20, 2021. [Online]. Available: <a href="https://blog.rust-lang.org/inside-rust/2020/07/23/rust-ci-is-moving-to-github-actions.html">https://blog.rust-lang.org/inside-rust/2020/07/23/rust-ci-is-moving-to-github-actions.html</a></div>
</div>
<div id="ref-RustlangciRust" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[8] </div><div class="csl-right-inline"><span>“Rust-lang-ci/rust,”</span> <em>GitHub</em>. Accessed: Apr. 26, 2021. [Online]. Available: <a href="https://github.com/rust-lang-ci/rust">https://github.com/rust-lang-ci/rust</a></div>
</div>
<div id="ref-CustomGitHubActions" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[9] </div><div class="csl-right-inline"><span>“Custom <span>GitHub Actions</span> runners - <span>Rust Forge</span>.”</span> Accessed: Apr. 23, 2021. [Online]. Available: <a href="https://forge.rust-lang.org/infra/docs/gha-self-hosted.html">https://forge.rust-lang.org/infra/docs/gha-self-hosted.html</a></div>
</div>
<div id="ref-RollupProcedureRust" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[10] </div><div class="csl-right-inline"><span>“Rollup <span>Procedure</span> - <span>Rust Forge</span>.”</span> Accessed: Apr. 23, 2021. [Online]. Available: <a href="https://forge.rust-lang.org/release/rollups.html">https://forge.rust-lang.org/release/rollups.html</a></div>
</div>
<div id="ref-StopRewritingPipelines2021" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[11] </div><div class="csl-right-inline"><span>“Stop re-writing pipelines! <span>Why GitHub Actions</span> drive the future of <span>CI</span>/<span>CD</span>,”</span> <em>codecentric AG Blog</em>. <a href="https://blog.codecentric.de/en/2021/03/github-actions-nextgen-cicd/">https://blog.codecentric.de/en/2021/03/github-actions-nextgen-cicd/</a>, Mar. 2021.</div>
</div>
<div id="ref-RustlangRusta" class="csl-entry" role="doc-biblioentry">
<div class="csl-left-margin">[12] </div><div class="csl-right-inline"><span>“Rust-lang/rust,”</span> <em>GitHub</em>. Accessed: Apr. 21, 2021. [Online]. Available: <a href="https://github.com/rust-lang/rust">https://github.com/rust-lang/rust</a></div>
</div>
</div>
</div>]]></summary>
</entry>
<entry>
    <title>Building with Nix Flakes for, eh .. reasons!</title>
    <link href="https://blog.ysndr.de/posts/internals/2021-01-01-flake-ification/index.html" />
    <id>https://blog.ysndr.de/posts/internals/2021-01-01-flake-ification/index.html</id>
    <published>2021-01-01T00:00:00Z</published>
    <updated>2021-01-01T00:00:00Z</updated>
    <summary type="html"><![CDATA[<h1 class="y-header" id="walking-through-snow-eh-nix-flakes-for-oss">
<span>Walking through Snow, eh Nix Flakes for OSS</span><a href="#walking-through-snow-eh-nix-flakes-for-oss" class="anchor las la-anchor" title="walking-through-snow-eh-nix-flakes-for-oss"></a>
</h1>
<div class="uk-alert-primary note box y-fill-horizontal">
<p>
This article is an update to my series on how this blog is built using <a href="/tags/haskell.html">Haskell</a> and <a href="/tags/nix.html">Nix</a>.
</p>
<ul>
<li>
Building a reproducible blog with Nix (<a href="/posts/internals/2020-04-10-built-with-nix">link</a>)
</li>
<li>
How this page is generated (<a href="/posts/internal/2019-12-31-built-with-hakyll-part-1.html">Part 01</a>, <a href="/posts/internal/2020-03-22-built-with-hakyll-part-2.html">Part 02</a>)
</li>
</ul>
</div>
<p>
I am happy to get back posting on this blog again after a while of silence. I had been kept busy lately with finishing my Bachelor’s and moving to Stockholm to start my Master’s at the Royal Institute of Technology. In the meantime I also started working for <a href="https://www.ngi.eu/ngi-projects/ngi-zero/">NGI-ZERO</a>, an initiative supporting open source projects led by the European Commission. As part of my work for them I package supported projects for the Nix ecosystem. The goal of this effort is to provide a reproducible and easy way to install and use this software. Due to the fact that those projects come in various shapes and sizes, need to be reviewed and should not clutter <code>nixpkgs</code> unnecessarily, <a href="https://github.com/ngi-nix">nig-nix</a> from builds on top of the latest feature to be added to Nix, <strong>Flakes</strong>.
</p>
<p>
Although still not available in stable Nix, Flakes can already be used using wrappers and the unstable nix package. Inspired by my work and eager to try them for some private project i migrated my blog’s tooling to use Flakes while also keeping up with the latest additions to the Haskell/Hakyll world.
</p>
<p>
Was it worth it? We will see but first, what am I even talking about?
</p>
<h1 class="y-header" id="flake-noun-fleɪk">
<span>Flake (<strong>noun</strong>, /fleɪk/)</span><a href="#flake-noun-fleɪk" class="anchor las la-anchor" title="flake-noun-fleɪk"></a>
</h1>
<blockquote>
<p>
a person you cannot trust to remember things or to do what they promise, or someone who behaves in a strange way
</p>
<p>
Cambridge Dictionary<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>
</p>
</blockquote>
<p>
Well, this was not too helpful and does not sound too promising either. So which other definition do we find there?
</p>
<blockquote>
<p>
a small, thin piece of something, especially if it has come from a surface covered with a layer of something
</p>
</blockquote>
<p>
This will definitely sound relatable in a moment.
</p>
<h2 class="y-header" id="why">
<span>Why?</span><a href="#why" class="anchor las la-anchor" title="why"></a>
</h2>
<p>
Nix derivations are not completely sand boxed! Well the build is, meaning during the phases no network access, or access to to the hosts file system is possible. What is not so hermetic is the nix expression itself. Have you ever seen this line?
</p>
<div class="y-fill-horizontal">
<div id="cb1" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ex">{pkgs</span> <span class="pp">?</span> import <span class="op">&lt;</span>nixpkgs<span class="op">&gt;</span> {}}:</span></code></pre>
</div>
</div>
<p>
Yes you have, certainly! One of the reasons why a derivation might fail on your system is due to this. The problem is that it relies on the <code>nixpkgs</code> channel currently active on <em>your system</em>, which is a major impurity, because people tend to not have the same version active or might even set it to different releases (<code>release-xx.xx</code>, <code>unstable</code>, …).<br /> The common way around this is to pin the <code>nixpkgs</code> used by the developer. This is only a convention though. There is no definite way how to do this. You can see an example in my <a href="/posts/internals/2020-04-10-built-with-nix#default.nix">previous aticle</a> about how I use nix on this blog. The main idea is to state the current version of <code>nixpkgs</code> in a file, fetch the tarball of that version and build against that. This is fine but requires us to update the version manually, and is not consistent among projects.<br /> Alternatively, the tool that emerged from this is <a href="https://github.com/nmattia/niv"><code>niv</code></a>. Niv provides an easy interface to add external sources and import them from the projects Nix file. Niv in the background writes a lockfile and streamlines updating.
</p>
<p>
So there might be a way to pin packages and with some discipline we can get around this impurity. How about this then?
</p>
<div class="y-fill-horizontal">
<div id="cb2" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">{</span> <span class="ex">develop</span> <span class="pp">?</span> true }:</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="ex">...</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="ex">develop</span> then ...</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>           <span class="cf">else</span> <span class="ex">...</span></span></code></pre>
</div>
</div>
<p>
So easily your derivation becomes dependent on some command line argument. In this case it’s a simple flag (<em>how do you know?</em>). In other cases it could expect a string even, like setting the ghc version used. This poses multiple problems. First you create an impurity, you depend on some command line flag to be given. More importantly, these inputs are not discoverable without inspecting the nix file, for string inputs, it might even be hard to figure out which values it takes, in which format, etc for this you need to dig through the definition. Also, even with defaults set, importing the project from another place expects the importer to know which arguments they can/must give and require them to inspect the definition again.
</p>
<p>
Another issue you might come across:
</p>
<div class="y-fill-horizontal">
<div id="cb3" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ex">{...}:</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="bu">let</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="ex">...</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="er">in</span> <span class="kw">{</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>  <span class="ex">inherit</span> shell app some-other-app<span class="kw">;</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span></code></pre>
</div>
</div>
<p>
How do you know what to import, what does it do? There are simply no inherent semantics and also no conventions.
</p>
<p>
Additionally to this Eelco also <a href="https://www.tweag.io/blog/2020-05-25-flakes/">lists</a> some more issues with this. Firstly, due to missing strong conventions and semantics composing packages is difficult, or not nice of an experience for the user. It also means that discovering packages can not be automated easily.
</p>
<div class="uk-alert-primary note box y-fill-horizontal" data-header="Summary of problems">
<div class="header">
<div>
<span class="las la-pencil-alt"></span>
<div class="badge">
<p>NOTE</p>
</div>
</div>
<div>
<p>
Summary of problems
</p>
</div>
</div>
<p>
Lets summarize the shortcomings we just discussed:
</p>
<ol type="1">
<li>
impure imports
</li>
<li>
no ultimate way to pin <code>nixpkgs</code>
</li>
<li>
no common (import) interface
</li>
<li>
impure arguments
</li>
<li>
no common (output) interface
</li>
<li>
poor discoverability
</li>
<li>
poor composability
</li>
</ol>
</div>
<h1 class="y-header" id="creating-a-flake-for-this-blog">
<span>Creating a flake for this blog</span><a href="#creating-a-flake-for-this-blog" class="anchor las la-anchor" title="creating-a-flake-for-this-blog"></a>
</h1>
<p>
To understand how flakes aim to solve those problems, lets - once again - have a look on the new definition of this blog.
</p>
<div class="y-fill-horizontal">
<div id="cb4" class="sourceCode" data-caption="./flake.nix">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">{</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>  <span class="ex">description</span> = <span class="st">&quot;Flake utils demo&quot;</span><span class="kw">;</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>  <span class="ex">inputs.nixpkgs.url</span> = <span class="st">&quot;github:nixos/nixpkgs&quot;</span><span class="kw">;</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>  <span class="ex">inputs.nur.url</span> = <span class="st">&quot;github:nix-community/NUR&quot;</span><span class="kw">;</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>  <span class="ex">inputs.flake-utils.url</span> = <span class="st">&quot;github:numtide/flake-utils&quot;</span><span class="kw">;</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>  <span class="ex">inputs.uikit-src</span> = {</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>    <span class="ex">url</span> = <span class="st">&quot;https://github.com/uikit/uikit/archive/v3.5.8.tar.gz&quot;</span><span class="kw">;</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>    <span class="ex">flake</span> = false<span class="kw">;</span></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">};</span></span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a>  <span class="ex">outputs</span> = { self, nixpkgs, nur, flake-utils, uikit-src }:</span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a>    <span class="bu">let</span></span>
<span id="cb4-17"><a href="#cb4-17" aria-hidden="true" tabindex="-1"></a>    <span class="er">in</span></span>
<span id="cb4-18"><a href="#cb4-18" aria-hidden="true" tabindex="-1"></a>      <span class="ex">flake-utils.lib.eachDefaultSystem</span> <span class="er">(</span></span>
<span id="cb4-19"><a href="#cb4-19" aria-hidden="true" tabindex="-1"></a>        <span class="ex">system:</span></span>
<span id="cb4-20"><a href="#cb4-20" aria-hidden="true" tabindex="-1"></a>          <span class="bu">let</span></span>
<span id="cb4-21"><a href="#cb4-21" aria-hidden="true" tabindex="-1"></a>            <span class="ex">pkgs</span> = import nixpkgs { inherit system<span class="kw">;</span> <span class="ex">overlays</span> = [ nur.overlay ]<span class="kw">;</span> <span class="er">}</span><span class="kw">;</span></span>
<span id="cb4-22"><a href="#cb4-22" aria-hidden="true" tabindex="-1"></a>            <span class="ex">blog</span> = pkgs.callPackage ./blog.nix {</span>
<span id="cb4-23"><a href="#cb4-23" aria-hidden="true" tabindex="-1"></a>              <span class="ex">inherit</span> pkgs<span class="kw">;</span></span>
<span id="cb4-24"><a href="#cb4-24" aria-hidden="true" tabindex="-1"></a>              <span class="ex">nur</span> = pkgs.nur<span class="kw">;</span></span>
<span id="cb4-25"><a href="#cb4-25" aria-hidden="true" tabindex="-1"></a>              <span class="ex">thirdparty</span> = [</span>
<span id="cb4-26"><a href="#cb4-26" aria-hidden="true" tabindex="-1"></a>                <span class="kw">{</span></span>
<span id="cb4-27"><a href="#cb4-27" aria-hidden="true" tabindex="-1"></a>                  <span class="ex">name</span> = <span class="st">&quot;uikit&quot;</span><span class="kw">;</span></span>
<span id="cb4-28"><a href="#cb4-28" aria-hidden="true" tabindex="-1"></a>                  <span class="ex">path</span> = <span class="st">&quot;</span><span class="va">${uikit</span><span class="er">-src</span><span class="va">}</span><span class="st">/src&quot;</span><span class="kw">;</span></span>
<span id="cb4-29"><a href="#cb4-29" aria-hidden="true" tabindex="-1"></a>                <span class="kw">}</span></span>
<span id="cb4-30"><a href="#cb4-30" aria-hidden="true" tabindex="-1"></a>              <span class="ex">]</span><span class="kw">;</span></span>
<span id="cb4-31"><a href="#cb4-31" aria-hidden="true" tabindex="-1"></a>            <span class="er">}</span><span class="kw">;</span></span>
<span id="cb4-32"><a href="#cb4-32" aria-hidden="true" tabindex="-1"></a>          <span class="er">in</span></span>
<span id="cb4-33"><a href="#cb4-33" aria-hidden="true" tabindex="-1"></a>            <span class="ex">rec</span> {</span>
<span id="cb4-34"><a href="#cb4-34" aria-hidden="true" tabindex="-1"></a>              <span class="ex">packages</span> = { inherit <span class="er">(</span><span class="ex">blog</span><span class="kw">)</span> <span class="ex">generator</span> generator-with-thirdparty ci shell<span class="kw">;</span> <span class="ex">htop</span> = pkgs.htop<span class="kw">;</span> <span class="er">}</span><span class="kw">;</span></span>
<span id="cb4-35"><a href="#cb4-35" aria-hidden="true" tabindex="-1"></a>              <span class="ex">defaultPackage</span> = blog.generator-with-thirdparty<span class="kw">;</span></span>
<span id="cb4-36"><a href="#cb4-36" aria-hidden="true" tabindex="-1"></a>              <span class="ex">apps.compile</span> =</span>
<span id="cb4-37"><a href="#cb4-37" aria-hidden="true" tabindex="-1"></a>                <span class="ex">flake-utils.lib.mkApp</span> { drv = blog.ci.compile<span class="kw">;</span> <span class="ex">exePath</span> = <span class="st">&quot;&quot;</span><span class="kw">;</span> <span class="er">}</span><span class="kw">;</span></span>
<span id="cb4-38"><a href="#cb4-38" aria-hidden="true" tabindex="-1"></a>              <span class="ex">defaultApp</span> = apps.compile<span class="kw">;</span></span>
<span id="cb4-39"><a href="#cb4-39" aria-hidden="true" tabindex="-1"></a>              <span class="ex">devShell</span> = blog.shell<span class="kw">;</span></span>
<span id="cb4-40"><a href="#cb4-40" aria-hidden="true" tabindex="-1"></a>            <span class="er">}</span></span>
<span id="cb4-41"><a href="#cb4-41" aria-hidden="true" tabindex="-1"></a>      <span class="kw">);</span></span>
<span id="cb4-42"><a href="#cb4-42" aria-hidden="true" tabindex="-1"></a><span class="er">}</span></span></code></pre>
</div>
</div>
<p>
So that’s a lot! And notice, its even simplified through the use of <a href="https://github.com/numtide/flake-utils"><code>flake-utils</code></a>. But it does come with some structure, which we will inspect more closely now.
</p>
<p>
<em>So what do we see here?</em>
</p>
<h2 class="y-header" id="pure-imports">
<span>Pure imports</span><a href="#pure-imports" class="anchor las la-anchor" title="pure-imports"></a>
</h2>
<p>
In flake mode nix expects the flake files to only contain the top level attributes <code>description::string</code>, <code>inputs::set</code> , <code>outputs::{inputs..}-&gt;set</code>. Notice, flakes are not a function at the top level anymore.<br /> What does that imply? First, there are no arguments to be given by command line (via <code>–arg</code>/<code>–argstr</code>). This means no <code>nixpkgs</code> attribute to be passed from a higher level. Instead, your dependencies are expected to be included in <code>inputs</code> you give. <code>inputs</code> is a set where each attribute is the identifier of one input.
</p>
<p>
The corresponding part in the above <code>flake.nix</code> is
</p>
<div class="y-fill-horizontal">
<div id="cb5" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>  <span class="ex">description</span> = <span class="st">&quot;Flake utils demo&quot;</span><span class="kw">;</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>  <span class="ex">inputs.nixpkgs.url</span> = <span class="st">&quot;github:nixos/nixpkgs&quot;</span><span class="kw">;</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>  <span class="ex">inputs.nur.url</span> = <span class="st">&quot;github:nix-community/NUR&quot;</span><span class="kw">;</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>  <span class="ex">inputs.flake-utils.url</span> = <span class="st">&quot;github:numtide/flake-utils&quot;</span><span class="kw">;</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>  <span class="ex">inputs.uikit-src</span> = {</span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>    <span class="ex">url</span> = <span class="st">&quot;https://github.com/uikit/uikit/archive/v3.5.8.tar.gz&quot;</span><span class="kw">;</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>    <span class="ex">flake</span> = false<span class="kw">;</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>  <span class="er">}</span><span class="kw">;</span></span></code></pre>
</div>
</div>
<p>
Each of these input follows this structure:
</p>
<div class="y-fill-horizontal">
<div id="cb6" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="ex">inputs.</span><span class="op">&lt;</span>inputname<span class="op">&gt;</span> = {</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>  <span class="ex">url</span> = git+<span class="op">&lt;</span>url-to-git-repo<span class="op">&gt;</span>[<span class="pp">?</span>ref=<span class="pp">****</span>[<span class="kw">&amp;</span><span class="va">rev</span><span class="op">=</span><span class="pp">****</span>]]</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>      <span class="kw">|</span> <span class="kw">(</span><span class="ex">github</span><span class="kw">|</span><span class="ex">gitlab</span><span class="kw">)</span><span class="bu">:</span><span class="op">&lt;</span>user<span class="op">&gt;</span>/<span class="op">&lt;</span>repo<span class="op">&gt;</span>[/<span class="op">&lt;</span>ref<span class="op">&gt;</span> <span class="kw">|</span> <span class="ex">?ref=****[</span><span class="kw">&amp;</span><span class="va">rev</span><span class="op">=</span><span class="pp">****</span>]]<span class="kw">;</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>      <span class="kw">|</span> <span class="op">&lt;</span>known-flake<span class="op">&gt;</span>[/<span class="op">&lt;</span>ref<span class="op">&gt;</span> <span class="kw">|</span> <span class="ex">?ref=****[</span><span class="kw">&amp;</span><span class="va">rev</span><span class="op">=</span><span class="pp">****</span>]]</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>      <span class="kw">|</span> <span class="ex">/absolute/path</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>  <span class="ex">flake</span> = true <span class="kw">|</span> <span class="fu">false</span><span class="kw">;</span> <span class="co"># default = true</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a><span class="er">}</span></span></code></pre>
</div>
</div>
<dl>
<dt>
Input url
</dt>
<dd>
use <code>git+&lt;url&gt;</code> to checkout a git repository at <code>&lt;url&gt;</code>
</dd>
<dd>
use <code>/local/absolute/path</code> to load a local source
</dd>
<dd>
use <code>gitlab:&lt;user&gt;/&lt;repo&gt;</code>/<code>github:&lt;user&gt;/&lt;repo&gt;</code> to shortcut gitlab or github repositories
</dd>
<dd>
use <code>&lt;known-flake&gt;</code> to shortcut to a globally defined alias
</dd>
<dt>
<code>known-flake</code>
</dt>
<dd>
nix will manage a registry of named flakes that can be included as is and are a shortcut to another repo
</dd>
<dd>
<p>
by default following global registry items are defined in <a href="https://github.com/NixOS/flake-registry">this repo</a> and available in every nix installation:
</p>
<div class="y-fill-horizontal">
<div id="cb7" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="ex">global</span> flake:blender-bin github:edolstra/nix-warez</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="ex">global</span> flake:dwarffs github:edolstra/dwarffs</span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="ex">global</span> flake:hydra github:NixOS/hydra</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="ex">global</span> flake:nimble github:nix-community/flake-nimble</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="ex">global</span> flake:nix github:NixOS/nix</span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a><span class="ex">global</span> flake:nixops github:NixOS/nixops</span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a><span class="ex">global</span> flake:nixos-hardware github:NixOS/nixos-hardware</span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a><span class="ex">global</span> flake:nixos-homepage github:NixOS/nixos-homepage/flake</span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a><span class="ex">global</span> flake:nur github:nix-community/NUR</span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a><span class="ex">global</span> flake:nixpkgs/release-19.09 github:edolstra/nixpkgs/release-19.09</span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a><span class="ex">global</span> flake:nixpkgs github:NixOS/nixpkgs</span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a><span class="ex">global</span> flake:templates github:NixOS/templates</span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a><span class="ex">global</span> flake:patchelf github:NixOS/patchelf</span></code></pre>
</div>
</div>
</dd>
<dd>
read more about registry on the <a href="https://nixos.wiki/wiki/Nix_command/registry">wiki</a>
</dd>
<dt>
Specifying a commit or branch
</dt>
<dd>
by default, the main branch of the repository pointed to will be used as to provide the dependency flake.
</dd>
<dd>
Nix will also update dependencies to the latest commit on <code>nix flake update</code> calls
</dd>
<dd>
to pin repositories to a certain commit or override the default branch append a <code>?ref=commit-ref</code> or <code>?&lt;branch&gt;</code> respectively
</dd>
<dt>
Non flake inputs
</dt>
<dd>
nix will try to interpret inputs as flakes, to suppress that, set <code class="sourceCode bash"><span class="op">&lt;</span>inputname<span class="op">&gt;</span>.flake <span class="ex">=</span> false</code>
</dd>
<dt>
Overriding dependency inputs
</dt>
<dd>
traditionally, if one wanted a dependency to use a certain nixpkgs version (i.e. to make use of binary caches) one would specify a certain <code>nixpkgs</code> argument while <code>import</code>’ing. Flakes allow the same thing by setting <code>inputs.&lt;inputname&gt;.inputs.&lt;inputname&gt;.follows = &lt;local inputsname&gt;</code>
</dd>
</dl>
<div class="notice box y-fill-horizontal">
<p>
If using a <code>&lt;known-flake&gt;</code> nix will not use your respective channel even if one with the same name such as <code>nixpkgs</code> exists.
</p>
</div>
<p>
See also the <a href="#reference">reference below</a> for more information and examples.
</p>
<div class="uk-alert-primary note box y-fill-horizontal" data-header="Issues solved here:">
<div class="header">
<div>
<span class="las la-pencil-alt"></span>
<div class="badge">
<p>NOTE</p>
</div>
</div>
<div>
<p>
Issues solved here:
</p>
</div>
</div>
<ol type="1">
<li>
impure imports
</li>
<li>
no ultimate way to pin <code>nixpkgs</code>
</li>
<li>
no common (import) interface
</li>
</ol>
<p>
First, a formal definition even a simple one as this alleviates us from the danger of importing dependencies impurely. All imports are formally defined and locked to a specific revision in the projects <code>flake.lock</code> file. By being able to also add a specific <code>ref</code> tag to inputs, this interface allows for intuitive pinning of dependencies. Finally, the way imports are specified and overridden is the same for all flakes, providing a familiar and unified interface.
</p>
</div>
<p>
So far so good, but we have only discussed about 10 lines of the flake s far…
</p>
<h2 class="y-header" id="pure-outputs">
<span>Pure outputs</span><a href="#pure-outputs" class="anchor las la-anchor" title="pure-outputs"></a>
</h2>
<p>
As mentioned above, nix flakes do not serve as top level function anymore. That does not mean there is no function involved. For flakes the output is the result of a function as well.
</p>
<pre><code>outputs = { self, nixpkgs, nur, flake-utils, uikit-src }:
  ...</code></pre>
<p>
This third and last attribute takes as arguments all the inputs defined earlier. But unlike classical nix approaches, only a certain set of attributes are allowed and expected as the result of this function.<br /> <em>An extensive list of output attributes is provided <a href="#output-attributes">below</a></em>.
</p>
<p>
Generally the format for these is:
</p>
<pre><code>&lt;kind&gt;.&lt;arch&gt;.&lt;output&gt; = ...;</code></pre>
<p>
or concretely
</p>
<pre><code>packages.&quot;x86_64-darwin&quot;.generator = blog.generator;</code></pre>
<p>
Notice how the architecture and OS of the target platform is explicitly encoded, allowing for specializations or exclusive packaging for specific platforms. This also means that the used <code>nixpkgs</code> needs to be instantiated for all desired platforms. In practice one will want to use a shortcut for that and while this is used for all our <a href="https://github.com/ngi-nix">projects packaged for NGI</a> so far, for my blog this shortcut is provided by <a href="https://github.com/numtide/flake-utils"><code>flake-utils</code></a>.
</p>
<p>
Using these, defining the outputs for this blog just becomes:
</p>
<div class="y-fill-horizontal">
<div id="cb11" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a>  <span class="bu">let</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>    <span class="er">in</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>      <span class="ex">flake-utils.lib.eachDefaultSystem</span> <span class="er">(</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>        <span class="ex">system:</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>          <span class="bu">let</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>            <span class="ex">pkgs</span><span class="st">&#39; = import nixpkgs { inherit system; overlays = [ nur.overlay ]; };</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a><span class="st">            blog = pkgs&#39;</span><span class="ex">.callPackage</span> ./blog.nix {</span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>              <span class="ex">pkgs</span> = pkgs<span class="st">&#39;;</span></span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a><span class="st">              nur = pkgs&#39;</span>.nur<span class="kw">;</span></span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a>              <span class="ex">thirdparty</span> = [</span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a>                <span class="kw">{</span></span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a>                  <span class="ex">name</span> = <span class="st">&quot;uikit&quot;</span><span class="kw">;</span></span>
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a>                  <span class="ex">path</span> = <span class="st">&quot;</span><span class="va">${uikit</span><span class="er">-src</span><span class="va">}</span><span class="st">/src&quot;</span><span class="kw">;</span></span>
<span id="cb11-14"><a href="#cb11-14" aria-hidden="true" tabindex="-1"></a>                <span class="kw">}</span></span>
<span id="cb11-15"><a href="#cb11-15" aria-hidden="true" tabindex="-1"></a>              <span class="ex">]</span><span class="kw">;</span></span>
<span id="cb11-16"><a href="#cb11-16" aria-hidden="true" tabindex="-1"></a>            <span class="er">}</span><span class="kw">;</span></span>
<span id="cb11-17"><a href="#cb11-17" aria-hidden="true" tabindex="-1"></a>          <span class="er">in</span></span>
<span id="cb11-18"><a href="#cb11-18" aria-hidden="true" tabindex="-1"></a>            <span class="ex">rec</span> {</span>
<span id="cb11-19"><a href="#cb11-19" aria-hidden="true" tabindex="-1"></a>              <span class="ex">packages</span> = {</span>
<span id="cb11-20"><a href="#cb11-20" aria-hidden="true" tabindex="-1"></a>                <span class="ex">inherit</span> <span class="er">(</span><span class="ex">blog</span><span class="kw">)</span> <span class="ex">generator</span> generator-with-thirdparty ci shell<span class="kw">;</span></span>
<span id="cb11-21"><a href="#cb11-21" aria-hidden="true" tabindex="-1"></a>              <span class="er">}</span><span class="kw">;</span></span>
<span id="cb11-22"><a href="#cb11-22" aria-hidden="true" tabindex="-1"></a>              <span class="ex">defaultPackage</span> = blog.generator-with-thirdparty<span class="kw">;</span></span>
<span id="cb11-23"><a href="#cb11-23" aria-hidden="true" tabindex="-1"></a>              <span class="ex">apps.compile</span> =</span>
<span id="cb11-24"><a href="#cb11-24" aria-hidden="true" tabindex="-1"></a>                <span class="ex">flake-utils.lib.mkApp</span> { drv = blog.ci.compile<span class="kw">;</span> <span class="ex">exePath</span> = <span class="st">&quot;&quot;</span><span class="kw">;</span> <span class="er">}</span><span class="kw">;</span></span>
<span id="cb11-25"><a href="#cb11-25" aria-hidden="true" tabindex="-1"></a>              <span class="ex">defaultApp</span> = apps.compile<span class="kw">;</span></span>
<span id="cb11-26"><a href="#cb11-26" aria-hidden="true" tabindex="-1"></a>              <span class="ex">devShell</span> = blog.shell<span class="kw">;</span></span>
<span id="cb11-27"><a href="#cb11-27" aria-hidden="true" tabindex="-1"></a>            <span class="er">}</span></span>
<span id="cb11-28"><a href="#cb11-28" aria-hidden="true" tabindex="-1"></a>      <span class="kw">);</span></span></code></pre>
</div>
</div>
<p>
To take this apart again, we face three different sections here.
</p>
<ol type="1">
<li>
<code>flake-utils.lib.eachDefaultSystem</code>, like its name suggests will provide the attribute set in its scope for all default systems (basically linux and darwin on x86_64 hardware). Hence, we don’t need to worry about these tags.
</li>
<li>
The actual output still needs to conform to flakes’ expected attributes. In this case we set <code>packages</code>, <code>defaultPackage</code>, <code>apps</code>, <code>defaultApp</code> and <code>devShell</code>. There are even more most importantly <code>overlay</code> which are referenced <a href="#output-attributes">below</a>
</li>
<li>
third one is the middle part and shows an important aspect of nix flakes. Because there is no access to impure variables (<code>--arg</code>, environment variables, the current system, etc.), <code>nixpkgs</code> must be imported explicitly for each system. Additionally, this gives the opportunity to apply any possible overlay. In the case of this blog everything is defined in an external <code>blog.nix</code> file and imported from there.
</li>
</ol>
<h3 class="y-header" id="output-attributes">
<span>Output attributes</span><a href="#output-attributes" class="anchor las la-anchor" title="output-attributes"></a>
</h3>
<div class="uk-alert-warning warning box y-fill-horizontal">
<p>
This section highlights some commands that are not yet available on stable nix. In fact, you will need to run either <code>nixUnstable</code> or <code>nixFlakes</code> from a recent <code>nixpkgs</code> set, at best <code>unstable</code>. Also you need to add <code>experimental-features = nix-command flakes</code> to your <code>nix.conf</code> file.
</p>
<p>
With that set trying out the commands can be done in a shell using
</p>
<pre><code>$ nix-shell -p nixUnstable</code></pre>
</div>
<p>
Coming back to the outputs. <code>packages</code> is the actual output that is used with <code>nix shell</code> and <code>nix build</code> commands in particular (yes there are/will be <a href="https://nixos.org/manual/nix/unstable/command-ref/experimental-commands.html">a lot more</a>).
</p>
<p>
To open a shell with specific packages available (alike <code>nix-shell -p</code>) run:
</p>
<pre><code>$ nix shell ./#generator-with-thirdparty

or from an external repo:

$ nix shell &quot;gitlab:pi-lar/neuropil#generator-with-thirdparty&quot;</code></pre>
<div class="info box y-fill-horizontal">
<p>
Replace <code>shell</code> with <code>build</code> to build it to a <code>./result</code> output link.
</p>
<p>
Shell does actually accept multiple derivation arguments so
</p>
<pre><code>$ nix shell nixpkgs#{htop,nodePackages.act,tealdeer}</code></pre>
<p>
is possible to use.
</p>
<p>
<em>Notice</em> that some inputs might need to be quoted due to substitution rules in your shell.
</p>
</div>
<p>
<code>apps</code> is used together with <code>nix run</code>, similarly to <code>npm run</code>. You can define binaries that can then be run directly without explicitly building them first. This allowed me to change the somewhat cryptic <code>$(nix-build -A packages.x86_64-linux.ci.compile --no-out-link)</code> to <code>nix run ./#compile</code> in the CI script. Actually given that <code>defaultApp</code> point to the same <code>compile</code> attribute, the argument <code>./#compile</code> could be elided paying with decreased clarity.
</p>
<p>
<code>devShell</code> is another special one used in combination with <code>nix develop</code> which opens a <em><code>bash</code></em> shell with the given derivation prepared.
</p>
<p>
Of course, project shells using for example <code>mkShell</code> do also still work (and are used here as well). Either by using <code>nix develop</code> with such a derivation or <code>nix shell</code> in combination with <code>buildEnv</code>.
</p>
<div class="uk-alert-warning warning box y-fill-horizontal">
<p>
<code>nix develop</code> <strong>always</strong> opens a <em><code>bash</code></em> shell. If you use <code>zsh</code> some work-arounds or relying on legacy <code>nix-shell</code> is needed for <code>zsh</code> enabled shells.
</p>
<p>
Using flakes, one alternative is to use a <code>buildEnv</code> derivation which is loaded using <code>nix</code><strong><code>shell</code></strong>.
</p>
</div>
<div class="uk-alert-primary note box y-fill-horizontal" data-header="Issues solved here">
<div class="header">
<div>
<span class="las la-pencil-alt"></span>
<div class="badge">
<p>NOTE</p>
</div>
</div>
<div>
<p>
Issues solved here
</p>
</div>
</div>
<ol type="1">
<li>
impure arguments
</li>
<li>
no common (output) interface
</li>
<li>
poor discoverability
</li>
</ol>
<p>
Here we see how a defined output interface helps to understand to organize the specific outputs and give the user semantic cues what the outputs are used for. It also allows nix to be more ergonomic as seen in the case of <code>nix run</code>. Although, being a matter of the tooling as well, having a well defined <code>flake.nix</code> file available to inspect, discovering attributes over several repositories becomes much more feasible. Finally due to the missing impurity, guaranties that some derivation will actually produce the same outputs are getting even stronger.
</p>
</div>
<h3 class="y-header" id="composing-flakes">
<span>Composing flakes</span><a href="#composing-flakes" class="anchor las la-anchor" title="composing-flakes"></a>
</h3>
<p>
In the last two sections I presented solutions for six of the seven problems that were identified in the beginning. That leaves us with:
</p>
<ol start="7" type="1">
<li>
poor composability
</li>
</ol>
<p>
Actually we’re almost there.. Remember how I mentioned the possibility to inject overlays when importing <code>nixpkgs</code>? Composing multiple sources of packages is easy if one can just drop them in there.<br /> Moreover, there are conventional output arguments <code>overlay</code> and <code>overlays</code> that make discovering the fakes; overlay(s) a bit easier.
</p>
<div class="y-fill-horizontal">
<div id="cb15" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">{</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>  <span class="ex">description</span> = <span class="st">&quot;Flake utils demo&quot;</span><span class="kw">;</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a>  <span class="ex">inputs.flake-utils.url</span> = <span class="st">&quot;github:numtide/flake-utils&quot;</span><span class="kw">;</span></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a>  <span class="co"># assuming that this flake exports an overlay attribute</span></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a>  <span class="ex">inputs.someflake.url</span> = <span class="st">&quot;foo.com/bar&quot;</span><span class="kw">;</span></span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a>  <span class="ex">outputs</span> = { self, nixpkgs, flake-utils, someflake }:</span>
<span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a>    <span class="ex">flake-utils.lib.eachDefaultSystem</span> <span class="er">(</span><span class="ex">system:</span></span>
<span id="cb15-10"><a href="#cb15-10" aria-hidden="true" tabindex="-1"></a>      <span class="bu">let</span></span>
<span id="cb15-11"><a href="#cb15-11" aria-hidden="true" tabindex="-1"></a>        <span class="ex">artifacts</span> = final: prev: {</span>
<span id="cb15-12"><a href="#cb15-12" aria-hidden="true" tabindex="-1"></a>          <span class="ex">my_hello</span> = prev.hello<span class="kw">;</span></span>
<span id="cb15-13"><a href="#cb15-13" aria-hidden="true" tabindex="-1"></a>        <span class="er">}</span><span class="kw">;</span></span>
<span id="cb15-14"><a href="#cb15-14" aria-hidden="true" tabindex="-1"></a>        <span class="ex">pkgs</span> = import nixpkgs {</span>
<span id="cb15-15"><a href="#cb15-15" aria-hidden="true" tabindex="-1"></a>          <span class="ex">overlays</span> = [ someflake.overlay artifacts ]<span class="kw">;</span></span>
<span id="cb15-16"><a href="#cb15-16" aria-hidden="true" tabindex="-1"></a>        <span class="er">}</span><span class="kw">;</span></span>
<span id="cb15-17"><a href="#cb15-17" aria-hidden="true" tabindex="-1"></a>      <span class="er">in</span></span>
<span id="cb15-18"><a href="#cb15-18" aria-hidden="true" tabindex="-1"></a>      <span class="co"># and here is the core of the consumer flake</span></span>
<span id="cb15-19"><a href="#cb15-19" aria-hidden="true" tabindex="-1"></a>      <span class="kw">{</span></span>
<span id="cb15-20"><a href="#cb15-20" aria-hidden="true" tabindex="-1"></a>        <span class="ex">defaultPackage</span> = pkgs.my_hello<span class="kw">;</span></span>
<span id="cb15-21"><a href="#cb15-21" aria-hidden="true" tabindex="-1"></a>        <span class="ex">overlay</span> = artifacts<span class="kw">;</span></span>
<span id="cb15-22"><a href="#cb15-22" aria-hidden="true" tabindex="-1"></a>      <span class="kw">}</span></span>
<span id="cb15-23"><a href="#cb15-23" aria-hidden="true" tabindex="-1"></a>    <span class="kw">);</span></span>
<span id="cb15-24"><a href="#cb15-24" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span></code></pre>
</div>
</div>
<p>
Adapted from <a href="https://discourse.nixos.org/t/how-to-determine-intended-use-of-nix-flakes-outputs/8633/2">this answer on the forum</a> this example shows how <code>someflake</code>’s overlay can be imported, and how to define your own overlay in the same manner. Here it is used rather uselessly, but one can imagine to define outputs in a separate file as overlay, that can then be plugged for use and export in the flake.
</p>
<div class="info box y-fill-horizontal">
<p>
As a kind of <em>new</em> convention now enforced by <code>nix check</code> is to call your overlay arguments <code>final: prev:</code> for greater clarity than the classical <code>self: super:</code> combination.
</p>
</div>
<h1 class="y-header" id="retrospective">
<span>Retrospective</span><a href="#retrospective" class="anchor las la-anchor" title="retrospective"></a>
</h1>
<p>
So I changed the nix setup of this blog to flakes… Was it worth it?
</p>
<p>
Of course it depends. For the project that is this blog the benefits of committing to flakes are rather unconvincing. No one uses this as a dependency or wants to discover it as such. I am the only one developing this, so I might have my own conventions to import things, pin my dependencies and define my interface. Also, maybe I do want to use CLI arguments to nix.
</p>
<p>
Personally though it did convince me (obviously). I am a great supporter of the Nix philosophy and the Flakes do make a great addition to the ecosystem. I first got into contact with them when starting to work on the NGI0 project at which time Eelco had just written the first public post about flakes and the documentation was sparse to say the least… But as a new thing it still caught my interest. Looking for projects outside NGI this blog seemed like a great candidate to apply this new technology to as it posed literally no risk whatsoever if it didn’t work out. It gave me a chance to make myself comfortable with the technology and dig deeper to write this article.
</p>
<p>
Now I really like how this turned out, especially the <code>nix run</code> part comes in handy here and the native caching might come in handy for quicker <code>direnv</code> shells.
</p>
<p>
One downturn is still that <code>nix develop</code> is not able to open zsh shells so the usual <code>mkShell</code> technique does not work with flakes and one needs to fall back to <code>nix-shell</code> or <code>buildEnv</code> alternatives. Also there are still flags and a special nix binary required to make use of the flake related nix features.
</p>
<h1 class="y-header" id="references">
<span>References</span><a href="#references" class="anchor las la-anchor" title="references"></a>
</h1>
<h2 class="y-header" id="flake-reference-conventions">
<span>Flake reference conventions</span><a href="#flake-reference-conventions" class="anchor las la-anchor" title="flake-reference-conventions"></a>
</h2>
<p>
Nix commands will eventually reference outputs. There are multiple ways how these can be referenced depending on where they come from:
</p>
<p>
A flake reference is actually structured similar to an URL:
</p>
<div class="y-fill-horizontal">
<div id="cb16" class="sourceCode">
<pre class="sourceCode txt"><code class="sourceCode default"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a>&lt;flake url&gt;[?&lt;git ref/rev&gt;][#&lt;output&gt;]</span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>    │</span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>    ├── git+&lt;url&gt;</span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>    ├── gitlab:&lt;user&gt;/&lt;repo&gt; or github:&lt;user&gt;/&lt;repo&gt;</span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a>    ├── /local/absolute/path</span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a>    ├──./relative/path (only as an argument to `nix` commands)</span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a>    └── a known source in the registry such as `nixpkgs`</span></code></pre>
</div>
</div>
<p>
If git repositories are pointed to directly query parameters can be added to select a specific branch and/or commit.
</p>
<p>
As nix has not yet adapted to some git providers renaming their <code>master</code> branches to <code>main</code> you might occasionally be confronted with an error similar to
</p>
<blockquote>
</blockquote>
<pre><code>fetching Git repository &#39;https://gitlab.com/pi-lar/neuropil&#39;fatal: couldn&#39;t find remote ref refs/heads/master</code></pre>
<p>
To resolve this the actual branch <code>main</code> or any tag might be explicated using the <code>ref</code> argument:
</p>
<pre><code>git+https://gitlab.com/pi-lar/neuropil.git?ref=main</code></pre>
<p>
If using the abbreviated GitLab/GitHub urls this can be expressed like this:
</p>
<pre><code>gitlab:pi-lar/neuropil/main</code></pre>
<p>
Similarly, if an exact commit is targeted, this can be pointed to using the <code>rev</code> argument
</p>
<pre><code>   gitlab:pi-lar/neuropil?rev=1043b9c1736c2a9b92938f0304ddb55ce4ab68a6
or gitlab:pi-lar/neuropil/1043b9c1736c2a9b92938f0304ddb55ce4ab68a6</code></pre>
<p>
The output is finally selected in the format known from the <code>-A</code> argument of old nix commands such as <code>nix-shell</code>:
</p>
<pre><code>   nixpkgs#haskellPackages.pandoc
or .#generator-with-thirdparty      (used to build this blog&#39;s generator)</code></pre>
<h2 class="y-header" id="output-attributes-1">
<span>Output attributes</span><a href="#output-attributes-1" class="anchor las la-anchor" title="output-attributes-1"></a>
</h2>
<p>
Following is a quick reference over all flake output attributes.
</p>
<div class="y-fill-horizontal">
<div id="cb22" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="kw">{</span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a>    <span class="co"># Executed by `nix flake check`</span></span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a>    <span class="ex">checks.</span><span class="st">&quot;&lt;system&gt;&quot;</span><span class="ex">.</span><span class="st">&quot;&lt;attr&gt;&quot;</span> = derivation<span class="kw">;</span></span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a>    <span class="co"># Executed by `nix build .#&lt;name&gt;`</span></span>
<span id="cb22-6"><a href="#cb22-6" aria-hidden="true" tabindex="-1"></a>    <span class="ex">packages.</span><span class="st">&quot;&lt;system&gt;&quot;</span><span class="ex">.</span><span class="st">&quot;&lt;attr&gt;&quot;</span> = derivation<span class="kw">;</span></span>
<span id="cb22-7"><a href="#cb22-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-8"><a href="#cb22-8" aria-hidden="true" tabindex="-1"></a>    <span class="co"># Executed by `nix build .`</span></span>
<span id="cb22-9"><a href="#cb22-9" aria-hidden="true" tabindex="-1"></a>    <span class="ex">defaultPackage.</span><span class="st">&quot;&lt;system&gt;&quot;</span> = derivation<span class="kw">;</span></span>
<span id="cb22-10"><a href="#cb22-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-11"><a href="#cb22-11" aria-hidden="true" tabindex="-1"></a>    <span class="co"># the derivation that is prepared when running `nix develop`</span></span>
<span id="cb22-12"><a href="#cb22-12" aria-hidden="true" tabindex="-1"></a>    <span class="co"># defaults to defaultPackage.&quot;&lt;system&gt;&quot;</span></span>
<span id="cb22-13"><a href="#cb22-13" aria-hidden="true" tabindex="-1"></a>    <span class="ex">devShell.</span><span class="st">&quot;&lt;system&gt;&quot;</span> = derivation<span class="kw">;</span></span>
<span id="cb22-14"><a href="#cb22-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-15"><a href="#cb22-15" aria-hidden="true" tabindex="-1"></a>    <span class="co"># Executed by `nix run .#&lt;name&gt;</span></span>
<span id="cb22-16"><a href="#cb22-16" aria-hidden="true" tabindex="-1"></a>    <span class="ex">apps.</span><span class="st">&quot;&lt;system&gt;&quot;</span><span class="ex">.</span><span class="st">&quot;&lt;attr&gt;&quot;</span> = {</span>
<span id="cb22-17"><a href="#cb22-17" aria-hidden="true" tabindex="-1"></a>      <span class="bu">type</span> = <span class="st">&quot;app&quot;</span><span class="kw">;</span></span>
<span id="cb22-18"><a href="#cb22-18" aria-hidden="true" tabindex="-1"></a>      <span class="ex">program</span> = <span class="st">&quot;&lt;store-path&gt;&quot;</span><span class="kw">;</span></span>
<span id="cb22-19"><a href="#cb22-19" aria-hidden="true" tabindex="-1"></a>    <span class="kw">};</span></span>
<span id="cb22-20"><a href="#cb22-20" aria-hidden="true" tabindex="-1"></a>    <span class="ex">defaultApp.</span><span class="st">&quot;&lt;system&gt;&quot;</span> = { type = <span class="st">&quot;app&quot;</span><span class="kw">;</span> <span class="ex">program</span> = <span class="st">&quot;...&quot;</span><span class="kw">;</span> <span class="er">}</span><span class="kw">;</span></span>
<span id="cb22-21"><a href="#cb22-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-22"><a href="#cb22-22" aria-hidden="true" tabindex="-1"></a>    <span class="co"># </span><span class="al">TODO</span><span class="co">: Only seen used in connection with nixpkgs</span></span>
<span id="cb22-23"><a href="#cb22-23" aria-hidden="true" tabindex="-1"></a>    <span class="ex">legacyPackages</span> = TODO<span class="kw">;</span></span>
<span id="cb22-24"><a href="#cb22-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-25"><a href="#cb22-25" aria-hidden="true" tabindex="-1"></a>    <span class="co"># overlay to easily override/packages in the package set of the importer</span></span>
<span id="cb22-26"><a href="#cb22-26" aria-hidden="true" tabindex="-1"></a>    <span class="ex">overlay</span> = final: prev: { }<span class="kw">;</span></span>
<span id="cb22-27"><a href="#cb22-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-28"><a href="#cb22-28" aria-hidden="true" tabindex="-1"></a>    <span class="co"># </span><span class="al">TODO</span><span class="co">: Same idea as overlay but several.</span></span>
<span id="cb22-29"><a href="#cb22-29" aria-hidden="true" tabindex="-1"></a>    <span class="ex">overlays.</span><span class="st">&quot;&lt;attr&gt;&quot;</span> = final: prev: { }<span class="kw">;</span></span>
<span id="cb22-30"><a href="#cb22-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-31"><a href="#cb22-31" aria-hidden="true" tabindex="-1"></a>    <span class="co"># Additionally to packages also modules for Nixos can be provided (Flakes can be used with `nixos-rebuild`)</span></span>
<span id="cb22-32"><a href="#cb22-32" aria-hidden="true" tabindex="-1"></a>    <span class="ex">nixosModule</span> = Module definition<span class="kw">;</span></span>
<span id="cb22-33"><a href="#cb22-33" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-34"><a href="#cb22-34" aria-hidden="true" tabindex="-1"></a>    <span class="co"># </span><span class="al">TODO</span><span class="co">: Same idea as nixosModule but several</span></span>
<span id="cb22-35"><a href="#cb22-35" aria-hidden="true" tabindex="-1"></a>    <span class="ex">nixosModules.</span><span class="st">&quot;&lt;attr&gt;&quot;</span> = Module definition<span class="kw">;</span></span>
<span id="cb22-36"><a href="#cb22-36" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-37"><a href="#cb22-37" aria-hidden="true" tabindex="-1"></a>    <span class="co"># Attrset of nixos configurations by hostname.</span></span>
<span id="cb22-38"><a href="#cb22-38" aria-hidden="true" tabindex="-1"></a>    <span class="ex">nixosConfigurations.</span><span class="st">&quot;&lt;hostname&gt;&quot;</span> = {}<span class="kw">;</span></span>
<span id="cb22-39"><a href="#cb22-39" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-40"><a href="#cb22-40" aria-hidden="true" tabindex="-1"></a>    <span class="co"># Hydra checks</span></span>
<span id="cb22-41"><a href="#cb22-41" aria-hidden="true" tabindex="-1"></a>    <span class="ex">hydraJobs.</span><span class="st">&quot;&lt;attr&gt;&quot;</span><span class="ex">.</span><span class="st">&quot;&lt;system&gt;&quot;</span> = derivation<span class="kw">;</span></span>
<span id="cb22-42"><a href="#cb22-42" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-43"><a href="#cb22-43" aria-hidden="true" tabindex="-1"></a>    <span class="co"># Used by `nix flake init -t &lt;flake&gt;`</span></span>
<span id="cb22-44"><a href="#cb22-44" aria-hidden="true" tabindex="-1"></a>    <span class="ex">defaultTemplate</span> = {</span>
<span id="cb22-45"><a href="#cb22-45" aria-hidden="true" tabindex="-1"></a>      <span class="ex">path</span> = <span class="st">&quot;&lt;store-path&gt;&quot;</span><span class="kw">;</span></span>
<span id="cb22-46"><a href="#cb22-46" aria-hidden="true" tabindex="-1"></a>      <span class="ex">description</span> = <span class="st">&quot;template description goes here?&quot;</span><span class="kw">;</span></span>
<span id="cb22-47"><a href="#cb22-47" aria-hidden="true" tabindex="-1"></a>    <span class="er">}</span><span class="kw">;</span></span>
<span id="cb22-48"><a href="#cb22-48" aria-hidden="true" tabindex="-1"></a>    <span class="co"># Used by `nix flake init -t &lt;flake&gt;#&lt;attr&gt;`</span></span>
<span id="cb22-49"><a href="#cb22-49" aria-hidden="true" tabindex="-1"></a>    <span class="ex">templates.</span><span class="st">&quot;&lt;attr&gt;&quot;</span> = { path = <span class="st">&quot;&lt;store-path&gt;&quot;</span><span class="kw">;</span> <span class="ex">description</span> = <span class="st">&quot;&quot;</span><span class="kw">;</span> <span class="er">)</span><span class="kw">;</span></span>
<span id="cb22-50"><a href="#cb22-50" aria-hidden="true" tabindex="-1"></a>  <span class="er">}</span></span></code></pre>
</div>
</div>
<div class="uk-alert-primary note box y-fill-horizontal" data-header="Further Reading/Resources">
<div class="header">
<div>
<span class="las la-pencil-alt"></span>
<div class="badge">
<p>NOTE</p>
</div>
</div>
<div>
<p>
Further Reading/Resources
</p>
</div>
</div>
<ul>
<li>
<a href="https://nixos.wiki/wiki/Flakes">wiki page on flakes</a>
</li>
<li>
<a href="https://zimbatm.com/NixFlakes/">zimbatm’s blog article</a>
</li>
<li>
Eelco’s blog article over at tweag.io
<ul>
<li>
<a href="https://www.tweag.io/blog/2020-05-25-flakes/">Part 1</a>
</li>
<li>
<a href="https://www.tweag.io/blog/2020-06-25-eval-cache/">Part 2</a>
</li>
<li>
<a href="https://www.tweag.io/blog/2020-07-31-nixos-flakes/">Part 3</a>
</li>
</ul>
</li>
<li>
<a href="https://nixos.wiki/wiki/Nix_command"><code>nix</code> commands</a>
</li>
</ul>
</div>
<p>
As always, thank you for reading this far I hope you enjoyed this article!
</p>
<p>
It helped me a lot to structure my knowledge about nix flakes and I am glad to share this to a wider audience.
</p>
<p>
If you have comments drop me a mail, or comment publicly on the media you where found this. For additions or corrections and critique feel free to use <a href="https://github.com/ysndr/blog/issues/new">GitHub issue tracker</a>.
</p>
<section class="footnotes" role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote">
<p>
<a href="https://dictionary.cambridge.org/dictionary/english/flake">Definition of Flake</a><a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a>
</p>
</li>
</ol>
</section>]]></summary>
</entry>
<entry>
    <title>Building a reproducible blog with Nix</title>
    <link href="https://blog.ysndr.de/posts/internals/2020-04-10-built-with-nix/index.html" />
    <id>https://blog.ysndr.de/posts/internals/2020-04-10-built-with-nix/index.html</id>
    <published>2020-04-10T00:00:00Z</published>
    <updated>2020-04-10T00:00:00Z</updated>
    <summary type="html"><![CDATA[<h1 class="y-header" id="building-a-reproducible-blog-with-nix">
<span>Building a reproducible blog with Nix</span><a href="#building-a-reproducible-blog-with-nix" class="anchor las la-anchor" title="building-a-reproducible-blog-with-nix"></a>
</h1>
<p>
This blog is hosted by <a href="https://pages.github.com/">GitHub Pages</a>. GitHub Pages, aside static HTML content, only supports building Jekyll pages natively. At some point a website like this one has to be <strong>generated</strong>, i.e. turned into static HTML content. This means Markdown has to be converted to HTML static pages (like the <a href="/">homepage</a>), an <a href="/archive.html">archive</a> has to be created, and <a href="/rss.xml">RSS</a> and <a href="/atom.xml">ATOM</a> feeds have to be produced. In this blog’s case, this is done by a Haskell DSL called <a href="https://jaspervdj.be/hakyll/">Hakyll</a>. More details about that can be found in <a href="2019-12-31-built-with-hakyll-part-1.html">prior articles</a>.
</p>
<p>
In order to keep everything in the same place, I use <a href="https://github.com/features/actions">GitHub Actions</a> as a mean to automatically build and publish this blog whenever I push updates or merge pull requests.
</p>
<p>
<strong>Was this not an article about Nix?</strong>
</p>
<p>
Yes indeed it is. In order to create reproducible builds of this blog I employ the <a href="https://nixos.org/nix">Nix</a> package manager. But in order…
</p>
<div class="info box y-fill-horizontal">
<p>
Jump to <a href="#nix-on-this-blog">Nix on this blog</a> if you know nix already.
</p>
</div>
<h2 class="y-header" id="what-is-nix">
<span>What is Nix?</span><a href="#what-is-nix" class="anchor las la-anchor" title="what-is-nix"></a>
</h2>
<p>
Nix is sort of a hybrid tool between a package manager and a build system. The Nix homepage states:
</p>
<blockquote>
<p>
Nix is a powerful package manager for Linux and other Unix systems that makes package management reliable and reproducible. It provides atomic upgrades and rollbacks, side-by-side installation of multiple versions of a package, multi-user package management and easy setup of build environments.
</p>
</blockquote>
<p>
Sounds… good? What does all of that mean though?
</p>
<p>
Nix (the package manager) is built around the functional programming language <code>nix</code> (what a coincidence, ha?). A program, library, etc. is built by Nix as the output of a pure function. Runtime/buildtime dependencies go in mix with the sources of the package, are built in an isolated space, and output an executable or whatever you want to build. Such a function is called a <strong>Derivation</strong>.
</p>
<p>
Everything that should be built with Nix has to be described as such a function. In fact, the whole set of packages that is there is just <a href="https://github.com/nixos/nixpkgs">a giant collection</a> of functions, each defined in their own files.
</p>
<p>
The isolated manner in which the packages are built also shows in the way they are managed. All packages are installed as such:
</p>
<pre><code>/nix/store/6fgjp1wsv1w44f890f6kvwywjnc32svr-zoxide-0.2.1/bin/zoxide</code></pre>
<p>
Lets take this apart:
</p>
<dl>
<dt>
<code>/nix/store/</code>
</dt>
<dd>
This is the nix store all packages are contained in this folder
</dd>
<dt>
<code>6fgjp1wsv1w44f890f6kvwywjnc32svr</code>
</dt>
<dd>
This is a hash of the producing function, it takes into account the function itself, and its inputs
</dd>
<dd>
It also easens binary caching.
</dd>
<dt>
<code>zoxide</code>
</dt>
<dd>
the package’s name
</dd>
<dt>
<code>0.2.1</code>
</dt>
<dd>
the packaged version
</dd>
<dt>
<code>/bin/zoxide</code>
</dt>
<dd>
the actual executable
</dd>
<dd>
actually the file structure of packages is similar to what you would normally find in places like <code>/usr</code> or <code>~/.local/</code>
</dd>
</dl>
<p>
Yet, while that package might exists in the store, this does not mean it is <em>installed</em> or usable. — Huh?
</p>
<p>
You see, the hash we have seen right now is there for a reason. It allows to have multiple versions of one and the same program at the same time, even with the same version. Normally all packages are built according to one specific state of the <code>nixpkgs</code> repo. <code>.nix</code> files get evaluated by writing a build instruction file (<code>.drv</code>). This resolves all dependencies (building them if they do not exist yet), prepares the package’s source and combines those into a hash. If one instead builds it with a newer version where some dependency was updated or changed, not only this derivation hash changes, but it also happens to change the target derivation’s hash, forcing it to be rebuilt using the new dependency. The same happens if sources change. As a result, many different versions of a package can coexist in the store.
</p>
<div class="uk-alert-primary note box y-fill-horizontal" data-header="">
<div class="header">
<div>
<span class="las la-pencil-alt"></span>
<div class="badge">
<p>NOTE</p>
</div>
</div>
<div>

</div>
</div>
<p>
As nix functions are pure, <strong>wherever</strong> one uses the same <code>nixpkgs</code> instance, the exact same inputs are used to create the exact same output. Also, it makes little to no difference on which machine the package is built. The binary will be the same(ish).
</p>
<p>
Actually, there is a <a href="https://r13y.com/">project</a> tracking how many builds (of a vital subset of nix) are reproducible on two different machines.
</p>
</div>
<h3 class="y-header" id="how-to-installuse-packages">
<span>How to install/use packages?</span><a href="#how-to-installuse-packages" class="anchor las la-anchor" title="how-to-installuse-packages"></a>
</h3>
<h4 class="y-header" id="global-installation">
<span>Global installation</span><a href="#global-installation" class="anchor las la-anchor" title="global-installation"></a>
</h4>
<p>
There are different ways to achive this. Using nix locally, the easiest but least idiomatic would be:
</p>
<div class="y-fill-horizontal">
<div id="cb2" class="sourceCode">
<pre class="sourceCode sh"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix-env <span class="at">-iA</span> zoxide</span></code></pre>
</div>
</div>
<p>
This installs <code>zoxide</code><a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>) globally for the current user, by linking all of zoxides contents to a special directory (<code>~/.nix-profile/</code>). The <code>bin</code> contents of this directory are on the <code><span class="math inline">$PATH&lt;/code&gt; making the package’s binary available to the user.&lt;/p&gt; &lt;p&gt;As mentioned this is not idiomatic Nix, which focuses on declerativity. If you want something installed, consider using &lt;a href="https://github.com/rycee/home-manager"&gt;&lt;code&gt;home-manager&lt;/code&gt;&lt;/a&gt; or add packages to your &lt;code&gt;configuration.nix&lt;/code&gt; if you are on &lt;a href="https://nixos.org/nixos"&gt;NixOS&lt;/a&gt;.&lt;/p&gt; &lt;h4 class="y-header" id="local-usage"&gt;&lt;span&gt;Local usage&lt;/span&gt;&lt;a href="#local-usage" class="anchor las la-anchor" title="local-usage"&gt;&lt;/a&gt;&lt;/h4&gt; &lt;p&gt;If you need a program but do not want to install it because you don’t need it often and you don’t want to clutter your &lt;code&gt;$</span>PATH</code>, or it’s a project specific tool you can make use of either <code>nix run</code> or <code>nix-shell</code>.
</p>
<div class="y-fill-horizontal">
<div id="cb3" class="sourceCode">
<pre class="sourceCode sh"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix run nixpkgs.git</span></code></pre>
</div>
</div>
<p>
This will drop you into a Bash shell with git available.
</p>
<div class="y-fill-horizontal">
<div id="cb4" class="sourceCode">
<pre class="sourceCode sh"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix-shell <span class="at">-p</span> git</span></code></pre>
</div>
</div>
<p>
This will essentially do the same but can do much more.
</p>
<ul>
<li>
<p>
<code>nix-shell</code> accepts multiple packages
</p>
</li>
<li>
<p>
can be used as a shebang (<a href="https://gist.github.com/travisbhartwell/f972aab227306edfcfea">see</a>)
</p>
</li>
<li>
<p>
can drop you into development environments of a specific derivation (<a href="https://nixos.org/nixos/nix-pills/developing-with-nix-shell.html">see</a>)
</p>
</li>
<li>
<p>
can be used to make development environments for a project.
</p>
</li>
</ul>
<p>
Let’s focus on the last point for this article.
</p>
<h2 class="y-header" id="nix-on-this-blog">
<span>Nix on this blog</span><a href="#nix-on-this-blog" class="anchor las la-anchor" title="nix-on-this-blog"></a>
</h2>
<p>
This blog uses a shell environment in which I have all the tools I need at hand. Let’s look at the structure file by file.
</p>
<h3 class="y-header" id="default.nix">
<span><code>default.nix</code></span><a href="#default.nix" class="anchor las la-anchor" title="default.nix"></a>
</h3>
<p>
By default, Nix commands such as <code>nix-build</code> read the <a href="https://github.com/ysndr/blog/default.nix"><code>default.nix</code></a> file in the directory they are executed from. In my projects, I use them to define and export everything that might be useful. This might include build tools, language environments, scripts or shells.
</p>
<p>
Generally my <code>default.nix</code> file looks like this:
</p>
<div class="y-fill-horizontal">
<div id="cb5" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="ex">{pkgs</span> <span class="pp">?</span> import <span class="er">(</span><span class="cf">if</span> <span class="ex">pin</span> == false then <span class="op">&lt;</span>nixpkgs<span class="op">&gt;</span> else pin<span class="kw">)</span> <span class="ex">{},</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a> <span class="ex">pin</span> <span class="pp">?</span> ./nixpkgs.nix, ... }:</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="ex">with</span> pkgs<span class="kw">;</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="bu">let</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="op">&lt;</span>some <span class="ex">packages</span> and configuration<span class="op">&gt;</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a><span class="ex">shell</span> = mkShell {</span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a><span class="ex">​</span>    name = <span class="st">&quot;&lt;name&gt;&quot;</span><span class="kw">;</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a><span class="ex">​</span>    buildInputs = [ <span class="op">&lt;</span>packages I want in my shell<span class="op">&gt;</span> ]<span class="kw">;</span></span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a><span class="ex">​</span>    shellHook = <span class="st">&#39;&#39;</span> <span class="co"># shell command to be executed when I enter the shell</span></span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a><span class="ex">​</span>    <span class="st">&#39;&#39;</span><span class="kw">;</span></span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a><span class="er">}</span></span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a><span class="er">in</span></span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a><span class="kw">{</span></span>
<span id="cb5-16"><a href="#cb5-16" aria-hidden="true" tabindex="-1"></a><span class="ex">​</span>    inherit shell<span class="kw">;</span></span>
<span id="cb5-17"><a href="#cb5-17" aria-hidden="true" tabindex="-1"></a><span class="ex">​</span>    inherit packageA, packageB, ...<span class="kw">;</span></span>
<span id="cb5-18"><a href="#cb5-18" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span></code></pre>
</div>
</div>
<p>
This exposes a shell environment for <code>nix-shell</code> and programs to be executed directy using <code>nix-build</code>.
</p>
<p>
So what about this blog’s <code>default.nix</code>?
</p>
<div class="y-fill-horizontal">
<div id="cb6" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="bu">let</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>  <span class="ex">all-hies</span> = import <span class="er">(</span><span class="ex">builtins.fetchTarball</span> <span class="st">&quot;https://github.com/infinisil/all-hies/tarball/master&quot;</span><span class="kw">)</span> <span class="ex">{}</span><span class="kw">;</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="er">in</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="ex">{pkgs</span> <span class="pp">?</span> import <span class="er">(</span><span class="cf">if</span> <span class="ex">pin</span> == false then <span class="op">&lt;</span>nixpkgs<span class="op">&gt;</span> else pin<span class="kw">)</span> <span class="ex">{},</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a> <span class="ex">pin</span> <span class="pp">?</span> ./nixpkgs.nix, ... }:</span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a><span class="ex">with</span> pkgs<span class="kw">;</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a><span class="bu">let</span></span></code></pre>
</div>
</div>
<p>
Aside from the default, I only priorly import <code>all-hies</code>, which is a project that maintains the <a href="https://github.com/infinisil/all-hies">Haskell Ide Engine</a> on Nix.
</p>
<div class="y-fill-horizontal">
<div id="cb7" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="co"># -------------- Utils -------------</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="ex">nur</span> = import <span class="er">(</span><span class="ex">builtins.fetchTarball</span> <span class="st">&quot;https://github.com/nix-community/NUR/archive/master.tar.gz&quot;</span><span class="kw">)</span> <span class="kw">{</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="ex">​</span>    pkgs=pkgs<span class="kw">;</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="kw">};</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a><span class="ex">script</span> = {...} @ args: nur.repos.ysndr.lib.wrap <span class="er">(</span><span class="kw">{</span></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a>  <span class="ex">shell</span> = true<span class="kw">;</span></span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span> <span class="ex">//</span> args<span class="kw">);</span></span></code></pre>
</div>
</div>
<p>
This are utilities I might use. <a href="https://github.com/nix-community/NUR">NUR</a> is the nix version of arch’s AUR, albeit not nearly as active sadly. From my own collection, I use the <code>shell</code> script which helps me putting together runnable scripts.
</p>
<div class="y-fill-horizontal">
<div id="cb8" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="co"># ------------- Haskell ------------</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="ex">hie</span> = all-hies.selection { selector = p: { inherit <span class="er">(</span><span class="ex">p</span><span class="kw">)</span> <span class="ex">ghc865</span><span class="kw">;</span> <span class="er">}</span><span class="kw">;</span> <span class="er">}</span><span class="kw">;</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="ex">myHaskellPackages</span> = haskell.packages.ghc865.extend<span class="er">(</span> <span class="ex">self:</span> super: { }<span class="kw">);</span></span></code></pre>
</div>
</div>
<p>
These lines prepare the Haskell environment I use here. I do not override anything from GHC so this is a bit superflous.
</p>
<div class="y-fill-horizontal">
<div id="cb9" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="co"># ------------ dist ---------------</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a><span class="ex">thirdparty</span> = linkFarm <span class="st">&quot;thirdparty&quot;</span> [</span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">{</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a><span class="ex">​</span>    name = <span class="st">&quot;uikit&quot;</span><span class="kw">;</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a><span class="ex">​</span>    path = <span class="er">(</span><span class="ex">fetchTarball</span> <span class="st">&quot;https://github.com/uikit/uikit/archive/v3.2.4.tar.gz&quot;</span><span class="kw">)</span> <span class="ex">+</span> <span class="st">&quot;/src&quot;</span><span class="kw">;</span></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">}</span></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a><span class="ex">]</span><span class="kw">;</span></span></code></pre>
</div>
</div>
<p>
I import all third party tools (only uikit currently) into the nix store.
</p>
<div class="y-fill-horizontal">
<div id="cb10" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="co"># ------------- generator -----------</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="ex">generator</span> = myHaskellPackages.callCabal2nix <span class="st">&quot;Site&quot;</span> ./generator {}<span class="kw">;</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a><span class="ex">generator-with-thirdparty</span> = generator.overrideAttrs<span class="er">(</span><span class="ex">old:</span> {</span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>  <span class="ex">nativeBuildInputs</span> = old.nativeBuildInputs or [] ++ [makeWrapper]<span class="kw">;</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>  <span class="ex">installPhase</span> = old.installPhase + <span class="st">&quot;\n&quot;</span> + <span class="st">&#39;&#39;</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a><span class="ex">​</span>    wrapProgram <span class="va">$out</span>/bin/generator <span class="at">--set</span> THIRDPARTY <span class="va">${thirdparty}</span></span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a>  <span class="st">&#39;&#39;</span><span class="kw">;</span></span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a><span class="er">}</span><span class="kw">);</span></span></code></pre>
</div>
</div>
<p>
Then, I define the <code>generator</code> as a derivation from its Cabal file and the corresponding “Site” executable key defined in <code>./generator/</code>. <code>generator-with-thirdparty</code> makes what I imported as thirdparty content available under the <code>$THIRDPARTY</code> environment variable.
</p>
<div class="uk-alert-primary note box y-fill-horizontal" data-header="">
<div class="header">
<div>
<span class="las la-pencil-alt"></span>
<div class="badge">
<p>NOTE</p>
</div>
</div>
<div>

</div>
</div>
<p>
<code>myHaskellPackages.callCabal2nix “Site” ./generator {};</code> is a great tool to quickly make haskell programms available through Nix.
</p>
<p>
Similar helpers also exist for Stack.
</p>
</div>
<div class="y-fill-horizontal">
<div id="cb11" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="co"># --------------- Commands ----------------</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="ex">generate-website</span> = script {</span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>  <span class="ex">name</span> = <span class="st">&quot;generate-website&quot;</span><span class="kw">;</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>  <span class="ex">paths</span> = [generator-with-thirdparty git]<span class="kw">;</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>  <span class="ex">script</span> = <span class="st">&#39;&#39;</span></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a><span class="ex">​</span>    generator rebuild</span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a>  <span class="st">&#39;&#39;</span><span class="kw">;</span></span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a><span class="er">}</span><span class="kw">;</span></span></code></pre>
</div>
</div>
<p>
<code>generate-website</code> is supposed to be a build command which, at this state, only runs <code>generator rebuild</code>.
</p>
<div class="y-fill-horizontal">
<div id="cb12" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="co"># ---------------- Shell ------------------</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a><span class="ex">haskell-env</span> = myHaskellPackages.ghcWithHoogle <span class="er">(</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>  <span class="ex">hp:</span> with hp<span class="kw">;</span> <span class="bu">[</span> cabal-install <span class="bu">]</span> <span class="ex">++</span> generator.buildInputs <span class="kw">);</span></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a><span class="ex">shell</span> = { enable-hie <span class="pp">?</span> false }: mkShell {</span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>  <span class="ex">name</span> = <span class="st">&quot;blog-env&quot;</span><span class="kw">;</span></span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a>  <span class="ex">buildInputs</span> = [</span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a><span class="ex">​</span>    <span class="co"># put packages here.</span></span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a><span class="ex">​</span>    <span class="co"># generator</span></span>
<span id="cb12-12"><a href="#cb12-12" aria-hidden="true" tabindex="-1"></a><span class="ex">​</span>    haskell-env</span>
<span id="cb12-13"><a href="#cb12-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-14"><a href="#cb12-14" aria-hidden="true" tabindex="-1"></a><span class="ex">​</span>    <span class="er">(</span><span class="ex">lib.optional</span> <span class="er">(</span><span class="ex">enable-hie</span><span class="kw">)</span> <span class="ex">hie</span><span class="kw">)</span> <span class="co"># optionally setup hie</span></span>
<span id="cb12-15"><a href="#cb12-15" aria-hidden="true" tabindex="-1"></a>  <span class="ex">]</span><span class="kw">;</span></span>
<span id="cb12-16"><a href="#cb12-16" aria-hidden="true" tabindex="-1"></a>  <span class="ex">shellHook</span> = <span class="st">&#39;&#39;</span></span>
<span id="cb12-17"><a href="#cb12-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-18"><a href="#cb12-18" aria-hidden="true" tabindex="-1"></a><span class="ex">​</span>    export THIRDPARTY=<span class="st">&quot;</span><span class="va">${thirdparty}</span><span class="st">&quot;</span></span>
<span id="cb12-19"><a href="#cb12-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-20"><a href="#cb12-20" aria-hidden="true" tabindex="-1"></a><span class="ex">​</span>    export HIE_HOOGLE_DATABASE=<span class="st">&quot;</span><span class="va">${haskell</span><span class="er">-env</span><span class="va">}</span><span class="st">/share/doc/hoogle/default.hoo&quot;</span></span>
<span id="cb12-21"><a href="#cb12-21" aria-hidden="true" tabindex="-1"></a><span class="ex">​</span>    export NIX_GHC=<span class="st">&quot;</span><span class="va">${haskell</span><span class="er">-env</span><span class="va">}</span><span class="st">/bin/ghc&quot;</span></span>
<span id="cb12-22"><a href="#cb12-22" aria-hidden="true" tabindex="-1"></a><span class="ex">​</span>    export NIX_GHCPKG=<span class="st">&quot;</span><span class="va">${haskell</span><span class="er">-env</span><span class="va">}</span><span class="st">/bin/ghc-pkg&quot;</span></span>
<span id="cb12-23"><a href="#cb12-23" aria-hidden="true" tabindex="-1"></a><span class="ex">​</span>    export NIX_GHC_DOCDIR=<span class="st">&quot;</span><span class="va">${haskell</span><span class="er">-env</span><span class="va">}</span><span class="st">/share/doc/ghc/html&quot;</span></span>
<span id="cb12-24"><a href="#cb12-24" aria-hidden="true" tabindex="-1"></a><span class="ex">​</span>    export NIX_GHC_LIBDIR=<span class="va">$(</span> <span class="va">$NIX_GHC</span> <span class="at">--print-libdir</span> <span class="va">)</span></span>
<span id="cb12-25"><a href="#cb12-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-26"><a href="#cb12-26" aria-hidden="true" tabindex="-1"></a>  <span class="st">&#39;&#39;</span><span class="kw">;</span></span>
<span id="cb12-27"><a href="#cb12-27" aria-hidden="true" tabindex="-1"></a><span class="er">}</span><span class="kw">;</span></span></code></pre>
</div>
</div>
<p>
Finally, I bundle everything together to build an environment with <code>ghc</code> and a Hoogle index containing the generators dependencies as well as <code>cabal-install</code> <strong>for reasons</strong>.
</p>
<p>
The shell has this Haskell environment and optionally the <code>hie</code> executable exposed. It also sets some exports that hie needs to properly function as well as the <code>$THIRDPARTY</code> variable to build the blog:
</p>
<div class="y-fill-horizontal">
<div id="cb13" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="er">in</span> <span class="kw">{</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>  <span class="ex">inherit</span> shell generator generate-website <span class="kw">;</span></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>  <span class="ex">ci</span> = {</span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a><span class="ex">​</span>    compile = generate-website<span class="kw">;</span></span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">};</span></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a><span class="er">}</span></span></code></pre>
</div>
</div>
<p>
All important parts are exported.
</p>
<h3 class="y-header" id="shell.nix-and-nixpkgs.nix">
<span><code>shell.nix</code> and <code>nixpkgs.nix</code></span><a href="#shell.nix-and-nixpkgs.nix" class="anchor las la-anchor" title="shell.nix-and-nixpkgs.nix"></a>
</h3>
<p>
The first file is used by nix-shell by default. All it does is call the shell attribute of the <code>default.nix</code> and controlling if hie is added, making use of the lazy nature of nix: hie will not get evaluated unless enabled.
</p>
<div class="y-fill-horizontal">
<div id="cb14" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="kw">{</span> <span class="ex">pin</span> <span class="pp">?</span> null, enable-hie <span class="pp">?</span> false } @ args:</span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a><span class="kw">(</span><span class="ex">import</span> ./default.nix args<span class="kw">)</span><span class="ex">.shell</span> { inherit enable-hie<span class="kw">;</span> <span class="kw">}</span></span></code></pre>
</div>
</div>
<p>
The <code>nixpkgs.nix</code> file defines a common snapshot of the nixpkgs repo, and is therefore important to ensure everything works on other machines.
</p>
<div class="y-fill-horizontal">
<div id="cb15" class="sourceCode">
<pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="ex">{}:</span> import <span class="er">(</span><span class="ex">builtins.fetchTarball</span> {</span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>  <span class="ex">url</span> = <span class="st">&quot;https://github.com/NixOS/nixpkgs/archive/88d9f776091.tar.gz&quot;</span><span class="kw">;</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>  <span class="ex">sha256</span> = <span class="st">&quot;sha256:0z8a0g69fmbbzi77jhvhwafv73dn5fg3gsr0q828lss6j5qpx995&quot;</span><span class="kw">;</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a><span class="er">}</span><span class="kw">)</span> <span class="ex">{}</span></span></code></pre>
</div>
</div>
<div class="uk-alert-primary note box y-fill-horizontal" data-header="">
<div class="header">
<div>
<span class="las la-pencil-alt"></span>
<div class="badge">
<p>NOTE</p>
</div>
</div>
<div>

</div>
</div>
<p>
Snapshots like these also allow rollbacks as they define which versions of dependencies get passed on.
</p>
</div>
<h2 class="y-header" id="nix-and-github-actions">
<span>Nix and GitHub Actions</span><a href="#nix-and-github-actions" class="anchor las la-anchor" title="nix-and-github-actions"></a>
</h2>
<p>
Nix has some integration with GitHub Actions through <a href="https://github.com/marketplace/actions/install-nix">install-nix</a>, an action that <strong>installs nix</strong> •_•
</p>
<p>
With nix installed, I run <code>$(nix-build -A ci.compile --no-out-link)</code> to make Nix build the blog generator and rebuild the blog’s content into <code>build/site</code>. This works because <code>nix-build --no-out-link</code> will just print the path of the resulting package to <code>stdout</code>, which in this case is only an executable script produced by the <code>script</code> function above. The next step is to take that content and push it to the deployment branch.
</p>
<p>
<a href="https://github.com/ysndr/blog/blob/release/.github/workflows/main.yml">See more…</a>
</p>
<div class="uk-alert-primary note box y-fill-horizontal" data-header="">
<div class="header">
<div>
<span class="las la-pencil-alt"></span>
<div class="badge">
<p>NOTE</p>
</div>
</div>
<div>

</div>
</div>
<p>
I previously did even more with nix but specific GitHub Actions tend to do the job well enough.
</p>
</div>
<h2 class="y-header" id="epilog">
<span>Epilog</span><a href="#epilog" class="anchor las la-anchor" title="epilog"></a>
</h2>
<p>
I see this has become more of a roundup about Nix. Nix is <strong>huge</strong> though.. and this article does not try to capture everything (obviously). From reading this, I hope you have a rough idea of what nix does and how it was applied here. If you knew Nix already, maybe you found something new or interesting among this pile of words and snippets. If you did not know Nix before, I hope this article was still of interest to you.
</p>
<div class="info box y-fill-horizontal" data-header="">
<div class="header">
<div>
<span class="las la-info"></span>
<div class="badge">
<p>INFO</p>
</div>
</div>
<div>

</div>
</div>
<p>
If you are hooked on the idea now, further fine grained introduction and resources are:
</p>
<ul>
<li>
The <a href="https://nixos.org/nixos/nix-pills/">Nix-Pills</a>
</li>
<li>
The <strong>unofficial</strong> <a href="https://nixos.wiki/wiki/Nix">wiki</a>
</li>
<li>
The nixpkgs <a href="https://github.com/nixos/nixpkgs">repo</a>. Trust me, if you plan to try out nix, bookmark this project and use the issue search.
</li>
</ul>
</div>
<p>
<strong>Thank you for getting here!</strong> I hope you enjoyed it and have learned something. If you have questions, improvements, or any other comment, do not hesitate to get in touch on <a href="https://github.com/ysndr/blog/issues/new">GitHub</a>.
</p>
<section class="footnotes" role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote">
<p>
<a href="https://github.com/ajeetdsouza/zoxide"><code>zoxide</code></a> (a great (fast) replacement for <code>z</code><a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a>
</p>
</li>
</ol>
</section>]]></summary>
</entry>
<entry>
    <title>How this page is generated - Part 02</title>
    <link href="https://blog.ysndr.de/posts/internals/2020-03-22-built-with-hakyll-part-2/index.html" />
    <id>https://blog.ysndr.de/posts/internals/2020-03-22-built-with-hakyll-part-2/index.html</id>
    <published>2020-03-22T00:00:00Z</published>
    <updated>2020-03-22T00:00:00Z</updated>
    <summary type="html"><![CDATA[<h1 class="y-header" id="built-with-hakyll-part-02-custom-fields">
<span>Built with Hakyll – Part 02: Custom Fields</span><a href="#built-with-hakyll-part-02-custom-fields" class="anchor las la-anchor" title="built-with-hakyll-part-02-custom-fields"></a>
</h1>
<ul>
<li>
Part 01: <a href="2019-12-31-built-with-hakyll-part-1.html">Hakyll basics and context</a>
</li>
<li>
Part 02: A collection of Custom Fields <em>this article</em>
</li>
</ul>
<p>
In the <a href="2019-12-31-built-with-hakyll-part-1.html">previous article</a> I introduced the basic mechanisms of Hakyll. Part of this introduction was that every content lives in Hakyll as an <code>Item</code>. An <code>Item</code> is created by loading some content from a file (or a wildcarded list of files). In most cases these are Markdown files. For example, this is what loading an <code>Item</code> looks like:
</p>
<div class="y-fill-horizontal">
<div id="cb1" class="sourceCode">
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>match <span class="st">&quot;posts/**.md&quot;</span> <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>    route <span class="op">$</span> setExtension <span class="st">&quot;html&quot;</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    compile</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>        <span class="op">$</span>   pandocCompiler</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>        <span class="op">&gt;&gt;=</span> loadAndApplyTemplate <span class="st">&quot;templates/post.html&quot;</span> postCtx</span></code></pre>
</div>
</div>
<p>
For each <code>*.md</code> file inside <code>posts/</code> an <code>.html</code> file is generated by compiling the document using pandoc (which turnsthe markup it into html) and including this content in a template, namely the <code>templates/post.html</code> template, by loading the template and applying it with a given <code>Context</code>.
</p>
<p>
What is a Context? Contexts deliver meta information to the templating engine. The information is constructed for each document individually and by default contains (in that order)
</p>
<ol>
<li>
A <span class="math inline"><em>b</em><em>o</em><em>d</em><em>y</em></span> field: current content of the document (usually after conversion using pandoc)
</li>
<li>
Metadata fields defined in the document’s frontmatter
</li>
<li>
A <span class="math inline"><em>u</em><em>r</em><em>l</em></span> urlField: url of the final document
</li>
<li>
A <span class="math inline"><em>p</em><em>a</em><em>t</em><em>h</em></span> pathField: path of the original file
</li>
<li>
A <span class="math inline"><em>t</em><em>i</em><em>t</em><em>l</em><em>e</em></span> titleField: title defined in frontmatter
</li>
</ol>
<p>
These variables can in turn be used in the template and will be substituted by Hakyll. You can read more about templates, again, on the official <a href="https://jaspervdj.be/hakyll/tutorials/04-compilers.html">Hakyll Website</a>
</p>
<h1 class="y-header" id="custom-fields">
<span>Custom fields</span><a href="#custom-fields" class="anchor las la-anchor" title="custom-fields"></a>
</h1>
<p>
Generally <code>Context</code>s are the only way to include dynamic content. Anything that is not plain text from the template or the document comes through a context <code>Field</code>. <code>Field</code>s hold data that is individually derived from each <code>Item</code> i.e. document. They are composed to form a full context which is fed into the templating engine. As <code>Field</code>s are implemented as <code>Monoids</code> composing gets very easy:
</p>
<div class="y-fill-horizontal">
<div id="cb2" class="sourceCode">
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="ot">context ::</span> <span class="dt">Context</span> <span class="dt">String</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>context <span class="ot">=</span> <span class="fu">mconcat</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>    [ defaultContext</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>    , pathField <span class="st">&quot;sourcefile&quot;</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>    ]</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="co">-- or</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>context <span class="ot">=</span> defaultContext</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>       <span class="op">&lt;&gt;</span> pathField <span class="st">&quot;sourcefile&quot;</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>       <span class="op">&lt;&gt;</span> constField <span class="st">&quot;field&quot;</span> <span class="st">&quot;value&quot;</span></span></code></pre>
</div>
</div>
<p>
Hakyll comes with a range of default fields:
</p>
<ul>
<li>
<a href="http://hackage.haskell.org/package/hakyll-4.13.2.0/docs/Hakyll-Web-Template-Context.html#v:boolField"><code>boolFields</code></a>
</li>
<li>
<a href="http://hackage.haskell.org/package/hakyll-4.13.2.0/docs/Hakyll-Web-Template-Context.html#v:constField"><code>constField</code></a>
</li>
<li>
<a href="http://hackage.haskell.org/package/hakyll-4.13.2.0/docs/Hakyll-Web-Template-Context.html#v:modificationTimeField">’modificationTimeField</a>
</li>
<li>
and some more that you can find <a href="http://hackage.haskell.org/package/hakyll-4.13.2.0/docs/Hakyll-Web-Template-Context.html">here</a>
</li>
</ul>
<p>
While setting up the structure of this blog I found the “need” of having some more fields available though. This is how I started to adapt some implementations I found on the internet, and developed my own. Find those in <a href="https://github.com/ysndr/blog/blob/release/generator/Fields.hs"><code>generator/Fields.hs</code></a>.
</p>
<p>
Most fields are created by giving an implementation of <code>(Item a -&gt; Compiler String)</code> to the following field function.
</p>
<div class="y-fill-horizontal">
<div id="cb3" class="sourceCode">
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ot">field ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> (<span class="dt">Item</span> a <span class="ot">-&gt;</span> <span class="dt">Compiler</span> <span class="dt">String</span>) <span class="ot">-&gt;</span> <span class="dt">Context</span> a</span></code></pre>
</div>
</div>
<div class="uk-alert-primary note box y-fill-horizontal" data-header="">
<div class="header">
<div>
<span class="las la-pencil-alt"></span>
<div class="badge">
<p>NOTE</p>
</div>
</div>
<div>

</div>
</div>
<p>
I am by no means an expert in Haskell at this point. I have learned alot writing the engine behind all this (Which in the end is actually my main motivator). But I am certain some implementations could be done more idiomatically and/or efficiently. Thus, take the ideas that I had critically.
</p>
<p>
I do welcome any coments in form of issues on <a href="https://github.com/ysndr/blog">Github</a>. :)
</p>
</div>
<h2 class="y-header" id="peekfield">
<span><code>peekField</code></span><a href="#peekfield" class="anchor las la-anchor" title="peekfield"></a>
</h2>
<p>
I showed this field already in the previous article, it is one of the first fields I made to understand the logic behind them. It simply takes the fist <code>length</code> words and makes them availlable to the template engine under <code>key</code>. As templates are applied after pandoc converted the document to html I needed to take the original content from an earlier created <code>snapshot</code> of the document.
</p>
<div class="y-fill-horizontal">
<div id="cb4" class="sourceCode">
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>peekField</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="ot">    ::</span> <span class="dt">String</span>           <span class="co">-- ^ Key to use</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>    <span class="ot">-&gt;</span> <span class="dt">Int</span>              <span class="co">-- ^ length to peak</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>    <span class="ot">-&gt;</span> <span class="dt">Snapshot</span>         <span class="co">-- ^ Snapshot to load</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>    <span class="ot">-&gt;</span> <span class="dt">Context</span> <span class="dt">String</span>   <span class="co">-- ^ Resulting context</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>peekField key <span class="fu">length</span> snapshot <span class="ot">=</span> field key <span class="op">$</span> \item <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>    body <span class="ot">&lt;-</span> itemBody <span class="op">&lt;$&gt;</span> loadSnapshot (itemIdentifier item) snapshot</span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>    <span class="fu">return</span> (peak body)</span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">where</span> peak <span class="ot">=</span> T.unpack <span class="op">.</span> T.unwords <span class="op">.</span> <span class="fu">take</span> <span class="fu">length</span> <span class="op">.</span> T.words <span class="op">.</span> T.pack</span></code></pre>
</div>
</div>
<p>
Problem with this is undeniably that it does not that markup into account at all. That way Code blocks are included without any styling and look very bad.
</p>
<h2 class="y-header" id="git-fields">
<span>Git Fields</span><a href="#git-fields" class="anchor las la-anchor" title="git-fields"></a>
</h2>
<p>
I wanted to allow readers of my blog to follow the history of an article. As the sourceof this blog is hosted on GitHub using GitHub’s history view would be an easy way to achieve this, I thought.
</p>
<div class="y-fill-horizontal">
<div id="cb5" class="sourceCode">
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Git related fields</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="co">--------------------------------------------------------------------------------</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">GitVersionContent</span> <span class="ot">=</span> <span class="dt">Hash</span> <span class="op">|</span> <span class="dt">Commit</span> <span class="op">|</span> <span class="dt">Full</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>     <span class="kw">deriving</span> (<span class="dt">Eq</span>, <span class="dt">Read</span>)</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Show</span> <span class="dt">GitVersionContent</span> <span class="kw">where</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>    <span class="fu">show</span> content <span class="ot">=</span> <span class="kw">case</span> content <span class="kw">of</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Hash</span> <span class="ot">-&gt;</span> <span class="st">&quot;%h&quot;</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Commit</span> <span class="ot">-&gt;</span> <span class="st">&quot;%h: %s&quot;</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Full</span> <span class="ot">-&gt;</span> <span class="st">&quot;%h: %s (%ai)&quot;</span></span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a><span class="co">-- Query information of a given file tracked with git</span></span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a><span class="ot">getGitVersion ::</span> <span class="dt">GitVersionContent</span> <span class="co">-- Kind of information</span></span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a>              <span class="ot">-&gt;</span> <span class="dt">FilePath</span>          <span class="co">-- File to query information of</span></span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a>              <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">String</span>         <span class="co">--</span></span>
<span id="cb5-16"><a href="#cb5-16" aria-hidden="true" tabindex="-1"></a>getGitVersion content path <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb5-17"><a href="#cb5-17" aria-hidden="true" tabindex="-1"></a>    (status, stdout, _) <span class="ot">&lt;-</span> readProcessWithExitCode <span class="st">&quot;git&quot;</span> [</span>
<span id="cb5-18"><a href="#cb5-18" aria-hidden="true" tabindex="-1"></a>        <span class="st">&quot;log&quot;</span>,</span>
<span id="cb5-19"><a href="#cb5-19" aria-hidden="true" tabindex="-1"></a>        <span class="st">&quot;-1&quot;</span>,</span>
<span id="cb5-20"><a href="#cb5-20" aria-hidden="true" tabindex="-1"></a>        <span class="st">&quot;--format=&quot;</span> <span class="op">++</span> (<span class="fu">show</span> content),</span>
<span id="cb5-21"><a href="#cb5-21" aria-hidden="true" tabindex="-1"></a>        <span class="st">&quot;--&quot;</span>,</span>
<span id="cb5-22"><a href="#cb5-22" aria-hidden="true" tabindex="-1"></a>        <span class="st">&quot;src/&quot;</span><span class="op">++</span>path] <span class="st">&quot;&quot;</span></span>
<span id="cb5-23"><a href="#cb5-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-24"><a href="#cb5-24" aria-hidden="true" tabindex="-1"></a>    <span class="fu">return</span> <span class="op">$</span> <span class="kw">case</span> status  <span class="kw">of</span></span>
<span id="cb5-25"><a href="#cb5-25" aria-hidden="true" tabindex="-1"></a>        <span class="dt">ExitSuccess</span> <span class="ot">-&gt;</span> trim stdout</span>
<span id="cb5-26"><a href="#cb5-26" aria-hidden="true" tabindex="-1"></a>        _           <span class="ot">-&gt;</span> <span class="st">&quot;&quot;</span></span>
<span id="cb5-27"><a href="#cb5-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-28"><a href="#cb5-28" aria-hidden="true" tabindex="-1"></a>    <span class="kw">where</span> trim <span class="ot">=</span> dropWhileEnd <span class="fu">isSpace</span></span>
<span id="cb5-29"><a href="#cb5-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-30"><a href="#cb5-30" aria-hidden="true" tabindex="-1"></a><span class="co">-- Field that contains the latest commit hash that hash touched the current item.</span></span>
<span id="cb5-31"><a href="#cb5-31" aria-hidden="true" tabindex="-1"></a><span class="ot">versionField ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">GitVersionContent</span> <span class="ot">-&gt;</span> <span class="dt">Context</span> <span class="dt">String</span></span>
<span id="cb5-32"><a href="#cb5-32" aria-hidden="true" tabindex="-1"></a>versionField name content <span class="ot">=</span> field name <span class="op">$</span> \item <span class="ot">-&gt;</span> unsafeCompiler <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb5-33"><a href="#cb5-33" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> path <span class="ot">=</span> toFilePath <span class="op">$</span> itemIdentifier item</span>
<span id="cb5-34"><a href="#cb5-34" aria-hidden="true" tabindex="-1"></a>    getGitVersion content  path</span>
<span id="cb5-35"><a href="#cb5-35" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-36"><a href="#cb5-36" aria-hidden="true" tabindex="-1"></a><span class="co">-- Field that contains the commit hash of HEAD.</span></span>
<span id="cb5-37"><a href="#cb5-37" aria-hidden="true" tabindex="-1"></a><span class="ot">headVersionField ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">GitVersionContent</span> <span class="ot">-&gt;</span> <span class="dt">Context</span> <span class="dt">String</span></span>
<span id="cb5-38"><a href="#cb5-38" aria-hidden="true" tabindex="-1"></a>headVersionField name content  <span class="ot">=</span> field name <span class="op">$</span> \_ <span class="ot">-&gt;</span> unsafeCompiler <span class="op">$</span> getGitVersion content  <span class="st">&quot;.&quot;</span></span></code></pre>
</div>
</div>
<p>
With the current implementation of <code>getGitVersion</code> I am able to get the latest commit that changed any given document. It spawns a <code>git</code> process and reads its output afterwards.
</p>
<p>
I can even choose from predefined formats:
</p>
<ul>
<li>
<code>Hash</code> gives the Commit’s hash,
</li>
<li>
<code>Commit</code> the Hash+Message
</li>
<li>
<code>Full</code> Hash+Message+Time
</li>
</ul>
<p>
Although I think for many pages the number of <code>git</code> invocations might lead to significantly longer build times, for the time being it works rather well.
</p>
<h2 class="y-header" id="readtimefield">
<span><code>readTimeField</code></span><a href="#readtimefield" class="anchor las la-anchor" title="readtimefield"></a>
</h2>
<p>
Another really simple but usefull function that naïvely computes the reading time of a document. Essentially it counts the words of the docutment snapshot and devides it by the average reading velocoty of about 200 words/min.
</p>
<div class="y-fill-horizontal">
<div id="cb6" class="sourceCode">
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="ot">readTimeField ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Snapshot</span> <span class="ot">-&gt;</span> <span class="dt">Context</span> <span class="dt">String</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>readTimeField name snapshot <span class="ot">=</span> field name <span class="op">$</span> \item <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>    body <span class="ot">&lt;-</span> itemBody <span class="op">&lt;$&gt;</span> loadSnapshot (itemIdentifier item) snapshot</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> <span class="fu">words</span> <span class="ot">=</span> <span class="fu">length</span> (T.words <span class="op">.</span> T.pack <span class="op">$</span> body)</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>    <span class="fu">return</span> <span class="op">$</span> <span class="fu">show</span> <span class="op">$</span> <span class="fu">div</span> <span class="fu">words</span> <span class="dv">200</span></span></code></pre>
</div>
</div>
<h2 class="y-header" id="publishedgroupfield">
<span><code>publishedGroupField</code></span><a href="#publishedgroupfield" class="anchor las la-anchor" title="publishedgroupfield"></a>
</h2>
<p>
Adapted from <a href="https://biosphere.cc/software-engineering/hakyll-group-posts-by-year/">biosphere.cc</a>
</p>
<p>
This field is actually a <code>listField</code>. It is used on the archive page to group posts by year. It is also a quite intimidating one at first sight, but it works perfectly, so 🤷🏼‍♂️.
</p>
<p>
It works by first extracting the year out of the date of every post using <code>extractYear</code>. It then groups the resulting tuples by the year item and merges the groups.
</p>
<p>
Have I already mentioned that working with elements contained in a <code>Compiler</code> Monad is incredibly weird? - <em>It is!</em>
</p>
<p>
Anyway, in the end the template can use the list referenced by <code>name</code> that exposes a field <code>year</code> containing the actual year of a list of posts that is accessable as <code>posts</code> and that have a given <code>postContext</code> applied.
</p>
<div class="y-fill-horizontal">
<div id="cb7" class="sourceCode">
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="ot">publishedGroupField ::</span> <span class="dt">String</span>           <span class="co">-- name</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>                    <span class="ot">-&gt;</span> [<span class="dt">Item</span> <span class="dt">String</span>]    <span class="co">-- posts</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>                    <span class="ot">-&gt;</span> <span class="dt">Context</span> <span class="dt">String</span>   <span class="co">-- Post context</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>                    <span class="ot">-&gt;</span> <span class="dt">Context</span> <span class="dt">String</span>   <span class="co">-- output context</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>publishedGroupField name posts postContext <span class="ot">=</span> listField name groupCtx <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>    tuples <span class="ot">&lt;-</span> <span class="fu">traverse</span> extractYear posts</span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> grouped <span class="ot">=</span> groupByYear tuples</span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> merged <span class="ot">=</span> <span class="fu">fmap</span> merge <span class="op">$</span> grouped</span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> itemized <span class="ot">=</span> <span class="fu">fmap</span> makeItem <span class="op">$</span> merged</span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a>    <span class="fu">sequence</span> itemized</span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a>    <span class="kw">where</span> groupCtx <span class="ot">=</span> field <span class="st">&quot;year&quot;</span> (<span class="fu">return</span> <span class="op">.</span> <span class="fu">show</span> <span class="op">.</span> <span class="fu">fst</span> <span class="op">.</span> itemBody)</span>
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a>                  <span class="op">&lt;&gt;</span> listFieldWith <span class="st">&quot;posts&quot;</span> postContext (<span class="fu">return</span> <span class="op">.</span> <span class="fu">snd</span> <span class="op">.</span> itemBody)</span>
<span id="cb7-15"><a href="#cb7-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-16"><a href="#cb7-16" aria-hidden="true" tabindex="-1"></a><span class="ot">          merge ::</span> [(<span class="dt">Integer</span>, [<span class="dt">Item</span> <span class="dt">String</span>])]  <span class="ot">-&gt;</span> (<span class="dt">Integer</span>, [<span class="dt">Item</span> <span class="dt">String</span>])</span>
<span id="cb7-17"><a href="#cb7-17" aria-hidden="true" tabindex="-1"></a>          merge gs <span class="ot">=</span> <span class="kw">let</span> conv (year, acc) (_, toAcc) <span class="ot">=</span> (year, toAcc <span class="op">++</span> acc)</span>
<span id="cb7-18"><a href="#cb7-18" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">in</span>  <span class="fu">foldr</span> conv (<span class="fu">head</span> gs) (<span class="fu">tail</span> gs)</span>
<span id="cb7-19"><a href="#cb7-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-20"><a href="#cb7-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-21"><a href="#cb7-21" aria-hidden="true" tabindex="-1"></a>          groupByYear <span class="ot">=</span> groupBy (\(y, _) (y&#39;, _) <span class="ot">-&gt;</span> y <span class="op">==</span> y&#39;)</span>
<span id="cb7-22"><a href="#cb7-22" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-23"><a href="#cb7-23" aria-hidden="true" tabindex="-1"></a><span class="ot">          extractYear ::</span> <span class="dt">Item</span> a <span class="ot">-&gt;</span> <span class="dt">Compiler</span> (<span class="dt">Integer</span>,  [<span class="dt">Item</span> a])</span>
<span id="cb7-24"><a href="#cb7-24" aria-hidden="true" tabindex="-1"></a>          extractYear item <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb7-25"><a href="#cb7-25" aria-hidden="true" tabindex="-1"></a>             time <span class="ot">&lt;-</span> getItemUTC defaultTimeLocale (itemIdentifier item)</span>
<span id="cb7-26"><a href="#cb7-26" aria-hidden="true" tabindex="-1"></a>             <span class="kw">let</span>    (year, _, _) <span class="ot">=</span> (toGregorian <span class="op">.</span> utctDay) time</span>
<span id="cb7-27"><a href="#cb7-27" aria-hidden="true" tabindex="-1"></a>             <span class="fu">return</span> (year, [item])</span></code></pre>
</div>
</div>
<h2 class="y-header" id="concatfield">
<span><code>concatField</code></span><a href="#concatfield" class="anchor las la-anchor" title="concatfield"></a>
</h2>
<p>
An actual use of <code>functionFields</code> – yey.
</p>
<p>
It is used to dynamically apply a different header in the base template. There I construct a path to a partial template using another <code>constField</code> (<code>item-type</code>) which, for posts will display a customized header
</p>
<div class="y-fill-horizontal">
<div id="cb8" class="sourceCode">
<pre class="sourceCode html"><code class="sourceCode html"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>$partial(concat(&quot;templates/includes/&quot;,item-type, &quot;-header.html&quot;))</span></code></pre>
</div>
</div>
<p>
The implementation is simply:
</p>
<div class="y-fill-horizontal">
<div id="cb9" class="sourceCode">
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="ot">concatField ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Context</span> <span class="dt">String</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>concatField name <span class="ot">=</span> functionField name (\args item <span class="ot">-&gt;</span> <span class="fu">return</span> <span class="op">$</span> <span class="fu">concat</span> args)</span></code></pre>
</div>
</div>
<h3 class="y-header" id="functionfields">
<span><code>FunctionFields</code></span><a href="#functionfields" class="anchor las la-anchor" title="functionfields"></a>
</h3>
<p>
For the unintroduced, function fields are defined as:
</p>
<div class="y-fill-horizontal">
<div id="cb10" class="sourceCode">
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="ot">functionField ::</span> <span class="dt">String</span>                                  <span class="co">-- name</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>              <span class="ot">-&gt;</span> ([<span class="dt">String</span>] <span class="ot">-&gt;</span> <span class="dt">Item</span> a <span class="ot">-&gt;</span> <span class="dt">Compiler</span> <span class="dt">String</span>) <span class="co">-- actual function</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>              <span class="ot">-&gt;</span> <span class="dt">Context</span> a</span></code></pre>
</div>
</div>
<p>
When used, like in the above example (<code>concat(“hello,” " “,”world")</code>) the function
</p>
<div class="y-fill-horizontal">
<div id="cb11" class="sourceCode">
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a>(\args item <span class="ot">-&gt;</span> <span class="fu">return</span> <span class="op">$</span> <span class="fu">concat</span> args)</span></code></pre>
</div>
</div>
<p>
is evaluated where args contains exactly the arguments given (<code>args == [“hello,”" “,”world"]</code>). as well as the <code>Item</code> it is used on i.e. the document. You can now do all you want with the document’s body and arguments given. Apparently though calling the functionField with the same field as argument is not possible.
</p>
<p>
For another explanation see also <a href="https://beerendlauwers.be/posts/2015-09-21-hakylls-functionfield.html">Beerend Lauwens’ post</a>
</p>
<h2 class="y-header" id="plaintocfield">
<span><code>plainTocField</code></span><a href="#plaintocfield" class="anchor las la-anchor" title="plaintocfield"></a>
</h2>
<p>
Although I have written another implementation of this one that allows additional classes applied on certain elements I would like to show this anyway. To generate a simple table of contents pandocs builtin toc gereator is leveraged. I load the documents body, give it to panodc to parse it into a <code>Pandoc _ [Block]</code> and use that to write html with the template <code><span class="math inline"><em>t</em><em>a</em><em>b</em><em>l</em><em>e</em> − <em>o</em><em>f</em> − <em>c</em><em>o</em><em>n</em><em>t</em><em>e</em><em>n</em><em>t</em><em>s</em></span></code>. The output of that is only the table of contents and nothing else.
</p>
<div class="y-fill-horizontal">
<div id="cb12" class="sourceCode">
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="ot">plainTocField ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Context</span> <span class="dt">String</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>plainTocField name depth snapshot <span class="ot">=</span> field name <span class="op">$</span> \item <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>    body <span class="ot">&lt;-</span> loadSnapshot (itemIdentifier item) snapshot</span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> writerOptions <span class="ot">=</span> def</span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>            {</span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a>              writerTableOfContents <span class="ot">=</span> <span class="dt">True</span></span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a>            , writerTOCDepth <span class="ot">=</span> depth</span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a>            , writerTemplate <span class="ot">=</span> <span class="dt">Just</span> <span class="st">&quot;$table-of-contents$&quot;</span></span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a>            }</span>
<span id="cb12-12"><a href="#cb12-12" aria-hidden="true" tabindex="-1"></a>        toc <span class="ot">=</span> <span class="kw">case</span> runPure (readHtml defaultHakyllReaderOptions</span>
<span id="cb12-13"><a href="#cb12-13" aria-hidden="true" tabindex="-1"></a>                                     (T.pack <span class="op">$</span> itemBody body))</span>
<span id="cb12-14"><a href="#cb12-14" aria-hidden="true" tabindex="-1"></a>               <span class="op">&gt;&gt;=</span> \pandoc <span class="ot">-&gt;</span> runPure ( writeHtml5String writerOptions pandoc) <span class="kw">of</span></span>
<span id="cb12-15"><a href="#cb12-15" aria-hidden="true" tabindex="-1"></a>                   <span class="dt">Left</span> err    <span class="ot">-&gt;</span> <span class="fu">fail</span> <span class="op">$</span> <span class="st">&quot;&quot;</span></span>
<span id="cb12-16"><a href="#cb12-16" aria-hidden="true" tabindex="-1"></a>                   <span class="dt">Right</span> item&#39; <span class="ot">-&gt;</span> T.unpack item&#39;</span>
<span id="cb12-17"><a href="#cb12-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-18"><a href="#cb12-18" aria-hidden="true" tabindex="-1"></a>    <span class="fu">return</span> toc</span></code></pre>
</div>
</div>
<h1 class="y-header" id="final-words">
<span>Final Words</span><a href="#final-words" class="anchor las la-anchor" title="final-words"></a>
</h1>
<p>
As I have already mentioned above, I am not the expert in Haskell that I’d like to be. But writing this blog’s engine has taught me much and was a great excuse to dive Haskell and understand its ideas.
</p>
<p>
I hope you enjoyed this post anyway. For ideas critic and about this use the <a href="https://github.com/ysndr/blog/issues/new">GitHub issue tracker</a>
</p>]]></summary>
</entry>
<entry>
    <title>How this page is generated - Part 01</title>
    <link href="https://blog.ysndr.de/posts/internals/2019-12-31-built-with-hakyll-part-1/index.html" />
    <id>https://blog.ysndr.de/posts/internals/2019-12-31-built-with-hakyll-part-1/index.html</id>
    <published>2019-12-31T00:00:00Z</published>
    <updated>2019-12-31T00:00:00Z</updated>
    <summary type="html"><![CDATA[<h1 class="y-header" id="hakyll-the-basics">
<span>Hakyll: The Basics</span><a href="#hakyll-the-basics" class="anchor las la-anchor" title="hakyll-the-basics"></a>
</h1>
<p>
Hakyll is tool to build static webpages and written in Haskell borrowing part of its name from it and the other from the renown static site engine <a href="https://jekyllrb.com/">Jekyll</a>. The fundamental difference is that instead of being a standalone program, Hakyll is implemented as a library offering a rich DSL to define the contents of a website. The DSL can be used to include static assets, compile pages using templates and even generate whole pages by itself i.e. RSS and ATOM feeds. As Hakyll is written in Haskell combining it with the great text conversion tool <a href="https://pandoc.org/">pandoc</a> is a low hanging fruit. The combination of both allows compiling from several different file formats including (an extended version of) Markdown, <a href="http://docutils.sourceforge.net/docs/ref/rst/introduction.html">RST</a> and Emacs <a href="http://orgmode.org/">Org-Mode</a>.
</p>
<div class="uk-alert-warning warning box y-fill-horizontal" data-header="Attention">
<div class="header">
<div>
<span class="las la-exclamation-circle"></span>
<div class="badge">
<p>WARN</p>
</div>
</div>
<div>
<p>
Attention
</p>
</div>
</div>
<p>
<em>I won’t go into all the things used in this article, instead there will be individual posts going into more detail about different elements</em>
</p>
</div>
<ul>
<li>
Part 01: Hakyll basics and context <em>(this article)</em>
</li>
<li>
Part 02: <a href="./2020-03-22-built-with-hakyll-part-2.html">Custom Fields</a>
</li>
</ul>
<h2 class="y-header" id="setup">
<span>Setup</span><a href="#setup" class="anchor las la-anchor" title="setup"></a>
</h2>
<p>
Setting up Hakyll in general using stack or cabal is already documented extensively. My take on this project involves using <a href="https://nixos.org/nix/">nix</a> as dependency/package manager. How I set up this blog using nix will also be discussed another time.
</p>
<h2 class="y-header" id="basic-concepts">
<span>Basic Concepts</span><a href="#basic-concepts" class="anchor las la-anchor" title="basic-concepts"></a>
</h2>
<p>
In this article I would like to introduce the basic concepts of Hakyll in an applied way.
</p>
<p>
The heart of this page is <a href="https://github.com/ysndr/blog/blob/release/generator/Main.hs"><code>generator/Main.hs</code></a>.
</p>
<p>
At it’s bare minimum a basic Hakyll generator looks like this:
</p>
<div class="y-fill-horizontal">
<div id="cb1" class="sourceCode">
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ot">config ::</span> <span class="dt">Configuration</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>config <span class="ot">=</span> defaultConfiguration {</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- config overrides such as the path to the page content source</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- and compiled item&#39;s destination</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="co">-- A context extending the default context by a date field</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="ot">postCtx ::</span> <span class="dt">Tags</span> <span class="ot">-&gt;</span> <span class="dt">Tags</span> <span class="ot">-&gt;</span> <span class="dt">Context</span> <span class="dt">String</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>postCtx tags category <span class="ot">=</span> dateField <span class="st">&quot;date&quot;</span> <span class="st">&quot;%B %e, %Y&quot;</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>                     <span class="op">&lt;&gt;</span> defaultContext</span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> hakyllWith config <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>    match <span class="st">&quot;posts/**.md&quot;</span> <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>        route <span class="op">$</span> setExtension <span class="st">&quot;html&quot;</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>        compile</span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a>            <span class="op">$</span>   pandocCompiler</span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a>            <span class="co">-- applies the post template</span></span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a>            <span class="op">&gt;&gt;=</span> loadAndApplyTemplate <span class="st">&quot;templates/post.html&quot;</span> postCtx</span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a>            <span class="co">-- embeds the rendered post into the page template</span></span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a>            <span class="op">&gt;&gt;=</span> loadAndApplyTemplate <span class="st">&quot;templates/default.html&quot;</span> postCtx</span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a>            <span class="op">&gt;&gt;=</span> relativizeUrls</span>
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-24"><a href="#cb1-24" aria-hidden="true" tabindex="-1"></a>    create [<span class="st">&quot;archive.html&quot;</span>] <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb1-25"><a href="#cb1-25" aria-hidden="true" tabindex="-1"></a>            route idRoute</span>
<span id="cb1-26"><a href="#cb1-26" aria-hidden="true" tabindex="-1"></a>            compile <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb1-27"><a href="#cb1-27" aria-hidden="true" tabindex="-1"></a>                posts <span class="ot">&lt;-</span> recentFirst <span class="op">=&lt;&lt;</span> loadAll <span class="st">&quot;posts/**&quot;</span></span>
<span id="cb1-28"><a href="#cb1-28" aria-hidden="true" tabindex="-1"></a>                <span class="kw">let</span> postCtx <span class="ot">=</span> postCtx tags categories</span>
<span id="cb1-29"><a href="#cb1-29" aria-hidden="true" tabindex="-1"></a>                <span class="kw">let</span> archiveCtx <span class="ot">=</span> listField <span class="st">&quot;posts&quot;</span> postCtx (<span class="fu">return</span> posts)</span>
<span id="cb1-30"><a href="#cb1-30" aria-hidden="true" tabindex="-1"></a>                            <span class="op">&lt;&gt;</span> constField <span class="st">&quot;title&quot;</span> <span class="st">&quot;Archive&quot;</span></span>
<span id="cb1-31"><a href="#cb1-31" aria-hidden="true" tabindex="-1"></a>                            <span class="op">&lt;&gt;</span> customBaseContext</span>
<span id="cb1-32"><a href="#cb1-32" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-33"><a href="#cb1-33" aria-hidden="true" tabindex="-1"></a>                makeItem <span class="st">&quot;&quot;</span></span>
<span id="cb1-34"><a href="#cb1-34" aria-hidden="true" tabindex="-1"></a>                    <span class="op">&gt;&gt;=</span> loadAndApplyTemplate <span class="st">&quot;templates/archive.html&quot;</span> archiveCtx</span>
<span id="cb1-35"><a href="#cb1-35" aria-hidden="true" tabindex="-1"></a>                    <span class="op">&gt;&gt;=</span> loadAndApplyTemplate <span class="st">&quot;templates/default.html&quot;</span> archiveCtx</span>
<span id="cb1-36"><a href="#cb1-36" aria-hidden="true" tabindex="-1"></a>                    <span class="op">&gt;&gt;=</span> relativizeUrls</span></code></pre>
</div>
</div>
<p>
This will render all markdown files under <code>posts/</code> to html files under our build route and setup an archive site listing all posts.
</p>
<p>
In this snipped we see several things lets go through them individually:
</p>
<ol type="1">
<li>
config
</li>
<li>
matching routes
</li>
<li>
compiling with pandoc
</li>
<li>
templates
</li>
<li>
contexts
</li>
</ol>
<h3 class="y-header" id="config">
<span>config</span><a href="#config" class="anchor las la-anchor" title="config"></a>
</h3>
<div class="y-fill-horizontal">
<div id="cb2" class="sourceCode">
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="ot">config ::</span> <span class="dt">Configuration</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>config <span class="ot">=</span> defaultConfiguration { }</span></code></pre>
</div>
</div>
<p>
This sets up the runtime configuration of hakyll itself. With it we can override among others the folder in which Hakyll searches for its content and where the result should be stored. All available options can be found inside the <a href="https://jaspervdj.be/hakyll/reference/Hakyll-Core-Configuration.html">documentation</a>
</p>
<h3 class="y-header" id="matching-routes">
<span>matching routes</span><a href="#matching-routes" class="anchor las la-anchor" title="matching-routes"></a>
</h3>
<div class="y-fill-horizontal">
<div id="cb3" class="sourceCode">
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>match <span class="st">&quot;posts/**.md&quot;</span> <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>    route <span class="op">$</span> setExtension <span class="st">&quot;html&quot;</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>    compile</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>        <span class="op">$</span>   pandocCompiler</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>        <span class="co">-- applies the post template</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>        <span class="op">&gt;&gt;=</span> loadAndApplyTemplate <span class="st">&quot;templates/post.html&quot;</span> postCtx</span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>        <span class="co">-- embeds the rendered post into the page template</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>        <span class="op">&gt;&gt;=</span> loadAndApplyTemplate <span class="st">&quot;templates/default.html&quot;</span> postCtx</span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>        <span class="op">&gt;&gt;=</span> relativizeUrls</span></code></pre>
</div>
</div>
<p>
In order to create a page from an existing source we use the match function. It takes a <code>FilePath</code> and a function telling it what to do with the file. <code>route</code> will then map the matched items to the paths created by <code>setExtension</code> which unsurprisingly only changes the resulting files extension to <code>html</code>. There are a few other functions that can be used here (basically all functions that return <code>Routes</code>). Those can be used to do more advanced route editing such as creating fancy paths using <code>index.html</code><a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>.
</p>
<p>
But what does this function actually do in particular? 1. It searches for all markdown files under the <code>posts/</code> directory. 2. Defines their final route 3. Compiles them to html using pandoc 4. Embedds them into a post template 5. Embedds raw posts into the default page template 6. And finally relativizes urls, which is a fancy function that keeps track of the resources referenced locally and keeps their links up to date.
</p>
<h3 class="y-header" id="compiling-with-pandoc">
<span>Compiling with Pandoc</span><a href="#compiling-with-pandoc" class="anchor las la-anchor" title="compiling-with-pandoc"></a>
</h3>
<p>
In the snippet above the default <code>pandocCompiler</code> function is used to read the content of the file and transform it into HTML using Hakyll’s default options for pandoc. Aside <code>pandocCompiler</code> there are a few more low level functions available that allow deeper customization in the regards of which pandoc templates are used, which extensions activated and so forth. There are also <code>pandocCompilerWithTransform</code> and <code>pandocCompilerWithTransformM</code> that allow editing the intermediate parsed content pandoc uses internally. At this point rich postprocessing can be applied, just alike the usual pandoc filters. The only grain is that existing pandoc filters (i.e. <a href="https://github.com/jgm/pandocfilters">pandocfilters</a> or <a href="https://github.com/sergiocorreia/panflute">panflute</a>) cannot be easily applied with Hakyll.
</p>
<h3 class="y-header" id="creating-routes">
<span>Creating Routes</span><a href="#creating-routes" class="anchor las la-anchor" title="creating-routes"></a>
</h3>
<p>
Additionally to matching existing files and compiling them, one can also generate fully independent files using the <code>create</code> function.
</p>
<div class="y-fill-horizontal">
<div id="cb4" class="sourceCode">
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>create [<span class="st">&quot;archive.html&quot;</span>] <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>    route idRoute</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>    compile <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>        posts <span class="ot">&lt;-</span> recentFirst <span class="op">=&lt;&lt;</span> loadAll <span class="st">&quot;posts/**&quot;</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> postCtx <span class="ot">=</span> postCtx tags categories</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> archiveCtx <span class="ot">=</span> listField <span class="st">&quot;posts&quot;</span> postCtx (<span class="fu">return</span> posts)</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>                    <span class="op">&lt;&gt;</span> constField <span class="st">&quot;title&quot;</span> <span class="st">&quot;Archive&quot;</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>                    <span class="op">&lt;&gt;</span> customBaseContext</span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>        makeItem <span class="st">&quot;&quot;</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>            <span class="op">&gt;&gt;=</span> loadAndApplyTemplate <span class="st">&quot;templates/archive.html&quot;</span> archiveCtx</span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a>            <span class="op">&gt;&gt;=</span> loadAndApplyTemplate <span class="st">&quot;templates/default.html&quot;</span> archiveCtx</span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a>            <span class="op">&gt;&gt;=</span> relativizeUrls</span></code></pre>
</div>
</div>
<p>
This creates a files <code>archive.html</code> which is built using the compile function that basically wraps an <code>Item a</code> in the <code>Compiler</code> monad. The corresponding item is created using <code>makeItem</code> that itroduces an empty String Item that is enriched first using the archive template and subsequently the default page template.
</p>
<p>
Notice the use of <code>loadAll</code> that makes the set of all posts availlable inside he compile scope. Most importantly though are the both contexts, especially the <code>archiveCtx</code> that makes the posts available to the template engine as a list of <code>postCtx</code>s.
</p>
<h3 class="y-header" id="contexts">
<span>Contexts</span><a href="#contexts" class="anchor las la-anchor" title="contexts"></a>
</h3>
<p>
Contexts contain the meta information that is available to the templating engine when building an <code>Item</code>. Thus allowing the usage of the computed value in the template files. A context holds a number of fields which are contexts as well. Each field’s value is created for every compilation item (this is every item the context will be applied on, usually individual posts).
</p>
<p>
Take for example the following field definition:
</p>
<div class="y-fill-horizontal">
<div id="cb5" class="sourceCode">
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>peekField</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="ot">    ::</span> <span class="dt">String</span>           <span class="co">-- ^ Key to use</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>    <span class="ot">-&gt;</span> <span class="dt">Int</span>              <span class="co">-- ^ length to peak</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>    <span class="ot">-&gt;</span> <span class="dt">Snapshot</span>         <span class="co">-- ^ Snapshot to load</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>    <span class="ot">-&gt;</span> <span class="dt">Context</span> <span class="dt">String</span>   <span class="co">-- ^ Resulting context</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>peekField key <span class="fu">length</span> snapshot <span class="ot">=</span> field key <span class="op">$</span> \item <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>    body <span class="ot">&lt;-</span> itemBody <span class="op">&lt;$&gt;</span> loadSnapshot (itemIdentifier item) snapshot</span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>    <span class="fu">return</span> (peak body)</span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">where</span> peak <span class="ot">=</span> T.unpack <span class="op">.</span> T.unwords <span class="op">.</span> <span class="fu">take</span> <span class="fu">length</span> <span class="op">.</span> T.words <span class="op">.</span> T.pack</span></code></pre>
</div>
</div>
<p>
This is a very simple field once created to serve as my own version of a teaser field. As you can see a <code>field</code> is created from a key and a function mapping an item to a string. In this case the item’s body is extracted from a <a href="https://jaspervdj.be/hakyll/tutorials/05-snapshots-feeds.html#snapshots">snapshot</a> of the item’s content. Then <code>length</code> words are taken and returned. (If you are in the actual need of a teaser field I would advice you though to use the <a href="https://jaspervdj.be/hakyll/reference/Hakyll-Web-Template-Context.html#v:teaserField"><code>teaserField</code></a>).
</p>
<p>
Yet what this example demonstate is the integral importance of <code>Item</code>s in Hakyll.
</p>
<h4 class="y-header" id="items">
<span>Items</span><a href="#items" class="anchor las la-anchor" title="items"></a>
</h4>
<p>
<code>Item</code>s are a simple datatypes that wrap a <code>body</code> of some type <code>a</code> (usually <code>String</code>) and an identifier.
</p>
<p>
Most of Hakyll’s functions that deal with content are working with <code>Item</code>s. As seen above <code>Item</code>s can also be stored in snapshots and retrieved later on. Especially in <code>field</code>s <code>Item</code>s contain the content from which the desired <code>field</code> can be derived from.
</p>
<hr />
<p>
I don’t mean to write an extensive documentation of all the concepts in Hakyll, an complete introductory tutorial as well as links to other peoples takes can be found at Jasper’s (the founder of Hakyll) <a href="https://jaspervdj.be/hakyll/tutorials.html">website</a>.
</p>
<p>
In a follow up article I would like to share a compilation of custom fields that I created or adapted from other blogs.
</p>
<section class="footnotes" role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote">
<p>
<a href="rohanjain.in/hakyll-clean-urls/">rohanjain.in/hakyll-clean-urls/</a><a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a>
</p>
</li>
</ol>
</section>]]></summary>
</entry>
<entry>
    <title>git commit -m "Initial Commit"</title>
    <link href="https://blog.ysndr.de/posts/2019-12-24-Welcome/index.html" />
    <id>https://blog.ysndr.de/posts/2019-12-24-Welcome/index.html</id>
    <published>2019-12-24T00:00:00Z</published>
    <updated>2019-12-24T00:00:00Z</updated>
    <summary type="html"><![CDATA[<h1 class="y-header" id="welcome">
<span>✨🎉 Welcome ✨🎉</span><a href="#welcome" class="anchor las la-anchor" title="welcome"></a>
</h1>
<p>
Hej, and welcome!
</p>
<p>
You appear to have successfully stumbled upon my Blog, nice to have you here.
</p>
<p>
This blog will be home to all the ideas that I mind worthy to be yelled out in the wild. Expect random thoughts posts about <a href="https://nixos.org/nix/">Nix</a>, <a href="https://www.rust-lang.org/">rust</a>, contents of my studies as well as the internals of this blog.
</p>]]></summary>
</entry>

</feed>
