mirror of
https://github.com/hercules-ci/arion.git
synced 2024-11-29 22:51:11 +03:00
Add doc/manual, tweak README
This commit is contained in:
parent
da85a4cbbe
commit
ccaac02a87
24
README.md
24
README.md
@ -4,10 +4,9 @@
|
|||||||
*Wait, what?*
|
*Wait, what?*
|
||||||
|
|
||||||
With Arion you can fire up containers without creating images for each
|
With Arion you can fire up containers without creating images for each
|
||||||
service. Instead, it uses a mostly empty image, sort of like a base
|
service. It can use a mostly empty image, and makes the host's Nix
|
||||||
image, and makes the host's Nix store available in the container,
|
store available in the container, allowing the container to run
|
||||||
allowing the container to run programs without having to re-package
|
programs without having to re-package them into a docker image.
|
||||||
them into a docker image.
|
|
||||||
|
|
||||||
Arion is configured using Nix with modules, like those in
|
Arion is configured using Nix with modules, like those in
|
||||||
NixOS. Similar to `docker-compose` it can therefore combine
|
NixOS. Similar to `docker-compose` it can therefore combine
|
||||||
@ -21,13 +20,10 @@ development environments while working
|
|||||||
on [Hercules CI](https://www.hercules-ci.com). (It was also born out
|
on [Hercules CI](https://www.hercules-ci.com). (It was also born out
|
||||||
of ancient Greek deities disguised as horses. More on that later.)
|
of ancient Greek deities disguised as horses. More on that later.)
|
||||||
|
|
||||||
We don't use it to deploy to 'real' environments and we have no plans
|
If you do want to use Arion for production environments, you'll
|
||||||
to do so in the future.
|
probably want to either build normal container images or manage
|
||||||
|
garbage collection roots if you control the deployment host. Neither
|
||||||
If you do want to use Arion for 'real' environments, you'll probably
|
scenario is made easier by arion at this time.
|
||||||
want to either build images or manage garbage collection roots if you
|
|
||||||
control the deployment host. Either of these has yet to be
|
|
||||||
implemented.
|
|
||||||
|
|
||||||
Support for other Linux than NixOS is untested.
|
Support for other Linux than NixOS is untested.
|
||||||
|
|
||||||
@ -68,7 +64,7 @@ This Nix expression serves the Nix manual at host port 8000 when launched with `
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The `pkgs` argument comes from a file called `arion-pkgs.nix`. It can be as simple as `import <nixpkgs> {}` to use the Nixpkgs from your `$NIX_PATH`.
|
The `pkgs` argument comes from a file called `arion-pkgs.nix`. It can be as simple as `import <nixpkgs> {}` to use the Nixpkgs from your `$NIX_PATH`, or you can use it to pin a specific Nixpkgs version.
|
||||||
|
|
||||||
# A full featured example
|
# A full featured example
|
||||||
|
|
||||||
@ -90,7 +86,7 @@ When it runs, it does the following:
|
|||||||
Most of the interesting stuff happens in Arion's Nix expressions,
|
Most of the interesting stuff happens in Arion's Nix expressions,
|
||||||
where it runs the module system (known from NixOS) and provides the configuration that makes the Docker Compose file do the things it needs to do.
|
where it runs the module system (known from NixOS) and provides the configuration that makes the Docker Compose file do the things it needs to do.
|
||||||
|
|
||||||
The interesting part is of course the [service-host-store.nix module](src/nix/service-host-store.nix) which performs the bind mounts to make the host Nix store available in the container.
|
One of the more interesting built-in modules is the [host-store.nix module](src/nix/modules/service/host-store.nix) which performs the bind mounts to make the host Nix store available in the container.
|
||||||
|
|
||||||
# FAQ
|
# FAQ
|
||||||
|
|
||||||
@ -101,7 +97,7 @@ Nope, it's just Nix and Docker Compose under the hood.
|
|||||||
|
|
||||||
### Does Arion support Docker images?
|
### Does Arion support Docker images?
|
||||||
|
|
||||||
Yes, you can still specify a docker image. For example:
|
Yes, you can also specify a normal Docker image. For example:
|
||||||
|
|
||||||
postgres = {
|
postgres = {
|
||||||
service.image = "postgres:10";
|
service.image = "postgres:10";
|
||||||
|
@ -2,4 +2,5 @@ args@{ pkgs ? import ./nix args, ... }:
|
|||||||
|
|
||||||
{
|
{
|
||||||
inherit (pkgs) arion tests;
|
inherit (pkgs) arion tests;
|
||||||
|
doc = pkgs.recurseIntoAttrs (import ./doc { inherit pkgs; });
|
||||||
}
|
}
|
||||||
|
8
doc/default.nix
Normal file
8
doc/default.nix
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{ pkgs ? import ../nix {} }:
|
||||||
|
let
|
||||||
|
inherit (pkgs) recurseIntoAttrs callPackage;
|
||||||
|
in
|
||||||
|
|
||||||
|
recurseIntoAttrs {
|
||||||
|
manual = callPackage ./manual {};
|
||||||
|
}
|
4
doc/manual/.gitignore
vendored
Normal file
4
doc/manual/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
introduction.xml
|
||||||
|
manual.html
|
||||||
|
options-composition.xml
|
||||||
|
options-service.xml
|
35
doc/manual/Makefile
Normal file
35
doc/manual/Makefile
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
xsltproc = xsltproc --nonet \
|
||||||
|
--param section.autolabel 0 \
|
||||||
|
--param section.label.includes.component.label 0 \
|
||||||
|
--param chapter.autolabel 0 \
|
||||||
|
--param chapter.label.includes.component.label 0 \
|
||||||
|
--param appendix.autolabel 0 \
|
||||||
|
--param appendix.label.includes.component.label 0 \
|
||||||
|
--param generate.toc "'book toc,title chapter nop section nop sect1 nop sect2 nop sect3 nop sect4 nop sect5 nop'" \
|
||||||
|
--param html.stylesheet \'style.css\' \
|
||||||
|
--param xref.with.number.and.title 0 \
|
||||||
|
--param toc.section.depth 3 \
|
||||||
|
--param admon.style \'\' \
|
||||||
|
--param callout.graphics.extension \'.gif\' \
|
||||||
|
--param contrib.inline.enabled 0
|
||||||
|
|
||||||
|
docbookxsl = http://docbook.sourceforge.net/release/xsl/current
|
||||||
|
|
||||||
|
all: manual.html
|
||||||
|
|
||||||
|
manual.html: manual.xml introduction.xml installation.xml options-composition.xml options-service.xml
|
||||||
|
$(xsltproc) --xinclude --stringparam profile.condition manual \
|
||||||
|
$(docbookxsl)/profiling/profile.xsl manual.xml | \
|
||||||
|
$(xsltproc) --output manual.html $(docbookxsl)/xhtml/docbook.xsl -
|
||||||
|
|
||||||
|
# -e 's_<book lang="en">__' -e 's_</book>__'
|
||||||
|
%.xml: %.asciidoc
|
||||||
|
asciidoctor --backend docbook45 --doctype article $<
|
||||||
|
sed -e 's/<!DOCTYPE.*//' -e 's/<?asciidoc-[a-z]*?>//' -i $@
|
||||||
|
|
||||||
|
options-composition.xml options-service.xml:
|
||||||
|
echo "options-composition.xml and options-service.xml should be written by the derivation. Are you running in 'nix-shell -A manual'?"; exit 1; fi
|
||||||
|
|
||||||
|
install: all
|
||||||
|
mkdir -p $(docdir)
|
||||||
|
cp manual.html style.css $(docdir)
|
120
doc/manual/default.nix
Normal file
120
doc/manual/default.nix
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
{ pkgs ? import ../../nix {}
|
||||||
|
, version ? "none"
|
||||||
|
# Default sourceUrl is for local development. Works with
|
||||||
|
# nix-build -A doc.manual
|
||||||
|
# For release, use: https://github.com/hercules-ci/arion/blob/${version}
|
||||||
|
, sourceUrl ? "../../.."
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (pkgs) recurseIntoAttrs callPackage runCommand lib stdenv ;
|
||||||
|
|
||||||
|
nixosManualPath = s: "${pkgs.path}/nixos/doc/manual/${s}";
|
||||||
|
|
||||||
|
# NixOS module system options in JSON format.
|
||||||
|
options = { moduleType, description, /*optionsList*/ optionsExpr }: recurseIntoAttrs rec {
|
||||||
|
optionsXML =
|
||||||
|
# builtins.toFile "options.xml" (builtins.toXML optionsList);
|
||||||
|
pkgs.runCommand "options.xml" {
|
||||||
|
buildInputs = [pkgs.nix pkgs.fakeroot pkgs.jq];
|
||||||
|
inherit optionsExpr;
|
||||||
|
} ''
|
||||||
|
export NIX_LOG_DIR=$PWD
|
||||||
|
export NIX_STATE_DIR=$PWD
|
||||||
|
nix-instantiate --option sandbox false --readonly-mode --eval --expr "$optionsExpr" --xml --strict >$out
|
||||||
|
'';
|
||||||
|
|
||||||
|
optionsDocBook = runCommand "options-db.xml" {} ''
|
||||||
|
optionsXML=${optionsXML}
|
||||||
|
${pkgs.buildPackages.libxslt.bin}/bin/xsltproc \
|
||||||
|
--stringparam revision '${version}' \
|
||||||
|
--stringparam sourceUrl '${sourceUrl}' \
|
||||||
|
-o intermediate.xml ${./options-to-docbook.xsl} $optionsXML
|
||||||
|
${pkgs.buildPackages.libxslt.bin}/bin/xsltproc \
|
||||||
|
-o "$out" ${nixosManualPath "postprocess-option-descriptions.xsl"} intermediate.xml
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
in
|
||||||
|
|
||||||
|
recurseIntoAttrs rec {
|
||||||
|
compositionOptions = options {
|
||||||
|
moduleType = "composition";
|
||||||
|
description = "List of Arion composition-level options in JSON format";
|
||||||
|
optionsExpr = let
|
||||||
|
src = ../../src/nix;
|
||||||
|
in ''
|
||||||
|
let pkgs = import ${pkgs.path} {};
|
||||||
|
fixPaths = opt: opt // {
|
||||||
|
declarations = map (d: "src/nix" + (lib.strings.removePrefix (toString ${src}) (toString d))) opt.declarations;
|
||||||
|
};
|
||||||
|
inherit (pkgs) lib;
|
||||||
|
composition = import ${src}/eval-composition.nix { inherit pkgs; };
|
||||||
|
in map fixPaths (lib.filter (opt: opt.visible && !opt.internal) (lib.optionAttrSetToDocList composition.options))
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
serviceOptions = options {
|
||||||
|
moduleType = "service";
|
||||||
|
description = "List of Arion service-level options in JSON format";
|
||||||
|
optionsExpr = let
|
||||||
|
src = ../../src/nix;
|
||||||
|
in ''
|
||||||
|
let pkgs = import ${pkgs.path} {};
|
||||||
|
fixPaths = opt: opt // {
|
||||||
|
declarations = map (d: "src/nix" + (lib.strings.removePrefix (toString ${src}) (toString d))) opt.declarations;
|
||||||
|
};
|
||||||
|
inherit (pkgs) lib;
|
||||||
|
composition = pkgs.callPackage ${src}/eval-service.nix {} { modules = []; host = {}; };
|
||||||
|
in map fixPaths (lib.filter (opt: opt.visible && !opt.internal) (lib.optionAttrSetToDocList composition.options))
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
generatedDocBook = runCommand "generated-docbook" {} ''
|
||||||
|
mkdir $out
|
||||||
|
ln -s ${compositionOptions.optionsDocBook} $out/options-composition.xml
|
||||||
|
ln -s ${serviceOptions.optionsDocBook} $out/options-service.xml
|
||||||
|
'';
|
||||||
|
manual = stdenv.mkDerivation {
|
||||||
|
src = lib.sourceByRegex ./. [
|
||||||
|
"Makefile$"
|
||||||
|
".*\.asciidoc$"
|
||||||
|
".*\.xsl$"
|
||||||
|
".*\.css$"
|
||||||
|
"^manual.xml$"
|
||||||
|
"^manual.xml$"
|
||||||
|
];
|
||||||
|
name = "arion-manual";
|
||||||
|
version = version;
|
||||||
|
buildInputs = [
|
||||||
|
(pkgs.libxslt.bin or pkgs.libxslt)
|
||||||
|
pkgs.asciidoctor
|
||||||
|
];
|
||||||
|
XML_CATALOG_FILES = "${pkgs.docbook_xsl}/xml/xsl/docbook/catalog.xml";
|
||||||
|
inherit generatedDocBook;
|
||||||
|
configurePhase = ''
|
||||||
|
export docdir=$out/doc
|
||||||
|
'';
|
||||||
|
postPatch = ''
|
||||||
|
substituteInPlace manual.xml --subst-var version
|
||||||
|
'';
|
||||||
|
prePatch = ''
|
||||||
|
cp ${generatedDocBook}/* .
|
||||||
|
substituteInPlace options-service.xml \
|
||||||
|
--replace 'xml:id="appendix-configuration-options"' 'xml:id="appendix-service-options"' \
|
||||||
|
--replace '<title>Configuration Options</title>' '<title>Service Options</title>' \
|
||||||
|
--replace 'xml:id="configuration-variable-list"' 'xml:id="service-variable-list"' \
|
||||||
|
;
|
||||||
|
substituteInPlace options-composition.xml \
|
||||||
|
--replace 'xml:id="appendix-configuration-options"' 'xml:id="appendix-composition-options"' \
|
||||||
|
--replace '<title>Configuration Options</title>' '<title>Composition Options</title>' \
|
||||||
|
--replace 'xml:id="configuration-variable-list"' 'xml:id="composition-variable-list"' \
|
||||||
|
;
|
||||||
|
'';
|
||||||
|
shellHook = ''
|
||||||
|
live-build() {
|
||||||
|
patchPhase
|
||||||
|
inotifywait -e MODIFY -m -r . | while read; do
|
||||||
|
make
|
||||||
|
done
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
37
doc/manual/installation.asciidoc
Normal file
37
doc/manual/installation.asciidoc
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
= Installation
|
||||||
|
|
||||||
|
== Imperative installation, bleeding edge
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone git@github.com:hercules-ci/arion.git
|
||||||
|
cd arion
|
||||||
|
nix-env -iA arion -f .
|
||||||
|
```
|
||||||
|
|
||||||
|
// TODO: replace the above with something like below
|
||||||
|
////
|
||||||
|
|
||||||
|
== Not installing: use it in a project
|
||||||
|
|
||||||
|
TODO: describe: using nix-shell or in a script, building images as
|
||||||
|
part of nix-build, pinning, see also todomvc-nix.
|
||||||
|
|
||||||
|
== Mac or traditional Linux
|
||||||
|
|
||||||
|
```
|
||||||
|
nix-env -iA nixpkgs.arion
|
||||||
|
```
|
||||||
|
|
||||||
|
== NixOS
|
||||||
|
|
||||||
|
Add this module to your NixOS configuration:
|
||||||
|
|
||||||
|
```
|
||||||
|
{ pkgs, ... } {
|
||||||
|
virtualisation.docker.enable = true;
|
||||||
|
environment.systemPackages = [ pkgs.arion ];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
////
|
33
doc/manual/introduction.asciidoc
Normal file
33
doc/manual/introduction.asciidoc
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
= Introduction
|
||||||
|
|
||||||
|
Arion is a tool for building and running applications that
|
||||||
|
consist of multiple docker containers. It has special support
|
||||||
|
for docker images that are built with Nix, for a smooth
|
||||||
|
development experience and improved performance.
|
||||||
|
|
||||||
|
It is built on top of https://docs.docker.com/compose/overview/[Docker
|
||||||
|
Compose], which implements the container orchestration functionality.
|
||||||
|
|
||||||
|
Instead of configuring the compositions in YAML files like
|
||||||
|
`docker-compose.yaml`, Arion uses the https://nixos.org/nix/[Nix]
|
||||||
|
language to declare the compositions. Because of this, Arion gives you
|
||||||
|
the ability to declare your deployments, configuration and packaging
|
||||||
|
in the same language. By replacing multiple tools with a single
|
||||||
|
language, you decrease your mental load and you can more easily
|
||||||
|
refactor and maintain your configurations.
|
||||||
|
|
||||||
|
Although Arion can be used as a Docker Compose with an improved
|
||||||
|
configuration front end, there is more to be gained from integrating
|
||||||
|
with Nix. In particular, the more structured approach of Nix compared
|
||||||
|
to Dockerfiles allows the following:
|
||||||
|
|
||||||
|
* Build components of your image in _parallel, automatically_.
|
||||||
|
* Share packages between images, regardless of the order they were
|
||||||
|
added.
|
||||||
|
* Improve performance by _skipping_ container
|
||||||
|
image creation.
|
||||||
|
* Work with _structured data_ instead of strings,
|
||||||
|
templates and a multitude of expression languages.
|
||||||
|
* Refactor across deployments, configuration and
|
||||||
|
packaging.
|
3
doc/manual/live-build
Executable file
3
doc/manual/live-build
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env nix-shell
|
||||||
|
#!nix-shell -A manual
|
||||||
|
#!nix-shell --run live-build
|
25
doc/manual/manual.xml
Normal file
25
doc/manual/manual.xml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<book xmlns="http://docbook.org/ns/docbook"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||||
|
|
||||||
|
<info>
|
||||||
|
|
||||||
|
<title>Arion Manual</title>
|
||||||
|
<subtitle>Version none</subtitle>
|
||||||
|
|
||||||
|
<author>
|
||||||
|
<affiliation>
|
||||||
|
<orgname>Hercules Labs and other Arion contributors</orgname>
|
||||||
|
</affiliation>
|
||||||
|
<contrib>Author</contrib>
|
||||||
|
</author>
|
||||||
|
|
||||||
|
</info>
|
||||||
|
|
||||||
|
<xi:include href="introduction.xml" xpointer="xpointer(/article)" />
|
||||||
|
<xi:include href="installation.xml" xpointer="xpointer(/article)" />
|
||||||
|
|
||||||
|
<xi:include href="options-composition.xml" />
|
||||||
|
<xi:include href="options-service.xml" />
|
||||||
|
|
||||||
|
</book>
|
224
doc/manual/options-to-docbook.xsl
Normal file
224
doc/manual/options-to-docbook.xsl
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
|
||||||
|
<xsl:stylesheet version="1.0"
|
||||||
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
xmlns:str="http://exslt.org/strings"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:nixos="tag:nixos.org"
|
||||||
|
xmlns="http://docbook.org/ns/docbook"
|
||||||
|
extension-element-prefixes="str"
|
||||||
|
>
|
||||||
|
|
||||||
|
<xsl:output method='xml' encoding="UTF-8" />
|
||||||
|
|
||||||
|
<xsl:param name="revision" />
|
||||||
|
<xsl:param name="program" />
|
||||||
|
<xsl:param name="sourceUrl" />
|
||||||
|
<xsl:param name="nixPathKey" />
|
||||||
|
|
||||||
|
<xsl:template match="/expr/list">
|
||||||
|
<appendix xml:id="appendix-configuration-options">
|
||||||
|
<title>Configuration Options</title>
|
||||||
|
<variablelist xml:id="configuration-variable-list">
|
||||||
|
<xsl:for-each select="attrs">
|
||||||
|
<xsl:variable name="id" select="concat('opt-', str:replace(str:replace(str:replace(str:replace(attr[@name = 'name']/string/@value, '*', '_'), '<', '_'), '>', '_'), '?', '_'))" />
|
||||||
|
<varlistentry>
|
||||||
|
<term xlink:href="#{$id}">
|
||||||
|
<xsl:attribute name="xml:id"><xsl:value-of select="$id"/></xsl:attribute>
|
||||||
|
<option>
|
||||||
|
<xsl:value-of select="attr[@name = 'name']/string/@value" />
|
||||||
|
</option>
|
||||||
|
</term>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
|
||||||
|
<nixos:option-description>
|
||||||
|
<para>
|
||||||
|
<xsl:value-of disable-output-escaping="yes"
|
||||||
|
select="attr[@name = 'description']/string/@value" />
|
||||||
|
</para>
|
||||||
|
</nixos:option-description>
|
||||||
|
|
||||||
|
<xsl:if test="attr[@name = 'type']">
|
||||||
|
<para>
|
||||||
|
<emphasis>Type:</emphasis>
|
||||||
|
<xsl:text> </xsl:text>
|
||||||
|
<xsl:value-of select="attr[@name = 'type']/string/@value"/>
|
||||||
|
<xsl:if test="attr[@name = 'readOnly']/bool/@value = 'true'">
|
||||||
|
<xsl:text> </xsl:text>
|
||||||
|
<emphasis>(read only)</emphasis>
|
||||||
|
</xsl:if>
|
||||||
|
</para>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<xsl:if test="attr[@name = 'default']">
|
||||||
|
<para>
|
||||||
|
<emphasis>Default:</emphasis>
|
||||||
|
<xsl:text> </xsl:text>
|
||||||
|
<xsl:apply-templates select="attr[@name = 'default']" mode="top" />
|
||||||
|
</para>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<xsl:if test="attr[@name = 'example']">
|
||||||
|
<para>
|
||||||
|
<emphasis>Example:</emphasis>
|
||||||
|
<xsl:text> </xsl:text>
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="attr[@name = 'example']/attrs[attr[@name = '_type' and string[@value = 'literalExample']]]">
|
||||||
|
<programlisting><xsl:value-of select="attr[@name = 'example']/attrs/attr[@name = 'text']/string/@value" /></programlisting>
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:apply-templates select="attr[@name = 'example']" mode="top" />
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</para>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<xsl:if test="attr[@name = 'relatedPackages']">
|
||||||
|
<para>
|
||||||
|
<emphasis>Related packages:</emphasis>
|
||||||
|
<xsl:text> </xsl:text>
|
||||||
|
<xsl:value-of disable-output-escaping="yes"
|
||||||
|
select="attr[@name = 'relatedPackages']/string/@value" />
|
||||||
|
</para>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<xsl:if test="count(attr[@name = 'declarations']/list/*) != 0">
|
||||||
|
<para>
|
||||||
|
<emphasis>Declared by:</emphasis>
|
||||||
|
</para>
|
||||||
|
<xsl:apply-templates select="attr[@name = 'declarations']" />
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<xsl:if test="count(attr[@name = 'definitions']/list/*) != 0">
|
||||||
|
<para>
|
||||||
|
<emphasis>Defined by:</emphasis>
|
||||||
|
</para>
|
||||||
|
<xsl:apply-templates select="attr[@name = 'definitions']" />
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
</xsl:for-each>
|
||||||
|
|
||||||
|
</variablelist>
|
||||||
|
</appendix>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="*" mode="top">
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="string[contains(@value, '
')]">
|
||||||
|
<programlisting>
|
||||||
|
<xsl:text>''
|
||||||
|
</xsl:text><xsl:value-of select='str:replace(string/@value, "${", "''${")' /><xsl:text>''</xsl:text></programlisting>
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:otherwise>
|
||||||
|
<literal><xsl:apply-templates /></literal>
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="null">
|
||||||
|
<xsl:text>null</xsl:text>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="string">
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="(contains(@value, '"') or contains(@value, '\')) and not(contains(@value, '
'))">
|
||||||
|
<xsl:text>''</xsl:text><xsl:value-of select='str:replace(@value, "${", "''${")' /><xsl:text>''</xsl:text>
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:text>"</xsl:text><xsl:value-of select="str:replace(str:replace(str:replace(str:replace(@value, '\', '\\'), '"', '\"'), '
', '\n'), '$', '\$')" /><xsl:text>"</xsl:text>
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="int">
|
||||||
|
<xsl:value-of select="@value" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="bool[@value = 'true']">
|
||||||
|
<xsl:text>true</xsl:text>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="bool[@value = 'false']">
|
||||||
|
<xsl:text>false</xsl:text>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="list">
|
||||||
|
[
|
||||||
|
<xsl:for-each select="*">
|
||||||
|
<xsl:apply-templates select="." />
|
||||||
|
<xsl:text> </xsl:text>
|
||||||
|
</xsl:for-each>
|
||||||
|
]
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="attrs[attr[@name = '_type' and string[@value = 'literalExample']]]">
|
||||||
|
<xsl:value-of select="attr[@name = 'text']/string/@value" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="attrs">
|
||||||
|
{
|
||||||
|
<xsl:for-each select="attr">
|
||||||
|
<xsl:value-of select="@name" />
|
||||||
|
<xsl:text> = </xsl:text>
|
||||||
|
<xsl:apply-templates select="*" /><xsl:text>; </xsl:text>
|
||||||
|
</xsl:for-each>
|
||||||
|
}
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="derivation">
|
||||||
|
<replaceable>(build of <xsl:value-of select="attr[@name = 'name']/string/@value" />)</replaceable>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="attr[@name = 'declarations' or @name = 'definitions']">
|
||||||
|
<simplelist>
|
||||||
|
<xsl:for-each select="list/string">
|
||||||
|
<member><filename>
|
||||||
|
<!-- Hyperlink the filename either to the NixOS Subversion
|
||||||
|
repository (if it’s a module and we have a revision number),
|
||||||
|
or to the local filesystem. -->
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="not(starts-with(@value, '/'))">
|
||||||
|
<xsl:attribute name="xlink:href"><xsl:value-of select="$sourceUrl"/>/<xsl:value-of select="@value"/></xsl:attribute>
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:attribute name="xlink:href">file://<xsl:value-of select="@value"/></xsl:attribute>
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
<!-- Print the filename and make it user-friendly by replacing the
|
||||||
|
/nix/store/<hash> prefix by the default location of nixos
|
||||||
|
sources. -->
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="$nixPathKey != ''">
|
||||||
|
<<xsl:value-of select="$nixPathKey"/>/<xsl:value-of select="@value"/>>
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:value-of select="@value" />
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</filename></member>
|
||||||
|
</xsl:for-each>
|
||||||
|
</simplelist>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:template match="function">
|
||||||
|
<xsl:text>λ</xsl:text>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
159
doc/manual/style.css
Normal file
159
doc/manual/style.css
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
|
||||||
|
hr { color: #ddd; margin-top: 3ex; }
|
||||||
|
h1, h2, h3, h4 { font-weight: bold; }
|
||||||
|
h1 { font-size: 200%; margin-top: 5ex; }
|
||||||
|
h2 { font-size: 160%; margin-top: 4ex; }
|
||||||
|
h3,h4 { font-size: 120%; margin-top: 3ex; }
|
||||||
|
|
||||||
|
/* From Semantic UI */
|
||||||
|
body {
|
||||||
|
font-family: Lato,'Helvetica Neue',Arial,Helvetica,sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.4285em;
|
||||||
|
color: rgba(0,0,0,.87);
|
||||||
|
}
|
||||||
|
|
||||||
|
code.literal {
|
||||||
|
background-color: #f7f7f7;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
background-color:transparent;
|
||||||
|
-webkit-text-decoration-skip:objects
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color:#4183c4;
|
||||||
|
text-decoration:none
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
color:#1e70bf;
|
||||||
|
text-decoration:none
|
||||||
|
}
|
||||||
|
::-webkit-selection {
|
||||||
|
background-color:#cce2ff;
|
||||||
|
color:rgba(0,0,0,.87)
|
||||||
|
}
|
||||||
|
::-moz-selection {
|
||||||
|
background-color:#cce2ff;
|
||||||
|
color:rgba(0,0,0,.87)
|
||||||
|
}
|
||||||
|
::selection {
|
||||||
|
background-color:#cce2ff;
|
||||||
|
color:rgba(0,0,0,.87)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* toc menu */
|
||||||
|
@media screen and (min-width: 60em) {
|
||||||
|
body {
|
||||||
|
margin-left: 16.5em;
|
||||||
|
}
|
||||||
|
div.toc {
|
||||||
|
position: fixed;
|
||||||
|
top: 0pt;
|
||||||
|
left: 1em;
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
width: 15.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media screen and (min-width: 90em) {
|
||||||
|
div.toc {
|
||||||
|
left: 5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* hide per chapter toc */
|
||||||
|
div.chapter div.toc {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* From Nixpkgs: */
|
||||||
|
|
||||||
|
div.book
|
||||||
|
{
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.book > div
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* based on https://medium.com/@zkareemz/golden-ratio-62b3b6d4282a
|
||||||
|
* we do 70 characters per line to fit code listings better
|
||||||
|
* 70 * (font-size / 1.618)
|
||||||
|
* expression for emacs:
|
||||||
|
* (* 70 (/ 1 1.618))
|
||||||
|
*/
|
||||||
|
max-width: 43.2em;
|
||||||
|
text-align: left;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
Special elements:
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
.term
|
||||||
|
{
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
div.variablelist dd p, div.glosslist dd p
|
||||||
|
{
|
||||||
|
margin-top: 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.variablelist dd, div.glosslist dd
|
||||||
|
{
|
||||||
|
margin-left: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.glosslist dt
|
||||||
|
{
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.varname
|
||||||
|
{
|
||||||
|
color: #004000;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.command strong
|
||||||
|
{
|
||||||
|
font-weight: normal;
|
||||||
|
color: #004000;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.calloutlist table
|
||||||
|
{
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
table
|
||||||
|
{
|
||||||
|
border-collapse: collapse;
|
||||||
|
box-shadow: 0.4em 0.4em 0.5em #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.simplelist
|
||||||
|
{
|
||||||
|
text-align: left;
|
||||||
|
color: #005aa0;
|
||||||
|
border: 0;
|
||||||
|
padding: 5px;
|
||||||
|
background: #fffff5;
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: italic;
|
||||||
|
box-shadow: none;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.navheader table, div.navfooter table {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.affiliation
|
||||||
|
{
|
||||||
|
font-style: italic;
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
self: super: {
|
self: super: {
|
||||||
arion = super.callPackage ../arion.nix {};
|
arion = super.callPackage ../arion.nix {};
|
||||||
tests = super.callPackage ../tests {};
|
tests = super.callPackage ../tests {};
|
||||||
|
doc = super.callPackage ../doc {};
|
||||||
}
|
}
|
||||||
|
25
src/nix/eval-service.nix
Normal file
25
src/nix/eval-service.nix
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{ lib, pkgs, ... }:
|
||||||
|
|
||||||
|
{ modules, host }:
|
||||||
|
let
|
||||||
|
composite = lib.evalModules {
|
||||||
|
check = true;
|
||||||
|
modules = builtinModules ++ modules;
|
||||||
|
};
|
||||||
|
|
||||||
|
builtinModules = [
|
||||||
|
argsModule
|
||||||
|
./modules/service/docker-compose-service.nix
|
||||||
|
./modules/service/host-store.nix
|
||||||
|
./modules/service/host.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
argsModule = {
|
||||||
|
_file = ./docker-compose.nix;
|
||||||
|
key = ./docker-compose.nix;
|
||||||
|
config._module.args.pkgs = lib.mkForce pkgs;
|
||||||
|
config.host = host;
|
||||||
|
};
|
||||||
|
|
||||||
|
in
|
||||||
|
composite
|
@ -10,47 +10,28 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
{ pkgs, lib, config, ... }:
|
{ pkgs, lib, config, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
evalService = name: modules:
|
evalService = name: modules: (pkgs.callPackage ../../eval-service.nix {} { inherit modules; inherit (config) host; }).config.build.service;
|
||||||
let
|
|
||||||
composite = lib.evalModules {
|
|
||||||
check = true;
|
|
||||||
modules = builtinModules ++ modules;
|
|
||||||
};
|
|
||||||
|
|
||||||
builtinModules = [
|
|
||||||
argsModule
|
|
||||||
../service/docker-compose-service.nix
|
|
||||||
../service/host-store.nix
|
|
||||||
../service/host.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
argsModule = {
|
|
||||||
_file = ./docker-compose.nix;
|
|
||||||
key = ./docker-compose.nix;
|
|
||||||
config._module.args.pkgs = lib.mkForce pkgs;
|
|
||||||
config.host = config.host;
|
|
||||||
};
|
|
||||||
|
|
||||||
in
|
|
||||||
composite.config.build.service;
|
|
||||||
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options = {
|
options = {
|
||||||
build.dockerComposeYaml = lib.mkOption {
|
build.dockerComposeYaml = lib.mkOption {
|
||||||
type = lib.types.package;
|
type = lib.types.package;
|
||||||
|
description = "A derivation that produces a docker-compose.yaml file for this composition.";
|
||||||
};
|
};
|
||||||
build.dockerComposeYamlText = lib.mkOption {
|
build.dockerComposeYamlText = lib.mkOption {
|
||||||
type = lib.types.string;
|
type = lib.types.string;
|
||||||
|
description = "The text of build.dockerComposeYaml.";
|
||||||
};
|
};
|
||||||
docker-compose.raw = lib.mkOption {
|
docker-compose.raw = lib.mkOption {
|
||||||
type = lib.types.attrs;
|
type = lib.types.attrs;
|
||||||
|
description = "Nested attribute set that will be turned into the docker-compose.yaml file, using Nix's toJSON builtin.";
|
||||||
};
|
};
|
||||||
docker-compose.services = lib.mkOption {
|
docker-compose.services = lib.mkOption {
|
||||||
default = {};
|
default = {};
|
||||||
type = with lib.types; attrsOf (coercedTo unspecified (a: [a]) (listOf unspecified));
|
type = with lib.types; attrsOf (coercedTo unspecified (a: [a]) (listOf unspecified));
|
||||||
|
description = "A attribute set of service configurations. A service specifies how to run an image. Each of these service configurations is specified using modules whose options are described in the Service Options section.";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
config = {
|
config = {
|
||||||
|
@ -8,8 +8,9 @@
|
|||||||
description = ''
|
description = ''
|
||||||
The numeric user id (UID) of the user running arion.
|
The numeric user id (UID) of the user running arion.
|
||||||
|
|
||||||
Assuming this user id is helpful when dealing with the user's
|
This lets you to write modules that interact with the host
|
||||||
files, mounted into the container as a volume.
|
user's files, which is helpful for local development, but not
|
||||||
|
intended for production-like deployment scenarios.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -9,79 +9,116 @@
|
|||||||
let
|
let
|
||||||
inherit (lib) mkOption types;
|
inherit (lib) mkOption types;
|
||||||
inherit (types) listOf nullOr attrsOf string either int bool;
|
inherit (types) listOf nullOr attrsOf string either int bool;
|
||||||
|
|
||||||
|
dockerComposeRef = fragment:
|
||||||
|
''See <link xlink:href="https://docs.docker.com/compose/compose-file/#${fragment}">Docker Compose#${fragment}</link>'';
|
||||||
|
dockerComposeKitchenSink = ''
|
||||||
|
Analogous to the <code>docker run</code> counterpart.
|
||||||
|
|
||||||
|
${dockerComposeRef "domainname-hostname-ipc-mac_address-privileged-read_only-shm_size-stdin_open-tty-user-working_dir"}
|
||||||
|
'';
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options = {
|
options = {
|
||||||
service.volumes = mkOption {
|
service.volumes = mkOption {
|
||||||
type = listOf types.unspecified;
|
type = listOf types.unspecified;
|
||||||
default = [];
|
default = [];
|
||||||
|
description = "";
|
||||||
};
|
};
|
||||||
service.build.context = mkOption {
|
service.build.context = mkOption {
|
||||||
type = nullOr string;
|
type = nullOr string;
|
||||||
default = null;
|
default = null;
|
||||||
|
description = ''
|
||||||
|
Locates a Dockerfile to use for creating an image to use in this service.
|
||||||
|
|
||||||
|
${dockerComposeRef "context"}
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
service.hostname = mkOption {
|
service.hostname = mkOption {
|
||||||
type = nullOr string;
|
type = nullOr string;
|
||||||
default = null;
|
default = null;
|
||||||
|
description = dockerComposeKitchenSink;
|
||||||
};
|
};
|
||||||
service.environment = mkOption {
|
service.environment = mkOption {
|
||||||
type = attrsOf (either string int);
|
type = attrsOf (either string int);
|
||||||
default = {};
|
default = {};
|
||||||
|
description = dockerComposeRef "environment";
|
||||||
};
|
};
|
||||||
service.image = mkOption {
|
service.image = mkOption {
|
||||||
type = string;
|
type = string;
|
||||||
|
description = dockerComposeRef "image";
|
||||||
};
|
};
|
||||||
service.command = mkOption {
|
service.command = mkOption {
|
||||||
type = nullOr types.unspecified;
|
type = nullOr types.unspecified;
|
||||||
default = null;
|
default = null;
|
||||||
|
description = dockerComposeRef "command";
|
||||||
};
|
};
|
||||||
service.depends_on = mkOption {
|
service.depends_on = mkOption {
|
||||||
type = listOf string;
|
type = listOf string;
|
||||||
default = [];
|
default = [];
|
||||||
|
description = dockerComposeRef "depends_on";
|
||||||
};
|
};
|
||||||
service.links = mkOption {
|
service.links = mkOption {
|
||||||
type = listOf string;
|
type = listOf string;
|
||||||
default = [];
|
default = [];
|
||||||
|
description = dockerComposeRef "links";
|
||||||
};
|
};
|
||||||
service.external_links = mkOption {
|
service.external_links = mkOption {
|
||||||
type = listOf string;
|
type = listOf string;
|
||||||
default = [];
|
default = [];
|
||||||
|
description = dockerComposeRef "external_links";
|
||||||
};
|
};
|
||||||
service.extra_hosts = mkOption {
|
service.extra_hosts = mkOption {
|
||||||
type = listOf string;
|
type = listOf string;
|
||||||
default = [];
|
default = [];
|
||||||
|
description = dockerComposeRef "extra_hosts";
|
||||||
};
|
};
|
||||||
service.working_dir = mkOption {
|
service.working_dir = mkOption {
|
||||||
type = nullOr string;
|
type = nullOr string;
|
||||||
default = null;
|
default = null;
|
||||||
|
description = dockerComposeKitchenSink;
|
||||||
};
|
};
|
||||||
service.privileged = mkOption {
|
service.privileged = mkOption {
|
||||||
type = nullOr bool;
|
type = nullOr bool;
|
||||||
default = null;
|
default = null;
|
||||||
|
description = dockerComposeKitchenSink;
|
||||||
};
|
};
|
||||||
service.entrypoint = mkOption {
|
service.entrypoint = mkOption {
|
||||||
type = nullOr string;
|
type = nullOr string;
|
||||||
default = null;
|
default = null;
|
||||||
|
description = dockerComposeRef "entrypoint";
|
||||||
};
|
};
|
||||||
service.restart = mkOption {
|
service.restart = mkOption {
|
||||||
type = nullOr string;
|
type = nullOr string;
|
||||||
default = null;
|
default = null;
|
||||||
|
description = dockerComposeRef "restart";
|
||||||
};
|
};
|
||||||
service.ports = mkOption {
|
service.ports = mkOption {
|
||||||
type = listOf types.unspecified;
|
type = listOf types.unspecified;
|
||||||
default = [];
|
default = [];
|
||||||
description = ''
|
description = ''
|
||||||
Expose ports on host. "host:container" or structured.
|
Expose ports on host. "host:container" or structured.
|
||||||
See https://docs.docker.com/compose/compose-file/#ports
|
|
||||||
|
${dockerComposeRef "ports"}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
service.expose = mkOption {
|
service.expose = mkOption {
|
||||||
type = listOf string;
|
type = listOf string;
|
||||||
default = [];
|
default = [];
|
||||||
|
description = dockerComposeRef "expose";
|
||||||
};
|
};
|
||||||
|
|
||||||
build.service = mkOption {
|
build.service = mkOption {
|
||||||
type = attrsOf types.unspecified;
|
type = attrsOf types.unspecified;
|
||||||
|
description = ''
|
||||||
|
Raw input for the service in <code>docker-compose.yaml</code>.
|
||||||
|
|
||||||
|
You should not need to use this option. If anything is
|
||||||
|
missing, please contribute the missing option.
|
||||||
|
|
||||||
|
This option is user accessible because it may serve as an
|
||||||
|
escape hatch for some.
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user