Merge pull request #125605 from ryantm/md-abstractions

nixos/doc: convert abstractions section to CommonMark
master
Ryan Mulligan 2021-06-07 20:20:37 -07:00 committed by GitHub
commit 8c2e0146d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 182 additions and 102 deletions

View File

@ -0,0 +1,80 @@
# Abstractions {#sec-module-abstractions}
If you find yourself repeating yourself over and over, its time to abstract. Take, for instance, this Apache HTTP Server configuration:
```nix
{
services.httpd.virtualHosts =
{ "blog.example.org" = {
documentRoot = "/webroot/blog.example.org";
adminAddr = "alice@example.org";
forceSSL = true;
enableACME = true;
enablePHP = true;
};
"wiki.example.org" = {
documentRoot = "/webroot/wiki.example.org";
adminAddr = "alice@example.org";
forceSSL = true;
enableACME = true;
enablePHP = true;
};
};
}
```
It defines two virtual hosts with nearly identical configuration; the only difference is the document root directories. To prevent this duplication, we can use a `let`:
```nix
let
commonConfig =
{ adminAddr = "alice@example.org";
forceSSL = true;
enableACME = true;
};
in
{
services.httpd.virtualHosts =
{ "blog.example.org" = (commonConfig // { documentRoot = "/webroot/blog.example.org"; });
"wiki.example.org" = (commonConfig // { documentRoot = "/webroot/wiki.example.com"; });
};
}
```
The `let commonConfig = ...` defines a variable named `commonConfig`. The `//` operator merges two attribute sets, so the configuration of the second virtual host is the set `commonConfig` extended with the document root option.
You can write a `let` wherever an expression is allowed. Thus, you also could have written:
```nix
{
services.httpd.virtualHosts =
let commonConfig = ...; in
{ "blog.example.org" = (commonConfig // { ... })
"wiki.example.org" = (commonConfig // { ... })
};
}
```
but not `{ let commonConfig = ...; in ...; }` since attributes (as opposed to attribute values) are not expressions.
**Functions** provide another method of abstraction. For instance, suppose that we want to generate lots of different virtual hosts, all with identical configuration except for the document root. This can be done as follows:
```nix
{
services.httpd.virtualHosts =
let
makeVirtualHost = webroot:
{ documentRoot = webroot;
adminAddr = "alice@example.org";
forceSSL = true;
enableACME = true;
};
in
{ "example.org" = (makeVirtualHost "/webroot/example.org");
"example.com" = (makeVirtualHost "/webroot/example.com");
"example.gov" = (makeVirtualHost "/webroot/example.gov");
"example.nl" = (makeVirtualHost "/webroot/example.nl");
};
}
```
Here, `makeVirtualHost` is a function that takes a single argument `webroot` and returns the configuration for a virtual host. That function is then called for several names to produce the list of virtual host configurations.

View File

@ -1,101 +0,0 @@
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="sec-module-abstractions">
<title>Abstractions</title>
<para>
If you find yourself repeating yourself over and over, its time to
abstract. Take, for instance, this Apache HTTP Server configuration:
<programlisting>
{
<xref linkend="opt-services.httpd.virtualHosts"/> =
{ "blog.example.org" = {
documentRoot = "/webroot/blog.example.org";
adminAddr = "alice@example.org";
forceSSL = true;
enableACME = true;
enablePHP = true;
};
"wiki.example.org" = {
documentRoot = "/webroot/wiki.example.org";
adminAddr = "alice@example.org";
forceSSL = true;
enableACME = true;
enablePHP = true;
};
};
}
</programlisting>
It defines two virtual hosts with nearly identical configuration; the only
difference is the document root directories. To prevent this
duplication, we can use a <literal>let</literal>:
<programlisting>
let
commonConfig =
{ adminAddr = "alice@example.org";
forceSSL = true;
enableACME = true;
};
in
{
<xref linkend="opt-services.httpd.virtualHosts"/> =
{ "blog.example.org" = (commonConfig // { documentRoot = "/webroot/blog.example.org"; });
"wiki.example.org" = (commonConfig // { documentRoot = "/webroot/wiki.example.com"; });
};
}
</programlisting>
The <literal>let commonConfig = <replaceable>...</replaceable></literal>
defines a variable named <literal>commonConfig</literal>. The
<literal>//</literal> operator merges two attribute sets, so the
configuration of the second virtual host is the set
<literal>commonConfig</literal> extended with the document root option.
</para>
<para>
You can write a <literal>let</literal> wherever an expression is allowed.
Thus, you also could have written:
<programlisting>
{
<xref linkend="opt-services.httpd.virtualHosts"/> =
let commonConfig = <replaceable>...</replaceable>; in
{ "blog.example.org" = (commonConfig // { <replaceable>...</replaceable> })
"wiki.example.org" = (commonConfig // { <replaceable>...</replaceable> })
};
}
</programlisting>
but not <literal>{ let commonConfig = <replaceable>...</replaceable>; in
<replaceable>...</replaceable>; }</literal> since attributes (as opposed to
attribute values) are not expressions.
</para>
<para>
<emphasis>Functions</emphasis> provide another method of abstraction. For
instance, suppose that we want to generate lots of different virtual hosts,
all with identical configuration except for the document root. This can be done
as follows:
<programlisting>
{
<xref linkend="opt-services.httpd.virtualHosts"/> =
let
makeVirtualHost = webroot:
{ documentRoot = webroot;
adminAddr = "alice@example.org";
forceSSL = true;
enableACME = true;
};
in
{ "example.org" = (makeVirtualHost "/webroot/example.org");
"example.com" = (makeVirtualHost "/webroot/example.com");
"example.gov" = (makeVirtualHost "/webroot/example.gov");
"example.nl" = (makeVirtualHost "/webroot/example.nl");
};
}
</programlisting>
Here, <varname>makeVirtualHost</varname> is a function that takes a single
argument <literal>webroot</literal> and returns the configuration for a virtual
host. That function is then called for several names to produce the list of
virtual host configurations.
</para>
</section>

View File

@ -19,7 +19,7 @@ xlink:href="https://nixos.org/nix/manual/#chap-writing-nix-expressions">Nix
constructs useful in NixOS configuration files.
</para>
<xi:include href="config-file.xml" />
<xi:include href="abstractions.xml" />
<xi:include href="../from_md/configuration/abstractions.section.xml" />
<xi:include href="modularity.xml" />
<xi:include href="summary.xml" />
</chapter>

View File

@ -0,0 +1,101 @@
<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-module-abstractions">
<title>Abstractions</title>
<para>
If you find yourself repeating yourself over and over, its time to
abstract. Take, for instance, this Apache HTTP Server configuration:
</para>
<programlisting language="bash">
{
services.httpd.virtualHosts =
{ &quot;blog.example.org&quot; = {
documentRoot = &quot;/webroot/blog.example.org&quot;;
adminAddr = &quot;alice@example.org&quot;;
forceSSL = true;
enableACME = true;
enablePHP = true;
};
&quot;wiki.example.org&quot; = {
documentRoot = &quot;/webroot/wiki.example.org&quot;;
adminAddr = &quot;alice@example.org&quot;;
forceSSL = true;
enableACME = true;
enablePHP = true;
};
};
}
</programlisting>
<para>
It defines two virtual hosts with nearly identical configuration;
the only difference is the document root directories. To prevent
this duplication, we can use a <literal>let</literal>:
</para>
<programlisting language="bash">
let
commonConfig =
{ adminAddr = &quot;alice@example.org&quot;;
forceSSL = true;
enableACME = true;
};
in
{
services.httpd.virtualHosts =
{ &quot;blog.example.org&quot; = (commonConfig // { documentRoot = &quot;/webroot/blog.example.org&quot;; });
&quot;wiki.example.org&quot; = (commonConfig // { documentRoot = &quot;/webroot/wiki.example.com&quot;; });
};
}
</programlisting>
<para>
The <literal>let commonConfig = ...</literal> defines a variable
named <literal>commonConfig</literal>. The <literal>//</literal>
operator merges two attribute sets, so the configuration of the
second virtual host is the set <literal>commonConfig</literal>
extended with the document root option.
</para>
<para>
You can write a <literal>let</literal> wherever an expression is
allowed. Thus, you also could have written:
</para>
<programlisting language="bash">
{
services.httpd.virtualHosts =
let commonConfig = ...; in
{ &quot;blog.example.org&quot; = (commonConfig // { ... })
&quot;wiki.example.org&quot; = (commonConfig // { ... })
};
}
</programlisting>
<para>
but not <literal>{ let commonConfig = ...; in ...; }</literal> since
attributes (as opposed to attribute values) are not expressions.
</para>
<para>
<emphasis role="strong">Functions</emphasis> provide another method
of abstraction. For instance, suppose that we want to generate lots
of different virtual hosts, all with identical configuration except
for the document root. This can be done as follows:
</para>
<programlisting language="bash">
{
services.httpd.virtualHosts =
let
makeVirtualHost = webroot:
{ documentRoot = webroot;
adminAddr = &quot;alice@example.org&quot;;
forceSSL = true;
enableACME = true;
};
in
{ &quot;example.org&quot; = (makeVirtualHost &quot;/webroot/example.org&quot;);
&quot;example.com&quot; = (makeVirtualHost &quot;/webroot/example.com&quot;);
&quot;example.gov&quot; = (makeVirtualHost &quot;/webroot/example.gov&quot;);
&quot;example.nl&quot; = (makeVirtualHost &quot;/webroot/example.nl&quot;);
};
}
</programlisting>
<para>
Here, <literal>makeVirtualHost</literal> is a function that takes a
single argument <literal>webroot</literal> and returns the
configuration for a virtual host. That function is then called for
several names to produce the list of virtual host configurations.
</para>
</section>