244 lines
25 KiB
Plaintext
244 lines
25 KiB
Plaintext
<!DOCTYPE html>
|
|
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="generator" content="pandoc" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
|
|
<meta name="author" content="By Pierre Neidhardt" />
|
|
<title>Continuous testing and packaging in Common Lisp</title>
|
|
<style type="text/css">
|
|
code{white-space: pre-wrap;}
|
|
span.smallcaps{font-variant: small-caps;}
|
|
span.underline{text-decoration: underline;}
|
|
div.column{display: inline-block; vertical-align: top; width: 50%;}
|
|
</style>
|
|
<style type="text/css">
|
|
a.sourceLine { display: inline-block; line-height: 1.25; }
|
|
a.sourceLine { pointer-events: none; color: inherit; text-decoration: inherit; }
|
|
a.sourceLine:empty { height: 1.2em; position: absolute; }
|
|
.sourceCode { overflow: visible; }
|
|
code.sourceCode { white-space: pre; position: relative; }
|
|
div.sourceCode { margin: 1em 0; }
|
|
pre.sourceCode { margin: 0; }
|
|
@media screen {
|
|
div.sourceCode { overflow: auto; }
|
|
}
|
|
@media print {
|
|
code.sourceCode { white-space: pre-wrap; }
|
|
a.sourceLine { text-indent: -1em; padding-left: 1em; }
|
|
}
|
|
pre.numberSource a.sourceLine
|
|
{ position: relative; }
|
|
pre.numberSource a.sourceLine:empty
|
|
{ position: absolute; }
|
|
pre.numberSource a.sourceLine::before
|
|
{ content: attr(data-line-number);
|
|
position: absolute; left: -5em; text-align: right; vertical-align: baseline;
|
|
border: none; pointer-events: all;
|
|
-webkit-touch-callout: none; -webkit-user-select: none;
|
|
-khtml-user-select: none; -moz-user-select: none;
|
|
-ms-user-select: none; user-select: none;
|
|
padding: 0 4px; width: 4em;
|
|
color: #aaaaaa;
|
|
}
|
|
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
|
|
div.sourceCode
|
|
{ }
|
|
@media screen {
|
|
a.sourceLine::before { text-decoration: underline; }
|
|
}
|
|
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
|
|
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
|
|
code span.at { color: #7d9029; } /* Attribute */
|
|
code span.bn { color: #40a070; } /* BaseN */
|
|
code span.bu { } /* BuiltIn */
|
|
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
|
|
code span.ch { color: #4070a0; } /* Char */
|
|
code span.cn { color: #880000; } /* Constant */
|
|
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
|
|
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
|
|
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
|
|
code span.dt { color: #902000; } /* DataType */
|
|
code span.dv { color: #40a070; } /* DecVal */
|
|
code span.er { color: #ff0000; font-weight: bold; } /* Error */
|
|
code span.ex { } /* Extension */
|
|
code span.fl { color: #40a070; } /* Float */
|
|
code span.fu { color: #06287e; } /* Function */
|
|
code span.im { } /* Import */
|
|
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
|
|
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
|
|
code span.op { color: #666666; } /* Operator */
|
|
code span.ot { color: #007020; } /* Other */
|
|
code span.pp { color: #bc7a00; } /* Preprocessor */
|
|
code span.sc { color: #4070a0; } /* SpecialChar */
|
|
code span.ss { color: #bb6688; } /* SpecialString */
|
|
code span.st { color: #4070a0; } /* String */
|
|
code span.va { color: #19177c; } /* Variable */
|
|
code span.vs { color: #4070a0; } /* VerbatimString */
|
|
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
|
|
</style>
|
|
<!--[if lt IE 9]>
|
|
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
|
|
<![endif]-->
|
|
</head>
|
|
<body>
|
|
<header>
|
|
<h1 class="title">Continuous testing and packaging in Common Lisp</h1>
|
|
<p class="author">By Pierre Neidhardt</p>
|
|
</header>
|
|
<p>In this article we are going to talk continuous testing and packaging in Common Lisp. The goal is to automate:</p>
|
|
<ul>
|
|
<li><p>Report coding errors on every push, including pull requests. This prevents unseen, long-standing breakages, and also helps with pull requests since the system will automatically report failing tests, compilation warnings, etc.</p></li>
|
|
<li><p>Ease the release process by automating package builds. This allows us to release often with a higher level of guarantees.</p></li>
|
|
</ul>
|
|
<p>Since Nyxt is currently hosted on GitHub, we are leveraging GitHub Actions for our continuous integration. Even though we are using GitHub Actions, we've designed our process to be platform independent. As a result, our GitHub-specific code remains small and trivial.</p>
|
|
<h1 id="testing">Testing</h1>
|
|
<p>Some Common Lisp compilers are particularly good at code analysis:</p>
|
|
<ul>
|
|
<li><p>No false positives, all warnings are meaningful.</p></li>
|
|
<li><p>They catch many errors at compile time, including typing errors.</p></li>
|
|
</ul>
|
|
<p><a href="http://www.sbcl.org/">SBCL</a> and <a href="https://ccl.clozure.com/">CCL</a> are two high-quality compilers that fit the bill. While only SBCL is officially supported to build Nyxt, CCL proves useful in catching some error and warning classes that SBCL misses. In particular, CCL is better at type-checking class slots.</p>
|
|
<p>Let's review what we want to automate to increase our quality assurance:</p>
|
|
<ul>
|
|
<li><p>Build: The project compiles with all compilers.</p></li>
|
|
<li><p>Testing: All test suites pass with all compilers.</p></li>
|
|
<li><p>Code checking: No warnings are reported with any compiler.</p></li>
|
|
</ul>
|
|
<p>In practice, the last two points suffice since the code checking is done by building the project.</p>
|
|
<p>Allow me to emphasize the importance of code checking: since the compilers don't report false positives, this forces us to have warning-free code at all time, which is a big boost for quality assurance!</p>
|
|
<h2 id="automatic-build">Automatic build</h2>
|
|
<p>First we need to set up the GitHub action in this <a href="https://github.com/atlas-engineer/nyxt/blob/2-pre-release-4/.github/workflows/tests.yml">YAML file</a>.</p>
|
|
<p>In short:</p>
|
|
<ul>
|
|
<li><p>We install the Nyxt dependencies using the image package manager, here APT.</p></li>
|
|
<li><p>Then we install <a href="https://github.com/roswell/roswell">Roswell</a>, a tool that will allow us to easily install the desired Common Lisp compilers since the host system package managers may not have them. Roswell includes <a href="https://www.quicklisp.org/beta/">Quicklisp</a>, so we will leverage this to install all the Common Lisp dependencies of Nyxt.</p></li>
|
|
<li><p>Some dependencies are missing from Quicklisp, so we fetch them via our Makefile dedicated rule, then register their location as per the <a href="https://common-lisp.net/project/asdf/asdf/Configuration-DSL.html#Configuration-DSL">ASDF API</a>.</p></li>
|
|
</ul>
|
|
<h2 id="automatic-testing">Automatic testing</h2>
|
|
<p>Finally, we run the following:</p>
|
|
<div class="sourceCode" id="cb1" data-org-language="lisp"><pre class="sourceCode commonlisp"><code class="sourceCode commonlisp"><a class="sourceLine" id="cb1-1" data-line-number="1">(<span class="kw">handler-bind</span> (#+asdf3<span class="fl">.2</span> (asdf:bad-system-name (<span class="kw">function</span> MUFFLE-WARNING)))</a>
|
|
<a class="sourceLine" id="cb1-2" data-line-number="2"> (<span class="kw">handler-case</span> (ql:quickload :nyxt/tests)</a>
|
|
<a class="sourceLine" id="cb1-3" data-line-number="3"> (<span class="kw">error</span> (a) (<span class="kw">format</span> <span class="kw">t</span> <span class="st">"caught error ~s~%~a~%"</span> a a) (uiop:quit <span class="dv">17</span>))))</a>
|
|
<a class="sourceLine" id="cb1-4" data-line-number="4"></a>
|
|
<a class="sourceLine" id="cb1-5" data-line-number="5">(asdf:test-system :nyxt)</a></code></pre></div>
|
|
<p>We load the tests which builds Nyxt itself. If the Nyxt build fails, the error is reported as part of the workflow.</p>
|
|
<p>We exit with a custom non-zero error code, here 17. This can help identify the cause of the error in case the output gets confusing.</p>
|
|
<p>The rest of the test controls happens in the <a href="https://github.com/atlas-engineer/nyxt/blob/2-pre-release-4/nyxt.asd">nyxt.asd</a> file. Our main <code>:nyxt</code> system lists all the tests so that call <code>(asdf:test-system :nyxt)</code> effectively runs the whole test suite.</p>
|
|
<p>Each individual test system is specified in the following form:</p>
|
|
<div class="sourceCode" id="cb2" data-org-language="lisp"><pre class="sourceCode commonlisp"><code class="sourceCode commonlisp"><a class="sourceLine" id="cb2-1" data-line-number="1">(asdf:defsystem nyxt/tests</a>
|
|
<a class="sourceLine" id="cb2-2" data-line-number="2"> :depends-on (nyxt prove)</a>
|
|
<a class="sourceLine" id="cb2-3" data-line-number="3"> :perform (asdf:test-op (op c)</a>
|
|
<a class="sourceLine" id="cb2-4" data-line-number="4"> (nyxt-run-test c <span class="st">"tests/"</span>)</a>
|
|
<a class="sourceLine" id="cb2-5" data-line-number="5"> (nyxt-run-test c <span class="st">"tests-network-needed/"</span> :network-needed-p <span class="kw">t</span>)))</a></code></pre></div>
|
|
<p>We've rolled out our own helper function <code>nyxt-run-test</code> to factor some recurring code.</p>
|
|
<div class="sourceCode" id="cb3" data-org-language="lisp"><pre class="sourceCode commonlisp"><code class="sourceCode commonlisp"><a class="sourceLine" id="cb3-1" data-line-number="1">(<span class="kw">defun</span><span class="fu"> nyxt-run-test </span>(c path &key network-needed-p)</a>
|
|
<a class="sourceLine" id="cb3-2" data-line-number="2"> (<span class="kw">and</span> (<span class="kw">or</span> (<span class="kw">not</span> network-needed-p)</a>
|
|
<a class="sourceLine" id="cb3-3" data-line-number="3"> (<span class="kw">not</span> (uiop:getenv <span class="st">"NYXT_TESTS_NO_NETWORK"</span>)))</a>
|
|
<a class="sourceLine" id="cb3-4" data-line-number="4"> (<span class="kw">not</span> (<span class="kw">funcall</span> (<span class="kw">read-from-string</span> <span class="st">"prove:run"</span>)</a>
|
|
<a class="sourceLine" id="cb3-5" data-line-number="5"> (asdf:system-relative-pathname c path)))</a>
|
|
<a class="sourceLine" id="cb3-6" data-line-number="6"> (uiop:getenv <span class="st">"NYXT_TESTS_ERROR_ON_FAIL"</span>)</a>
|
|
<a class="sourceLine" id="cb3-7" data-line-number="7"> (uiop:quit <span class="dv">18</span>)))</a></code></pre></div>
|
|
<p>We've added some knobs that we can control externally:</p>
|
|
<ul>
|
|
<li><p>If the <code>NYXT_TESTS_NO_NETWORK</code> environment variable is set, the test is not run. This is useful to disable tests require a network connection. Some build systems (like Guix) disable network connectivity during builds.</p></li>
|
|
<li><p>If <code>NXYT_TESTS_ERROR_ON_FAIL</code> is set, the process will exit with a non-zero error code, which will cause the build system, or the integration pipeline to fail and report. This is necessary because otherwise the ASDF test operation does not "fail" in the sense that the process returns the 0 error code by default.</p>
|
|
<p>In the YAML file, we set this variable to <code>yes</code>, thus externally commanding our test suite to reflect its error on the pipeline.</p></li>
|
|
</ul>
|
|
<h2 id="automatic-code-checking">Automatic code checking</h2>
|
|
<p>Finally, our last step in our YAML file is very simple: it loads a file and executes the <code>compilation-conditions</code> function on systems we want to test, here <code>nyxt</code> and the renderers.</p>
|
|
<p>Let's look at <a href="https://github.com/atlas-engineer/nyxt/blob/2-pre-release-4/build-scripts/report-warnings.lisp">this file</a> more closely:</p>
|
|
<ul>
|
|
<li><p>First <code>compilation-conditions</code> calls <code>load-system-silently</code> on the recursive dependencies of the system as returned by <code>list-dependencies</code>.</p>
|
|
<p>We do this to <em>pre-compile</em> the Nyxt dependencies, thus ensuring that when we compile Nyxt the compiler only reports warnings related to Nyxt and not its dependencies.</p>
|
|
<p><code>load-system-silently</code> is like ASDF's <code>load-system</code> but muffles the output to keep the pipeline output shorter.</p></li>
|
|
<li><p>An amazing feature of Common Lisp is that the <code>compile</code> function is built into the language, which allows us to control the compilation process in Common Lisp itself!</p>
|
|
<p>Thus we collect all conditions that are not redefinitions:</p>
|
|
<div class="sourceCode" id="cb4" data-org-language="lisp"><pre class="sourceCode commonlisp"><code class="sourceCode commonlisp"><a class="sourceLine" id="cb4-1" data-line-number="1">(<span class="kw">handler-bind</span> ((<span class="kw">warning</span> (<span class="kw">lambda</span> (c)</a>
|
|
<a class="sourceLine" id="cb4-2" data-line-number="2"> (<span class="kw">unless</span> (redefinition-p c)</a>
|
|
<a class="sourceLine" id="cb4-3" data-line-number="3"> (<span class="kw">push</span> c conditions)))))</a>
|
|
<a class="sourceLine" id="cb4-4" data-line-number="4"> (asdf:load-system <span class="kw">system</span> :force <span class="kw">t</span>))</a></code></pre></div>
|
|
<p>Thanks to <a href="https://old.reddit.com/r/Common_Lisp/comments/jadiv0/how_can_i_report_compilation_warnings_in_ci/g8s5oj4/"><span class="citation" data-cites="phoe">@phoe</span></a> for this tip!</p>
|
|
<p>Note to the attentive reader: <code>redefinition-p</code> is not the proper way to check if a condition is a redefinition. The redefinition condition type is not portable, so the code should be different between SBCL and CCL, but it turns out that this "hack" works in our case.</p></li>
|
|
<li><p>Finally, we report the conditions to the standard output (which will display in the continuous testing web interface) and return a custom non-zero error code.</p></li>
|
|
</ul>
|
|
<h1 id="packaging">Packaging</h1>
|
|
<p>Since none of us at Atlas are using a Debian-based distribution such as Ubuntu, and since these distributions are among the most popular platforms, it has become increasingly necessary to automate the process of distributing a pre-built <code>.deb</code> package</p>
|
|
<p>Automating packaging is no simple task, for this we leverage the <a href="https://gitlab.com/ralt/linux-packaging">linux-packaging</a> Common Lisp library, which itself is based on <a href="https://github.com/jordansissel/fpm">fpm</a>.</p>
|
|
<p><code>linux-packaging</code> is a real life saver: it abstracts the tasks of packaging for various package managers (as November 2020, <code>.deb</code>, <code>.rpm</code> and <a href="https://www.archlinux.org/pacman/">pacman</a>'s formats are supported) in a consistent Common Lisp interface that sits on top of ASDF.</p>
|
|
<p>Beside wrapping <code>fpm</code>, <code>linux-packaging</code> automatically guesses the operating system dependencies for the FFI libraries and statically links the FFI-generated objects into the Lisp image. No more problem distributing <a href="http://www.common-lisp.net/project/osicat/">Osicat</a>!</p>
|
|
<p>As for continuous testing, we have a <a href="https://github.com/atlas-engineer/nyxt/blob/2-pre-release-4/.github/workflows/package-ubuntu.yml">YAML file</a> which has roughly the same steps except that we don't leverage Roswell here because we are going to build our own SBCL compiler: indeed, <code>linux-packaging</code> requires SBCL to be built with the non-default <code>--with-sb-linkable-runtime</code> option.</p>
|
|
<p>Notice the new dependency line:</p>
|
|
<div class="sourceCode" id="cb5"><pre class="sourceCode yaml"><code class="sourceCode yaml"><a class="sourceLine" id="cb5-1" data-line-number="1">sudo apt-get install -y ruby ruby-dev rubygems dpkg-dev sbcl curl git-core zlib1g-dev</a></code></pre></div>
|
|
<p>Ruby is required for <code>fpm</code> and SBCL for… rebuilding SBCL!</p>
|
|
<p>Not much here since everything happens in the <a href="https://github.com/atlas-engineer/nyxt/blob/2-pre-release-4/build-scripts/build-ubuntu-package.sh">build-ubuntu-package.sh</a> script:</p>
|
|
<ul>
|
|
<li>We first install <code>fpm</code>.</li>
|
|
<li>Then we build <code>SBCL</code> with the <code>--with-sb-linkable-runtime
|
|
--with-sb-dynamic-core</code> options.</li>
|
|
<li>We install Quicklisp manually since this time we don't have Roswell.</li>
|
|
<li>We install <code>linux-packaging</code>.</li>
|
|
<li>Pitfall: We install a modern version of ASDF since <code>linux-packaging</code> requires a version that's more recent than the one shipped with SBCL (at least as of 2.0.10).</li>
|
|
<li>As for continuous testing, we register the current directory in the ASDF registry so that it finds the Nyxt ASDF systems.</li>
|
|
</ul>
|
|
<p>Finally, the package build happens in the last command:</p>
|
|
<div class="sourceCode" id="cb6" data-org-language="sh"><pre class="sourceCode bash"><code class="sourceCode bash"><a class="sourceLine" id="cb6-1" data-line-number="1"><span class="ex">sbcl</span> \</a>
|
|
<a class="sourceLine" id="cb6-2" data-line-number="2"> --eval <span class="st">'(setf *debugger-hook* (lambda (c h) (declare (ignore h)) (format t "~A~%" c) (sb-ext:quit :unix-status -1)))'</span> \</a>
|
|
<a class="sourceLine" id="cb6-3" data-line-number="3"> --load ~/quicklisp/setup.lisp \</a>
|
|
<a class="sourceLine" id="cb6-4" data-line-number="4"> --eval <span class="st">"(ql:quickload :linux-packaging)"</span> \</a>
|
|
<a class="sourceLine" id="cb6-5" data-line-number="5"> --eval <span class="st">"(ql:quickload :nyxt)"</span> \</a>
|
|
<a class="sourceLine" id="cb6-6" data-line-number="6"> --eval <span class="st">"(ql:quickload :nyxt-ubuntu-package)"</span> \</a>
|
|
<a class="sourceLine" id="cb6-7" data-line-number="7"> --eval <span class="st">"(asdf:make :nyxt-ubuntu-package)"</span> \</a>
|
|
<a class="sourceLine" id="cb6-8" data-line-number="8"> --quit</a></code></pre></div>
|
|
<p><code>quickload</code> will drag all <code>linux-packaging</code> and <code>nyxt</code> dependencies. Then we load and make an ASDF system that's dedicated to the creation of the package.</p>
|
|
<p>This system is declared in a <a href="https://github.com/atlas-engineer/nyxt/blob/2-pre-release-4/nyxt-ubuntu-package.asd">separate file</a> because otherwise it would make Nyxt depend on <code>linux-packaging</code>, which the end user does not need.</p>
|
|
<p>Let's review it:</p>
|
|
<div class="sourceCode" id="cb7" data-org-language="lisp"><pre class="sourceCode commonlisp"><code class="sourceCode commonlisp"><a class="sourceLine" id="cb7-1" data-line-number="1">(defsystem <span class="st">"nyxt-ubuntu-package"</span></a>
|
|
<a class="sourceLine" id="cb7-2" data-line-number="2"> :defsystem-depends-on (<span class="st">"linux-packaging"</span>)</a>
|
|
<a class="sourceLine" id="cb7-3" data-line-number="3"> :class <span class="st">"linux-packaging:deb"</span></a>
|
|
<a class="sourceLine" id="cb7-4" data-line-number="4"> :build-operation <span class="st">"linux-packaging:build-op"</span></a></code></pre></div>
|
|
<p>Here we declare that loading this system will trigger the <code>linux-packaging:build-op</code> operation which will generate a <code>linux-packaging:deb</code> package.</p>
|
|
<p>Notice that there is only one knob to control the type of package we want to produce. It's enough to change this value to <code>linux-packaging:rpm</code> to produce an RPM!</p>
|
|
<div class="sourceCode" id="cb8" data-org-language="lisp"><pre class="sourceCode commonlisp"><code class="sourceCode commonlisp"><a class="sourceLine" id="cb8-1" data-line-number="1">:depends-on (<span class="st">"nyxt/gtk"</span>)</a>
|
|
<a class="sourceLine" id="cb8-2" data-line-number="2">:entry-point <span class="st">"nyxt:entry-point"</span></a></code></pre></div>
|
|
<p>Here we list the Common Lisp systems we want to include in our image. Since <code>nyxt/gtk</code> depends on everything else, it's the only system that we need to list.</p>
|
|
<p>The <code>:entry-point</code> is the same we use to build Nyxt from the <code>Makefile</code>.</p>
|
|
<div class="sourceCode" id="cb9" data-org-language="lisp"><pre class="sourceCode commonlisp"><code class="sourceCode commonlisp"><a class="sourceLine" id="cb9-1" data-line-number="1">:package-name <span class="st">"nyxt"</span></a>
|
|
<a class="sourceLine" id="cb9-2" data-line-number="2"><span class="bu">:version</span> #.(asdf:system-version (asdf:find-system :nyxt))</a>
|
|
<a class="sourceLine" id="cb9-3" data-line-number="3">:author #.(asdf:system-author (asdf:find-system :nyxt))</a>
|
|
<a class="sourceLine" id="cb9-4" data-line-number="4">:homepage #.(asdf:system-homepage (asdf:find-system :nyxt))</a>
|
|
<a class="sourceLine" id="cb9-5" data-line-number="5">:description #.(asdf:system-description (asdf:find-system :nyxt))</a>
|
|
<a class="sourceLine" id="cb9-6" data-line-number="6">:license #.(asdf:system-license (asdf:find-system :nyxt))</a></code></pre></div>
|
|
<p>Here we list all the metadata for the <code>.deb</code>. Since we decided to store this system in a separate <code>.asd</code> file, it can't automatically inherit from the metadata of the <code>nyxt</code> system. So we need to use a reader macro to explicitly tell ASDF to look for the metadata of Nyxt.</p>
|
|
<div class="sourceCode" id="cb10" data-org-language="lisp"><pre class="sourceCode commonlisp"><code class="sourceCode commonlisp"><a class="sourceLine" id="cb10-1" data-line-number="1">:additional-dependencies (<span class="st">"glib-networking"</span></a>
|
|
<a class="sourceLine" id="cb10-2" data-line-number="2"> <span class="st">"gsettings-desktop-schemas"</span></a>
|
|
<a class="sourceLine" id="cb10-3" data-line-number="3"> <span class="st">"xclip"</span></a>
|
|
<a class="sourceLine" id="cb10-4" data-line-number="4"> <span class="st">"enchant"</span></a>
|
|
<a class="sourceLine" id="cb10-5" data-line-number="5"> <span class="st">"notify-osd"</span>)</a></code></pre></div>
|
|
<p>The attentive reader may have noticed that I said that <code>linux-packaging</code> automatically derived the operating system dependencies for FFI packages. Indeed, we don't need to declare that WebKitGTK is a dependency here for instance.</p>
|
|
<p>However, some of our code has optional dependencies. While WebKitGTK would work without <code>glib-networking</code> it would have limited functionality, like no HTTPS support.</p>
|
|
<p>Other dependencies include those that are typically used by Common Lisp libraries that depend on executables, like <a href="https://github.com/snmsts/trivial-clipboard">trivial-clipboard</a> which depends on an external clipboard program like <code>xclip</code>.</p>
|
|
<div class="sourceCode" id="cb11" data-org-language="lisp"><pre class="sourceCode commonlisp"><code class="sourceCode commonlisp"><a class="sourceLine" id="cb11-1" data-line-number="1">:additional-files ((<span class="st">"assets/nyxt.desktop"</span> . <span class="st">"usr/share/applications/"</span>)</a>
|
|
<a class="sourceLine" id="cb11-2" data-line-number="2"> (<span class="st">"assets/nyxt_16x16.png"</span> . #p<span class="st">"usr/share/icons/hicolor/16x16/apps/nyxt.png"</span>)</a>
|
|
<a class="sourceLine" id="cb11-3" data-line-number="3"> (<span class="st">"assets/nyxt_32x32.png"</span> . #p<span class="st">"usr/share/icons/hicolor/32x32/apps/nyxt.png"</span>)</a>
|
|
<a class="sourceLine" id="cb11-4" data-line-number="4"> (<span class="st">"assets/nyxt_128x128.png"</span> . #p<span class="st">"usr/share/icons/hicolor/128x128/apps/nyxt.png"</span>)</a>
|
|
<a class="sourceLine" id="cb11-5" data-line-number="5"> (<span class="st">"assets/nyxt_256x256.png"</span> . #p<span class="st">"usr/share/icons/hicolor/256x256/apps/nyxt.png"</span>)</a>
|
|
<a class="sourceLine" id="cb11-6" data-line-number="6"> (<span class="st">"assets/nyxt_512x512.png"</span> . #p<span class="st">"usr/share/icons/hicolor/512x512/apps/nyxt.png"</span>))</a>
|
|
<a class="sourceLine" id="cb11-7" data-line-number="7">:build-pathname <span class="st">"nyxt"</span>)</a></code></pre></div>
|
|
<p>Finally, we list all the assets to include in the <code>.deb</code>: icons, <code>.desktop</code> file, etc.</p>
|
|
<p>The <code>build-pathname</code> field is the name of the produced executable which will be automatically stored to <code>/usr/bin</code> in the package.</p>
|
|
<h1 id="future-work">Future work</h1>
|
|
<ul>
|
|
<li><p>Guix test and packaging</p>
|
|
<p>We have a <a href="https://github.com/atlas-engineer/nyxt/blob/2-pre-release-4/build-scripts/guix.scm">Guix recipe</a> to build Nyxt using the <a href="https://guix.gnu.org/">Guix</a> package manager. There are many benefits in providing a Guix package, among others it allows us to provide a create a <a href="https://guix.gnu.org/en/blog/2018/tarballs-the-ultimate-container-image-format/">Guix pack</a> which is an self-containing, portable tarball that can be unpacked and run on any operating system with a Linux kernel.</p>
|
|
<p>Another benefit of packaging for Guix is that it uses its own Common Lisp packages instead of Quicklisp to manage the Common Lisp dependencies. This validates our quality assurance one step further.</p></li>
|
|
<li><p>Code coverage</p>
|
|
<p>SBCL supports coverage reporting thanks to its <code>sb-cover</code> extension. We hope to make use of it to provide the most exhaustive test suite possible.</p></li>
|
|
</ul>
|
|
<p>Thanks for reading!</p>
|
|
<h1 id="special-thanks">Special thanks</h1>
|
|
<p>Florian Margaine for his awesome work on <a href="https://gitlab.com/ralt/linux-packaging">linux-packaging</a>.</p>
|
|
<p><a href="https://github.com/phoe/"><span class="citation" data-cites="phoe">@phoe</span></a> for his Common Lisp tips.</p>
|
|
</body>
|
|
</html>
|