git.iko.soy/typeable/nix-pills-ru
on master help sign in
5 files changed+15−865
since splitsnapshots
unifiedsplit
README.md+1−1 default.nix−2 nix.html−860 nix.pdf presentation.md+14−2
README.md+1−1
@@ -1,6 +1,6 @@
11# Nix pills in russian
22
3−This repo contains a presentation about nix based on the wonderful [nix-pills](https://nixos.org/nixops/nix-pills).
3+This repo contains a presentation about nix based on the wonderful [nix-pills](https://nixos.org/nixos/nix-pills).
44
55Markdown document is located [here](./presentation.md).
66
default.nix−2
@@ -26,6 +26,4 @@ in stdenv.mkDerivation rec {
2626 phases = [ "buildPhase" ];
2727
2828 preferLocalBuild = true;
29−
30− shellHook = "make build";
3129}
nix.htmldeleted−860
@@ -1,860 +0,0 @@
1−<div id="вступление" class="slide section level1">
2−<h1>Вступление</h1>
3−<!--
4−<meta charset="utf8" />
5−<title>Заметки выступающего</title>
6−-->
7−<p>Основано на <a href="https://nixos.org/nixos/nix-pills" class="uri">https://nixos.org/nixos/nix-pills</a> . Огромная благодарность <span class="citation">@Lethalman</span> и <span class="citation">@grahamc</span> за написание и поддержку этого материала!</p>
8−<p>Я хотел бы, чтобы к концу презентации всем стало понятно</p>
9−<ul>
10−<li>Что такое Nix</li>
11−<li>Как собрать пакеты из <code>contractor</code> с помощью nix</li>
12−<li>Что находится в <code>contractor/nix/pkgs</code></li>
13−<li>Что находится в <code>contractor/nix/overlay.nix</code></li>
14−<li>Как писать несложные выражения на nix, не совершая неочевидных ошибок</li>
15−</ul>
16−<p>Вы можете прекратить слушать после любой секции, и я надеюсь, что вы унесете какую-то полезную для себя информацию.</p>
17−<p>Исходники, собранный pdf и заметки докладчика для этой презентации находятся на <a href="https://github.com/typeable/nix-pills-ru" class="uri">https://github.com/typeable/nix-pills-ru</a></p>
18−<!--
19−Как вы все скорее всего знаете, мы используем Nix для сборки и тестирования нашего кода. Я, Александр Бантьев (@balsoft) отвечаю за инфраструктуру сборки пакетов (Hydra, NixOps), а также за поддержание инструкций сборки в актуальном состоянии. Я бы хотел рассказать вам про nix с помощью вольного пересказа отличной серии статей ["Nix pills"](https://nixos.org/nixos/nix-pills)
20−-->
21−<h2 id="что-такое-nix">Что такое nix?</h2>
22−<!--
23−Говоря "Nix", мы подразумеваем одну из двух его ипостасей -- Nix как язык или Nix как пакетный менеджер. Такая путаница возникла из-за того, что как DSL Nix имеет смысл только в связке со своим пакетным менеджером, а как пакетный менеджер он без своего языка слишком сложен в использовании, и Eelco Dolstra (создатель Nix) решил не разделять их.
24−-->
25−<p><a href="https://nixos.org/nix">Nix</a> – это</p>
26−<ol style="list-style-type: decimal">
27−<li>Язык
28−<ul>
29−<li>Декларативный</li>
30−<li>Функциональный</li>
31−<li>Чистый</li>
32−<li>Ленивый</li>
33−<li>Динамически типизированный</li>
34−</ul></li>
35−<li>Пакетный менеджер
36−<ul>
37−<li>Атомарный</li>
38−<li>Повторяемый</li>
39−<li>Source/Binary</li>
40−</ul></li>
41−</ol>
42−<h2 id="экосистема">Экосистема</h2>
43−<!--
44−Nix довольно быстро стал широко известен в узких кругах, и вокруг него возникла большая экосистема декларативных, атомарных инструментов, в том числе:
45−
46−* nixpkgs, репозиторий описаний пакетов на языке nix;
47−* NixOS, дистрибутив GNU/Linux с интересным подходом к конфигурации системы;
48−* NixOps, инструментарий для разворачивания виртуальных машин и приложений на них на базе NixOS;
49−* Hydra, CI -- сервер;
50−* Disnix, система для разворачивания распределенных систем.
51−-->
52−<p><img src="images/graphviz-8192fc5615858231309e589f5892c04c8314b9078de8fb84b070abd59b0b1934.png" alt="digraph {
53− graph [ dpi = 200; font = Hack; ];
54− subgraph cluster_nix {
55− &quot;nix (пакетный менеджер)&quot; -&gt; &quot;nix (язык)&quot;;
56− &quot;nix (язык)&quot; -&gt; &quot;nix (пакетный менеджер)&quot;;
57− color = blue;
58− }
59− cluster_nix -&gt; Disnix;
60− cluster_nix -&gt; Hydra;
61− cluster_nix -&gt; nixpkgs -&gt; NixOS -&gt; NixOps;
62−}" /></p>
63−</div>
64−<div id="nix-как-пакетный-менеджер" class="slide section level1">
65−<h1>Nix как пакетный менеджер</h1>
66−<blockquote>
67−<p>Nix is a powerful package manager for Linux and other Unix systems that makes package management reliable and reproducible. It provides atomic upgrades and rollbacks, side-by-side installation of multiple versions of a package, multi-user package management and easy setup of build environments.</p>
68−</blockquote>
69−<p><em>— nixos.org/nix</em></p>
70−<!--
71−На https://nixos.org/nix заявлено, что nix -- это все-таки пакетный менеджер. С этого компонента мы и начнем.
72−-->
73−<h2 id="хранилище-nix-store">Хранилище (nix store)</h2>
74−<!--
75−Центральным местом файловой системы для Nix является Хранилище (nix store). Именно здесь хранятся все файлы, с которыми оперирует наш пакетный менеджер: инструкции сборки и её результаты -- исполняемые файлы, документация, заголовочные файлы, etc.
76−
77−Все элементы директории `/nix/store` имеют одинаковый формат имени -- `<hash>-<name>[-version][-output]`. Хэш вычисляется при добавлении в хранилище или при сборке на основе содержимого файла либо содержимого деривации (инструкции сборки), из которого этот путь был собран.
78−-->
79−<blockquote>
80−<p>In the beginning was the Store, and the Store was with Nix, and the Store was Nix.</p>
81−</blockquote>
82−<p><em>— Nix manual, 1:1</em></p>
83−<div class="sourceCode" id="cb1"><pre class="sourceCode bash"><code class="sourceCode bash"><a class="sourceLine" id="cb1-1" title="1">$ <span class="fu">ls</span> /nix/store <span class="kw">|</span> <span class="fu">wc</span> -l</a>
84−<a class="sourceLine" id="cb1-2" title="2"><span class="ex">46251</span></a>
85−<a class="sourceLine" id="cb1-3" title="3">$ <span class="ex">nix</span> add-to-store nix.conf</a>
86−<a class="sourceLine" id="cb1-4" title="4"><span class="ex">/nix/store/za34q8y0jcx3qsrnbrd005mh8zcnlrlr-nix.conf</span></a></code></pre></div>
87−<h3 id="формат-имени">Формат имени</h3>
88−<pre><code>&lt;hash&gt;-&lt;name&gt;[-version][-output]</code></pre>
89−<p>Например,</p>
90−<pre><code>/nix/store/04mm93j20jlnwvhh21db674b3vy6fs54-pandoc-2.7.1-data
91− | hash | name | ver | out |</code></pre>
92−<h2 id="принцип-работы">Принцип работы</h2>
93−<!--
94−В общих чертах, получение результата любого выражения (в терминологии ПМ -- пакета) на nix состоит из двух этапов -- вычисления (за это отвечает nix как язык), и сборки -- именно эта часть ложится на плечи nix как пакетного менеджера.
95−-->
96−<p><img src="images/graphviz-a226e3212ab86c6caf182261f96850451237da3d2f6e3a4ed9b2eb38cb343d17.png" alt="digraph {
97− graph [ dpi = 200; font = Hack; ];
98− &quot;myname.nix&quot; -&gt; &quot;/nix/store/...-myname.drv&quot; [ label = &quot; Вычисление (nix как язык)&quot; ];
99− &quot;/nix/store/...-myname.drv&quot; -&gt; &quot;/nix/store/...-myname&quot; [ label = &quot; Сборка (nix как пакетный менеджер)&quot; ];
100−}" /></p>
101−<h2 id="деривации-derivations-.drv-files">Деривации (derivations, <code>.drv</code> files)</h2>
102−<!--
103−Для сборки пакетов любому пакетному менеджеру нужны инструкции. Например, ABS (Arch build system) использует PKGBUILD, portage (Gentoo) использует EBUILD, brew использует recepies. Nix не является исключением, и для сборки он использует Деривации (.drv). Пример деривации (с добавленными мною переносами строки и пробелами для улучшения читаемости) -- на слайде.
104−-->
105−<h3 id="nixstorez3hhlxbckx4g3n9sw91nnvlkjvyw754p-myname.drv"><code>/nix/store/z3hhlxbckx4g3n9sw91nnvlkjvyw754p-myname.drv</code></h3>
106−<pre><code>Derive
107−([(&quot;out&quot;
108− ,&quot;/nix/store/40s0qmrfb45vlh6610rk29ym318dswdr-myname&quot;,&quot;&quot;,&quot;&quot;)]
109−,[]
110−,[]
111−,&quot;mysystem&quot;
112−,&quot;mybuilder&quot;
113−,[]
114−,[(&quot;builder&quot;,&quot;mybuilder&quot;)
115− ,(&quot;name&quot;,&quot;myname&quot;)
116− ,(&quot;out&quot;,&quot;/nix/store/40s0qmrfb45vlh6610rk29ym318dswdr-myname&quot;)
117− ,(&quot;system&quot;,&quot;mysystem&quot;) ] )</code></pre>
118−<h2 id="краткая-справка-по-инструментарию">Краткая справка по инструментарию</h2>
119−<h3 id="собрать-buildrealize-деривацию">Собрать (build/realize) деривацию</h3>
120−<pre><code>$ nix-store -r /nix/store/z3hhlxbckx4g3n9sw91nnvlkjvyw754p-myname.drv</code></pre>
121−<h3 id="вычислить-evaluate-и-затем-собрать-содержимое-файла-default.nix">Вычислить (evaluate) и затем собрать содержимое файла <code>default.nix</code></h3>
122−<pre><code>$ nix build -f default.nix # или nix-build default.nix</code></pre>
123−<h3 id="вычислить-собрать-и-запустить-интерактивное-окружение">Вычислить, собрать и запустить интерактивное окружение</h3>
124−<pre><code>$ nix run -f default.nix # или nix-shell default.nix</code></pre>
125−</div>
126−<div id="nix-как-язык" class="slide section level1">
127−<h1>Nix как язык</h1>
128−<!--
129−В общих чертах разобравшись с пакетным менеджером, перейдем к языку. Большая часть синтаксиса, конструкций и идей будет знакома вам по другим языкам, поэтому мы быстро пробежимся по примерам, останавливаясь лишь на уникальных чертах и граблях, на которые легко наступить.
130−-->
131−<p>Рассмотрим основы синтаксиса Nix.</p>
132−<p>Краткая инструкция для желающих повторить:</p>
133−<div class="sourceCode" id="cb8"><pre class="sourceCode bash"><code class="sourceCode bash"><a class="sourceLine" id="cb8-1" title="1">$ <span class="ex">curl</span> https://nixos.org/nix/install <span class="kw">|</span> <span class="fu">sh</span></a>
134−<a class="sourceLine" id="cb8-2" title="2"><span class="op">&lt;</span><span class="ex">...</span><span class="op">&gt;</span></a>
135−<a class="sourceLine" id="cb8-3" title="3">$ <span class="ex">nix</span> repl</a></code></pre></div>
136−<h2 id="числа-арифметика-и-комментарии">Числа, арифметика и комментарии</h2>
137−<pre><code>nix-repl&gt; :t 4 # Показать тип выражения
138−an integer
139−nix-repl&gt; 1 + 2 - 3 * 2
140−-3
141−nix-repl&gt; 1 / 2
142−0
143−nix-repl&gt; builtins.add 1 2
144−3
145−nix-repl&gt; # Однострочный комментарий
146−nix-repl&gt; /* Многострочный комментарий */</code></pre>
147−<h3 id="замечание">Замечание</h3>
148−<p>Арифметические операторы лучше обносить пробелами! У символов <code>/</code> и <code>-</code> есть особые значения в Nix</p>
149−<pre><code>nix-repl&gt; 6/2
150−/home/balsoft/6/2</code></pre>
151−<h2 id="булевы-булева-арифметика-и-if">Булевы, булева арифметика и if</h2>
152−<pre><code>nix-repl&gt; :t true
153−a boolean
154−nix-repl&gt; true &amp;&amp; false
155−false
156−nix-repl&gt; true || false
157−true
158−nix-repl&gt; if true || false then 3 else 4
159−3
160−nix-repl&gt; if false then 5 else 6
161−6</code></pre>
162−<h2 id="строки-strings">Строки (strings)</h2>
163−<pre><code>nix-repl&gt; &quot;foo&quot;
164−&quot;foo&quot;
165−nix-repl&gt; :t &quot;foo&quot;
166−a string
167−nix-repl&gt; &quot;Привет&quot;
168−&quot;Привет&quot;
169−nix-repl&gt; &#39;&#39;foo&#39;&#39;
170−&quot;foo&quot;
171−nix-repl&gt; &#39;&#39;
172− foo
173− bar
174− &#39;&#39;
175−&quot;foo\nbar\n&quot;</code></pre>
176−<h2 id="переменные-и-стороковая-интерполяция">Переменные и стороковая интерполяция</h2>
177−<pre><code>nix-repl&gt; foo = &quot;hello&quot;
178−nix-repl&gt; &quot;${foo}, world!&quot;
179−&quot;hello, world!&quot;</code></pre>
180−<h3 id="замечание-1">Замечание</h3>
181−<p>Названия переменных могут содержать знак <code>-</code></p>
182−<pre><code>nix-repl&gt; foo-bar = 10
183−nix-repl&gt; foo-bar
184−10</code></pre>
185−<p>Но не могут содержать не-ASCII!</p>
186−<pre><code>nix-repl&gt; привет
187−error: syntax error, unexpected $undefined, at (string):1:1</code></pre>
188−<h2 id="как-избежать-интерполяции">Как избежать интерполяции?</h2>
189−<p>Довольно часто встречаются ситуации, когда мы хотим вставить в строку последовательность <code>${...}</code> (например, в bash-код).</p>
190−<pre><code>nix-repl&gt; &quot;\${foo}&quot;
191−&quot;${foo}&quot;
192−
193−nix-repl&gt; &#39;&#39;test &#39;&#39;${foo} test&#39;&#39;
194−&quot;test ${foo} test&quot;</code></pre>
195−<h2 id="пути-paths-и-url">Пути (paths) и URL</h2>
196−<pre><code>nix-repl&gt; /bin/sh
197−/bin/sh
198−nix-repl&gt; :t /bin/sh
199−a path
200−nix-repl&gt; ./hello # Относительно текущего .nix файла или PWD для repl
201−/home/balsoft/hello
202−nix-repl&gt; https://typeable.io # Синтаксический сахар для строк
203−&quot;https://typeable.io&quot;
204−nix-repl&gt; :t https://typeable.io
205−a string</code></pre>
206−<h3 id="замечание-2">Замечание</h3>
207−<p>Пути, как и названия переменных, не могут содержать не-ASCII. Я бы рассматривал это, как баг.</p>
208−<pre><code>nix-repl&gt; /home/balsoft/Документы
209−error: path &#39;/home/balsoft/&#39; has a trailing slash</code></pre>
210−<h2 id="nix_path-и-nixpkgs"><code>NIX_PATH</code> и <code>&lt;nixpkgs&gt;</code></h2>
211−<!--
212−`NIX_PATH` -- переменная, очень похожая на `PATH` по синтаксису значений (значения разделены двоеточием), в которой nix ищет пути запрошенные через синтаксис `<path>`.
213−-->
214−<pre><code>$ NIX_PATH=home=$HOME nix repl
215−nix-repl&gt; &lt;home&gt;
216−/home/balsoft
217−^D
218−$ NIX_PATH=/home nix repl
219−nix-repl&gt; &lt;balsoft&gt;
220−/home/balsoft
221−$ nix repl
222−nix-repl&gt; &lt;nixpkgs&gt;
223−/nix/store/zzjhgd7p1y879z0y9pz70vjd45yfi9iz-nixpkgs</code></pre>
224−<h2 id="списки-lists">Списки (lists)</h2>
225−<p>Списки в Nix иммутабельны и могут содержать значения любых типов вперемешку.</p>
226−<pre><code>nix-repl&gt; [ 2 &quot;foo&quot; true (2+3) ]
227−[ 2 &quot;foo&quot; true 5 ]
228−</code></pre>
229−<h3 id="замечание-3">Замечание</h3>
230−<p>Обратите внимание: элементы списка не разделены запятыми!</p>
231−<pre><code>nix-repl&gt; [ 1 + 2 ]
232−error: syntax error, unexpected &#39;+&#39;, at (string):1:5
233−nix-repl&gt; [ (1 + 2) ]
234−[ 3 ]
235−nix-repl&gt; [ import ./hello.nix {} ]
236−[ «primop-app» /home/balsoft/hello.nix { ... } ]</code></pre>
237−<h2 id="множества-аттрибутов-attribute-sets-attrsets">Множества аттрибутов (attribute sets, attrsets)</h2>
238−<pre><code>nix-repl&gt; s = { foo = &quot;bar&quot;; a-b = &quot;baz&quot;; &quot;123&quot; = &quot;num&quot;; }
239−nix-repl&gt; :t s
240−a set
241−nix-repl&gt; s
242−{ &quot;123&quot; = &quot;num&quot;; a-b = &quot;baz&quot;; foo = &quot;bar&quot;; }
243−nix-repl&gt; s.a-b
244−&quot;baz&quot;
245−nix-repl&gt; s.&quot;123&quot;
246−&quot;num&quot;
247−nix-repl&gt; s.${toString (122 + 1)}
248−&quot;num&quot;</code></pre>
249−<h2 id="множества-аттрибутов">Множества аттрибутов</h2>
250−<pre><code>nix-repl&gt; s ? &quot;123&quot;
251−true
252−nix-repl&gt; s ? a-b
253−true
254−nix-repl&gt; s ? abc
255−false
256−nix-repl&gt; s.abc or &quot;not found&quot; # Note that `or` is a keyword
257−&quot;not found&quot;
258−nix-repl&gt; s // { a = 10; }
259−{ &quot;123&quot; = &quot;num&quot;; a = 10; a-b = &quot;baz&quot;; foo = &quot;bar&quot;; }
260−nix-repl&gt; rec { a = 3; b = a + 4; } # Recursive attrset
261−{ a = 3; b = 7; }</code></pre>
262−<h2 id="let-with-и-inherit">Let, with и inherit</h2>
263−<pre><code>nix-repl&gt; let a = 3; b = 4; in a + b
264−7
265−nix-repl&gt; let a = 4; b = a + 5; in b # Let definitions are recursive
266−9
267−nix-repl&gt; let a = 3; a = 8; in a
268−error: attribute `a&#39; at (string):1:12 already defined at (string):1:5
269−nix-repl&gt; longName = { a = 3; b = 4; }
270−nix-repl&gt; with longName; a + b
271−7
272−nix-repl&gt; let a = 10; b = 20; in { inherit a; b = b + 1; }
273−{ a = 10; b = 21; }
274−nix-repl&gt; { inherit (s) &quot;123&quot; foo; }
275−{ &quot;123&quot; = &quot;num&quot;; foo = &quot;bar&quot;; }</code></pre>
276−<h2 id="функции-functions">Функции (functions)</h2>
277−<pre><code>nix-repl&gt; x: x*2
278−«lambda»
279−nix-repl&gt; double = x: x * 2
280−nix-repl&gt; :t double
281−a function
282−nix-repl&gt; double 3
283−6
284−nix-repl&gt; greet = end: name: &quot;Hello, ${name} ${end}&quot;
285−nix-repl&gt; greet &quot;dredozubov&quot; &quot;!&quot;
286−&quot;Hello, dredozubov !&quot;
287−nix-repl&gt; greetExclamaition = greet &quot;!&quot;
288−nix-repl&gt; greetExclamaition &quot;s9gf4ult&quot;
289−&quot;Hello, s9gf4ult !&quot;</code></pre>
290−<h2 id="паттерн-матчинг">Паттерн-матчинг</h2>
291−<pre><code>nix-repl&gt; greet = { name, end }: &quot;Hello, ${name} ${end}&quot;
292−nix-repl&gt; greet { name = &quot;ak3n&quot;; exc = &quot;!&quot;; }
293−&quot;Hello, ak3n !&quot;
294−nix-repl&gt; greet = { name, end ? &quot;!&quot; }: &quot;Hello, ${name} ${end}&quot;
295−nix-repl&gt; greet { name = &quot;ak3n&quot;; }
296−&quot;Hello, ak3n !&quot;
297−nix-repl&gt; greet { name = &quot;ak3n&quot;; end = &quot;.&quot;; }
298−&quot;Hello, ak3n .&quot;
299−nix-repl&gt; greet = { name, end ? &quot;!&quot;, ... }: &quot;Hello, ${name} ${end}&quot;
300−nix-repl&gt; greet { name = &quot;ak3n&quot;; end = &quot;.&quot;; extra = &quot;foo&quot;; }
301−&quot;Hello, ak3n .&quot;
302−nix-repl&gt; foo = {a, ...}@args: args // { a = a + 3; }
303−nix-repl&gt; foo { a = 10; b = 11; }
304−{ a = 13; b = 11; }</code></pre>
305−<h2 id="подключения-файлов-import">Подключения файлов (import)</h2>
306−<h3 id="number.nix"><code>number.nix</code></h3>
307−<pre><code>3</code></pre>
308−<h3 id="function.nix"><code>function.nix</code></h3>
309−<pre><code>a: a + 3</code></pre>
310−<h3 id="обратно-в-наш-уютный-repl">Обратно в наш уютный repl</h3>
311−<pre><code>nix-repl&gt; a = import ./number.nix
312−nix-repl&gt; f = import ./function.nix
313−nix-repl&gt; f a
314−6</code></pre>
315−<h2 id="деривации-derivation">Деривации (derivation)</h2>
316−<!--
317−Вот мы и подошли к моменту, когда мы можем сделать свою собственную деривацию! Исследуем встроенную функцию `derivation`. Она возвращает attrset, но nix показывает его как `derivation`. Странные дела!
318−-->
319−<pre><code>nix-repl&gt; d = derivation {
320− name = &quot;myname&quot;;
321− builder = &quot;mybuilder&quot;;
322− system = &quot;mysystem&quot;; }
323−nix-repl&gt; :t d
324−a set
325−nix-repl&gt; d
326−«derivation /nix/store/z3hhlxbckx4g3n9sw91nnvlkjvyw754p-myname.drv»</code></pre>
327−<h2 id="деривации-сборка">Деривации: сборка</h2>
328−<!--
329−Как вы помните, деривации -- это инструкции сборки для nix. Попробуем собрать нашу фейковую деривацию. nix подсказывает, что у нас система не `mysystem`, а `x86\_64-
330−linux`. Исправим это и попробуем ещё раз. Теперь проблема в том, что файла `mybuilder`, который должен собрать наш пакет, не существует. Fail. Остановимся и исследуем `derivation` поподробнее.
331−-->
332−<pre><code>nix-repl&gt; :b d
333−[...]
334−error: a `mysystem&#39; is required to build ..., but I am a `x86_64-linux&#39;
335−nix-repl&gt; d = derivation {
336− name = &quot;myname&quot;;
337− builder = &quot;mybuilder&quot;;
338− system = builtins.currentSystem; }
339−nix-repl&gt; :b d
340−[...]
341−[...]: executing &#39;mybuilder&#39;: No such file or directory</code></pre>
342−<h2 id="деривации-что-внутри">Деривации: что внутри?</h2>
343−<!--
344−Так как derivation -- это обычный attrset, мы можем исследовать его аттрибуты с помощью встроенного инструментария. Заметим, что `drvAttrs` содержит аргументы, переданные в функцию `derivation`, `out` совпадает с самой деривацией (т.к. на данный момент у нашей деривации только один результат), ну и восхитимся магией типизации на аттрибутах (так вот почему nix так странно себя ведет, показывая derivation вместо сета!). Также заметим, что `toString` превращает в строки только те сеты, которые содержат аттрибут `outPath`.
345−-->
346−<pre><code>nix-repl&gt; builtins.attrNames d
347−[ &quot;all&quot; &quot;builder&quot; &quot;drvAttrs&quot; &quot;drvPath&quot; &quot;name&quot;
348− &quot;out&quot; &quot;outPath&quot; &quot;outputName&quot; &quot;system&quot; &quot;type&quot; ]
349−nix-repl&gt; d.drvAttrs
350−{ builder = &quot;mybuilder&quot;; name = &quot;myname&quot;; system = &quot;x86_64-linux&quot;; }
351−nix-repl&gt; (d == d.out)
352−true
353−nix-repl&gt; { type = &quot;derivation&quot;; } # Типизация истинных джентельменов
354−«derivation ???»
355−nix-repl&gt; toString d
356−&quot;/nix/store/qaq9ir9w2a34dzkjmk3igfbibi5q59sd-myname&quot;
357−nix-repl&gt; toString { outPath = &quot;blah&quot;; }
358−&quot;blah&quot;
359−nix-repl&gt; toString { a = 10; }
360−error: cannot coerce a set to a string, at (string):1:1</code></pre>
361−<h2 id="деривации-добавляем-зависимости">Деривации: добавляем зависимости</h2>
362−<pre><code>nix-repl&gt; :l &lt;nixpkgs&gt; # nixpkgs -- это огромная куча дериваций!
363−Added 10082 variables.
364−nix-repl&gt; coreutils
365−«derivation /nix/store/...-coreutils-8.30.drv»
366−nix-repl&gt; toString coreutils
367−&quot;/nix/store/...-coreutils-8.30&quot;
368−nix-repl&gt; d = derivation {
369− name = &quot;myname&quot;;
370− builder = &quot;${coreutils}/bin/true&quot;;
371− system = builtins.currentSystem; }
372−nix-repl&gt; :b d
373−builder for &#39;...-myname.drv&#39; failed to produce output path &#39;...-myname&#39;</code></pre>
374−<h2 id="деривации-смотрим-на-зависимости">Деривации: смотрим на зависимости</h2>
375−<!--
376−`nix show-derivation` показывает содержимое деривации в виде pretty-printed JSON. Как мы видим, у нас в зависимостях появилась ссылка на coreutils.drv, и builder стал указывать на true.
377−-->
378−<pre><code>$ nix show-derivation /nix/store/...-myname.drv
379−{
380− &quot;/nix/store/apvmj79y84wivsnjc2vkv2q79a37nf7l-myname.drv&quot;: {
381− [...]
382− &quot;inputDrvs&quot;: {
383− &quot;...-coreutils-8.30.drv&quot;: [
384− &quot;out&quot;
385− ]
386− },
387− &quot;builder&quot;: &quot;...-coreutils-8.30/bin/true&quot;,
388− [...]
389− }
390−}</code></pre>
391−<h2 id="деривации-рабочая-деривация">Деривации: рабочая деривация!</h2>
392−<!--
393−Исправим ошибку, которая не дает нам получить нашу первую собирающуюся деривацию! Создадим скрипт `builder.sh`, который создаст outPath. Обратите внимание: мы не будем указывать hashbang для нашего скрипта, потому что даже сам исполняемый файл bash лежит в `/nix/store`, и путь к нему мы можем определить только из nix. Из-за невозможности добавить hashbang, будем запускать наш сборщик как `bash builder.sh`:
394−-->
395−<h3 id="builder.sh"><code>builder.sh</code></h3>
396−<div class="sourceCode" id="cb35"><pre class="sourceCode bash"><code class="sourceCode bash"><a class="sourceLine" id="cb35-1" title="1"><span class="bu">declare</span> -xp</a>
397−<a class="sourceLine" id="cb35-2" title="2"><span class="bu">echo</span> foo <span class="op">&gt;</span> <span class="va">$out</span></a></code></pre></div>
398−<h3 id="уютный-nix-repl">Уютный <code>nix repl</code></h3>
399−<pre><code>nix-repl&gt; :l &lt;nixpkgs&gt;
400−Added 10082 variables.
401−nix-repl&gt; d = derivation {
402− name = &quot;foo&quot;;
403− builder = &quot;${bash}/bin/bash&quot;;
404− args = [ ./builder.sh ];
405− system = builtins.currentSystem; }
406−nix-repl&gt; :b d
407−this derivation produced the following outputs:
408− out -&gt; /nix/store/82jrv90z3aj1lmzr437jpp7m9krnrrzf-foo</code></pre>
409−<h2 id="деривации-посмотрим-на-env">Деривации: посмотрим на env</h2>
410−<!--
411−Посмотрим на то, что показал `declare -xp` (т.е. на переменные окружения, которые доступны внутри сборщика). `nix log` показывает вывод сборщика при сборке определенного пути.
412−
413−* `$HOME` указывает в пустой `/homeless-shelter`
414−* `$PATH` тоже пуст
415−* `$PWD` указывает во временную директорию `/build` (на самом деле она находистся в `/tmp`)
416−
417−Замечу, что все аргументы derivation окажутся в env сборщика.
418−-->
419−<pre><code>$ nix log /nix/store/...-foo
420−[...]
421−declare -x HOME=&quot;/homeless-shelter&quot;
422−declare -x NIX_BUILD_CORES=&quot;0&quot;
423−declare -x NIX_BUILD_TOP=&quot;/build&quot;
424−declare -x NIX_LOG_FD=&quot;2&quot;
425−declare -x NIX_STORE=&quot;/nix/store&quot;
426−declare -x PATH=&quot;/path-not-set&quot;
427−declare -x PWD=&quot;/build&quot;
428−declare -x TEMP=&quot;/build&quot;
429−declare -x builder=&quot;/nix/store/...-bash-4.4-p23/bin/bash&quot;
430−declare -x name=&quot;foo&quot;
431−declare -x out=&quot;/nix/store/82jrv90z3aj1lmzr437jpp7m9krnrrzf-foo&quot;
432−declare -x system=&quot;x86_64-linux&quot;</code></pre>
433−<h2 id="деривации-опакетим-простую-программу-на-c">Деривации: опакетим простую программу на C</h2>
434−<!--
435−Теперь, когда мы умеем создавать рабочие деривации, добавлять зависимости и передавать произвольные переменные в env их сборщика, попробуем опакетить простую программу на C.
436−На этот раз вылезем из привычного `nix repl` и напишем файл!
437−
438−Для сборки программы нам нужны coreutils (для создания выходной директории) и gcc (для сборки). К счастью, эти (и десятки тысяч других) приложения уже опакечены в nixpkgs. Передадим их деривации как аргументы нашему `derivation`, и они окажутся в env сборщика.
439−-->
440−<h3 id="simple.c"><code>simple.c</code></h3>
441−<div class="sourceCode" id="cb38"><pre class="sourceCode c"><code class="sourceCode c"><a class="sourceLine" id="cb38-1" title="1"><span class="dt">void</span> main() {</a>
442−<a class="sourceLine" id="cb38-2" title="2"> puts(<span class="st">&quot;Simple!&quot;</span>);</a>
443−<a class="sourceLine" id="cb38-3" title="3">}</a></code></pre></div>
444−<h3 id="simple_builder.sh"><code>simple_builder.sh</code></h3>
445−<div class="sourceCode" id="cb39"><pre class="sourceCode bash"><code class="sourceCode bash"><a class="sourceLine" id="cb39-1" title="1"><span class="bu">export</span> <span class="va">PATH=</span><span class="st">&quot;</span><span class="va">$coreutils</span><span class="st">/bin:</span><span class="va">$gcc</span><span class="st">/bin&quot;</span> <span class="co"># Переменные из derivation</span></a>
446−<a class="sourceLine" id="cb39-2" title="2"><span class="fu">mkdir</span> -p <span class="va">$out</span>/bin <span class="co"># Создадим выходную директорию</span></a>
447−<a class="sourceLine" id="cb39-3" title="3"><span class="fu">gcc</span> -o <span class="va">$out</span>/bin/simple <span class="va">$src</span> <span class="co"># Соберем нашу программу</span></a></code></pre></div>
448−</div>
449−<div class="slide section level1">
450−
451−<h3 id="simple.nix"><code>simple.nix</code></h3>
452−<pre><code>with (import &lt;nixpkgs&gt; {});
453−derivation {
454− name = &quot;simple&quot;;
455− builder = &quot;${bash}/bin/bash&quot;;
456− args = [ ./simple_builder.sh ]; # Сборщик
457− inherit gcc coreutils; # Зависимости
458− src = ./simple.c;
459− system = builtins.currentSystem;
460−}</code></pre>
461−<h3 id="поехали">Поехали!</h3>
462−<pre><code>$ nix build -f simple.nix
463−[1 built, 0.0 MiB DL]
464−$ ./result/bin/simple
465−Simple!</code></pre>
466−<!--
467−Успех!
468−-->
469−</div>
470−<div class="slide section level1">
471−
472−<h3 id="посмотрим-граф-зависимостей-nix-store--q-result---graph">Посмотрим граф зависимостей (<code>nix-store -q result --graph</code>)</h3>
473−<p><img src="images/graphviz-51a061c1cc85aa203111e4121c911fb0fa438cb89e96a16302b17a4be9c75885.png" alt="digraph G {
474−graph [ dpi=200; ]
475−&quot;/nix/store/p6a11dai9b7xw3xgf44pgyr5kdlnr9rf-simple&quot; [label = &quot;simple&quot;, shape = box, style = filled];
476−&quot;/nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27&quot; -&gt; &quot;/nix/store/p6a11dai9b7xw3xgf44pgyr5kdlnr9rf-simple&quot; [color = &quot;black&quot;];
477−&quot;/nix/store/9sll05wmn9b05f0pm1pwfmmq92fg0syh-simple.c&quot; -&gt; &quot;/nix/store/p6a11dai9b7xw3xgf44pgyr5kdlnr9rf-simple&quot; [color = &quot;red&quot;];
478−&quot;/nix/store/d4n93jn9fdq8fkmkm1q8f32lfagvibjk-gcc-7.4.0&quot; -&gt; &quot;/nix/store/p6a11dai9b7xw3xgf44pgyr5kdlnr9rf-simple&quot; [color = &quot;green&quot;];
479−&quot;/nix/store/hlnxw4k6931bachvg5sv0cyaissimswb-gcc-7.4.0-lib&quot; -&gt; &quot;/nix/store/p6a11dai9b7xw3xgf44pgyr5kdlnr9rf-simple&quot; [color = &quot;blue&quot;];
480−&quot;/nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27&quot; [label = &quot;glibc-2.27&quot;, shape = box, style = filled];
481−&quot;/nix/store/9sll05wmn9b05f0pm1pwfmmq92fg0syh-simple.c&quot; [label = &quot;simple.c&quot;, shape = box, style = filled];
482−&quot;/nix/store/d4n93jn9fdq8fkmkm1q8f32lfagvibjk-gcc-7.4.0&quot; [label = &quot;gcc-7.4.0&quot;, shape = box, style = filled];
483−&quot;/nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27&quot; -&gt; &quot;/nix/store/d4n93jn9fdq8fkmkm1q8f32lfagvibjk-gcc-7.4.0&quot; [color = &quot;magenta&quot;];
484−&quot;/nix/store/hlnxw4k6931bachvg5sv0cyaissimswb-gcc-7.4.0-lib&quot; -&gt; &quot;/nix/store/d4n93jn9fdq8fkmkm1q8f32lfagvibjk-gcc-7.4.0&quot; [color = &quot;burlywood&quot;];
485−&quot;/nix/store/iiymx8j7nlar3gc23lfkcscvr61fng8s-zlib-1.2.11&quot; -&gt; &quot;/nix/store/d4n93jn9fdq8fkmkm1q8f32lfagvibjk-gcc-7.4.0&quot; [color = &quot;black&quot;];
486−&quot;/nix/store/sr4253np2gz2bpha4gn8gqlmiw604155-glibc-2.27-dev&quot; -&gt; &quot;/nix/store/d4n93jn9fdq8fkmkm1q8f32lfagvibjk-gcc-7.4.0&quot; [color = &quot;red&quot;];
487−&quot;/nix/store/hlnxw4k6931bachvg5sv0cyaissimswb-gcc-7.4.0-lib&quot; [label = &quot;gcc-7.4.0-lib&quot;, shape = box, style = filled];
488−&quot;/nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27&quot; -&gt; &quot;/nix/store/hlnxw4k6931bachvg5sv0cyaissimswb-gcc-7.4.0-lib&quot; [color = &quot;green&quot;];
489−&quot;/nix/store/iiymx8j7nlar3gc23lfkcscvr61fng8s-zlib-1.2.11&quot; [label = &quot;zlib-1.2.11&quot;, shape = box, style = filled];
490−&quot;/nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27&quot; -&gt; &quot;/nix/store/iiymx8j7nlar3gc23lfkcscvr61fng8s-zlib-1.2.11&quot; [color = &quot;blue&quot;];
491−&quot;/nix/store/sr4253np2gz2bpha4gn8gqlmiw604155-glibc-2.27-dev&quot; [label = &quot;glibc-2.27-dev&quot;, shape = box, style = filled];
492−&quot;/nix/store/5lyvydxv0w4f2s1ba84pjlbpvqkgn1ni-linux-headers-4.19.16&quot; -&gt; &quot;/nix/store/sr4253np2gz2bpha4gn8gqlmiw604155-glibc-2.27-dev&quot; [color = &quot;magenta&quot;];
493−&quot;/nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27&quot; -&gt; &quot;/nix/store/sr4253np2gz2bpha4gn8gqlmiw604155-glibc-2.27-dev&quot; [color = &quot;burlywood&quot;];
494−&quot;/nix/store/f5wl80zkrd3fc1jxsljmnpn7y02lz6v1-glibc-2.27-bin&quot; -&gt; &quot;/nix/store/sr4253np2gz2bpha4gn8gqlmiw604155-glibc-2.27-dev&quot; [color = &quot;black&quot;];
495−&quot;/nix/store/5lyvydxv0w4f2s1ba84pjlbpvqkgn1ni-linux-headers-4.19.16&quot; [label = &quot;linux-headers-4.19.16&quot;, shape = box, style = filled];
496−&quot;/nix/store/f5wl80zkrd3fc1jxsljmnpn7y02lz6v1-glibc-2.27-bin&quot; [label = &quot;glibc-2.27-bin&quot;, shape = box, style = filled];
497−&quot;/nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27&quot; -&gt; &quot;/nix/store/f5wl80zkrd3fc1jxsljmnpn7y02lz6v1-glibc-2.27-bin&quot; [color = &quot;red&quot;];
498−}" /></p>
499−</div>
500−<div id="стандартные-паттерны-в-nix.-nixpkgs." class="slide section level1">
501−<h1>Стандартные паттерны в Nix. nixpkgs.</h1>
502−<h2 id="mkderivation"><code>mkDerivation</code></h2>
503−<!--
504−Итак, у нас есть мощный и специализированный язык, а также пакетный менеджер, который предоставляет удобную, изолированную среду для сборки пакетов. Для того, чтобы опакечивать софт было проще, создадим функцию, которая будет обобщать `derivation` и уменьшать бойлерплейт. Назовем эту функцию...
505−-->
506−<p>Неудобства <code>derivation</code></p>
507−<ul>
508−<li>Очень большая часть написанного кода будет повторяться из пакета в пакет
509−<ul>
510−<li>Распаковка (чаще всего достаточно <code>tar -xf</code>)</li>
511−<li>Добавление зависимостей (<code>gcc</code>, <code>coreutils</code>, <code>bash</code>, <code>awk</code>, <code>make</code>, …)</li>
512−<li>Сборка (очень часто можно обойтись <code>./configure &amp;&amp; make</code>)</li>
513−<li>Установка (<code>make install</code>)</li>
514−</ul></li>
515−<li>Требует как минимум два файла – builder и expression</li>
516−<li>После вычисления уже нельзя поменять отдельные аргументы, а это может быть удобно</li>
517−</ul>
518−<p>Создадим свой <code>derivation</code> <del>c блекджеком и шлюхами</del> без этих недостатков!</p>
519−<h2 id="mkderivation-зависимости-и-стандартный-сборщик"><code>mkDerivation</code>: зависимости и стандартный сборщик</h2>
520−<!--
521−Для начала, напишем сборщик в файле `generic-builder.sh`. Сначала поставим свой `$PATH`, собрав его из содержимого `buildInputs`. Затем распакуем архив, переданный нам в `$src` и перейдем в свежесозданную директорию. Там сконфигурируем, соберем и установим наш autotools-проект.
522−-->
523−<h3 id="generic-builder.sh"><code>generic-builder.sh</code></h3>
524−<pre><code>set -e
525−unset PATH
526−for p in $buildInputs $baseInputs; do
527− export PATH=$p/bin${PATH:+:}$PATH
528−done
529−tar -xf $src
530−for d in *; do
531− if [ -d &quot;$d&quot; ]; then
532− cd &quot;$d&quot;
533− break
534− fi
535−done
536−./configure --prefix=$out
537−make
538−make install</code></pre>
539−</div>
540−<div class="slide section level1">
541−
542−<!--
543−В nix-части напишем функцию, которая создает деривацию с нашим сборщиком и некоторыми пакетами по-умолчанию, которые будут полезны при создании любого пакета.
544−-->
545−<h3 id="generic-builder.nix"><code>generic-builder.nix</code></h3>
546−<pre><code>pkgs: attrs:
547− with pkgs;
548− let defaultAttrs = {
549− builder = &quot;${bash}/bin/bash&quot;;
550− args = [ ./builder.sh ];
551− baseInputs = [ gnutar gzip gnumake gcc binutils-unwrapped
552− coreutils gawk gnused gnugrep findutils ];
553− buildInputs = [];
554− system = builtins.currentSystem;
555− };
556− in
557−derivation (defaultAttrs // attrs)</code></pre>
558−<h2 id="mkderivation-добавляем-фазы"><code>mkDerivation</code>: добавляем фазы</h2>
559−<!--
560−Создадим файл `setup.sh`, в котором определим стандартные "фазы" сборки, которые затем будем использовать в `builder.sh`.
561−-->
562−<pre><code>unset PATH
563−for p in $baseInputs $buildInputs; do
564− export PATH=$p/bin${PATH:+:}$PATH
565−done
566−
567−function unpackPhase() {
568− tar -xzf $src
569−
570− for d in *; do
571− if [ -d &quot;$d&quot; ]; then
572− cd &quot;$d&quot;
573− break
574− fi
575− done
576−}</code></pre>
577−</div>
578−<div class="slide section level1">
579−
580−<pre><code>function configurePhase() {
581− ./configure --prefix=$out
582−}
583−function buildPhase() {
584− make
585−}
586−function installPhase() {
587− make install
588−}
589−function genericBuild() {
590− unpackPhase
591− configurePhase
592− buildPhase
593− installPhase
594− fixupPhase
595−}</code></pre>
596−</div>
597−<div class="slide section level1">
598−
599−<h3 id="builder.sh-1"><code>builder.sh</code></h3>
600−<pre><code>set -e
601−source $setup
602−genericBuild</code></pre>
603−</div>
604−<div class="slide section level1">
605−
606−<h3 id="generic-builder.nix-1"><code>generic-builder.nix</code></h3>
607−<pre><code>pkgs: attrs:
608− with pkgs;
609− let defaultAttrs = {
610− builder = &quot;${bash}/bin/bash&quot;;
611− args = [ ./builder.sh ];
612− setup = ./setup.sh;
613− baseInputs = [ gnutar gzip gnumake gcc binutils-unwrapped
614− coreutils gawk gnused gnugrep findutils ];
615− buildInputs = [];
616− system = builtins.currentSystem;
617− };
618− in
619−derivation (defaultAttrs // attrs)</code></pre>
620−<h2 id="mkderivation-воспользуемся-нашей-функцией"><code>mkDerivation</code>: воспользуемся нашей функцией!</h2>
621−<!--
622−Отлично! Наша функция умеет собирать autotools-проекты, при этом `builder.sh` получился очень простым благодаря `setup.nix`. Теперь если мы хотим собрать проект не на основе autotools, мы можем это легко сделать, пропустив некоторые фазы в builder.
623−-->
624−<h3 id="default.nix"><code>default.nix</code></h3>
625−<pre><code>let
626− pkgs = import &lt;nixpkgs&gt; {};
627− mkDerivation = import ./generic-builder.nix pkgs;
628−in
629−mkDerivation {
630− name = &quot;hello&quot;;
631− src = ./hello-2.10.tar.gz;
632−};</code></pre>
633−<h2 id="пакеты-как-функции-от-зависимостей-паттерн-inputs">Пакеты как функции от зависимостей: паттерн inputs</h2>
634−<!--
635−Сделаем наш репозиторий ещё удобнее, вынеся определения пакетов в отдельные файлы. В каждом таком файле будет находиться функция, принимающая в качестве аргументов зависимости пакета и возвращающая деривацию (который мы будем создавать с помощью нашего `mkDerivation`)
636−-->
637−<h3 id="hello.nix"><code>hello.nix</code></h3>
638−<pre><code>{ mkDerivation }:
639−mkDerivation {
640− name = &quot;hello&quot;;
641− src = ./hello-2.10.tar.gz;
642−}</code></pre>
643−<h3 id="default.nix-1"><code>default.nix</code></h3>
644−<pre><code>let
645− pkgs = import &lt;nixpkgs&gt; {};
646− mkDerivation = import ./generic-builder.nix pkgs;
647−in
648−{
649− hello = import ./hello.nix { inherit mkDerivation };
650−}</code></pre>
651−<h2 id="сборка-с-библиотеками-nix_cflags_compile-nix_ldflags">Сборка с библиотеками: <code>NIX_CFLAGS_COMPILE</code>, <code>NIX_LDFLAGS</code></h2>
652−<!--
653−Если мы хотим собирать пакеты, которые зависят от сторонних библиотек, нам понадобится ещё немного магии: нужно указать GCC и ld, где искать заголовочные и объектные файлы библиотек. Для этого существуют переменные `NIX CFLAGS COMPILE` и `NIX LDFLAGS`
654−-->
655−<h3 id="generic-builder.sh-1"><code>generic-builder.sh</code></h3>
656−<pre><code>[...]
657−for p in $baseInputs $buildInputs; do
658− [...]
659− if [ -d $p/include ]; then
660− export NIX_CFLAGS_COMPILE=&quot;-I $p/include${NIX_CFLAGS_COMPILE:+ }\
661−$NIX_CFLAGS_COMPILE&quot;
662− fi
663− if [ -d $p/lib ]; then
664− export NIX_LDFLAGS=&quot;-rpath $p/lib -L \
665−$p/lib${NIX_LDFLAGS:+ }$NIX_LDFLAGS&quot;
666− fi
667−done
668−[...]</code></pre>
669−</div>
670−<div class="slide section level1">
671−
672−<h3 id="graphviz.nix"><code>graphviz.nix</code></h3>
673−<pre><code>{ mkDerivation, gdSupport ? true, gd, fontconfig, libjpeg, bzip2 }:
674−
675−mkDerivation {
676− name = &quot;graphviz&quot;;
677− src = ./graphviz-2.38.0.tar.gz;
678− buildInputs = if gdSupport
679− then [ gd fontconfig libjpeg bzip2 ]
680− else [];
681−}</code></pre>
682−</div>
683−<div class="slide section level1">
684−
685−<h3 id="default.nix-2"><code>default.nix</code></h3>
686−<pre><code>let
687− pkgs = import &lt;nixpkgs&gt; {};
688− mkDerivation = import ./generic-builder.nix pkgs;
689−in
690−{
691− hello = import ./hello.nix { inherit mkDerivation };
692− graphviz = import ./graphviz.nix { inherit mkDerivation
693− gd fontconfig libjpeg bzip2; };
694− graphvizCore = import ./graphviz.nix {
695− inherit mkDerivation gd fontconfig libjpeg bzip2;
696− gdSupport = false;
697− };
698−}</code></pre>
699−<h2 id="паттерн-callpackage">Паттерн <code>callPackage</code></h2>
700−<!--
701−Здорово! Мы сделали свой небольшой репозиторий с красивой файловой структурой, научились собирать пакеты с помощью autotools с возможностью легко перейти на другие системы сборки и даже собирать пакеты с библиотеками. Теперь пора уменьшить бойлерплейт. Можно заметить, что в корневом файле репозитория мы повторяем названия аргументов функции при её вызове. Это будет происходить постоянно при структуре репозитория, похожего на наш. Для того, чтобы исправить эту проблему, мы создадим функцию `callPackage`, которая будет вызывать функцию из указанного файла, автоматически передавая ей аргументы из указанного attrset. Например:
702−-->
703−<h3 id="default.nix-3"><code>default.nix</code></h3>
704−<pre><code>let
705− pkgs = import &lt;nixpkgs&gt; {};
706− mkDerivation = import ./generic-builder.nix pkgs;
707−in
708−{
709− hello = callPackage ./hello.nix { };
710− graphviz = callPackage ./graphviz.nix { };
711− graphvizCore = callPackage ./graphviz.nix { gdSupport = false; };
712−}</code></pre>
713−</div>
714−<div class="slide section level1">
715−
716−<!--
717−Для начала разберемся с тем, как же нам найти названия аргументов функции. В nix для этого существует встроенная функция `builins.functionArgs`. Она возвращает attrset, в котором названию аргументов соответствует наличие у них значения по-умолчанию.
718−-->
719−<pre><code>nix-repl&gt; add = { a ? 3, b }: a+b
720−nix-repl&gt; builtins.functionArgs add
721−{ a = true; b = false; }</code></pre>
722−<!--
723−Также в nix существует удобный builtin для "пересечения" двух attrset-ов. Он возвращает attrset, в котором имена аттрибутов -- пересечение имен аттрибутов его аргументов, а их значения берутся из второго аргумента. Например:
724−-->
725−<pre><code>nix-repl&gt; values = { a = 3; b = 5; c = 10; }
726−nix-repl&gt; builtins.intersectAttrs values (builtins.functionArgs add)
727−{ a = true; b = false; }
728−nix-repl&gt; builtins.intersectAttrs (builtins.functionArgs add) values
729−{ a = 3; b = 5; }</code></pre>
730−<h2 id="простой-вариант-callpackage">Простой вариант <code>callPackage</code></h2>
731−<!--
732−Обладая этими знаниями, напишем простую реализацию нашего callPackage.
733−-->
734−<pre><code>nix-repl&gt; callPackage = set: f:
735− f (builtins.intersectAttrs
736− (builtins.functionArgs f)
737− set)
738−nix-repl&gt; callPackage values add
739−8
740−nix-repl&gt; with values; add { inherit a b; }
741−8</code></pre>
742−<h2 id="callpackage-добавляем-оверрайды"><code>callPackage</code>: добавляем оверрайды</h2>
743−<!--
744−Добавим возможность перегружать значения с помощью последнего аргумента...
745−-->
746−<pre><code>nix-repl&gt; callPackage = set: f: overrides:
747− f ((builtins.intersectAttrs
748− (builtins.functionArgs f)
749− set)
750− // overrides)
751−nix-repl&gt; callPackage values add { }
752−8
753−nix-repl&gt; callPackage values add { b = 12; }
754−15</code></pre>
755−<h2 id="callpackage-используем"><code>callPackage</code>: используем!</h2>
756−<pre><code>let
757− nixpkgs = import &lt;nixpkgs&gt; {};
758− allPkgs = nixpkgs // pkgs;
759− callPackage = path: overrides:
760− let f = import path;
761− in f ((builtins.intersectAttrs
762− (builtins.functionArgs f)
763− allPkgs)
764− // overrides);
765− pkgs = with nixpkgs; {
766− mkDerivation = import ./generic-builder.nix nixpkgs;
767− hello = callPackage ./hello.nix { };
768− graphviz = callPackage ./graphviz.nix { };
769− graphvizCore = callPackage ./graphviz.nix { gdSupport = false; };
770− };
771−in pkgs</code></pre>
772−<h2 id="паттерн-override">Паттерн <code>override</code></h2>
773−<!--
774−Nix -- это функциональный язык. Одна из идей функциональной парадигмы состоит в композиции функций. Это может быть очень удобно при работе с деривациями. Например, если мы хотим получить `graphviz`, собранный с нашей собственной версией библиотеки gd, на данный момент нам придется заново делать `callPackage ./graphviz.nix { gd = customgd; }` Это неудобно и добавляет бойлерплейт.
775−-->
776−<pre><code>mygraphviz = callPackage ./graphviz.nix { gd = customgd; }
777−
778−VS.
779−
780−mygraphviz = pkgs.graphviz.override { gd = customgd }</code></pre>
781−<h2 id="паттерн-override-makeoverridable">Паттерн <code>override</code>: <code>makeOverridable</code></h2>
782−<!--
783−Для реализации нашей затеи напишем функцию `mkOverridable`, которая будет принимать функцию, возвращающую attrset, и attrset (который будет являться "дефолтными" аргументами для данной функции). Вернет `makeOverridable` тот же attrset, что вернула бы данная функция, с добавлением аттрибута `override`, который является функцией, позволяющей нам "перегружать" стандартные аргументы.
784−-->
785−<h3 id="lib.nix"><code>lib.nix</code></h3>
786−<pre><code>rec {
787− makeOverridable = f: origArgs:
788− let
789− origRes = f origArgs;
790− in
791− origRes // {
792− override = newArgs:
793− makeOverridable f (origArgs // newArgs);
794− };
795−}</code></pre>
796−<h2 id="паттерн-override-потестируем">Паттерн <code>override</code>: потестируем!</h2>
797−<!--
798−Работает! Теперь мы можем легко "перегружать" аргументы пакетов (которые, напомню, просто функции) в нашем репозитории. Нужно только не забыть вызывать все эти пакеты с makeOverridable.
799−-->
800−<pre><code>nix-repl&gt; :l lib.nix
801−Added 1 variables.
802−nix-repl&gt; f = { a, b }: { result = a+b; }
803−nix-repl&gt; res = makeOverridable f { a = 3; b = 5; }
804−nix-repl&gt; res2 = res.override { a = 10; }
805−nix-repl&gt; res2
806−{ override = «lambda»; result = 15; }
807−nix-repl&gt; res2.override { b = 20; }
808−{ override = «lambda»; result = 30; }</code></pre>
809−<h2 id="паттерн-override-объединяем-с-callpackage">Паттерн <code>override</code>: объединяем с <code>callPackage</code></h2>
810−<h3 id="lib.nix-1"><code>lib.nix</code></h3>
811−<pre><code>rec {
812− [...]
813− callPackage = pkgs: path: overrides:
814− let f = import path;
815− in makeOverridable
816− f ((builtins.intersectAttrs
817− (builtins.functionArgs f)
818− pkgs)
819− // overrides);
820−}</code></pre>
821−<h2 id="паттерн-override-репозиторий">Паттерн <code>override</code>: репозиторий</h2>
822−<h3 id="default.nix-4"><code>default.nix</code></h3>
823−<pre><code>let
824− lib = import ./lib.nix;
825− nixpkgs = import &lt;nixpkgs&gt; {};
826− callPackage = lib.callPackage allPkgs;
827− allPkgs = nixpkgs // pkgs;
828− pkgs = with nixpkgs; rec {
829− mkDerivation = import ./generic-builder.nix nixpkgs;
830− hello = callPackage ./hello.nix { };
831− graphviz = callPackage ./graphviz.nix { };
832− graphvizCore = graphviz.override { gdSupport = false };
833− };
834−in pkgs</code></pre>
835−<h2 id="nixpkgs-краткая-справка">nixpkgs: краткая справка</h2>
836−<h3 id="общая-конфигурация-для-всех-пакетов">Общая конфигурация для всех пакетов</h3>
837−<ul>
838−<li><code>import &lt;nixpkgs&gt; { config = {...}; }</code></li>
839−<li><code>$NIXPKGS_CONFIG</code></li>
840−<li><code>~/.config/nixpkgs/config.nix</code></li>
841−</ul>
842−<h3 id="перегрузка-пакетов">Перегрузка пакетов</h3>
843−<pre><code>config.packageOverrides = oldPkgs: {
844− graphviz = oldPkgs.graphviz.override { gd = customgd; };
845−}</code></pre>
846−<h3 id="оверлеи">Оверлеи</h3>
847−<pre><code>nixpkgs.overlays = [ (self: super: {
848− graphviz = super.graphviz.override { gd = customgd; };
849−} ) ];</code></pre>
850−<h2 id="что-осталось-за-кадром-в-этом-разделе">Что осталось за кадром в этом разделе</h2>
851−<!--
852−Нельзя объять необъятное -- а nixpkgs действительно необъятен, более 20МБ кода на данный момент -- и поэтому я оставлю изучение частностей на совести слушателя.
853−-->
854−<ul>
855−<li><code>stdenv</code></li>
856−<li><code>lib</code></li>
857−<li><code>fix</code></li>
858−</ul>
859−<p><a href="https://nixos.org/nixos/nix-pills" class="uri">https://nixos.org/nixos/nix-pills</a> и <a href="https://nixos.org/nixpkgs/manual" class="uri">https://nixos.org/nixpkgs/manual</a> – для тех, кому надо или интересно!</p>
860−</div>
nix.pdfdeleted

Binary file not shown.

presentation.md+14−2
@@ -1052,15 +1052,27 @@ nixpkgs.overlays = [ (self: super: {
10521052} ) ];
10531053```
10541054
1055+## `stdenv.mkDerivation`: прокачиваем наш `mkDerivation`
1056+<!--
1057+Наша функция `mkDerivation`, без сомнения, прекарасна, но можно лучше! `stdenv.mkDerivation` из nixpkgs предоставляет интерфейс (т.е принимаемые и возвращаемые значения) очень похожие на наш `mkDerivation`, с несколькими отличиями:
1058+-->
1059+`stdenv.mkDerivation` может...
1060+
1061+* Изменять поведение фаз, например `{ buildPhase = "make"; }`
1062+* Изменять список фаз `{ phases = [ "buildPhase" ]; }`
1063+* Перегружать аргументы с помощью `overrideAttrs`
1064+* Автоматически добавлять хуки на проброс зависимостей с помощью `propogatedBuildInputs`
1065+
1066+
10551067## Что осталось за кадром в этом разделе
10561068
10571069<!--
1058−Нельзя объять необъятное -- а nixpkgs действительно необъятен, более 20МБ кода на данный момент -- и поэтому я оставлю изучение частностей на совести слушателя.
1070+Нельзя объять необъятное -- а nixpkgs действительно необъятен, более 100МБ кода на данный момент -- и поэтому я оставлю изучение частностей на совести слушателя.
10591071-->
10601072
10611073* `stdenv`
10621074* `lib`
10631075* `fix`
1064−
1076+* ...
10651077<https://nixos.org/nixos/nix-pills> и <https://nixos.org/nixpkgs/manual> -- для тех, кому надо или интересно!
10661078