<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
      <title>tori</title>
      <link>https://tori.jutty.dev</link>
      <description>Track and replicate your system&#x27;s configuration</description>
      <generator>Zola</generator>
      <language>en</language>
      <atom:link href="https://tori.jutty.dev/rss.xml" rel="self" type="application/rss+xml"/>
      <lastBuildDate>Sat, 20 Sep 2025 01:28:00 -0300</lastBuildDate>
      <item>
          <title>iganaq: OCaml</title>
          <pubDate>Sat, 20 Sep 2025 01:28:00 -0300</pubDate>
          <author>Juno Takano</author>
          <link>https://tori.jutty.dev/updates/iganaq-ocaml/</link>
          <guid>https://tori.jutty.dev/updates/iganaq-ocaml/</guid>
          <description xml:base="https://tori.jutty.dev/updates/iganaq-ocaml/">&lt;p&gt;&lt;em&gt;As part of the &lt;a href=&quot;https:&#x2F;&#x2F;tori.jutty.dev&#x2F;updates&#x2F;iganaq&#x2F;&quot;&gt;iganaq experiment&lt;&#x2F;a&gt;, work is ongoing to decide on what language the future versions of tori will be implemented in. For this purpose, I’ve defined a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;codeberg.org&#x2F;tori&#x2F;iganaq&#x2F;src&#x2F;branch&#x2F;main&#x2F;README.md#specification&quot;&gt;minimal specification&lt;&#x2F;a&gt; that I’m using to prototype and experiment with three different languages: OCaml, Haskell and Rust. The balance after all three are done will inform the final decision.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In other news, I’ve recently made arrangements to make tori the topic of my dissertation for the Systems Analysis undergraduate program at the São Paulo Federal Institute.&lt;&#x2F;p&gt;
&lt;p&gt;In this post, I’ll comment on the OCaml implementation, finished on May 17th, 2025. For the corresponding OCaml source code, you can refer to the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;codeberg.org&#x2F;tori&#x2F;iganaq&#x2F;src&#x2F;branch&#x2F;main&#x2F;ocaml&quot;&gt;main repository&lt;&#x2F;a&gt; or any of its &lt;a href=&quot;&#x2F;code&quot;&gt;mirrors&lt;&#x2F;a&gt; on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;codeberg.org&#x2F;tori&#x2F;iganaq&#x2F;src&#x2F;branch&#x2F;main&#x2F;ocaml&quot;&gt;Codeberg&lt;&#x2F;a&gt; or &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tori-nest&#x2F;iganaq&#x2F;tree&#x2F;main&#x2F;ocaml&quot;&gt;GitHub&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;language&quot;&gt;Language&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;type-system&quot;&gt;Type system&lt;&#x2F;h3&gt;
&lt;p&gt;OCaml’s type system is one of its highlights. It is very expressive and at the same time concise, with the potential for very clean syntax with little to no type annotations at all due to type inference. As a type freak myself, I do prefer to explicitly type most things, because I like my errors to come up as early as possible. But it’s a feature.&lt;&#x2F;p&gt;
&lt;p&gt;What I particularly like about inference is not being able to leave out type declarations, it’s the compiler’s ability to consider what type something &lt;em&gt;must&lt;&#x2F;em&gt; be. It is particularly interesting when, because you have not typed something, you still have a clue as to what its type &lt;em&gt;would be&lt;&#x2F;em&gt; given the context, and the compiler is one step ahead of you and just says “this is typed as &lt;code&gt;x&lt;&#x2F;code&gt;, but it should be &lt;code&gt;y&lt;&#x2F;code&gt;”.&lt;&#x2F;p&gt;
&lt;p&gt;In this sense, there is something very “best of both worlds” about inference. Static types without inference will tell you what type something is, but just because someone told it before – helpful, but not as intelligent. Conversely, dynamic types will infer &lt;em&gt;everything&lt;&#x2F;em&gt; for you, but they can’t tell you what is being inferred, because they don’t know either.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;syntax&quot;&gt;Syntax&lt;&#x2F;h3&gt;
&lt;p&gt;OCaml syntax is extremely clean, in fact I feel it’s one of the cleanest I have ever seen. This is a huge positive to me as it makes &lt;em&gt;reading&lt;&#x2F;em&gt; it easier, with no trying to understand which bracket matches what, with tooling or not.&lt;&#x2F;p&gt;
&lt;p&gt;Having its roots in the ML family of languages, it’s very different from C-style languages. This is a positive for me, as I feel it’s more readable, but adding another syntax style also adds more cognitive load in a world where most languages are C-style. It’s easy to call something “concise” and “readable” with bare-bones examples that are not far from the Hello, World stage. It’s a different matter entirely to write concise and readable code for a complex problem.&lt;&#x2F;p&gt;
&lt;p&gt;Coupled with inference, a clean syntax results in very succint code. Add the powerful type system and the ample scope of the language, which is functional first with imperative and object-oriented capabilities, and you have a very high degree of expressiveness.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ecosystem&quot;&gt;Ecosystem&lt;&#x2F;h3&gt;
&lt;p&gt;Aside from the experience of writing in the language itself, another crucial aspect for evaluating it for a project is the ecosystem, by which I mean everything around the language that supports it in several ways: documentation, tooling, governance, community.&lt;&#x2F;p&gt;
&lt;p&gt;The OCaml ecosystem is not the most lively of the three being evaluated. This is merely my impression, as it’s hard to compare the liveliness of ecosystems quantitatively. Say we went for the total number of packages in the main library repository: a lousy metric because each language has a different standard library that gives different reasons for libraries to exist or not.&lt;&#x2F;p&gt;
&lt;p&gt;While it is not as lively as the other two, it is by no means small or in a halt. It is alive, people are constantly chatting about it in the official forums and chat rooms, new versions of libraries and whole new libraries are announced all the time, and there is more than enough to solve a plethora of problems.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;libraries&quot;&gt;Libraries&lt;&#x2F;h4&gt;
&lt;p&gt;According to the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;opam.ocaml.org&#x2F;&quot;&gt;official opam website&lt;&#x2F;a&gt;, there are 4563 packages available. The &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ocaml&#x2F;opam-repository&#x2F;pulse&#x2F;monthly&quot;&gt;repository&lt;&#x2F;a&gt; had 160 pull requests merged in the past 30 days.&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; I still think these are lousy metrics that would need more work to be useful, but they can give us an overall view other than my personal impressions.&lt;&#x2F;p&gt;
&lt;p&gt;For iganaq, no libraries were necessary, and that is something I very much wanted to evaluate: can it be done with the language’s standard library alone? The OCaml standard library is known for being very slim, so much so that the ecosystem includes more than one “third-party standard library” that you can install to expand and override the defaults.&lt;&#x2F;p&gt;
&lt;p&gt;This does seem to be changing, though. In recent versions of OCaml and the OCaml standard library, the trend seems to be making it more complete and capable with every release, rather than staying small.&lt;&#x2F;p&gt;
&lt;p&gt;A contentious topic, as mostly any topic around programming languages, but personally I do prefer bulkier, batteries-included standard libraries, so I can get more done with less dependencies.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;documentation&quot;&gt;Documentation&lt;&#x2F;h4&gt;
&lt;p&gt;I find the documentation for the core language itself quite satisfying, but I can’t say the same about third-party libraries. Most of them will provide the output of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ocaml&#x2F;odoc&#x2F;&quot;&gt;odoc&lt;&#x2F;a&gt;, the OCaml documentation compiler, which may or may not be as useful as documentation written by and for humans, with examples and explanations on usage, not just symbols. This is &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;discuss.ocaml.org&#x2F;t&#x2F;an-example-for-every-ocaml-package&#x2F;16953&#x2F;1&quot;&gt;not entirely overlooked&lt;&#x2F;a&gt; though.&lt;&#x2F;p&gt;
&lt;p&gt;OCaml has documentation for mostly anything the standard library provides. Take, for example, the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ocaml.org&#x2F;manual&#x2F;5.3&#x2F;api&#x2F;Unix.html&quot;&gt;docs for the &lt;code&gt;Unix&lt;&#x2F;code&gt; module&lt;&#x2F;a&gt;, which I consulted a lot while implementing iganaq. References to types that are not primitives are clickable and several descriptions are extensive. Working with these wasn’t an issue, and everything is available over the web, including extensive prose on the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ocaml.org&#x2F;manual&#x2F;5.3&#x2F;api&#x2F;index.html&quot;&gt;fundamentals of the language&lt;&#x2F;a&gt; and its &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ocaml.org&#x2F;manual&#x2F;5.3&#x2F;index.html&quot;&gt;inner workings&lt;&#x2F;a&gt;, with interesting highlights being &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;doc.sherlocode.com&#x2F;&quot;&gt;Sherlodoc&lt;&#x2F;a&gt;, the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;hoogle.haskell.org&#x2F;&quot;&gt;Hoogle&lt;&#x2F;a&gt; of OCaml, and the near-cannon &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dev.realworldocaml.org&#x2F;toc.html&quot;&gt;Real World OCaml&lt;&#x2F;a&gt; book, written by Anil Madhavapeddy, an OCaml &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ocaml.org&#x2F;policies&#x2F;governance#b-delegates&quot;&gt;delegate&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;governance&quot;&gt;Governance&lt;&#x2F;h4&gt;
&lt;p&gt;My main criteria around governance is project independence from profit-motivated organizations, which is a motivation that may or may not prioritize the language and its community over their bottom line. One other red flag for me is the idea of a “benevolent dictator for life”, which I feel is a poor way to direct a project as versatile as a programming language, particularly given how large, vibrant and involved the communities that form around programming languages can become.&lt;&#x2F;p&gt;
&lt;p&gt;OCaml is known as an “academic” language, and indeed its history seems to have several branches coming from and going back into academia. But it seems to me its roots are more entwined with government, with a strong relationship to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.inria.fr&#x2F;en&quot;&gt;Inria&lt;&#x2F;a&gt;, France’s “National Institute for Research in Digital Science and Technology”.&lt;&#x2F;p&gt;
&lt;p&gt;Despite that, its &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ocaml.org&#x2F;policies&#x2F;governance&quot;&gt;governance policy&lt;&#x2F;a&gt; describes it as having an “Owner”, and goes on to say:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;it is the community that actively contributes to the day-to-day maintenance of these initiatives, but the general strategic direction is drawn by the Owner&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;While this may sound autocratic at first, it continues:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is the community’s role to guide the decisions of the Owner through active engagement, contributions, and discussions. To foster a healthy and growing community, the Owner will make the goals and decisions clear and public.&lt;&#x2F;p&gt;
&lt;p&gt;It is anticipated that the Projects themselves will be self-managing and will resolve issues within their communities, without recourse to the Owner. Where the Owner needs to become involved, he&#x2F;she will act as arbitrator.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I think this governance model could be a problem with a problematic owner, but I’m not aware, as someone not too deeply involved, of any controversies involving the role.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;community&quot;&gt;Community&lt;&#x2F;h4&gt;
&lt;p&gt;While niche, OCaml does have an active community. The official &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;discuss.ocaml.org&#x2F;t&#x2F;relocatable-compiler-work&#x2F;11218&#x2F;5&quot;&gt;forums&lt;&#x2F;a&gt; are where most search queries landed, rather than Stack Overflow, and I never stumbled upon rude and pedantic answers signaling an elitism culture, a major red flag for me when evaluating any software project.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;tooling&quot;&gt;Tooling&lt;&#x2F;h4&gt;
&lt;p&gt;I think tooling is the only aspect of OCaml that I can’t say I’m happy about. This hinges on two main issues: an unintuitive build tool and the lack of a relocatable compiler. And I am happy to report that a solution to the second issue is &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;discuss.ocaml.org&#x2F;t&#x2F;relocatable-ocaml&#x2F;17253&quot;&gt;on the way&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;OCaml’s most used build tool is &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dune.build&#x2F;&quot;&gt;Dune&lt;&#x2F;a&gt;, which uses S-expressions for its configuration language. I am not the biggest fan of S-expressions because I don’t think they nest well and end up with poor readability as complexity increases.&lt;&#x2F;p&gt;
&lt;p&gt;Dune gets the job done. One feature I miss in it is the ability to define arbitrary commands to eliminate the need for a Makefile or equivalent alongside it, but that is also not a major issue.&lt;&#x2F;p&gt;
&lt;p&gt;The problem with not having a relocatable compiler, which means the system expects the compiler to be  at a specific path, preventing, for instance, multiple OCaml projects from reusing the same compiler, is that whenever you’d create a new environment to work on a new OCaml project, you’d have to recompile the OCaml compiler (!). That is not fast depending on your hardware, so it can slow you down.&lt;&#x2F;p&gt;
&lt;p&gt;This however is being worked on and from what it looks like it’s something with a very advanced solution already. With this solution on the way and the other issues being minor ones, while a bit annoying at times, OCaml tooling is not a deal-breaker.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;implementation&quot;&gt;Implementation&lt;&#x2F;h2&gt;
&lt;p&gt;Now to the actual insides of what it was like to implement iganaq in OCaml.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;entry-point&quot;&gt;Entry point&lt;&#x2F;h3&gt;
&lt;p&gt;Another feature I appreciate having available in OCaml is &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ocaml.org&#x2F;docs&#x2F;basic-data-types&quot;&gt;pattern matching&lt;&#x2F;a&gt;. The program’s entry point is exactly that: a pattern matching expression against the command line arguments:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#393A34, #D8DEE9); background-color: light-dark(#FFFFFF, #2E3440);&quot;&gt;&lt;code data-lang=&quot;ocaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; ()&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;    match&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;to_list&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; Sys&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;argv&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt; with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt;    |&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #EBCB8B);font-weight: bold;&quot;&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; ::&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #D8DEE9);&quot;&gt; tail&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#AB5959, #81A1C1);&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; past&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; ConfigFetcher&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;fetch&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; Tori&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt;Schema&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;origin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;            |&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; Tori&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt;Checks&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;post_config&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#AB5959, #81A1C1);&quot;&gt;        in&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#AB5959, #81A1C1);&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; future&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; Tori&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt;Parsers&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt;Argument&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;interpret&lt;&#x2F;span&gt;&lt;span&gt; past&lt;&#x2F;span&gt;&lt;span&gt; tail&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;            |&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; Tori&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt;Checks&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;exit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#AB5959, #81A1C1);&quot;&gt;        in&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        exit&lt;&#x2F;span&gt;&lt;span&gt; future&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;meta&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;status&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt;    |&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; assert&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here, I drop the first element in the argument array (the command name, &lt;code&gt;tori&lt;&#x2F;code&gt;) and pass all others (&lt;code&gt;tail&lt;&#x2F;code&gt;) to an argument parser along with the values from configuration stored on disk.&lt;&#x2F;p&gt;
&lt;p&gt;The argument parser will then return a &lt;code&gt;future&lt;&#x2F;code&gt; from this, which is then used to set the exit status. I use this pattern a lot in the implementation: call the function input or some previous state the &lt;code&gt;past&lt;&#x2F;code&gt;, work inside the function with a &lt;code&gt;present&lt;&#x2F;code&gt; and construct a &lt;code&gt;future&lt;&#x2F;code&gt; to be returned. The type of all three is usually a &lt;code&gt;schema&lt;&#x2F;code&gt;, to be detailed below.&lt;&#x2F;p&gt;
&lt;p&gt;The last pattern matching case, &lt;code&gt;[] -&amp;gt; assert false&lt;&#x2F;code&gt; is there only to make the matching exhaustive, since &lt;code&gt;Sys.argv&lt;&#x2F;code&gt; will always at least contain the program name.&lt;&#x2F;p&gt;
&lt;p&gt;So by looking at the entry point above, we can see that everything that really happens is contained in three steps:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;a &lt;code&gt;past&lt;&#x2F;code&gt; is retrieved from the configuration parser&lt;&#x2F;li&gt;
&lt;li&gt;a &lt;code&gt;future&lt;&#x2F;code&gt; is obtained by passing this &lt;code&gt;past&lt;&#x2F;code&gt; and the command line arguments to the argument parser&lt;&#x2F;li&gt;
&lt;li&gt;the &lt;code&gt;future&lt;&#x2F;code&gt;’s exit status is passed to the standard library’s &lt;code&gt;exit&lt;&#x2F;code&gt; function, terminating the program&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;modules&quot;&gt;Modules&lt;&#x2F;h3&gt;
&lt;p&gt;For implementing the spec, I ended up with the following module structure:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#393A34, #D8DEE9); background-color: light-dark(#FFFFFF, #2E3440);&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;lib&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── checks&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └── checks.ml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── parsers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   ├── argument.ml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └── config&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│       ├── fetcher.ml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│       ├── lexer.ml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│       └── parser.ml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── schema&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └── schema.ml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── system&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   ├── file.ml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   ├── os.ml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   ├── package.ml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └── process&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│       ├── command.ml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│       ├── fork.ml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│       ├── reader.ml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│       └── su.ml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── types&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └── structures.ml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── utilities&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── aliases.ml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── exceptions.ml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── log.ml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    └── text.ml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;schema&quot;&gt;Schema&lt;&#x2F;h4&gt;
&lt;p&gt;I like the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;guide.elm-lang.org&#x2F;architecture&#x2F;&quot;&gt;Elm Architecture&lt;&#x2F;a&gt; concept and I end up replicating some variation of it in a lot of things I do.&lt;&#x2F;p&gt;
&lt;p&gt;For this project, I wanted a data structure I could pass around to atomically represent the application state at any given point in time, instead of spreading state all over the place. I called this the “schema”:&lt;&#x2F;p&gt;
&lt;p&gt;Many functions in the implementation receive a schema as an argument (sometimes the only one), transform it and then also return a schema. This allows me to pass a schema to a sequence of functions through pipes and get an end-state of all their transformations as the result, greatly simplifying control flow.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#393A34, #D8DEE9); background-color: light-dark(#FFFFFF, #2E3440);&quot;&gt;&lt;code data-lang=&quot;ocaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; origin&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; :&lt;&#x2F;span&gt;&lt;span&gt; schema&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;    meta&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;        version&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt; major&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt; minor&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt; patch&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; }&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;        help&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;            short&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;lt;short help&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;            long&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;lt;long help&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;        }&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;        error_level&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; Clear&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;        status&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;        defaults&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;            paths&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;                configuration&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; Unix&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;getenv&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;HOME&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; ^&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&#x2F;.config&#x2F;tori&#x2F;tori.conf&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;            }&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;        }&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;    }&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;    input&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;        configuration&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;            main&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;                su_command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;su&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;-c&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; ]&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;                su_command_quoted&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; Default&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;                interactive&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; true&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;                simulate&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; false&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;            }&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;        }&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;    }&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;    output&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt; main&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt; log&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; }&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;    host&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;        os&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; Unknown&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;        name&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;Unknown Host&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;    }&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Type definitions aside, the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;codeberg.org&#x2F;tori&#x2F;iganaq&#x2F;src&#x2F;branch&#x2F;main&#x2F;ocaml&#x2F;lib&#x2F;schema&#x2F;schema.ml&quot;&gt;&lt;code&gt;schema.ml&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; file contains some helper functions and this &lt;code&gt;origin&lt;&#x2F;code&gt; schema, which is used as the starting point for application state, establishing the defaults.&lt;&#x2F;p&gt;
&lt;p&gt;For example, the following function will format a version from the schema into a string in the conventional &lt;code&gt;v1.2.3&lt;&#x2F;code&gt; format:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#393A34, #D8DEE9); background-color: light-dark(#FFFFFF, #2E3440);&quot;&gt;&lt;code data-lang=&quot;ocaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; format_version&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #D8DEE9);&quot;&gt;version&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; :&lt;&#x2F;span&gt;&lt;span&gt; version&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; :&lt;&#x2F;span&gt;&lt;span&gt; string&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;v&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; ^&lt;&#x2F;span&gt;&lt;span&gt; string_of_int&lt;&#x2F;span&gt;&lt;span&gt; version&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;major&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; ^&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; ^&lt;&#x2F;span&gt;&lt;span&gt; string_of_int&lt;&#x2F;span&gt;&lt;span&gt; version&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;minor&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; ^&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; ^&lt;&#x2F;span&gt;&lt;span&gt; string_of_int&lt;&#x2F;span&gt;&lt;span&gt; version&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;patch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This one will take a configuration &lt;code&gt;key&lt;&#x2F;code&gt; from the sum type &lt;code&gt;configuration_key&lt;&#x2F;code&gt; and return a string, which was useful for logging purposes:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#393A34, #D8DEE9); background-color: light-dark(#FFFFFF, #2E3440);&quot;&gt;&lt;code data-lang=&quot;ocaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; string_of_key&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #D8DEE9);&quot;&gt; key&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;    match&lt;&#x2F;span&gt;&lt;span&gt; key&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt; with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt;        |&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; SuCommand&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;su_command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt;        |&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; SuCommandQuoted&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;su_command_quoted&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt;        |&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; Interactive&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;interactive&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt;        |&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; Simulate&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;simulate&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt;        |&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; Unknown&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;lt;unknown key&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I think these functions are great examples of how minimal and clean OCaml syntax can look like. See, for instance, the type definition for &lt;code&gt;configuration_key&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#393A34, #D8DEE9); background-color: light-dark(#FFFFFF, #2E3440);&quot;&gt;&lt;code data-lang=&quot;ocaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;type&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; configuration_key&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt;    |&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; SuCommand&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt;    |&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; SuCommandQuoted&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt;    |&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; Interactive&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt;    |&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; Simulate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt;    |&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; Unknown&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is not only very readable and concise, but by leveraging a sum type I get free exhaustion checks anywhere I use this when pattern matching. And by encapsulating most (all?) state in a single data structure with a tiny memory budget and several specialized inner types, nearly everything that happens changes only within the constraints of the schema.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;parsers&quot;&gt;Parsers&lt;&#x2F;h4&gt;
&lt;p&gt;I implemented two simple parsers for this project: an argument parser and a configuration parser for a subset of the &lt;code&gt;ini&lt;&#x2F;code&gt; configuration format.&lt;&#x2F;p&gt;
&lt;h5 id=&quot;the-configuration-lexer-and-parser&quot;&gt;The configuration lexer and parser&lt;&#x2F;h5&gt;
&lt;p&gt;The &lt;code&gt;Config&lt;&#x2F;code&gt; submodule in the &lt;code&gt;Parsers&lt;&#x2F;code&gt; module provides a &lt;code&gt;fetch&lt;&#x2F;code&gt; function that starts from the &lt;code&gt;origin&lt;&#x2F;code&gt; schema and passes the configuration path defined in it to the other modules main functions: &lt;code&gt;Lexer.scan&lt;&#x2F;code&gt;, &lt;code&gt;Lexer.concat&lt;&#x2F;code&gt;, &lt;code&gt;Parser.parse&lt;&#x2F;code&gt; and finally &lt;code&gt;Parser.apply&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The lexer and parser are your typical run-of-the-mill textbook lexer and parser. One distinction is that they know what keys to expect not from their own code, but from the types defined as possible keys in the schema. If the schema changes, type checking will therefore immediately break in the lexer, which I think is an excellent way to wire things up.&lt;&#x2F;p&gt;
&lt;h6 id=&quot;the-configuration-lexer&quot;&gt;The configuration lexer&lt;&#x2F;h6&gt;
&lt;p&gt;What &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;codeberg.org&#x2F;tori&#x2F;iganaq&#x2F;src&#x2F;branch&#x2F;main&#x2F;ocaml&#x2F;lib&#x2F;parsers&#x2F;config&#x2F;lexer.ml&quot;&gt;&lt;code&gt;the lexer&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; is concerned with is matching string literals found in a text file with these key types it knows from the schema and the possible tokens that can encapsulate their values. Because we are working with a subset of &lt;code&gt;ini&lt;&#x2F;code&gt; (which in itself is already very simple), it finds a middle position from the &lt;code&gt;=&lt;&#x2F;code&gt; character and a final position from a newline and there you go, to the left are possible keys and to the right are possible values:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#393A34, #D8DEE9); background-color: light-dark(#FFFFFF, #2E3440);&quot;&gt;&lt;code data-lang=&quot;ocaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; scan_line&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #D8DEE9);&quot;&gt;input&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; char&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; list&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; token&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; list&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#AB5959, #81A1C1);&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; rec&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; to_tokens&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #D8DEE9);&quot;&gt;chars&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; char&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; list&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #D8DEE9);&quot;&gt;position&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; int&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #D8DEE9);&quot;&gt;tokens&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; token&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; list&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span&gt; position&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span&gt; length&lt;&#x2F;span&gt;&lt;span&gt; chars&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt; then&lt;&#x2F;span&gt;&lt;span&gt; tokens&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;        else&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5959, #81A1C1);&quot;&gt; let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #D8DEE9);&quot;&gt; token&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #D8DEE9);&quot;&gt; next_position&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; lex&lt;&#x2F;span&gt;&lt;span&gt; chars&lt;&#x2F;span&gt;&lt;span&gt; position&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5959, #81A1C1);&quot;&gt; in&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            to_tokens&lt;&#x2F;span&gt;&lt;span&gt; chars&lt;&#x2F;span&gt;&lt;span&gt; next_position&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; $&lt;&#x2F;span&gt;&lt;span&gt; token&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; ::&lt;&#x2F;span&gt;&lt;span&gt; tokens&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#AB5959, #81A1C1);&quot;&gt;    in&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    reverse&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; $&lt;&#x2F;span&gt;&lt;span&gt; to_tokens&lt;&#x2F;span&gt;&lt;span&gt; input&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#005CC5, #EBCB8B);font-weight: bold;&quot;&gt;(*&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #EBCB8B);font-weight: bold;&quot;&gt; char_lists has the contents of the configuration file &lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #EBCB8B);font-weight: bold;&quot;&gt;*)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; scan&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #D8DEE9);&quot;&gt;char_lists&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; char&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; lists&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; token&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; lists&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#AB5959, #81A1C1);&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; tokens&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; rmap&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;scan_line&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt; char_lists&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; $:&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;End&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5959, #81A1C1);&quot;&gt; in&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    elog&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; ~&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;context&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;Parsing&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; $&lt;&#x2F;span&gt;&lt;span&gt; string_of_tokens&lt;&#x2F;span&gt;&lt;span&gt; tokens&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    tokens&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note I defined some custom operators above, which also shows something OCaml can do which I like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#393A34, #D8DEE9); background-color: light-dark(#FFFFFF, #2E3440);&quot;&gt;&lt;code data-lang=&quot;ocaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;@@&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;$:&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #D8DEE9);&quot;&gt; list&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #D8DEE9);&quot;&gt; element&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; list&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; @&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; [&lt;&#x2F;span&gt;&lt;span&gt;element&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h6 id=&quot;the-configuration-parser&quot;&gt;The configuration parser&lt;&#x2F;h6&gt;
&lt;p&gt;Once the lexer has turned a text file into a list of tokens, the configuration fetcher will pipe this list of tokens to the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;codeberg.org&#x2F;tori&#x2F;iganaq&#x2F;src&#x2F;branch&#x2F;main&#x2F;ocaml&#x2F;lib&#x2F;parsers&#x2F;config&#x2F;parser.ml&quot;&gt;configuration parser&lt;&#x2F;a&gt;, which is responsible for finally assembling a schema that reflects what was defined in the configuration.&lt;&#x2F;p&gt;
&lt;p&gt;This closes the circle for the fetcher, which works on the outer boundary, receiving and returning a schema.&lt;&#x2F;p&gt;
&lt;p&gt;Other than this reliance on the schema as the final state, the parser implementation is pretty undifferentiated and uninteresting. In fact, it’s likely fair to say a significant portion of it is logging code, and it would look rather tiny if there weren’t any logging or if logging was abstracted away.&lt;&#x2F;p&gt;
&lt;h5 id=&quot;the-argument-parser&quot;&gt;The argument parser&lt;&#x2F;h5&gt;
&lt;p&gt;The argument parser takes the schema that resulted from the configuration parser’s work and a list of strings (the command line arguments). It looks at the arguments, calls the corresponding functions for the commands, such as &lt;code&gt;check&lt;&#x2F;code&gt;, &lt;code&gt;version&lt;&#x2F;code&gt; or &lt;code&gt;help&lt;&#x2F;code&gt;, or prints an error message in case the command matches none of its known strings.&lt;&#x2F;p&gt;
&lt;p&gt;I left a note in a comment here. The flow could be simplified by passing more data back in the schema, returning a data structure containing orders and outputs to be executed and printed in a later step, by other functions, rather than using what was supposed to be a parser as a glorified switch that calls all sorts of side effects into execution.&lt;&#x2F;p&gt;
&lt;p&gt;This however was a tiny implementation meant simply to evaluate OCaml itself, so I left that as possible improvement for later (as I did in several other spots, if you are curious enough to check the source code).&lt;&#x2F;p&gt;
&lt;h4 id=&quot;system-calls&quot;&gt;System calls&lt;&#x2F;h4&gt;
&lt;p&gt;The &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;codeberg.org&#x2F;tori&#x2F;iganaq&#x2F;src&#x2F;branch&#x2F;main&#x2F;ocaml&#x2F;lib&#x2F;system&quot;&gt;&lt;code&gt;System&lt;&#x2F;code&gt; module&lt;&#x2F;a&gt; is what the argument parser calls to execute most of the commands it was given in the command line.&lt;&#x2F;p&gt;
&lt;p&gt;To fulfill its mission, it only needs to be able to read file contents, determine what is the operating system it’s running on, and, more elaborately, execute commands and interface with the system package manager to list, install and uninstall packages.&lt;&#x2F;p&gt;
&lt;p&gt;These goals are fulfilled by the submodules &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;codeberg.org&#x2F;tori&#x2F;iganaq&#x2F;src&#x2F;branch&#x2F;main&#x2F;ocaml&#x2F;lib&#x2F;system&#x2F;file.ml&quot;&gt;&lt;code&gt;File&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;codeberg.org&#x2F;tori&#x2F;iganaq&#x2F;src&#x2F;branch&#x2F;main&#x2F;ocaml&#x2F;lib&#x2F;system&#x2F;os.ml&quot;&gt;&lt;code&gt;OS&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;codeberg.org&#x2F;tori&#x2F;iganaq&#x2F;src&#x2F;branch&#x2F;main&#x2F;ocaml&#x2F;lib&#x2F;system&#x2F;process&quot;&gt;&lt;code&gt;Process&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;codeberg.org&#x2F;tori&#x2F;iganaq&#x2F;src&#x2F;branch&#x2F;main&#x2F;ocaml&#x2F;lib&#x2F;system&#x2F;package.ml&quot;&gt;&lt;code&gt;Package&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;File&lt;&#x2F;code&gt; module is so boilerplatey I won’t even mention its code. The &lt;code&gt;OS&lt;&#x2F;code&gt; module is just a bit less tiny:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#393A34, #D8DEE9); background-color: light-dark(#FFFFFF, #2E3440);&quot;&gt;&lt;code data-lang=&quot;ocaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; identify&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; :&lt;&#x2F;span&gt;&lt;span&gt; string&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#AB5959, #81A1C1);&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; os_release&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; String&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;split_on_char&lt;&#x2F;span&gt;&lt;span&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;\n&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt;File&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;read&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&#x2F;etc&#x2F;os-release&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5959, #81A1C1);&quot;&gt; in&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt;    Utilities&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt;Log&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;elog&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; ~&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;context&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;OS&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt;String&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;concat&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; os_release&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#AB5959, #81A1C1);&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; os_equals&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; List&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;find&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt;String&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;starts_with&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; ~&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;prefix&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;NAME=&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt; os_release&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5959, #81A1C1);&quot;&gt; in&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;    match&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; String&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;split_on_char&lt;&#x2F;span&gt;&lt;span&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; os_equals&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt; with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt;    |&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #EBCB8B);font-weight: bold;&quot;&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #D8DEE9);&quot;&gt; s&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; ]&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt;        String&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;trim&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; @@&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; String&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;map&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5959, #81A1C1);&quot;&gt;fun&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #D8DEE9);&quot;&gt; c&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt; if&lt;&#x2F;span&gt;&lt;span&gt; c&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt; then&lt;&#x2F;span&gt;&lt;span&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt; else&lt;&#x2F;span&gt;&lt;span&gt; c&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt; s&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt;    |&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #EBCB8B);font-weight: bold;&quot;&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;Unknown&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It uses the &lt;code&gt;File&lt;&#x2F;code&gt; module’s functions to read the contents of the &lt;code&gt;&#x2F;etc&#x2F;os-release&lt;&#x2F;code&gt; file. It then does some silly string manipulation to strip quotes and get a clean OS name instead of double-quoted text.&lt;&#x2F;p&gt;
&lt;h5 id=&quot;process&quot;&gt;Process&lt;&#x2F;h5&gt;
&lt;p&gt;Certainly &lt;code&gt;Process&lt;&#x2F;code&gt; is the most intricate of these four modest submodules. It’s responsible for executing commands available in the underlying Unix descendant tori is running on, bridging a realm of more narrowly-defined interactions and transformations to another of heavy side effects — not that I strived to keep the former realm very pure.&lt;&#x2F;p&gt;
&lt;p&gt;Process has four inner modules I’ll spare you from calling subsubmodules:&lt;&#x2F;p&gt;
&lt;h6 id=&quot;command&quot;&gt;&lt;code&gt;Command&lt;&#x2F;code&gt;&lt;&#x2F;h6&gt;
&lt;p&gt;Defines types to abstract the concept of a command, including its arguments, execution status and exit code:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#393A34, #D8DEE9); background-color: light-dark(#FFFFFF, #2E3440);&quot;&gt;&lt;code data-lang=&quot;ocaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;type&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; status&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; Exit&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt; of&lt;&#x2F;span&gt;&lt;span&gt; int&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; Unevaluated&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;type&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt; name&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; :&lt;&#x2F;span&gt;&lt;span&gt; string&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt; arguments&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; :&lt;&#x2F;span&gt;&lt;span&gt; string&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; list&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt; status&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; :&lt;&#x2F;span&gt;&lt;span&gt; status&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It also has a “to string” utility function for logging purposes.&lt;&#x2F;p&gt;
&lt;h6 id=&quot;fork&quot;&gt;&lt;code&gt;Fork&lt;&#x2F;code&gt;&lt;&#x2F;h6&gt;
&lt;p&gt;A run-of-the-mill function mostly just wrapping the standard library’s &lt;code&gt;Unix.fork&lt;&#x2F;code&gt; function for running a command as defined in the previous &lt;code&gt;Command&lt;&#x2F;code&gt; module.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#393A34, #D8DEE9); background-color: light-dark(#FFFFFF, #2E3440);&quot;&gt;&lt;code data-lang=&quot;ocaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; run&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #D8DEE9);&quot;&gt;command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; :&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; Command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; :&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; Command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;    match&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; Unix&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;fork&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; ()&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt; with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt;    |&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; Unix&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;execvp&lt;&#x2F;span&gt;&lt;span&gt; command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;name&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt;Array&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;of_list&lt;&#x2F;span&gt;&lt;span&gt; command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;arguments&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt;    |&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #D8DEE9);&quot;&gt; pid&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt; (&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#AB5959, #81A1C1);&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #EBCB8B);font-weight: bold;&quot;&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #D8DEE9);&quot;&gt; status&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; Unix&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;waitpid&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt; pid&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5959, #81A1C1);&quot;&gt; in&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;        match&lt;&#x2F;span&gt;&lt;span&gt; status&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt; with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt;        |&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; WSTOPPED&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #D8DEE9);&quot;&gt; n&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; WSIGNALED&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #D8DEE9);&quot;&gt; n&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; WEXITED&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #D8DEE9);&quot;&gt; n&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;            {&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt; command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; with&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt; status&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; Exit&lt;&#x2F;span&gt;&lt;span&gt; n&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt;      )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It returns the same command data, but with updated execution status and exit code. Its companion, &lt;code&gt;run_many&lt;&#x2F;code&gt; simply applies a map function to do the exact same thing but across two lists of commands:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#393A34, #D8DEE9); background-color: light-dark(#FFFFFF, #2E3440);&quot;&gt;&lt;code data-lang=&quot;ocaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; run_many&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #D8DEE9);&quot;&gt;commands&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; :&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; Command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; list&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; :&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; Command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; list&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt;    List&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;map&lt;&#x2F;span&gt;&lt;span&gt; run&lt;&#x2F;span&gt;&lt;span&gt; commands&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;See what I mean about conciseness? If we remove the type nerd fluff we get:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#393A34, #D8DEE9); background-color: light-dark(#FFFFFF, #2E3440);&quot;&gt;&lt;code data-lang=&quot;ocaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; run_many&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #D8DEE9);&quot;&gt; commands&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; List&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;map&lt;&#x2F;span&gt;&lt;span&gt; run&lt;&#x2F;span&gt;&lt;span&gt; commands&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Makes you wonder if that function existing was even necessary.&lt;&#x2F;p&gt;
&lt;h6 id=&quot;reader&quot;&gt;&lt;code&gt;Reader&lt;&#x2F;code&gt;&lt;&#x2F;h6&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;codeberg.org&#x2F;tori&#x2F;iganaq&#x2F;src&#x2F;branch&#x2F;main&#x2F;ocaml&#x2F;lib&#x2F;system&#x2F;process&#x2F;reader.ml&quot;&gt;&lt;code&gt;Reader&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; is certainly the most undifferentiated and boring of all the modules. It’s basically a copy of How To Read a Buffer and just repeats the old routine of reading data until the end of a stream.&lt;&#x2F;p&gt;
&lt;h6 id=&quot;su&quot;&gt;&lt;code&gt;Su&lt;&#x2F;code&gt;&lt;&#x2F;h6&gt;
&lt;p&gt;Finally, &lt;code&gt;Su&lt;&#x2F;code&gt;, which is not about adding a subtle touch of salt and vinegar to cooked rice, rather, it’s about how to determine the available way to elevate privileges to &lt;strong&gt;s&lt;&#x2F;strong&gt;uper&lt;strong&gt;u&lt;&#x2F;strong&gt;ser.&lt;&#x2F;p&gt;
&lt;p&gt;If a value for the &lt;code&gt;su_command&lt;&#x2F;code&gt; configuration key is not present, it must default to &lt;code&gt;su -c&lt;&#x2F;code&gt;. Otherwise, it must use whatever was provided:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#393A34, #D8DEE9); background-color: light-dark(#FFFFFF, #2E3440);&quot;&gt;&lt;code data-lang=&quot;ocaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; elevate_wrapped&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #D8DEE9);&quot;&gt;schema&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; schema&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #D8DEE9);&quot;&gt;command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; string&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; list&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; string&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; list&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#AB5959, #81A1C1);&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; su_command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; schema&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;input&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;configuration&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;main&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;su_command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5959, #81A1C1);&quot;&gt; in&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;    match&lt;&#x2F;span&gt;&lt;span&gt; schema&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;input&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;configuration&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;main&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;su_command_quoted&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt; with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt;    |&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; true&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt;|&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;Default&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; List&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;concat&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; [&lt;&#x2F;span&gt;&lt;span&gt; su_command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt;String&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;concat&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt;    |&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; false&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; List&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;concat&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; [&lt;&#x2F;span&gt;&lt;span&gt; su_command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;--&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If the value for &lt;code&gt;su_command&lt;&#x2F;code&gt; was never set, it will contain the default value as set in the &lt;code&gt;origin&lt;&#x2F;code&gt; schema, which will never have been overwritten by the configuration parser. Because of this, the &lt;code&gt;Su&lt;&#x2F;code&gt; module does not need to concern itself with or even know what this default is.&lt;&#x2F;p&gt;
&lt;p&gt;What it does concern itself with is whether or not the configuration establishes that the command must be quoted, which is true for &lt;code&gt;su -c&lt;&#x2F;code&gt; but not true for &lt;code&gt;sudo&lt;&#x2F;code&gt; or &lt;code&gt;doas&lt;&#x2F;code&gt;. So it simply constructs a string list with a quoted or unquoted command and returns that.&lt;&#x2F;p&gt;
&lt;h5 id=&quot;package&quot;&gt;Package&lt;&#x2F;h5&gt;
&lt;p&gt;Another submodule that’s a bit more involved than many in the &lt;code&gt;System&lt;&#x2F;code&gt; module is &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;codeberg.org&#x2F;tori&#x2F;iganaq&#x2F;src&#x2F;branch&#x2F;main&#x2F;ocaml&#x2F;lib&#x2F;system&#x2F;package.ml&quot;&gt;the &lt;code&gt;Package&lt;&#x2F;code&gt; submodule&lt;&#x2F;a&gt;. It creates an abstraction layer between tori and the package manager running in the current operating system.&lt;&#x2F;p&gt;
&lt;p&gt;For the purposes of the iganaq experiment, this OS is &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;alpinelinux.org&#x2F;&quot;&gt;Alpine Linux&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;To abstract away a package manager, we’ll need some types:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#393A34, #D8DEE9); background-color: light-dark(#FFFFFF, #2E3440);&quot;&gt;&lt;code data-lang=&quot;ocaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;type&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt; interactive&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; string&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; list&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt; batch&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; string&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; list&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;type&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; manager&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt; install&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt; remove&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;type&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; manager_table&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt; apk&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; manager&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Which we can now use to create a table of supported package managers:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#393A34, #D8DEE9); background-color: light-dark(#FFFFFF, #2E3440);&quot;&gt;&lt;code data-lang=&quot;ocaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; table&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; manager_table&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;    apk&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;        install&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;            interactive&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;apk&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;-i&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;add&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; ]&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;            batch&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;apk&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;--no-interactive&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;add&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; ]&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;        }&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;        remove&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;            interactive&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;apk&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;-i&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;del&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; ]&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;            batch&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;apk&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;--no-interactive&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;del&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; ]&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;On this foundation, we can write a function that will ask the system’s package manager for a list of manually installed packages and compare it to what state the current schema has, conciliating them by adding&#x2F;removing packages until both lists match.&lt;&#x2F;p&gt;
&lt;p&gt;Remember the intention is not to provide actually useful functionality, rather, it’s to learn and demonstrate how both tasks — installing and uninstalling a system package — can be accomplished in each programming language.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#393A34, #D8DEE9); background-color: light-dark(#FFFFFF, #2E3440);&quot;&gt;&lt;code data-lang=&quot;ocaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; merge&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #D8DEE9);&quot;&gt;schema&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; :&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; Schema&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;schema&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #D8DEE9);&quot;&gt;packages&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; :&lt;&#x2F;span&gt;&lt;span&gt; string&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; list&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; :&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; Schema&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;schema&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;    match&lt;&#x2F;span&gt;&lt;span&gt; packages&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt; with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt;    |&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #EBCB8B);font-weight: bold;&quot;&gt; (*&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #EBCB8B);font-weight: bold;&quot;&gt; do-nothing empty package list case suppressed for brevity &lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #EBCB8B);font-weight: bold;&quot;&gt;*)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt;    |&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #EBCB8B);font-weight: bold;&quot;&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#AB5959, #81A1C1);&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; su_command_line&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; schema&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;input&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;configuration&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;main&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;su_command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5959, #81A1C1);&quot;&gt; in&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#AB5959, #81A1C1);&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; su_command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; Process&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt;Su&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;head_of_su_command&lt;&#x2F;span&gt;&lt;span&gt; su_command_line&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5959, #81A1C1);&quot;&gt; in&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#AB5959, #81A1C1);&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; su&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; Process&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt;Su&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;elevate_wrapped&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; commands&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; :&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; Process&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt;Command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; list&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;            [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;              {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;                name&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; su_command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;                arguments&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; su&lt;&#x2F;span&gt;&lt;span&gt; schema&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; $&lt;&#x2F;span&gt;&lt;span&gt; manager&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;install&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;interactive&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; @&lt;&#x2F;span&gt;&lt;span&gt; packages&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;                status&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; Unevaluated&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;              }&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;              {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;                name&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; su_command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;                arguments&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; su&lt;&#x2F;span&gt;&lt;span&gt; schema&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; $&lt;&#x2F;span&gt;&lt;span&gt; manager&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;remove&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;interactive&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; @&lt;&#x2F;span&gt;&lt;span&gt; packages&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#59873A, #81A1C1);background-color: light-dark(#F0FFF4, #2E3440);&quot;&gt;                status&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; Unevaluated&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;              }&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;            ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        in&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; log_output&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;            if&lt;&#x2F;span&gt;&lt;span&gt; simulate&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;                &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;Would execute:&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; ^&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt;                String&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;concat&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt;Process&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt;Command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;format_many&lt;&#x2F;span&gt;&lt;span&gt; commands&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;            else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#AB5959, #81A1C1);&quot;&gt;                let&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#59873A, #88C0D0);&quot;&gt; ran&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#998418, #8FBCBB);&quot;&gt; =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;                    if&lt;&#x2F;span&gt;&lt;span&gt; simulate&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt; then&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B07D48, #8FBCBB);&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt; else&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt; Process&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt;Fork&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;run_many&lt;&#x2F;span&gt;&lt;span&gt; commands&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5959, #81A1C1);&quot;&gt; in&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;                &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;Executed:&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#AB5E3F, #EBCB8B);&quot;&gt; ^&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt;                String&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;concat&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B56959, #A3BE8C);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt;Process&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#2F798A, #B48EAD);&quot;&gt;Command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#1E754F, #81A1C1);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;format_many&lt;&#x2F;span&gt;&lt;span&gt; ran&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#999999, #81A1C1);&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt; in&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          schema with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          output = { schema.output with log = log_output; };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;What I like about this is that commands can’t really be executed here without getting captured into the &lt;code&gt;ran&lt;&#x2F;code&gt; contents, which is a pattern I’d like to move further into the &lt;code&gt;Process&lt;&#x2F;code&gt; module. It also provides a way to simply simulate rather than execute commands, which is useful when running some tests.&lt;&#x2F;p&gt;
&lt;p&gt;What I don’t like about this are the several &lt;code&gt;su&lt;&#x2F;code&gt;, &lt;code&gt;su_command&lt;&#x2F;code&gt;, &lt;code&gt;su_command_line&lt;&#x2F;code&gt;, &lt;code&gt;head_of_su_command&lt;&#x2F;code&gt; declarations, which I frankly find confusing writing about this a few months later, so there’s definitely some room for improvement here.&lt;&#x2F;p&gt;
&lt;p&gt;As you can see in the code above, the &lt;code&gt;Package&lt;&#x2F;code&gt; module actually &lt;em&gt;constructs&lt;&#x2F;em&gt; a sequence of commands (install then uninstall, as was the goal set out by the spec) and then passes them to the &lt;code&gt;Process&lt;&#x2F;code&gt; module to handle actual execution.&lt;&#x2F;p&gt;
&lt;p&gt;I tried to place the explanation of modules and submodules in the order from least to most dependent so mostly everything is already explained by the time it’s covered, and this is where most of it comes together: with the &lt;code&gt;Package&lt;&#x2F;code&gt; module making use of most of the other code.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;testing&quot;&gt;Testing&lt;&#x2F;h3&gt;
&lt;p&gt;For testing that the implementation fulfills the spec, I also needed to also write some tests.&lt;&#x2F;p&gt;
&lt;p&gt;Dune has this interesting feature called &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dune.readthedocs.io&#x2F;en&#x2F;stable&#x2F;reference&#x2F;cram.html&quot;&gt;“Cram Tests”&lt;&#x2F;a&gt; (though &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;bitheap.org&#x2F;cram&#x2F;&quot;&gt;not Dune’s creation&lt;&#x2F;a&gt;) which are a way to define integration tests running from a shell and executing your compiled binaries. That is something I hadn’t known to exist in any any other build tool I tried.&lt;&#x2F;p&gt;
&lt;p&gt;Here’s an example of a cram test that executes &lt;code&gt;tori os&lt;&#x2F;code&gt; and checks if the output contains the actual OS&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#393A34, #D8DEE9); background-color: light-dark(#FFFFFF, #2E3440);&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;B2.3. os -&amp;gt; MUST print the os name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  $ os_name=$(cat &#x2F;etc&#x2F;os-release | grep &amp;#39;^NAME=&amp;#39; | cut -d= -f 2 | sed &amp;#39;s&#x2F;&amp;quot;&#x2F;&#x2F;g&amp;#39;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  $ tori_os=$(tori os)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  $ test -n &amp;quot;$os_name&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  $ test -n &amp;quot;$tori_os&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  $ test &amp;quot;$os_name&amp;quot; = &amp;quot;$tori_os&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;codeberg.org&#x2F;tori&#x2F;iganaq&#x2F;src&#x2F;branch&#x2F;main&#x2F;ocaml&#x2F;test&#x2F;cram.t&quot;&gt;used this feature extensively&lt;&#x2F;a&gt; to verify that the implementation was doing as the spec states.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;It probably shows that I &lt;em&gt;enjoy&lt;&#x2F;em&gt; writing OCaml, so it’s likely the language I am the most biased towards among the three candidates. Creating this implementation and refactoring it until I was satisfied only reinforced that.&lt;&#x2F;p&gt;
&lt;p&gt;The only thing I think one can hold against OCaml is that it’s not a highly popular language with a vibrant ecosystem. And that is not something under the full control of the OCaml project. But it can give you pause if you consider questions such as “will this choice make it less likely that others will contribute to the project?” or “How hard does this choice make for others to compile the project themselves?”&lt;&#x2F;p&gt;
&lt;p&gt;But as the first one, it’s still early to tell. So we’ll see in the next implementations.&lt;&#x2F;p&gt;
&lt;p&gt;As before, you can reach out with your comments through &lt;a href=&quot;&#x2F;support&quot;&gt;IRC or Matrix&lt;&#x2F;a&gt; rooms, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;mastodon.bsd.cafe&#x2F;@jutty&quot;&gt;Mastodon&lt;&#x2F;a&gt; or privately via &lt;a href=&quot;mailto:tori@jutty.dev&quot;&gt;email&lt;&#x2F;a&gt;. You can also follow development through the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;codeberg.org&#x2F;tori&#x2F;iganaq&quot;&gt;code repository&lt;&#x2F;a&gt; or its &lt;a href=&quot;&#x2F;code&quot;&gt;mirror&lt;&#x2F;a&gt; on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tori-nest&#x2F;iganaq&quot;&gt;GitHub&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;August 19, 2025 – September 19, 2025 &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</description>
      </item>
      <item>
          <title>Exploring alternative tori implementations</title>
          <pubDate>Sat, 12 Apr 2025 00:00:00 +0000</pubDate>
          <author>Juno Takano</author>
          <link>https://tori.jutty.dev/updates/iganaq/</link>
          <guid>https://tori.jutty.dev/updates/iganaq/</guid>
          <description xml:base="https://tori.jutty.dev/updates/iganaq/">&lt;p&gt;Thanks to some free time during the university break, I started some work on porting tori to Void and Alpine Linux.&lt;&#x2F;p&gt;
&lt;p&gt;This process prompted some other changes, namely improving tori’s testability, crucial to be able to develop for three operating systems without breaking things on any other platform. But even when tests passed, I had this bad feeling because I knew they all relied on shell exit codes to pass.&lt;&#x2F;p&gt;
&lt;p&gt;So far, tori has been implemented using POSIX shell scripts. The rationale for this choice has been explained in the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;tori.jutty.dev&#x2F;docs&#x2F;development&#x2F;portability.html&quot;&gt;documentation&lt;&#x2F;a&gt; and leans heavily on the fact that, because mostly any unix system is bound to have a POSIX shell available, this means you can run (and modify) tori without any extra requirements, not even a compiler or any libraries.&lt;&#x2F;p&gt;
&lt;p&gt;While I still believe this is an interesting reason to use shell scripting, going forward I will be doing something I already expected to do eventually: a tori implementation using a more robust programming language.&lt;&#x2F;p&gt;
&lt;p&gt;The main reason I decided to do this now is not really bound to what &lt;em&gt;can&lt;&#x2F;em&gt; be done with shell scripting. It is &lt;em&gt;possible&lt;&#x2F;em&gt; to keep writing new features using it. What really tipped the scale for me was how &lt;em&gt;uncertain&lt;&#x2F;em&gt; I felt when running tests in the form of shell scripts. It all depends on the underlying shell’s &lt;code&gt;errexit&lt;&#x2F;code&gt; and &lt;code&gt;nounset&lt;&#x2F;code&gt; options, which can be unpredictable depending on the shell implementation and the context you are evaluating in (e.g. inside a function, inside a subshell, inside an if condition etc).&lt;&#x2F;p&gt;
&lt;p&gt;Going forward, I’ll be working towards v0.8 as the first version in a different language. But which language? For now, I have created a separate repository for a sandbox project codenamed &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;codeberg.org&#x2F;tori&#x2F;iganaq&quot;&gt;iganaq&lt;&#x2F;a&gt;. The name is a reference to a location in the migration routes of puffin birds, the bird used as tori’s symbol.&lt;&#x2F;p&gt;
&lt;p&gt;My plan is to evaluate three candidate languages: OCaml, Haskell and Rust. They were chosen for their ability to compile to portable binaries and for their rich type systems that can support predictable and strict logic requirements. OCaml and Haskell, particularly, are interesting candidates for configuration parsing and execution of side-effects only in an outer layer of the application.&lt;&#x2F;p&gt;
&lt;p&gt;Each language will be used to implement a simple command-line interface that fulfills a so-called &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;codeberg.org&#x2F;tori&#x2F;iganaq&#x2F;src&#x2F;branch&#x2F;main&#x2F;README.md#specification&quot;&gt;napkin specification&lt;&#x2F;a&gt;. By “simple” I mean the goal is not to cover corner cases, but to prototype and experiment in order to make a decision based on language syntax, ergonomics, expressiveness, documentation, ecosystem, tooling and overall experience.&lt;&#x2F;p&gt;
&lt;p&gt;Obviously, being the sole author and maintainer of tori, my personal preferences for languages that I either enjoy working with or would like to learn more about also play a part here, as I’d have little to go on with in a language I am neither skilled nor interested in.&lt;&#x2F;p&gt;
&lt;p&gt;More updates will come in the future on how this experiment is going. Feel free to chime in with your thoughts on the new implementation language. You can reach out through &lt;a href=&quot;&#x2F;support&quot;&gt;IRC or Matrix&lt;&#x2F;a&gt; rooms, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;mastodon.bsd.cafe&#x2F;@jutty&quot;&gt;Mastodon&lt;&#x2F;a&gt; or privately via &lt;a href=&quot;mailto:tori@jutty.dev&quot;&gt;email&lt;&#x2F;a&gt;. You can also follow development through the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;codeberg.org&#x2F;tori&#x2F;iganaq&quot;&gt;code repository&lt;&#x2F;a&gt; or its mirror on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tori-nest&#x2F;iganaq&quot;&gt;GitHub&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>File management merged</title>
          <pubDate>Tue, 03 Sep 2024 00:00:00 +0000</pubDate>
          <author>Juno Takano</author>
          <link>https://tori.jutty.dev/updates/file-management/</link>
          <guid>https://tori.jutty.dev/updates/file-management/</guid>
          <description xml:base="https://tori.jutty.dev/updates/file-management/">&lt;p&gt;A first strategy for file management was merged. Called &lt;strong&gt;tree&lt;&#x2F;strong&gt;, this strategy allows tori to manage files by mimicking the root of the file system from &lt;code&gt;~&#x2F;.config&#x2F;tori&#x2F;base&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Whenever a conflict is detected, you will see the following dialog when running &lt;code&gt;tori check&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#393A34, #D8DEE9); background-color: light-dark(#FFFFFF, #2E3440);&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Differs: ~&#x2F;.shrc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; [1] Overwrite system&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; [2] Overwrite configuration&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; [3] Show difference&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; [0] Exit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Choose an option number:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Check out the updated &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;tori.jutty.dev&#x2F;docs&#x2F;usage&#x2F;configuration.html#base-files&quot;&gt;documentation&lt;&#x2F;a&gt; for details on how it works.&lt;&#x2F;p&gt;
&lt;p&gt;This version also includes file backups prior to any destructive operation. The backups will live in &lt;code&gt;~&#x2F;.local&#x2F;state&#x2F;tori&#x2F;backup&lt;&#x2F;code&gt;. The &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;tori.jutty.dev&#x2F;docs&#x2F;usage&#x2F;backups.html&quot;&gt;backups documentation page&lt;&#x2F;a&gt; was also updated with more details.&lt;&#x2F;p&gt;
&lt;p&gt;With this feature, tori can now fulfill the role of package management and file management in replicating a FreeBSD system. Most likely to be implemented next are imperative commands for adding and removing packages from your &lt;code&gt;packages&lt;&#x2F;code&gt; file.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Website updates and file management</title>
          <pubDate>Fri, 30 Aug 2024 00:00:00 +0000</pubDate>
          <author>Juno Takano</author>
          <link>https://tori.jutty.dev/updates/2024-08-update/</link>
          <guid>https://tori.jutty.dev/updates/2024-08-update/</guid>
          <description xml:base="https://tori.jutty.dev/updates/2024-08-update/">&lt;p&gt;Work has begun on file management. A basic implementation for a file merging strategy by mirroring the root of the file system from &lt;code&gt;~&#x2F;.config&#x2F;tori&#x2F;base&lt;&#x2F;code&gt; is already functional. This is better explained in &lt;a href=&quot;&#x2F;docs&#x2F;usage&#x2F;configuration.html#base-files&quot;&gt;the docs&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;After this strategy is finished, particularly with handling backups before overwriting files, imperative commands for package management are likely to be worked on before file management is tackled again.&lt;&#x2F;p&gt;
&lt;p&gt;You can follow development on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;codeberg.org&#x2F;tori&#x2F;tori&#x2F;commits&#x2F;branch&#x2F;file-copy&quot;&gt;the file-copy branch&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The website has gained a few more pages, namely &lt;a href=&quot;&#x2F;discover&quot;&gt;Discover&lt;&#x2F;a&gt;, &lt;a href=&quot;&#x2F;get-started&quot;&gt;Get Started&lt;&#x2F;a&gt; and &lt;a href=&quot;&#x2F;support-matrix&quot;&gt;Support Matrix&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The intention with the first two is to give someone who just discovered tori a chance to quickly know what it is about and then the minimal set of instructions needed to install and run it.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;a href=&quot;&#x2F;support-matrix&quot;&gt;Support Matrix&lt;&#x2F;a&gt; is where users can refer to in order to know if their operating system is supported and to what extent. It’s linked to from &lt;a href=&quot;&#x2F;get-started&quot;&gt;Get Started&lt;&#x2F;a&gt; in its first step – checking compatibility.&lt;&#x2F;p&gt;
&lt;p&gt;Unrelated to &lt;em&gt;support&lt;&#x2F;em&gt; matrices, a Matrix room (as in the protocol) was created for users to ask questions or just talk about tori. If you are interested in joining, you can just &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;matrix.to&#x2F;#&#x2F;#tori:bsd.cafe&quot;&gt;use the room link&lt;&#x2F;a&gt; or lookup &lt;code&gt;#tori:bsd.cafe&lt;&#x2F;code&gt; from your client.&lt;&#x2F;p&gt;
&lt;p&gt;One more minor change to the website was moving the Git repositories links to a dedicated &lt;a href=&quot;&#x2F;code&quot;&gt;code&lt;&#x2F;a&gt; page to make space for the new pages in the navigation menu.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Package conflict resolution is live</title>
          <pubDate>Sat, 20 Jul 2024 00:00:00 +0000</pubDate>
          <author>Juno Takano</author>
          <link>https://tori.jutty.dev/updates/package-conflict-resolution/</link>
          <guid>https://tori.jutty.dev/updates/package-conflict-resolution/</guid>
          <description xml:base="https://tori.jutty.dev/updates/package-conflict-resolution/">&lt;p&gt;With the last strategy for package conflict resolution ready, tori now has a working implementation for handling conflicts between your configuration and the actual list of installed packages.&lt;&#x2F;p&gt;
&lt;p&gt;Whenever a conflict is detected, you will see the following dialog when running &lt;code&gt;tori check&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#393A34, #D8DEE9); background-color: light-dark(#FFFFFF, #2E3440);&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[tori] 16:38:19: System and configuration packages differ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Packages on configuration but not installed: fend ksh xh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  [1] Install all&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  [2] Enter packages to install&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  [3] Remove all from configuration&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  [4] Enter packages to remove from configuration&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  [5] Decide on editor&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  [6] Cancel&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Choose an option [1-6]:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Check out the &lt;a href=&quot;&#x2F;docs&#x2F;usage&#x2F;package_conflict_resolution.html&quot;&gt;documentation&lt;&#x2F;a&gt; if you want to know more about how it works.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>New web pages</title>
          <pubDate>Fri, 12 Jul 2024 00:00:00 +0000</pubDate>
          <author>Juno Takano</author>
          <link>https://tori.jutty.dev/updates/new-web-pages/</link>
          <guid>https://tori.jutty.dev/updates/new-web-pages/</guid>
          <description xml:base="https://tori.jutty.dev/updates/new-web-pages/">&lt;p&gt;tori now has online pages for project updates and documentation.&lt;&#x2F;p&gt;
&lt;p&gt;You can access the docs on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;tori.jutty.dev&#x2F;docs&quot;&gt;tori.jutty.dev&#x2F;docs&lt;&#x2F;a&gt; and the project updates right where you are.&lt;&#x2F;p&gt;
&lt;p&gt;An &lt;a href=&quot;&#x2F;rss.xml&quot;&gt;RSS feed&lt;&#x2F;a&gt; is also available.&lt;&#x2F;p&gt;
</description>
      </item>
    </channel>
</rss>
