Merge 'staging' into multiple-outputs

Conflicts:
	pkgs/applications/audio/flac/default.nix
	pkgs/build-support/gcc-wrapper/builder.sh
	pkgs/development/libraries/apr-util/default.nix
	pkgs/development/libraries/apr/default.nix
	pkgs/development/libraries/atk/default.nix
	pkgs/development/libraries/freetype/default.nix
	pkgs/development/libraries/gdk-pixbuf/default.nix
	pkgs/development/libraries/glib/default.nix
	pkgs/development/libraries/glibc/2.17/builder.sh
	pkgs/development/libraries/glibc/2.17/locales.nix
	pkgs/development/libraries/libjpeg/default.nix
	pkgs/development/libraries/libogg/default.nix
	pkgs/development/libraries/libsamplerate/default.nix
	pkgs/development/libraries/libtiff/default.nix
	pkgs/development/libraries/libvorbis/default.nix
	pkgs/development/libraries/mesa/default.nix
	pkgs/development/libraries/pango/default.nix
	pkgs/development/web/nodejs/default.nix
	pkgs/os-specific/linux/pam/default.nix
	pkgs/os-specific/linux/systemd/default.nix
	pkgs/stdenv/generic/setup.sh
	pkgs/stdenv/linux/default.nix
	pkgs/top-level/all-packages.nix
	pkgs/top-level/release-small.nix
This commit is contained in:
Vladimír Čunát 2014-08-23 16:04:53 +02:00
commit 96cec2a7bd
6628 changed files with 165219 additions and 65293 deletions

11
.gitignore vendored
View File

@ -3,8 +3,11 @@
.*.swp .*.swp
.*.swo .*.swo
result result
doc/NEWS.html result-*
doc/NEWS.txt /doc/NEWS.html
doc/manual.html /doc/NEWS.txt
doc/manual.pdf /doc/manual.html
/doc/manual.pdf
.version-suffix .version-suffix
.DS_Store

View File

@ -1 +1 @@
13.10 14.10

10
README.md Normal file
View File

@ -0,0 +1,10 @@
Nixpkgs is a collection of packages for [Nix](http://nixos.org/nix/) package
manager. Nixpkgs also includes [NixOS](http://nixos.org/nixos/) linux distribution source code.
* [NixOS installation instructions](http://nixos.org/nixos/manual/#ch-installation)
* [Manual (How to write packages for Nix)](http://nixos.org/nixpkgs/manual/)
* [Manual (NixOS)](http://nixos.org/nixos/manual/)
* [Continuous build](http://hydra.nixos.org/jobset/nixos/trunk-combined)
* [Tests](http://hydra.nixos.org/job/nixos/trunk-combined/tested#tabs-constituents)
* [Mailing list](http://lists.science.uu.nl/mailman/listinfo/nix-dev)
* [IRC - #nixos on freenode.net](irc://irc.freenode.net/#nixos)

View File

@ -1 +1,7 @@
import ./pkgs/top-level/all-packages.nix if ! builtins ? nixVersion || builtins.compareVersions "1.6" builtins.nixVersion == 1 then
abort "This version of Nixpkgs requires Nix >= 1.6, please upgrade!"
else
import ./pkgs/top-level/all-packages.nix

View File

@ -21,18 +21,18 @@ all: NEWS.html NEWS.txt manual.html manual.pdf
NEWS.html: release-notes.xml NEWS.html: release-notes.xml
$(XSLTPROC) --nonet --xinclude --output $@ $(NEWS_OPTS) \ $(XSLTPROC) --nonet --xinclude --output $@ $(NEWS_OPTS) \
$(docbookxsl)/html/docbook.xsl release-notes.xml $(docbookxsl)/xhtml/docbook.xsl release-notes.xml
NEWS.txt: release-notes.xml NEWS.txt: release-notes.xml
$(XSLTPROC) --nonet --xinclude quote-literals.xsl release-notes.xml | \ $(XSLTPROC) --nonet --xinclude quote-literals.xsl release-notes.xml | \
$(XSLTPROC) --nonet --output $@.tmp.html $(NEWS_OPTS) \ $(XSLTPROC) --nonet --output $@.tmp.html $(NEWS_OPTS) \
$(docbookxsl)/html/docbook.xsl - $(docbookxsl)/xhtml/docbook.xsl -
LANG=en_US w3m -dump $@.tmp.html > $@ LANG=en_US w3m -dump $@.tmp.html > $@
rm $@.tmp.html rm $@.tmp.html
manual.html: *.xml manual.html: *.xml
$(XSLTPROC) --nonet --xinclude --output manual.html \ $(XSLTPROC) --nonet --xinclude --output manual.html \
$(docbookxsl)/html/docbook.xsl manual.xml $(docbookxsl)/xhtml/docbook.xsl manual.xml
manual.pdf: *.xml manual.pdf: *.xml
$(dblatex) \ $(dblatex) \

View File

@ -235,12 +235,7 @@ Most of the time, these are the same. For instance, the package
bound to the variable name <varname>e2fsprogs</varname> in bound to the variable name <varname>e2fsprogs</varname> in
<filename>all-packages.nix</filename>, and the Nix expression is in <filename>all-packages.nix</filename>, and the Nix expression is in
<filename>pkgs/os-specific/linux/e2fsprogs/default.nix</filename>. <filename>pkgs/os-specific/linux/e2fsprogs/default.nix</filename>.
However, identifiers in the Nix language dont allow certain </para>
characters (e.g. dashes), so sometimes a different variable name
should be used. For instance, the
<literal>module-init-tools</literal> package is bound to the
<literal>module_init_tools</literal> variable in
<filename>all-packages.nix</filename>.</para>
<para>There are a few naming guidelines: <para>There are a few naming guidelines:
@ -261,17 +256,20 @@ should be used. For instance, the
a package named <literal>hello-svn</literal> by a package named <literal>hello-svn</literal> by
<command>nix-env</command>.</para></listitem> <command>nix-env</command>.</para></listitem>
<listitem><para>Dashes in the package name should be changed to <listitem><para>Dashes in the package name should be preserved
underscores in variable names, rather than to camel case — e.g., in new variable names, rather than converted to underscores
<varname>module_init_tools</varname> instead of (which was convention up to around 2013 and most names
<varname>moduleInitTools</varname>.</para></listitem> still have underscores instead of dashes) — e.g.,
<varname>http-parser</varname> instead of
<varname>http_parser</varname>.</para></listitem>
<listitem><para>If there are multiple versions of a package, this <listitem><para>If there are multiple versions of a package, this
should be reflected in the variable names in should be reflected in the variable names in
<filename>all-packages.nix</filename>, <filename>all-packages.nix</filename>,
e.g. <varname>hello_0_3</varname> and <varname>hello_0_4</varname>. e.g. <varname>json-c-0-9</varname> and <varname>json-c-0-11</varname>.
If there is an obvious “default” version, make an attribute like If there is an obvious “default” version, make an attribute like
<literal>hello = hello_0_4;</literal>.</para></listitem> <literal>json-c = json-c-0-9;</literal>.
See also <xref linkend="sec-versioning" /></para></listitem>
</itemizedlist> </itemizedlist>
@ -288,7 +286,7 @@ dashes between words — not in camel case. For instance, it should be
<filename>allPackages.nix</filename> or <filename>allPackages.nix</filename> or
<filename>AllPackages.nix</filename>.</para> <filename>AllPackages.nix</filename>.</para>
<section><title>Hierachy</title> <section><title>Hierarchy</title>
<para>Each package should be stored in its own directory somewhere in <para>Each package should be stored in its own directory somewhere in
the <filename>pkgs/</filename> tree, i.e. in the <filename>pkgs/</filename> tree, i.e. in
@ -567,7 +565,7 @@ splitting up an existing category.</para>
</section> </section>
<section><title>Versioning</title> <section xml:id="sec-versioning"><title>Versioning</title>
<para>Because every version of a package in Nixpkgs creates a <para>Because every version of a package in Nixpkgs creates a
potential maintenance burden, old versions of a package should not be potential maintenance burden, old versions of a package should not be

21
doc/contributing.xml Normal file
View File

@ -0,0 +1,21 @@
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xml:id="chap-contributing">
<title>Contributing</title>
<para>If you make modifications to the manual, it's important to build the manual before contributing:</para>
<orderedlist>
<listitem><para><command>$ git clone git://github.com/NixOS/nixpkgs.git</command></para></listitem>
<listitem><para><command>$ cd nixpkgs/pkgs/top-level</command></para></listitem>
<listitem><para><command>$ nix-build -A tarball release.nix</command></para></listitem>
<listitem><para>Inside the built derivation you shall see <literal>manual/index.html</literal> file.</para></listitem>
</orderedlist>
</chapter>

View File

@ -108,7 +108,7 @@ a <varname>preConfigure</varname> hook to generate a configuration
file used by <filename>Makefile.PL</filename>: file used by <filename>Makefile.PL</filename>:
<programlisting> <programlisting>
{buildPerlPackage, fetchurl, db4}: {buildPerlPackage, fetchurl, db}:
buildPerlPackage rec { buildPerlPackage rec {
name = "BerkeleyDB-0.36"; name = "BerkeleyDB-0.36";
@ -119,8 +119,8 @@ buildPerlPackage rec {
}; };
preConfigure = '' preConfigure = ''
echo "LIB = ${db4}/lib" > config.in echo "LIB = ${db}/lib" > config.in
echo "INCLUDE = ${db4}/include" >> config.in echo "INCLUDE = ${db}/include" >> config.in
''; '';
} }
</programlisting> </programlisting>
@ -233,10 +233,83 @@ twisted = buildPythonPackage {
</section> </section>
<section><title>Java</title> <section xml:id="ssec-language-java"><title>Java</title>
<para>Java packages should install JAR files in <para>Ant-based Java packages are typically built from source as follows:
<filename>$out/lib/java</filename>.</para>
<programlisting>
stdenv.mkDerivation {
name = "...";
src = fetchurl { ... };
buildInputs = [ jdk ant ];
buildPhase = "ant";
}
</programlisting>
Note that <varname>jdk</varname> is an alias for the OpenJDK.</para>
<para>JAR files that are intended to be used by other packages should
be installed in <filename>$out/share/java</filename>. The OpenJDK has
a stdenv setup hook that adds any JARs in the
<filename>share/java</filename> directories of the build inputs to the
<envar>CLASSPATH</envar> environment variable. For instance, if the
package <literal>libfoo</literal> installs a JAR named
<filename>foo.jar</filename> in its <filename>share/java</filename>
directory, and another package declares the attribute
<programlisting>
buildInputs = [ jdk libfoo ];
</programlisting>
then <envar>CLASSPATH</envar> will be set to
<filename>/nix/store/...-libfoo/share/java/foo.jar</filename>.</para>
<para>Private JARs
should be installed in a location like
<filename>$out/share/<replaceable>package-name</replaceable></filename>.</para>
<para>If your Java package provides a program, you need to generate a
wrapper script to run it using the OpenJRE. You can use
<literal>makeWrapper</literal> for this:
<programlisting>
buildInputs = [ makeWrapper ];
installPhase =
''
mkdir -p $out/bin
makeWrapper ${jre}/bin/java $out/bin/foo \
--add-flags "-cp $out/share/java/foo.jar org.foo.Main"
'';
</programlisting>
Note the use of <literal>jre</literal>, which is the part of the
OpenJDK package that contains the Java Runtime Environment. By using
<literal>${jre}/bin/java</literal> instead of
<literal>${jdk}/bin/java</literal>, you prevent your package from
depending on the JDK at runtime.</para>
<para>It is possible to use a different Java compiler than
<command>javac</command> from the OpenJDK. For instance, to use the
Eclipse Java Compiler:
<programlisting>
buildInputs = [ jre ant ecj ];
</programlisting>
(Note that here you dont need the full JDK as an input, but just the
JRE.) The ECJ has a stdenv setup hook that sets some environment
variables to cause Ant to use ECJ, but this doesnt work with all Ant
files. Similarly, you can use the GNU Java Compiler:
<programlisting>
buildInputs = [ gcj ant ];
</programlisting>
Here, Ant will automatically use <command>gij</command> (the GNU Java
Runtime) instead of the OpenJRE.</para>
</section> </section>

View File

@ -32,6 +32,7 @@
<xi:include href="language-support.xml" /> <xi:include href="language-support.xml" />
<xi:include href="package-notes.xml" /> <xi:include href="package-notes.xml" />
<xi:include href="coding-conventions.xml" /> <xi:include href="coding-conventions.xml" />
<xi:include href="contributing.xml" />
</book> </book>

View File

@ -17,7 +17,9 @@ meta = {
It is fully customizable. It is fully customizable.
''; '';
homepage = http://www.gnu.org/software/hello/manual/; homepage = http://www.gnu.org/software/hello/manual/;
license = "GPLv3+"; license = stdenv.lib.licenses.gpl3Plus;
maintainers = [ stdenv.lib.maintainers.eelco ];
platforms = stdenv.lib.platforms.all;
}; };
</programlisting> </programlisting>
@ -31,16 +33,42 @@ the package. The value of a meta-attribute must a string.</para>
command-line using <command>nix-env</command>: command-line using <command>nix-env</command>:
<screen> <screen>
$ nix-env -qa hello --meta --xml $ nix-env -qa hello --meta --json
&lt;?xml version='1.0' encoding='utf-8'?> {
&lt;items> "hello": {
&lt;item attrPath="hello" name="hello-2.3" system="i686-linux"> "meta": {
&lt;meta name="description" value="A program that produces a familiar, friendly greeting" /> "description": "A program that produces a familiar, friendly greeting",
&lt;meta name="homepage" value="http://www.gnu.org/software/hello/manual/" /> "homepage": "http://www.gnu.org/software/hello/manual/",
&lt;meta name="license" value="GPLv3+" /> "license": {
&lt;meta name="longDescription" value="GNU Hello is a program that prints &amp;quot;Hello, world!&amp;quot; when you run it.&amp;#xA;It is fully customizable.&amp;#xA;" /> "fullName": "GNU General Public License version 3 or later",
&lt;/item> "shortName": "GPLv3+",
&lt;/items> "url": "http://www.fsf.org/licensing/licenses/gpl.html"
},
"longDescription": "GNU Hello is a program that prints \"Hello, world!\" when you run it.\nIt is fully customizable.\n",
"maintainers": [
"Ludovic Court\u00e8s &lt;ludo@gnu.org>"
],
"platforms": [
"i686-linux",
"x86_64-linux",
"armv5tel-linux",
"armv7l-linux",
"mips64el-linux",
"x86_64-darwin",
"i686-cygwin",
"i686-freebsd",
"x86_64-freebsd",
"i686-openbsd",
"x86_64-openbsd"
],
"position": "/home/user/dev/nixpkgs/pkgs/applications/misc/hello/ex-2/default.nix:14"
},
"name": "hello-2.9",
"system": "x86_64-linux"
}
}
</screen> </screen>
<command>nix-env</command> knows about the <command>nix-env</command> knows about the
@ -92,20 +120,23 @@ interpretation:</para>
<varlistentry> <varlistentry>
<term><varname>license</varname></term> <term><varname>license</varname></term>
<listitem><para>The license for the package. See below for the <listitem><para>The license for the package. One from attribute set defined in
allowed values.</para></listitem> <link xlink:href="https://github.com/NixOS/nixpkgs/blob/master/lib/licenses.nix">
<filename>nixpkgs/lib/licenses.nix</filename></link>.
Example:
<literal>stdenv.lib.licenses.gpl3</literal>.</para></listitem>
See details in <xref linkend='sec-meta-license'/>,
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><varname>maintainers</varname></term> <term><varname>maintainers</varname></term>
<listitem><para>A list of names and e-mail addresses of the <listitem><para>A list of names and e-mail addresses of the
maintainers of this Nix expression, e.g. <literal>["Alice maintainers of this Nix expression. If
&lt;alice@example.org>" "Bob &lt;bob@example.com>"]</literal>. If you would like to be a maintainer of a package, you may want to add
you are the maintainer of multiple packages, you may want to add
yourself to <link yourself to <link
xlink:href="https://github.com/NixOS/nixpkgs/blob/master/pkgs/lib/maintainers.nix"><filename>pkgs/lib/maintainers.nix</filename></link> xlink:href="https://github.com/NixOS/nixpkgs/blob/master/lib/maintainers.nix"><filename>nixpkgs/lib/maintainers.nix</filename></link>
and write something like <literal>[stdenv.lib.maintainers.alice and write something like <literal>[ stdenv.lib.maintainers.alice
stdenv.lib.maintainers.bob]</literal>.</para></listitem> stdenv.lib.maintainers.bob ]</literal>.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
@ -118,6 +149,52 @@ interpretation:</para>
package).</para></listitem> package).</para></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>platforms</varname></term>
<listitem><para>The list of Nix platform types on which the
package is supported. Hydra builds packages according to the
platform specified. If no platform is specified, the package does
not have prebuilt binaries. An example is:
<programlisting>
meta.platforms = stdenv.lib.platforms.linux;
</programlisting>
Attribute Set <varname>stdenv.lib.platforms</varname> in
<link xlink:href="https://github.com/NixOS/nixpkgs/blob/master/lib/platforms.nix">
<filename>nixpkgs/lib/platforms.nix</filename></link> defines various common
lists of platforms types.
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>hydraPlatforms</varname></term>
<listitem><para>The list of Nix platform types for which the Hydra
instance at <literal>hydra.nixos.org</literal> will build the
package. (Hydra is the Nix-based continuous build system.) It
defaults to the value of <varname>meta.platforms</varname>. Thus,
the only reason to set <varname>meta.hydraPlatforms</varname> is
if you want <literal>hydra.nixos.org</literal> to build the
package on a subset of <varname>meta.platforms</varname>, or not
at all, e.g.
<programlisting>
meta.platforms = stdenv.lib.platforms.linux;
meta.hydraPlatforms = [];
</programlisting>
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>broken</varname></term>
<listitem><para>If set to <literal>true</literal>, the package is
marked as “broken”, meaning that it wont show up in
<literal>nix-env -qa</literal>, and cannot be built or installed.
Such packages should be removed from Nixpkgs eventually unless
they are fixed.</para></listitem>
</varlistentry>
</variablelist> </variablelist>
@ -126,80 +203,23 @@ interpretation:</para>
<section xml:id="sec-meta-license"><title>Licenses</title> <section xml:id="sec-meta-license"><title>Licenses</title>
<note><para>This is just a first attempt at standardising the license <para>The <varname>meta.license</varname> attribute should preferrably contain
attribute.</para></note> a value from <varname>stdenv.lib.licenses</varname> defined in
<link xlink:href="https://github.com/NixOS/nixpkgs/blob/master/lib/licenses.nix">
<para>The <varname>meta.license</varname> attribute must be one of the <filename>nixpkgs/lib/licenses.nix</filename></link>,
following: or in-place license description of the same format if the license is
unlikely to be useful in another expression.
A few generic options are available, although it's typically better
to indicate the specific license:
<variablelist> <variablelist>
<varlistentry>
<term><varname>GPL</varname></term>
<listitem><para>GNU General Public License; version not
specified.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>GPLv2</varname></term>
<listitem><para>GNU General Public License, version
2.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>GPLv2+</varname></term>
<listitem><para>GNU General Public License, version
2 or higher.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>GPLv3</varname></term>
<listitem><para>GNU General Public License, version
3.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>GPLv3+</varname></term>
<listitem><para>GNU General Public License, version
3 or higher.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>bsd</varname></term>
<listitem><para>Catch-all for licenses that are essentially
similar to <link
xlink:href="http://www.gnu.org/licenses/license-list.html#ModifiedBSD">the
original BSD license with the advertising clause removed</link>,
i.e. permissive non-copyleft free software licenses. This
includes the <link
xlink:href="http://www.gnu.org/licenses/license-list.html#X11License">X11
(“MIT”) License</link>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>perl5</varname></term>
<listitem><para>The Perl 5 license (Artistic License, version 1
and GPL, version 1 or later).</para></listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><varname>free</varname></term> <term><varname>free</varname></term>
<listitem><para>Catch-all for free software licenses not listed <listitem><para>Catch-all for free software licenses not listed
above.</para></listitem> above.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>free-copyleft</varname></term>
<listitem><para>Catch-all for free, copyleft software licenses not
listed above.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>free-non-copyleft</varname></term>
<listitem><para>Catch-all for free, non-copyleft software licenses
not listed above.</para></listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><varname>unfree-redistributable</varname></term> <term><varname>unfree-redistributable</varname></term>
<listitem><para>Unfree package that can be redistributed in binary <listitem><para>Unfree package that can be redistributed in binary

View File

@ -1,158 +0,0 @@
- The standard environment
(Some of this can be moved from the Nix manual)
- Special attributes
- Generic builder
- Helper functions
- GCC / ld wrapper (+ env vars)
- Phases (+ how to add phases) and hooks
- Override functions for stdenv
- Overriding GCC
- Overriding the setup script
- Predefined override functions in all-packages.nix: static binary
stdenv, dietlibc stdenv
- Stdenv bootstrap; how to update the Linux bootstrap binaries
- Specific platform notes (Linux, Native, Cygwin, Mingw)
- Support for specific languages
- Perl
- Generic Perl builder
- Python
- Wrapper generation
- Haskell
- TODO
- Java
- TODO; Java needs lots of improvement
- TeX/LaTeX
- Special support for building TeX documents
- Special kinds of applications
- OpenGL apps
- Binary-only apps
- Linux kernel modules
- Mozilla plugins/extensions
- X apps
- KDE apps
- GConf-based apps
- Programs that need wrappers
- makeWrapper etc.
- Initial ramdisks
- Library functions
- i.e. in lib/default.nix
- Specific package notes
- Linux kernel; how to update; feature tests
- X.org; how to update
- Gnome; how to update
- GCC?
- GHC?
- ...
- Meta attributes
- License attr; possible values
- Virtual machine support (for the build farm)
- vmtools
- KVM notes
- Performing a build in a VM
- In the host FS
- In a disk image
- RPM builds
- RPM image creation
- Deb builds
- Deb image creation
- Debugging VM builds
- Guidelines for Nixpkgs contributions
- File naming conventions
- Versioning of packages
- Tree organisation
- Variable naming
- Layout / indentations style
- Output FS hierarchy (e.g. $out/share/man instead of $out/man)
- Misc
- Building outside of the Nixpkgs tree
- Config options
- Downloading stuff
- fetchurl
- mirror:// scheme
- fetchsvn
- fetchcvs
- fetchdarcs
- Appendix: Nixpkgs config options

View File

@ -71,7 +71,7 @@ $ git add pkgs/development/libraries/libfoo/default.nix</screen>
<listitem> <listitem>
<para>GNU Multiple Precision arithmetic library (GMP): <link <para>GNU Multiple Precision arithmetic library (GMP): <link
xlink:href="https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/libraries/gmp/5.1.1.nix"><filename>pkgs/development/libraries/gmp/5.1.1.nix</filename></link>. xlink:href="https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/libraries/gmp/5.1.x.nix"><filename>pkgs/development/libraries/gmp/5.1.x.nix</filename></link>.
Also done by the generic builder, but has a dependency on Also done by the generic builder, but has a dependency on
<varname>m4</varname>.</para> <varname>m4</varname>.</para>
</listitem> </listitem>
@ -155,9 +155,10 @@ $ git add pkgs/development/libraries/libfoo/default.nix</screen>
</listitem> </listitem>
<listitem> <listitem>
<para>You can use <command>nix-prefetch-url</command> <para>You can use <command>nix-prefetch-url</command> (or similar nix-prefetch-git, etc)
<replaceable>url</replaceable> to get the SHA-256 hash of <replaceable>url</replaceable> to get the SHA-256 hash of
source distributions.</para> source distributions. There are similar commands as <command>nix-prefetch-git</command> and
<command>nix-prefetch-hg</command> available in <literal>nix-prefetch-scripts</literal> package.</para>
</listitem> </listitem>
<listitem> <listitem>
@ -196,7 +197,8 @@ $ emacs pkgs/top-level/all-packages.nix</screen>
</listitem> </listitem>
<listitem> <listitem>
<para>Test whether the package builds: <para>To test whether the package builds, run the following command
from the root of the nixpkgs source tree:
<screen> <screen>
$ nix-build -A libfoo</screen> $ nix-build -A libfoo</screen>
@ -220,17 +222,10 @@ $ nix-env -f . -iA libfoo</screen>
</listitem> </listitem>
<listitem> <listitem>
<para>Optionally commit the new package, or send a patch to <para>Optionally commit the new package and open a pull request, or send a patch to
<literal>nix-dev@cs.uu.nl</literal>.</para> <literal>nix-dev@cs.uu.nl</literal>.</para>
</listitem> </listitem>
<listitem>
<para>If you want the TU Delft build farm to build binaries of the
package and make them available in the <link
xlink:href="http://nixos.org/releases/nixpkgs/channels/nixpkgs-unstable/"><literal>nixpkgs</literal>
channel</link>, add it to <link
xlink:href="https://github.com/NixOS/nixpkgs/blob/master/pkgs/top-level/release.nix"><filename>pkgs/top-level/release.nix</filename></link>.</para>
</listitem>
</orderedlist> </orderedlist>

View File

@ -446,7 +446,7 @@ xlink:href='http://nixos.org/releases/nix/nix-0.10/'>Nix
<literal>stdenv</literal>; the formed changes the C compiler, and <literal>stdenv</literal>; the formed changes the C compiler, and
the latter adds additional packages to the front of the latter adds additional packages to the front of
<literal>stdenv</literal>s initial <envar>PATH</envar>, allowing <literal>stdenv</literal>s initial <envar>PATH</envar>, allowing
tools to be overriden.</para> tools to be overridden.</para>
<para>For instance, the package <varname>strategoxt</varname> <para>For instance, the package <varname>strategoxt</varname>
doesnt build with the GNU Make in <literal>stdenv</literal> doesnt build with the GNU Make in <literal>stdenv</literal>

View File

@ -56,7 +56,7 @@ details.)</para>
<para>Often it is necessary to override or modify some aspect of the <para>Often it is necessary to override or modify some aspect of the
build. To make this easier, the standard environment breaks the build. To make this easier, the standard environment breaks the
package build into a number of <emphasis>phases</emphasis>, all of package build into a number of <emphasis>phases</emphasis>, all of
which can be overriden or modified individually: unpacking the which can be overridden or modified individually: unpacking the
sources, applying patches, configuring, building, and installing. sources, applying patches, configuring, building, and installing.
(There are some others; see <xref linkend="ssec-stdenv-phases"/>.) (There are some others; see <xref linkend="ssec-stdenv-phases"/>.)
For instance, a package that doesnt supply a makefile but instead has For instance, a package that doesnt supply a makefile but instead has
@ -233,7 +233,7 @@ specific parts of the build (e.g., unpacking the sources or installing
the binaries). Furthermore, it allows a nicer presentation of build the binaries). Furthermore, it allows a nicer presentation of build
logs in the Nix build farm.</para> logs in the Nix build farm.</para>
<para>Each phase can be overriden in its entirety either by setting <para>Each phase can be overridden in its entirety either by setting
the environment variable the environment variable
<varname><replaceable>name</replaceable>Phase</varname> to a string <varname><replaceable>name</replaceable>Phase</varname> to a string
containing some shell commands to be executed, or by redefining the containing some shell commands to be executed, or by redefining the
@ -298,6 +298,13 @@ executed and in what order:
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>preFixupPhases</varname></term>
<listitem>
<para>Additional phases executed just before the fixup phase.</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><varname>preDistPhases</varname></term> <term><varname>preDistPhases</varname></term>
<listitem> <listitem>
@ -1156,12 +1163,27 @@ echo @foo@
to Qts path.</para></listitem> to Qts path.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>gdk-pixbuf</term>
<listitem><para>Exports <envar>GDK_PIXBUF_MODULE_FILE</envar>
environment variable the the builder. Add librsvg package
to <varname>buildInputs</varname> to get svg support.</para></listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term>GHC</term> <term>GHC</term>
<listitem><para>Creates a temporary package database and registers <listitem><para>Creates a temporary package database and registers
every Haskell build input in it (TODO: how?).</para></listitem> every Haskell build input in it (TODO: how?).</para></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>GStreamer</term>
<listitem><para>Adds the
GStreamer plugins subdirectory of
each build input to the <envar>GST_PLUGIN_SYSTEM_PATH_1_0</envar> or
<envar>GST_PLUGIN_SYSTEM_PATH</envar> environment variable.</para></listitem>
</varlistentry>
</variablelist> </variablelist>
</para> </para>

View File

@ -1,7 +1,7 @@
# Operations on attribute sets. # Operations on attribute sets.
with { with {
inherit (builtins) head tail isString; inherit (builtins) head tail;
inherit (import ./trivial.nix) or; inherit (import ./trivial.nix) or;
inherit (import ./default.nix) fold; inherit (import ./default.nix) fold;
inherit (import ./strings.nix) concatStringsSep; inherit (import ./strings.nix) concatStringsSep;
@ -20,7 +20,7 @@ rec {
let attr = head attrPath; let attr = head attrPath;
in in
if attrPath == [] then e if attrPath == [] then e
else if builtins ? hasAttr && hasAttr attr e else if hasAttr attr e
then attrByPath (tail attrPath) default (getAttr attr e) then attrByPath (tail attrPath) default (getAttr attr e)
else default; else default;
@ -100,7 +100,7 @@ rec {
(AttrSet -> Bool) -> AttrSet -> AttrSet (AttrSet -> Bool) -> AttrSet -> AttrSet
Example: Example:
collect builtins.isList { a = { b = ["b"]; }; c = [1]; } collect isList { a = { b = ["b"]; }; c = [1]; }
=> [["b"] [1]] => [["b"] [1]]
collect (x: x ? outPath) collect (x: x ? outPath)
@ -110,7 +110,7 @@ rec {
collect = pred: attrs: collect = pred: attrs:
if pred attrs then if pred attrs then
[ attrs ] [ attrs ]
else if builtins.isAttrs attrs then else if isAttrs attrs then
concatMap (collect pred) (attrValues attrs) concatMap (collect pred) (attrValues attrs)
else else
[]; [];

View File

@ -1,15 +1,74 @@
{lib, pkgs} : {lib, pkgs} :
let inherit (lib) nv nvs; in let inherit (lib) nv nvs; in
{ {
# see for example:
# - development/interpreters/php_configurable/default.nix # composableDerivation basically mixes these features:
# - .. search composableDerivation in all-packages.nix .. # - fix function
# - mergeAttrBy
# - provides shortcuts for "options" such as "--enable-foo" and adding
# buildInputs, see php example
# #
# You should be able to override anything you like easily # It predates styles which are common today, such as
# grep the mailinglist by title "python proposal" (dec 08) # * the config attr
# -> http://mail.cs.uu.nl/pipermail/nix-dev/2008-December/001571.html # * mkDerivation.override feature
# to see why this got complicated when using all its features # * overrideDerivation (lib/customization.nix)
# TODO add newer example using new syntax (kernel derivation proposal -> mailinglist) #
# Some of the most more important usage examples (which could be rewritten if it was important):
# * php
# * postgis
# * vim_configurable
#
# A minimal example illustrating most features would look like this:
# let base = composableDerivation { (fixed : let inherit (fixed.fixed) name in {
# src = fetchurl {
# }
# buildInputs = [A];
# preConfigre = "echo ${name}";
# # attention, "name" attr is missing, thus you cannot instantiate "base".
# }
# in {
# # These all add name attribute, thus you can instantiate those:
# v1 = base.merge ({ name = "foo-add-B"; buildInputs = [B]; }); // B gets merged into buildInputs
# v2 = base.merge ({ name = "mix-in-pre-configure-lines" preConfigre = ""; });
# v3 = base.replace ({ name = "foo-no-A-only-B;" buildInputs = [B]; });
# }
#
# So yes, you can think about it being something like nixos modules, and
# you'd be merging "features" in one at a time using .merge or .replace
# Thanks Shea for telling me that I rethink the documentation ..
#
# issues:
# * its complicated to understand
# * some "features" such as exact merge behaviour are burried in mergeAttrBy
# and defaultOverridableDelayableArgs assuming the default behaviour does
# the right thing in the common case
# * Eelco once said using such fix style functions are slow to evaluate
# * Too quick & dirty. Hard to understand for others. The benefit was that
# you were able to create a kernel builder like base derivation and replace
# / add patches the way you want without having to declare function arguments
#
# nice features:
# declaring "optional featuers" is modular. For instance:
# flags.curl = {
# configureFlags = ["--with-curl=${curl}" "--with-curlwrappers"];
# buildInputs = [curl openssl];
# };
# flags.other = { .. }
# (Example taken from PHP)
#
# alternative styles / related features:
# * Eg see function supporting building the kernel
# * versionedDerivation (discussion about this is still going on - or ended)
# * composedArgsAndFun
# * mkDerivation.override
# * overrideDerivation
# * using { .., *Support ? false }: like configurable options.
# To find those examples use grep
#
# To sum up: It exists for historical reasons - and for most commonly used
# tasks the alternatives should be used
#
# If you have questions about this code ping Marc Weber.
composableDerivation = { composableDerivation = {
mkDerivation ? pkgs.stdenv.mkDerivation, mkDerivation ? pkgs.stdenv.mkDerivation,

View File

@ -21,8 +21,6 @@ let
in in
{ inherit trivial lists strings stringsWithDeps attrsets sources options { inherit trivial lists strings stringsWithDeps attrsets sources options
modules types meta debug maintainers licenses platforms systems; modules types meta debug maintainers licenses platforms systems;
# Pull in some builtins not included elsewhere.
inherit (builtins) pathExists readFile;
} }
# !!! don't include everything at top-level; perhaps only the most # !!! don't include everything at top-level; perhaps only the most
# commonly used functions. # commonly used functions.

View File

@ -1,137 +1,175 @@
{ let
/* License identifiers loosely based on: http://fedoraproject.org/wiki/Licensing spdx = lic: lic // {
url = "http://spdx.org/licenses/${lic.shortName}";
};
in
rec {
/* License identifiers from spdx.org where possible.
* If you cannot find your license here, then look for a similar license or * If you cannot find your license here, then look for a similar license or
* add it to this list. The URL mentioned above is a good source for inspiration. * add it to this list. The URL mentioned above is a good source for inspiration.
*/ */
artistic2 = { agpl3 = spdx {
shortName = "Artistic 2.0"; shortName = "AGPL-3.0";
fullName = "Artistic 2.0"; fullName = "GNU Affero General Public License v3.0";
url = "http://opensource.org/licenses/artistic-license-2.0.php";
};
agpl3 = {
shortName = "AGPLv3";
fullName = "GNU Affero General Public License version 3 only";
url = https://www.gnu.org/licenses/agpl.html;
}; };
agpl3Plus = { agpl3Plus = {
shortName = "AGPLv3+"; shortName = "AGPL-3.0+";
fullName = "GNU Affero General Public License version 3 or later"; fullName = "GNU Affero General Public License v3.0 or later";
url = https://www.gnu.org/licenses/agpl.html; inherit (agpl3) url;
}; };
amd = { amd = {
shortName = "amd"; shortName = "amd";
fullName = "AMD License Agreement"; fullName = "AMD License Agreement";
url = "http://developer.amd.com/amd-license-agreement/"; url = http://developer.amd.com/amd-license-agreement/;
};#
apsl20 = spdx {
shortName = "APSL-2.0";
fullName = "Apple Public Source License 2.0";
}; };
amdadl = { artistic2 = spdx {
shortName = "amd-adl"; shortName = "Artistic-2.0";
fullName = "amd-adl license"; fullName = "Artistic License 2.0";
url = "http://sources.gentoo.org/cgi-bin/viewvc.cgi/gentoo-x86/licenses/AMD-ADL?revision=1.1";
}; };
# Apple Public Source License 2.0; asl20 = spdx {
# http://opensource.org/licenses/APSL-2.0 shortName = "Apache-2.0";
apsl20 = "APSL 2.0"; fullName = "Apache License 2.0";
asl20 = {
shortName = "ASL2.0";
fullName = "Apache Software License 2.0";
url = http://www.apache.org/licenses/LICENSE-2.0;
}; };
boost = { boost = spdx {
shortName = "boost"; shortName = "BSL-1.0";
fullName = "Boost Software License"; fullName = "Boost Software License 1.0";
url = http://www.boost.org/LICENSE_1_0.txt;
}; };
bsd2 = { bsd2 = spdx {
shortName = "BSD-2"; shortName = "BSD-2-Clause";
fullName = "BSD license (2 clause)"; fullName = ''BSD 2-clause "Simplified" License'';
url = http://opensource.org/licenses/BSD-2-Clause;
}; };
bsd3 = { bsd3 = spdx {
shortName = "BSD-3"; shortName = "BSD-3-Clause";
fullName = "BSD license (3 clause)"; fullName = ''BSD 3-clause "New" or "Revised" License'';
url = http://opensource.org/licenses/BSD-3-Clause;
}; };
bsdOriginal = { bsdOriginal = spdx {
shortName = "BSD-original"; shortName = "BSD-4-Clause";
fullName = "Original BSD license with advertising clause"; fullName = ''BSD 4-clause "Original" or "Old" License'';
url = https://fedoraproject.org/wiki/Licensing/BSD;
}; };
cddl = { cc-by-30 = spdx {
shortName = "CDDL"; shortName = "CC-BY-3.0";
fullName = "Common Development Distribution License "; fullName = "Creative Commons Attribution 3.0";
url = http://www.opensolaris.org/os/licensing/cddllicense.txt;
}; };
cpl10 = { cddl = spdx {
shortName = "CPL 1.0"; shortName = "CDDL-1.0";
fullName = "Common Public License version 1.0"; fullName = "Common Development and Distribution License 1.0";
url = http://www.eclipse.org/legal/cpl-v10.html;
}; };
epl10 = { cecill-c = spdx {
shortName = "EPL 1.0"; shortName = "CECILL-C";
fullName = "Eclipse Public License version 1.0"; fullName = "CeCILL-C Free Software License Agreement";
url = http://www.eclipse.org/legal/epl-v10.html;
}; };
gpl2 = "GPLv2"; cpl10 = spdx {
shortName = "CPL-1.0";
fullName = "Common Public License 1.0";
};
epl10 = spdx {
shortName = "EPL-1.0";
fullName = "Eclipse Public License 1.0";
};
free = "free";
gpl2 = spdx {
shortName = "GPL-2.0";
fullName = "GNU General Public License v2.0 only";
};
gpl2Oss = { gpl2Oss = {
shortName = "GPLv2+OSS"; shortName = "GPL-2.0-with-OSS";
fullName = "GNU General Public License version 2 only (with OSI approved licenses linking exception)"; fullName = "GNU General Public License version 2 only (with OSI approved licenses linking exception)";
url = http://www.mysql.com/about/legal/licensing/foss-exception; url = http://www.mysql.com/about/legal/licensing/foss-exception;
}; };
# GNU General Public License version 2 or later; gpl2Plus = spdx {
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html shortName = "GPL-2.0+";
gpl2Plus = "GPLv2+"; fullName = "GNU General Public License v2.0 or later";
gpl3 = {
shortName = "GPLv3";
fullName = "GNU General Public License version 3 only";
url = http://www.fsf.org/licensing/licenses/gpl.html;
}; };
gpl3Plus = { gpl3 = spdx {
shortName = "GPLv3+"; shortName = "GPL-3.0";
fullName = "GNU General Public License version 3 or later"; fullName = "GNU General Public License v3.0 only";
url = http://www.fsf.org/licensing/licenses/gpl.html; };
gpl3Plus = spdx {
shortName = "GPL-3.0+";
fullName = "GNU General Public License v3.0 or later";
}; };
gpl3ClasspathPlus = { gpl3ClasspathPlus = {
shortName = "GPLv3+classpath+"; shortName = "GPL-3.0+-with-classpath-exception";
fullName = "GNU General Public License version 3 or later (with Classpath exception)"; fullName = "GNU General Public License v3.0 or later (with Classpath exception)";
url = https://fedoraproject.org/wiki/Licensing/GPL_Classpath_Exception; url = https://fedoraproject.org/wiki/Licensing/GPL_Classpath_Exception;
}; };
isc = { inria = {
shortName = "INRIA-NCLA";
fullName = "INRIA Non-Commercial License Agreement";
url = "http://compcert.inria.fr/doc/LICENSE";
};
ipa = spdx {
shortName = "IPA";
fullName = "IPA Font License";
};
ipl10 = spdx {
shortName = "IPL-1.0";
fullName = "IBM Public License v1.0";
};
isc = spdx {
shortName = "ISC"; shortName = "ISC";
fullName = "Internet Systems Consortium License"; fullName = "ISC License";
url = http://www.opensource.org/licenses/ISC;
}; };
ipl10 = { lgpl2 = spdx {
shortName = "IPL 1.0"; shortName = "LGPL-2.0";
fullName = "IBM Public License Version 1.0"; fullName = "GNU Library General Public License v2 only";
url = http://www.ibm.com/developerworks/opensource/library/os-i18n2/os-ipl.html;
}; };
ijg = { lgpl2Plus = spdx {
shortName = "IJG"; shortName = "LGPL-2.0+";
fullName = "Independent JPEG Group License"; fullName = "GNU Library General Public License v2 or later";
url = https://fedoraproject.org/wiki/Licensing/IJG; };
lgpl21 = spdx {
shortName = "LGPL-2.1";
fullName = "GNU Library General Public License v2.1 only";
};
lgpl21Plus = spdx {
shortName = "LGPL-2.1+";
fullName = "GNU Library General Public License v2.1 or later";
};
lgpl3 = spdx {
shortName = "LGPL-3.0";
fullName = "GNU Lesser General Public License v3.0 only";
};
lgpl3Plus = spdx {
shortName = "LGPL-3.0+";
fullName = "GNU Lesser General Public License v3.0 or later";
}; };
libtiff = { libtiff = {
@ -140,62 +178,52 @@
url = https://fedoraproject.org/wiki/Licensing/libtiff; url = https://fedoraproject.org/wiki/Licensing/libtiff;
}; };
lgpl2 = "LGPLv2";
lgpl2Plus = {
shortName = "LGPLv2+";
fullName = "GNU Library General Public License version 2 or later";
url = http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html;
};
lgpl21 = "LGPLv2.1";
lgpl21Plus = {
shortName = "LGPLv2.1+";
fullName = "GNU Lesser General Public License version 2.1 or later";
url = http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html;
};
llgpl21 = { llgpl21 = {
shortName = "LLGPLv2.1"; shortName = "LLGPL-2.1";
fullName = "Lisp LGPL; GNU Lesser General Public License version 2.1 with Franz Inc. preamble for clarification of LGPL terms in context of Lisp"; fullName = "Lisp LGPL; GNU Lesser General Public License version 2.1 with Franz Inc. preamble for clarification of LGPL terms in context of Lisp";
url = http://opensource.franz.com/preamble.html; url = http://opensource.franz.com/preamble.html;
}; };
lgpl3 = { lpl-102 = spdx {
shortName = "LGPLv3"; shortName = "LPL-1.02";
fullName = "GNU Lesser General Public License version 3 only"; fullName = "Lucent Public License v1.02";
url = http://www.fsf.org/licensing/licenses/lgpl.html;
}; };
lgpl3Plus = { mit = spdx {
shortName = "LGPLv3+";
fullName = "GNU Lesser General Public License version 3 or later";
url = http://www.fsf.org/licensing/licenses/lgpl.html;
};
mit = {
shortName = "MIT"; shortName = "MIT";
fullName = "MIT/X11 license"; fullName = "MIT License";
url = http://www.opensource.org/licenses/mit-license.php;
}; };
mpl11 = { mpl11 = spdx {
shortName = "MPL1.1"; shortName = "MPL-1.1";
fullName = "Mozilla Public License version 1.1"; fullName = "Mozilla Public License 1.1";
url = http://www.mozilla.org/MPL/MPL-1.1.html;
}; };
mpl20 = { mpl20 = spdx {
shortName = "MPL2.0"; shortName = "MPL-2.0";
fullName = "Mozilla Public License version 2.0"; fullName = "Mozilla Public License 2.0";
url = https://www.mozilla.org/MPL/2.0;
}; };
openssl = { msrla = {
shortName = "openssl"; shortName = "MSR-LA";
fullName = "OpenSSL license"; fullName = "Microsoft Research License Agreement";
url = http://www.openssl.org/source/license.html; url = "http://research.microsoft.com/en-us/projects/pex/msr-la.txt";
};
ofl = spdx {
shortName = "OFL-1.1";
fullName = "SIL Open Font License 1.1";
};
openssl = spdx {
shortName = "OpenSSL";
fullName = "OpenSSL License";
};
psfl = spdx {
shortName = "Python-2.0";
fullName = "Python Software Foundation License version 2";
#url = http://docs.python.org/license.html;
}; };
publicDomain = { publicDomain = {
@ -203,10 +231,9 @@
fullname = "Public Domain"; fullname = "Public Domain";
}; };
psfl = { sleepycat = spdx {
shortName = "PSFL"; shortName = "Sleepycat";
fullName = "Python Software Foundation License"; fullName = "Sleepycat License";
url = http://docs.python.org/license.html;
}; };
tcltk = { tcltk = {
@ -221,21 +248,26 @@
unfreeRedistributableFirmware = "unfree-redistributable-firmware"; unfreeRedistributableFirmware = "unfree-redistributable-firmware";
zlib = { wadalab = {
shortName = "zlib"; shortName = "wadalab";
fullName = "zlib license"; fullName = "Wadalab Font License";
url = http://www.gzip.org/zlib/zlib_license.html; url = https://fedoraproject.org/wiki/Licensing:Wadalab?rd=Licensing/Wadalab;
}; };
zpt20 = { zlib = spdx {
shortName = "ZPT2.0"; shortName = "Zlib";
fullName = "zlib License";
};
zpt20 = spdx { # FIXME: why zpt* instead of zpl*
shortName = "ZPL-2.0";
fullName = "Zope Public License 2.0"; fullName = "Zope Public License 2.0";
url = "http://old.zope.org/Resources/License/ZPL-2.0";
}; };
zpt21 = { zpt21 = spdx {
shortName = "ZPT2.1"; shortName = "ZPL-2.1";
fullName = "Zope Public License 2.1"; fullName = "Zope Public License 2.1";
url = "http://old.zope.org/Resources/License/ZPL-2.1";
}; };
} }

View File

@ -1,14 +1,16 @@
# General list operations. # General list operations.
let
inherit (import ./trivial.nix) deepSeq; with import ./trivial.nix;
let
inc = builtins.add 1; inc = builtins.add 1;
dec = n: builtins.sub n 1; dec = n: builtins.sub n 1;
in rec { in rec {
inherit (builtins) head tail length isList add sub lessThan elemAt;
inherit (builtins) head tail length isList elemAt concatLists filter elem;
# Create a list consisting of a single element. `singleton x' is # Create a list consisting of a single element. `singleton x' is
@ -56,10 +58,6 @@ in rec {
in imap' 0; in imap' 0;
# Concatenate a list of lists.
concatLists = builtins.concatLists or (fold (x: y: x ++ y) []);
# Map and concatenate the result. # Map and concatenate the result.
concatMap = f: list: concatLists (map f list); concatMap = f: list: concatLists (map f list);
@ -73,24 +71,10 @@ in rec {
else [x]; else [x];
# Filter a list using a predicate; that is, return a list containing
# every element from `list' for which `pred' returns true.
filter =
builtins.filter or
(pred: list:
fold (x: y: if pred x then [x] ++ y else y) [] list);
# Remove elements equal to 'e' from a list. Useful for buildInputs. # Remove elements equal to 'e' from a list. Useful for buildInputs.
remove = e: filter (x: x != e); remove = e: filter (x: x != e);
# Return true if `list' has an element `x'.
elem =
builtins.elem or
(x: list: fold (a: bs: x == a || bs) false list);
# Find the sole element in the list matching the specified # Find the sole element in the list matching the specified
# predicate, returns `default' if no such element exists, or # predicate, returns `default' if no such element exists, or
# `multiple' if there are multiple matching elements. # `multiple' if there are multiple matching elements.
@ -136,14 +120,14 @@ in rec {
# If argument is a list, return it; else, wrap it in a singleton # If argument is a list, return it; else, wrap it in a singleton
# list. If you're using this, you should almost certainly # list. If you're using this, you should almost certainly
# reconsider if there isn't a more "well-typed" approach. # reconsider if there isn't a more "well-typed" approach.
toList = x: if builtins.isList x then x else [x]; toList = x: if isList x then x else [x];
# Return a list of integers from `first' up to and including `last'. # Return a list of integers from `first' up to and including `last'.
range = first: last: range = first: last:
if builtins.lessThan last first if lessThan last first
then [] then []
else [first] ++ range (builtins.add first 1) last; else [first] ++ range (add first 1) last;
# Partition the elements of a list in two lists, `right' and # Partition the elements of a list in two lists, `right' and
@ -160,7 +144,7 @@ in rec {
let let
len1 = length fst; len1 = length fst;
len2 = length snd; len2 = length snd;
len = if builtins.lessThan len1 len2 then len1 else len2; len = if lessThan len1 len2 then len1 else len2;
zipListsWith' = n: zipListsWith' = n:
if n != len then if n != len then
[ (f (elemAt fst n) (elemAt snd n)) ] [ (f (elemAt fst n) (elemAt snd n)) ]
@ -220,6 +204,7 @@ in rec {
in drop' (dec len); in drop' (dec len);
# Return the last element of a list.
last = list: last = list:
assert list != []; elemAt list (dec (length list)); assert list != []; elemAt list (dec (length list));
@ -237,5 +222,9 @@ in rec {
else []; else [];
in zipTwoLists' 0; in zipTwoLists' 0;
deepSeqList = xs: y: if any (x: deepSeq x false) xs then y else y; deepSeqList = xs: y: if any (x: deepSeq x false) xs then y else y;
crossLists = f: foldl (fs: args: concatMap (f: map f args) fs) [f];
} }

View File

@ -4,38 +4,72 @@
/* Add your name and email address here. Keep the list /* Add your name and email address here. Keep the list
alphabetically sorted. */ alphabetically sorted. */
_1126 = "Christian Lask <mail@elfsechsundzwanzig.de>";
aforemny = "Alexander Foremny <alexanderforemny@googlemail.com>"; aforemny = "Alexander Foremny <alexanderforemny@googlemail.com>";
ak = "Alexander Kjeldaas <ak@formalprivacy.com>";
akc = "Anders Claesson <akc@akc.is>";
algorith = "Dries Van Daele <dries_van_daele@telenet.be>"; algorith = "Dries Van Daele <dries_van_daele@telenet.be>";
all = "Nix Committers <nix-commits@lists.science.uu.nl>"; all = "Nix Committers <nix-commits@lists.science.uu.nl>";
amiddelk = "Arie Middelkoop <amiddelk@gmail.com>"; amiddelk = "Arie Middelkoop <amiddelk@gmail.com>";
amorsillo = "Andrew Morsillo <andrew.morsillo@gmail.com>"; amorsillo = "Andrew Morsillo <andrew.morsillo@gmail.com>";
AndersonTorres = "Anderson Torres <torres.anderson.85@gmail.com>";
andres = "Andres Loeh <ksnixos@andres-loeh.de>"; andres = "Andres Loeh <ksnixos@andres-loeh.de>";
antono = "Antono Vasiljev <self@antono.info>"; antono = "Antono Vasiljev <self@antono.info>";
arobyn = "Alexei Robyn <shados@shados.net>";
astsmtl = "Alexander Tsamutali <astsmtl@yandex.ru>"; astsmtl = "Alexander Tsamutali <astsmtl@yandex.ru>";
aszlig = "aszlig <aszlig@redmoonstudios.org>"; aszlig = "aszlig <aszlig@redmoonstudios.org>";
auntie = "Jonathan Glines <auntieNeo@gmail.com>";
bbenoist = "Baptist BENOIST <return_0@live.com>"; bbenoist = "Baptist BENOIST <return_0@live.com>";
bennofs = "Benno Fünfstück <benno.fuenfstueck@gmail.com>";
berdario = "Dario Bertini <berdario@gmail.com>";
bjg = "Brian Gough <bjg@gnu.org>"; bjg = "Brian Gough <bjg@gnu.org>";
bjornfor = "Bjørn Forsman <bjorn.forsman@gmail.com>"; bjornfor = "Bjørn Forsman <bjorn.forsman@gmail.com>";
bluescreen303 = "Mathijs Kwik <mathijs@bluescreen303.nl>"; bluescreen303 = "Mathijs Kwik <mathijs@bluescreen303.nl>";
bodil = "Bodil Stokke <nix@bodil.org>"; bodil = "Bodil Stokke <nix@bodil.org>";
bosu = "Boris Sukholitko <boriss@gmail.com>";
calrama = "Moritz Maxeiner <moritz@ucworks.org>";
cfouche = "Chaddaï Fouché <chaddai.fouche@gmail.com>";
chaoflow = "Florian Friesdorf <flo@chaoflow.net>"; chaoflow = "Florian Friesdorf <flo@chaoflow.net>";
coconnor = "Corey O'Connor <coreyoconnor@gmail.com>"; coconnor = "Corey O'Connor <coreyoconnor@gmail.com>";
coroa = "Jonas Hörsch <jonas@chaoflow.net>"; coroa = "Jonas Hörsch <jonas@chaoflow.net>";
cstrahan = "Charles Strahan <charles.c.strahan@gmail.com>";
DamienCassou = "Damien Cassou <damien.cassou@gmail.com>";
ederoyd46 = "Matthew Brown <matt@ederoyd.co.uk>";
edwtjo = "Edward Tjörnhammar <ed@cflags.cc>"; edwtjo = "Edward Tjörnhammar <ed@cflags.cc>";
eelco = "Eelco Dolstra <eelco.dolstra@logicblox.com>"; eelco = "Eelco Dolstra <eelco.dolstra@logicblox.com>";
ertes = "Ertugrul Söylemez <es@ertes.de>"; emery = "Emery Hemingway <emery@vfemail.net>";
ertes = "Ertugrul Söylemez <ertesx@gmx.de>";
falsifian = "James Cook <james.cook@utoronto.ca>";
flosse = "Markus Kohlhase <mail@markus-kohlhase.de>";
fuuzetsu = "Mateusz Kowalczyk <fuuzetsu@fuuzetsu.co.uk>";
garbas = "Rok Garbas <rok@garbas.si>"; garbas = "Rok Garbas <rok@garbas.si>";
goibhniu = "Cillian de Róiste <cillian.deroiste@gmail.com>"; goibhniu = "Cillian de Róiste <cillian.deroiste@gmail.com>";
guibert = "David Guibert <david.guibert@gmail.com>"; guibert = "David Guibert <david.guibert@gmail.com>";
hinton = "Tom Hinton <t@larkery.com>";
hrdinka = "Christoph Hrdinka <c.nix@hrdinka.at>";
ianwookim = "Ian-Woo Kim <ianwookim@gmail.com>";
iElectric = "Domen Kozar <domen@dev.si>"; iElectric = "Domen Kozar <domen@dev.si>";
iyzsong = "Song Wenwu <iyzsong@gmail.com>"; iyzsong = "Song Wenwu <iyzsong@gmail.com>";
jcumming = "Jack Cummings <jack@mudshark.org>"; jcumming = "Jack Cummings <jack@mudshark.org>";
jgeerds = "Jascha Geerds <jg@ekby.de>";
joamaki = "Jussi Maki <joamaki@gmail.com>";
joelteon = "Joel Taylor <me@joelt.io>";
jwiegley = "John Wiegley <johnw@newartisans.com>";
kkallio = "Karn Kallio <tierpluspluslists@gmail.com>"; kkallio = "Karn Kallio <tierpluspluslists@gmail.com>";
ktosiek = "Tomasz Kontusz <tomasz.kontusz@gmail.com>";
lethalman = "Luca Bruno <lucabru@src.gnome.org>";
linquize = "Linquize <linquize@yahoo.com.hk>";
lovek323 = "Jason O'Conal <jason@oconal.id.au>"; lovek323 = "Jason O'Conal <jason@oconal.id.au>";
ludo = "Ludovic Courtès <ludo@gnu.org>"; ludo = "Ludovic Courtès <ludo@gnu.org>";
madjar = "Georges Dubus <georges.dubus@compiletoi.net>";
marcweber = "Marc Weber <marco-oweber@gmx.de>"; marcweber = "Marc Weber <marco-oweber@gmx.de>";
matejc = "Matej Cotman <cotman.matej@gmail.com>";
meisternu = "Matt Miemiec <meister@krutt.org>";
modulistic = "Pablo Costa <modulistic@gmail.com>"; modulistic = "Pablo Costa <modulistic@gmail.com>";
mornfall = "Petr Ročkai <me@mornfall.net>"; mornfall = "Petr Ročkai <me@mornfall.net>";
msackman = "Matthew Sackman <matthew@wellquite.org>";
nathan-gs = "Nathan Bijnens <nathan@nathan.gs>";
notthemessiah = "Brian Cohen <brian.cohen.88@gmail.com>";
ocharles = "Oliver Charles <ollie@ocharles.org.uk>"; ocharles = "Oliver Charles <ollie@ocharles.org.uk>";
offline = "Jaka Hudoklin <jakahudoklin@gmail.com>"; offline = "Jaka Hudoklin <jakahudoklin@gmail.com>";
orbitz = "Malcolm Matalka <mmatalka@gmail.com>"; orbitz = "Malcolm Matalka <mmatalka@gmail.com>";
@ -43,24 +77,46 @@
phreedom = "Evgeny Egorochkin <phreedom@yandex.ru>"; phreedom = "Evgeny Egorochkin <phreedom@yandex.ru>";
pierron = "Nicolas B. Pierron <nixos@nbp.name>"; pierron = "Nicolas B. Pierron <nixos@nbp.name>";
piotr = "Piotr Pietraszkiewicz <ppietrasa@gmail.com>"; piotr = "Piotr Pietraszkiewicz <ppietrasa@gmail.com>";
pkmx = "Chih-Mao Chen <pkmx.tw@gmail.com>";
plcplc = "Philip Lykke Carlsen <plcplc@gmail.com>";
pSub = "Pascal Wittmann <mail@pascal-wittmann.de>"; pSub = "Pascal Wittmann <mail@pascal-wittmann.de>";
qknight = "Joachim Schiele <js@lastlog.de>"; qknight = "Joachim Schiele <js@lastlog.de>";
raskin = "Michael Raskin <7c6f434c@mail.ru>"; raskin = "Michael Raskin <7c6f434c@mail.ru>";
redbaron = "Maxim Ivanov <ivanov.maxim@gmail.com>";
refnil = "Martin Lavoie <broemartino@gmail.com>";
relrod = "Ricky Elrod <ricky@elrod.me>";
rickynils = "Rickard Nilsson <rickynils@gmail.com>"; rickynils = "Rickard Nilsson <rickynils@gmail.com>";
rob = "Rob Vermaas <rob.vermaas@gmail.com>"; rob = "Rob Vermaas <rob.vermaas@gmail.com>";
roconnor = "Russell O'Connor <roconnor@theorem.ca>"; roconnor = "Russell O'Connor <roconnor@theorem.ca>";
roelof = "Roelof Wobben <rwobben@hotmail.com>";
romildo = "José Romildo Malaquias <malaquias@gmail.com>";
rszibele = "Richard Szibele <richard_szibele@hotmail.com>";
sander = "Sander van der Burg <s.vanderburg@tudelft.nl>"; sander = "Sander van der Burg <s.vanderburg@tudelft.nl>";
shlevy = "Shea Levy <shea@shealevy.com>"; shlevy = "Shea Levy <shea@shealevy.com>";
simons = "Peter Simons <simons@cryp.to>"; simons = "Peter Simons <simons@cryp.to>";
skeidel = "Sven Keidel <svenkeidel@gmail.com>";
smironov = "Sergey Mironov <ierton@gmail.com>"; smironov = "Sergey Mironov <ierton@gmail.com>";
sprock = "Roger Mason <rmason@mun.ca>";
tailhook = "Paul Colomiets <paul@colomiets.name>";
thammers = "Tobias Hammerschmidt <jawr@gmx.de>"; thammers = "Tobias Hammerschmidt <jawr@gmx.de>";
the-kenny = "Moritz Ulrich <moritz@tarn-vedra.de>"; the-kenny = "Moritz Ulrich <moritz@tarn-vedra.de>";
thoughtpolice = "Austin Seipp <aseipp@pobox.com>";
tomberek = "Thomas Bereknyei <tomberek@gmail.com>";
ttuegel = "Thomas Tuegel <ttuegel@gmail.com>";
tv = "Tomislav Viljetić <tv@shackspace.de>";
urkud = "Yury G. Kudryashov <urkud+nix@ya.ru>"; urkud = "Yury G. Kudryashov <urkud+nix@ya.ru>";
vbmithr = "Vincent Bernardoff <vb@luminar.eu.org>";
vcunat = "Vladimír Čunát <vcunat@gmail.com>"; vcunat = "Vladimír Čunát <vcunat@gmail.com>";
viric = "Lluís Batlle i Rossell <viric@viric.name>"; viric = "Lluís Batlle i Rossell <viric@viric.name>";
vizanto = "Danny Wilson <danny@prime.vc>"; vizanto = "Danny Wilson <danny@prime.vc>";
vlstill = "Vladimír Štill <xstill@fi.muni.cz>"; vlstill = "Vladimír Štill <xstill@fi.muni.cz>";
winden = "Antonio Vargas Gonzalez <windenntw@gmail.com>"; winden = "Antonio Vargas Gonzalez <windenntw@gmail.com>";
wizeman = "Ricardo M. Correia <rcorreia@wizy.org>";
wjlroe = "William Roe <willroe@gmail.com>";
wkennington = "William A. Kennington III <william@wkennington.com>";
wmertens = "Wout Mertens <Wout.Mertens@gmail.com>";
z77z = "Marco Maggesi <maggesi@math.unifi.it>"; z77z = "Marco Maggesi <maggesi@math.unifi.it>";
zef = "Zef Hemel <zef@zef.me>"; zef = "Zef Hemel <zef@zef.me>";
zimbatm = "zimbatm <zimbatm@zimbatm.com>";
zoomulator = "Kim Simmons <zoomulator@gmail.com>";
} }

View File

@ -1,6 +1,9 @@
/* Some functions for manipulating meta attributes, as well as the /* Some functions for manipulating meta attributes, as well as the
name attribute. */ name attribute. */
let lib = import ./default.nix;
in
rec { rec {
@ -11,7 +14,7 @@ rec {
addMetaAttrs {description = "Bla blah";} somePkg addMetaAttrs {description = "Bla blah";} somePkg
*/ */
addMetaAttrs = newAttrs: drv: addMetaAttrs = newAttrs: drv:
drv // { meta = (if drv ? meta then drv.meta else {}) // newAttrs; }; drv // { meta = (drv.meta or {}) // newAttrs; };
/* Change the symbolic name of a package for presentation purposes /* Change the symbolic name of a package for presentation purposes
@ -28,11 +31,15 @@ rec {
updateName = updater: drv: drv // {name = updater (drv.name);}; updateName = updater: drv: drv // {name = updater (drv.name);};
/* Append a suffix to the name of a package. !!! the suffix should /* Append a suffix to the name of a package (before the version
really be appended *before* the version, at least most of the part). */
time. appendToName = suffix: updateName (name:
let x = builtins.parseDrvName name; in "${x.name}-${suffix}-${x.version}");
/* Apply a function to each derivation and only to derivations in an attrset
*/ */
appendToName = suffix: updateName (name: "${name}-${suffix}"); mapDerivationAttrset = f: set: lib.mapAttrs (name: pkg: if lib.isDerivation pkg then (f pkg) else pkg) set;
/* Decrease the nix-env priority of the package, i.e., other /* Decrease the nix-env priority of the package, i.e., other
@ -40,9 +47,20 @@ rec {
*/ */
lowPrio = drv: addMetaAttrs { priority = "10"; } drv; lowPrio = drv: addMetaAttrs { priority = "10"; } drv;
/* Apply lowPrio to an attrset with derivations
*/
lowPrioSet = set: mapDerivationAttrset lowPrio set;
/* Increase the nix-env priority of the package, i.e., this /* Increase the nix-env priority of the package, i.e., this
version/variant of the package will be preferred. version/variant of the package will be preferred.
*/ */
hiPrio = drv: addMetaAttrs { priority = "-10"; } drv; hiPrio = drv: addMetaAttrs { priority = "-10"; } drv;
/* Apply hiPrio to an attrset with derivations
*/
hiPrioSet = set: mapDerivationAttrset hiPrio set;
} }

View File

@ -12,7 +12,7 @@ rec {
and config: the nested set of all option values. */ and config: the nested set of all option values. */
evalModules = { modules, prefix ? [], args ? {}, check ? true }: evalModules = { modules, prefix ? [], args ? {}, check ? true }:
let let
args' = args // result; args' = args // { lib = import ./.; } // result;
closed = closeModules modules args'; closed = closeModules modules args';
# Note: the list of modules is reversed to maintain backward # Note: the list of modules is reversed to maintain backward
# compatibility with the old module system. Not sure if this is # compatibility with the old module system. Not sure if this is
@ -42,7 +42,7 @@ rec {
closeModules = modules: args: closeModules = modules: args:
let let
toClosureList = file: parentKey: imap (n: x: toClosureList = file: parentKey: imap (n: x:
if isAttrs x || builtins.isFunction x then if isAttrs x || isFunction x then
unifyModuleSyntax file "${parentKey}:anon-${toString n}" (applyIfFunction x args) unifyModuleSyntax file "${parentKey}:anon-${toString n}" (applyIfFunction x args)
else else
unifyModuleSyntax (toString x) (toString x) (applyIfFunction (import x) args)); unifyModuleSyntax (toString x) (toString x) (applyIfFunction (import x) args));
@ -74,7 +74,7 @@ rec {
config = removeAttrs m ["key" "_file" "require" "imports"]; config = removeAttrs m ["key" "_file" "require" "imports"];
}; };
applyIfFunction = f: arg: if builtins.isFunction f then f arg else f; applyIfFunction = f: arg: if isFunction f then f arg else f;
/* Merge a list of modules. This will recurse over the option /* Merge a list of modules. This will recurse over the option
declarations in all modules, combining them into a single set. declarations in all modules, combining them into a single set.
@ -155,8 +155,14 @@ rec {
let let
# Process mkOverride properties, adding in the default # Process mkOverride properties, adding in the default
# value specified in the option declaration (if any). # value specified in the option declaration (if any).
defsFinal = filterOverrides defsFinal' = filterOverrides
((if opt ? default then [{ file = head opt.declarations; value = mkOptionDefault opt.default; }] else []) ++ defs); ((if opt ? default then [{ file = head opt.declarations; value = mkOptionDefault opt.default; }] else []) ++ defs);
# Sort mkOrder properties.
defsFinal =
# Avoid sorting if we don't have to.
if any (def: def.value._type or "" == "order") defsFinal'
then sortProperties defsFinal'
else defsFinal';
files = map (def: def.file) defsFinal; files = map (def: def.file) defsFinal;
# Type-check the remaining definitions, and merge them if # Type-check the remaining definitions, and merge them if
# possible. # possible.
@ -180,7 +186,7 @@ rec {
}; };
/* Given a config set, expand mkMerge properties, and push down the /* Given a config set, expand mkMerge properties, and push down the
mkIf properties into the children. The result is a list of other properties into the children. The result is a list of
config sets that do not have properties at top-level. For config sets that do not have properties at top-level. For
example, example,
@ -188,7 +194,7 @@ rec {
is transformed into is transformed into
[ { boot = set1; } { boot = mkIf cond set2; services mkIf cond set3; } ]. [ { boot = set1; } { boot = mkIf cond set2; services = mkIf cond set3; } ].
This transform is the critical step that allows mkIf conditions This transform is the critical step that allows mkIf conditions
to refer to the full configuration without creating an infinite to refer to the full configuration without creating an infinite
@ -201,7 +207,7 @@ rec {
map (mapAttrs (n: v: mkIf cfg.condition v)) (pushDownProperties cfg.content) map (mapAttrs (n: v: mkIf cfg.condition v)) (pushDownProperties cfg.content)
else if cfg._type or "" == "override" then else if cfg._type or "" == "override" then
map (mapAttrs (n: v: mkOverride cfg.priority v)) (pushDownProperties cfg.content) map (mapAttrs (n: v: mkOverride cfg.priority v)) (pushDownProperties cfg.content)
else else # FIXME: handle mkOrder?
[ cfg ]; [ cfg ];
/* Given a config value, expand mkMerge properties, and discharge /* Given a config value, expand mkMerge properties, and discharge
@ -253,6 +259,19 @@ rec {
strip = def: if def.value._type or "" == "override" then def // { value = def.value.content; } else def; strip = def: if def.value._type or "" == "override" then def // { value = def.value.content; } else def;
in concatMap (def: if getPrio def == highestPrio then [(strip def)] else []) defs; in concatMap (def: if getPrio def == highestPrio then [(strip def)] else []) defs;
/* Sort a list of properties. The sort priority of a property is
1000 by default, but can be overriden by wrapping the property
using mkOrder. */
sortProperties = defs:
let
strip = def:
if def.value._type or "" == "order"
then def // { value = def.value.content; inherit (def.value) priority; }
else def;
defs' = map strip defs;
compare = a: b: (a.priority or 1000) < (b.priority or 1000);
in sort compare defs';
/* Hack for backward compatibility: convert options of type /* Hack for backward compatibility: convert options of type
optionSet to configOf. FIXME: remove eventually. */ optionSet to configOf. FIXME: remove eventually. */
fixupOptionType = loc: opt: fixupOptionType = loc: opt:
@ -260,7 +279,7 @@ rec {
options' = opt.options or options' = opt.options or
(throw "Option `${showOption loc'}' has type optionSet but has no option attribute."); (throw "Option `${showOption loc'}' has type optionSet but has no option attribute.");
coerce = x: coerce = x:
if builtins.isFunction x then x if isFunction x then x
else { config, ... }: { options = x; }; else { config, ... }: { options = x; };
options = map coerce (flatten options'); options = map coerce (flatten options');
f = tp: f = tp:
@ -300,10 +319,17 @@ rec {
mkForce = mkOverride 50; mkForce = mkOverride 50;
mkVMOverride = mkOverride 10; # used by nixos-rebuild build-vm mkVMOverride = mkOverride 10; # used by nixos-rebuild build-vm
mkStrict = builtins.trace "`mkStrict' is obsolete; use `mkOverride 0' instead." (mkOverride 0);
mkFixStrictness = id; # obsolete, no-op mkFixStrictness = id; # obsolete, no-op
# FIXME: Add mkOrder back in. It's not currently used anywhere in mkOrder = priority: content:
# NixOS, but it should be useful. { _type = "order";
inherit priority content;
};
mkBefore = mkOrder 500;
mkAfter = mkOrder 1500;
/* Compatibility. */ /* Compatibility. */

View File

@ -34,12 +34,12 @@ rec {
mergeDefaultOption = loc: defs: mergeDefaultOption = loc: defs:
let list = getValues defs; in let list = getValues defs; in
if length list == 1 then head list if length list == 1 then head list
else if all builtins.isFunction list then x: mergeDefaultOption loc (map (f: f x) list) else if all isFunction list then x: mergeDefaultOption loc (map (f: f x) list)
else if all isList list then concatLists list else if all isList list then concatLists list
else if all isAttrs list then fold lib.mergeAttrs {} list else if all isAttrs list then fold lib.mergeAttrs {} list
else if all builtins.isBool list then fold lib.or false list else if all isBool list then fold lib.or false list
else if all builtins.isString list then lib.concatStrings list else if all isString list then lib.concatStrings list
else if all builtins.isInt list && all (x: x == head list) list then head list else if all isInt list && all (x: x == head list) list then head list
else throw "Cannot merge definitions of `${showOption loc}' given in ${showFiles (getFiles defs)}."; else throw "Cannot merge definitions of `${showOption loc}' given in ${showFiles (getFiles defs)}.";
/* Obsolete, will remove soon. Specify an option type or apply /* Obsolete, will remove soon. Specify an option type or apply
@ -54,7 +54,7 @@ rec {
mergeListOption = mergeTypedOption "list" isList concatLists; mergeListOption = mergeTypedOption "list" isList concatLists;
mergeStringOption = mergeTypedOption "string" builtins.isString lib.concatStrings; mergeStringOption = mergeTypedOption "string" isString lib.concatStrings;
mergeOneOption = loc: defs: mergeOneOption = loc: defs:
if defs == [] then abort "This case should never happen." if defs == [] then abort "This case should never happen."

View File

@ -2,15 +2,15 @@ let lists = import ./lists.nix; in
rec { rec {
gnu = linux; /* ++ hurd ++ kfreebsd ++ ... */ gnu = linux; /* ++ hurd ++ kfreebsd ++ ... */
linux = ["i686-linux" "x86_64-linux" "powerpc-linux" "armv5tel-linux" "armv7l-linux" "mips64el-linux"]; linux = ["i686-linux" "x86_64-linux" "armv5tel-linux" "armv7l-linux" "mips64el-linux"];
darwin = ["x86_64-darwin"]; darwin = ["x86_64-darwin"];
freebsd = ["i686-freebsd" "x86_64-freebsd" "powerpc-freebsd"]; freebsd = ["i686-freebsd" "x86_64-freebsd"];
openbsd = ["i686-openbsd" "x86_64-openbsd"]; openbsd = ["i686-openbsd" "x86_64-openbsd"];
netbsd = ["i686-netbsd" "x86_64-netbsd"]; netbsd = ["i686-netbsd" "x86_64-netbsd"];
cygwin = ["i686-cygwin"]; cygwin = ["i686-cygwin" "x86_64-cygwin"];
unix = linux ++ darwin ++ freebsd ++ openbsd; unix = linux ++ darwin ++ freebsd ++ openbsd;
all = linux ++ darwin ++ cygwin ++ freebsd ++ openbsd; all = linux ++ darwin ++ cygwin ++ freebsd ++ openbsd;
none = []; none = [];
allBut = platform: lists.filter (x: platform != x) all; allBut = platforms: lists.filter (x: !(builtins.elem x platforms)) all;
mesaPlatforms = ["i686-linux" "x86_64-linux" "x86_64-darwin" "armv5tel-linux" "armv6l-linux"]; mesaPlatforms = ["i686-linux" "x86_64-linux" "x86_64-darwin" "armv5tel-linux" "armv6l-linux"];
} }

View File

@ -10,9 +10,12 @@ rec {
cleanSource = cleanSource =
let filter = name: type: let baseName = baseNameOf (toString name); in ! ( let filter = name: type: let baseName = baseNameOf (toString name); in ! (
# Filter out Subversion and CVS directories. # Filter out Subversion and CVS directories.
(type == "directory" && (baseName == ".git" || baseName == ".svn" || baseName == "CVS")) || (type == "directory" && (baseName == ".git" || baseName == ".svn" || baseName == "CVS" || baseName == ".hg")) ||
# Filter out backup files. # Filter out backup files.
(lib.hasSuffix "~" baseName) lib.hasSuffix "~" baseName ||
# Filter out generates files.
lib.hasSuffix ".o" baseName ||
lib.hasSuffix ".so" baseName
); );
in src: builtins.filterSource filter src; in src: builtins.filterSource filter src;

View File

@ -7,7 +7,8 @@ inherit (builtins) add sub lessThan length;
in in
rec { rec {
inherit (builtins) stringLength substring head tail;
inherit (builtins) stringLength substring head tail isString;
# Concatenate a list of strings. # Concatenate a list of strings.
@ -55,12 +56,15 @@ rec {
optionalString = cond: string: if cond then string else ""; optionalString = cond: string: if cond then string else "";
# Determine whether a filename ends in the given suffix. # Determine whether a string has given prefix/suffix.
hasSuffix = ext: fileName: hasPrefix = pref: str:
let lenFileName = stringLength fileName; eqStrings (substring 0 (stringLength pref) str) pref;
lenExt = stringLength ext; hasSuffix = suff: str:
in !(lessThan lenFileName lenExt) && let
substring (sub lenFileName lenExt) lenFileName fileName == ext; lenStr = stringLength str;
lenSuff = stringLength suff;
in lenStr >= lenSuff &&
eqStrings (substring (lenStr - lenSuff) lenStr str) suff;
# Convert a string to a list of characters (i.e. singleton strings). # Convert a string to a list of characters (i.e. singleton strings).
@ -115,17 +119,21 @@ rec {
toLower = replaceChars upperChars lowerChars; toLower = replaceChars upperChars lowerChars;
toUpper = replaceChars lowerChars upperChars; toUpper = replaceChars lowerChars upperChars;
# Appends string context from another string
addContextFrom = a: b: (substring 0 0 a)+b;
# Compares strings not requiring context equality # Compares strings not requiring context equality
# Obviously, a workaround but works on all Nix versions # Obviously, a workaround but works on all Nix versions
eqStrings = a: b: (a+(substring 0 0 b)) == ((substring 0 0 a)+b); eqStrings = a: b: addContextFrom b a == addContextFrom a b;
# Cut a string with a separator and produces a list of strings which were # Cut a string with a separator and produces a list of strings which were
# separated by this separator. e.g., # separated by this separator. e.g.,
# `splitString "." "foo.bar.baz"' returns ["foo" "bar" "baz"]. # `splitString "." "foo.bar.baz"' returns ["foo" "bar" "baz"].
splitString = sep: s: splitString = _sep: _s:
let let
sep = addContextFrom _s _sep;
s = addContextFrom _sep _s;
sepLen = stringLength sep; sepLen = stringLength sep;
sLen = stringLength s; sLen = stringLength s;
lastSearch = sub sLen sepLen; lastSearch = sub sLen sepLen;
@ -154,8 +162,18 @@ rec {
preLen = stringLength pre; preLen = stringLength pre;
sLen = stringLength s; sLen = stringLength s;
in in
if pre == substring 0 preLen s then if hasPrefix pre s then
substring preLen (sub sLen preLen) s substring preLen (sLen - preLen) s
else
s;
removeSuffix = suf: s:
let
sufLen = stringLength suf;
sLen = stringLength s;
in
if sufLen <= sLen && eqStrings suf (substring (sLen - sufLen) sufLen s) then
substring 0 (sLen - sufLen) s
else else
s; s;

View File

@ -35,4 +35,19 @@ rec {
else if builtins.isAttrs x else if builtins.isAttrs x
then deepSeqAttrs x y then deepSeqAttrs x y
else seq x y; else seq x y;
# Pull in some builtins not included elsewhere.
inherit (builtins)
pathExists readFile isBool isFunction
isInt add sub lessThan;
# Return the Nixpkgs version number.
nixpkgsVersion =
let suffixFile = ../.version-suffix; in
readFile ../.version
+ (if pathExists suffixFile then readFile suffixFile else "pre-git");
# Whether we're being called by nix-shell. This is useful to
inNixShell = builtins.getEnv "IN_NIX_SHELL" == "1";
} }

View File

@ -10,7 +10,6 @@ with import ./strings.nix;
rec { rec {
isType = type: x: (x._type or "") == type; isType = type: x: (x._type or "") == type;
typeOf = x: x._type or "";
setType = typeName: value: value // { setType = typeName: value: value // {
_type = typeName; _type = typeName;
@ -48,19 +47,19 @@ rec {
bool = mkOptionType { bool = mkOptionType {
name = "boolean"; name = "boolean";
check = builtins.isBool; check = isBool;
merge = loc: fold (x: y: x.value || y) false; merge = loc: fold (x: y: x.value || y) false;
}; };
int = mkOptionType { int = mkOptionType {
name = "integer"; name = "integer";
check = builtins.isInt; check = isInt;
merge = mergeOneOption; merge = mergeOneOption;
}; };
str = mkOptionType { str = mkOptionType {
name = "string"; name = "string";
check = builtins.isString; check = isString;
merge = mergeOneOption; merge = mergeOneOption;
}; };
@ -68,7 +67,7 @@ rec {
# separator between the values). # separator between the values).
separatedString = sep: mkOptionType { separatedString = sep: mkOptionType {
name = "string"; name = "string";
check = builtins.isString; check = isString;
merge = loc: defs: concatStringsSep sep (getValues defs); merge = loc: defs: concatStringsSep sep (getValues defs);
}; };
@ -132,7 +131,7 @@ rec {
{ inherit (def) file; { inherit (def) file;
value = listToAttrs ( value = listToAttrs (
imap (elemIdx: elem: imap (elemIdx: elem:
{ name = "unnamed-${toString defIdx}.${toString elemIdx}"; { name = elem.name or "unnamed-${toString defIdx}.${toString elemIdx}";
value = elem; value = elem;
}) def.value); }) def.value);
} }
@ -170,7 +169,7 @@ rec {
functionTo = elemType: mkOptionType { functionTo = elemType: mkOptionType {
name = "function that evaluates to a(n) ${elemType.name}"; name = "function that evaluates to a(n) ${elemType.name}";
check = builtins.isFunction; check = isFunction;
merge = loc: defs: merge = loc: defs:
fnArgs: elemType.merge loc (map (fn: { inherit (fn) file; value = fn.value fnArgs; }) defs); fnArgs: elemType.merge loc (map (fn: { inherit (fn) file; value = fn.value fnArgs; }) defs);
getSubOptions = elemType.getSubOptions; getSubOptions = elemType.getSubOptions;
@ -183,10 +182,10 @@ rec {
in in
mkOptionType rec { mkOptionType rec {
name = "submodule"; name = "submodule";
check = x: isAttrs x || builtins.isFunction x; check = x: isAttrs x || isFunction x;
merge = loc: defs: merge = loc: defs:
let let
coerce = def: if builtins.isFunction def then def else { config = def; }; coerce = def: if isFunction def then def else { config = def; };
modules = opts' ++ map (def: { _file = def.file; imports = [(coerce def.value)]; }) defs; modules = opts' ++ map (def: { _file = def.file; imports = [(coerce def.value)]; }) defs;
in (evalModules { inherit modules; args.name = last loc; prefix = loc; }).config; in (evalModules { inherit modules; args.name = last loc; prefix = loc; }).config;
getSubOptions = prefix: (evalModules getSubOptions = prefix: (evalModules
@ -195,6 +194,18 @@ rec {
args = { name = ""; }; }).options; args = { name = ""; }; }).options;
}; };
enum = values: mkOptionType {
name = "one of ${concatStringsSep ", " values}";
check = flip elem values;
merge = mergeOneOption;
};
either = t1: t2: mkOptionType {
name = "${t1.name} or ${t2.name}";
check = x: t1.check x || t2.check x;
merge = mergeOneOption;
};
# Obsolete alternative to configOf. It takes its option # Obsolete alternative to configOf. It takes its option
# declarations from the options attribute of containing option # declarations from the options attribute of containing option
# declaration. # declaration.

View File

@ -1,45 +0,0 @@
#! /bin/sh -e
distDir=${NIX_TARBALLS_CACHE:-/tarballs}
url="$1"
file="$2"
if [ -z "$url" ]; then echo "syntax: $0 URL"; exit 0; fi
base="$(basename "$url")"
if [ -z "$base" ]; then echo "bad URL"; exit 1; fi
dstPath="$distDir/$base"
if [ -e "$dstPath" ]; then if [ -n "$VERBOSE" ]; then echo "$dstPath already exists"; fi; exit 0; fi
if [ -z "$file" ]; then
echo "downloading $url to $dstPath"
if [ -n "$DRY_RUN" ]; then exit 0; fi
declare -a res
if ! res=($(PRINT_PATH=1 nix-prefetch-url "$url")); then
exit
fi
storePath=${res[1]}
else
storePath="$file"
fi
cp $storePath "$dstPath.tmp.$$"
mv -f "$dstPath.tmp.$$" "$dstPath"
echo "hashing $dstPath"
md5=$(nix-hash --flat --type md5 "$dstPath")
ln -sfn "../$base" $distDir/md5/$md5
sha1=$(nix-hash --flat --type sha1 "$dstPath")
ln -sfn "../$base" $distDir/sha1/$sha1
sha256=$(nix-hash --flat --type sha256 "$dstPath")
ln -sfn "../$base" $distDir/sha256/$sha256
ln -sfn "../$base" $distDir/sha256/$(nix-hash --type sha256 --to-base32 "$sha256")

View File

@ -0,0 +1,97 @@
#! /run/current-system/sw/bin/perl -w
use strict;
use XML::Simple;
use File::Basename;
use File::Path;
use File::Copy 'cp';
use IPC::Open2;
use Nix::Store;
my $myDir = dirname($0);
my $tarballsCache = $ENV{'NIX_TARBALLS_CACHE'} // "/tarballs";
my $xml = `nix-instantiate --eval-only --xml --strict '<nixpkgs/maintainers/scripts/find-tarballs.nix>'`;
die "$0: evaluation failed\n" if $? != 0;
my $data = XMLin($xml) or die;
mkpath($tarballsCache);
mkpath("$tarballsCache/md5");
mkpath("$tarballsCache/sha1");
mkpath("$tarballsCache/sha256");
foreach my $file (@{$data->{list}->{attrs}}) {
my $url = $file->{attr}->{url}->{string}->{value};
my $algo = $file->{attr}->{type}->{string}->{value};
my $hash = $file->{attr}->{hash}->{string}->{value};
if ($url !~ /^http:/ && $url !~ /^https:/ && $url !~ /^ftp:/ && $url !~ /^mirror:/) {
print STDERR "skipping $url (unsupported scheme)\n";
next;
}
$url =~ /([^\/]+)$/;
my $fn = $1;
if (!defined $fn) {
print STDERR "skipping $url (no file name)\n";
next;
}
if ($fn =~ /[&?=%]/ || $fn =~ /^\./) {
print STDERR "skipping $url (bad character in file name)\n";
next;
}
if ($fn !~ /[a-zA-Z]/) {
print STDERR "skipping $url (no letter in file name)\n";
next;
}
if ($fn !~ /[0-9]/) {
print STDERR "skipping $url (no digit in file name)\n";
next;
}
if ($fn !~ /[-_\.]/) {
print STDERR "skipping $url (no dash/dot/underscore in file name)\n";
next;
}
my $dstPath = "$tarballsCache/$fn";
next if -e $dstPath;
print "downloading $url to $dstPath...\n";
next if $ENV{DRY_RUN};
$ENV{QUIET} = 1;
$ENV{PRINT_PATH} = 1;
my $fh;
my $pid = open($fh, "-|", "nix-prefetch-url", "--type", $algo, $url, $hash) or die;
waitpid($pid, 0) or die;
if ($? != 0) {
print STDERR "failed to fetch $url: $?\n";
next;
}
<$fh>; my $storePath = <$fh>; chomp $storePath;
die unless -e $storePath;
cp($storePath, $dstPath) or die;
my $md5 = hashFile("md5", 0, $storePath) or die;
symlink("../$fn", "$tarballsCache/md5/$md5");
my $sha1 = hashFile("sha1", 0, $storePath) or die;
symlink("../$fn", "$tarballsCache/sha1/$sha1");
my $sha256 = hashFile("sha256", 0, $storePath) or die;
symlink("../$fn", "$tarballsCache/sha256/$sha256");
$sha256 = hashFile("sha256", 1, $storePath) or die;
symlink("../$fn", "$tarballsCache/sha256/$sha256");
}

View File

@ -1,27 +0,0 @@
#! /bin/sh -e
urls=$(nix-instantiate --eval-only --xml --strict '<nixpkgs/maintainers/scripts/eval-release.nix>' \
| grep -A2 'name="urls"' \
| grep '<string value=' \
| sed 's/.*"\(.*\)".*/\1/' \
| sort | uniq)
for url in $urls; do
if echo "$url" | grep -q -E "www.cs.uu.nl|nixos.org|.stratego-language.org|java.sun.com|ut2004|linuxq3a|RealPlayer|Adbe|belastingdienst|microsoft|armijn/.nix|sun.com|archive.eclipse.org"; then continue; fi
# Check the URL scheme.
if ! echo "$url" | grep -q -E "^[a-z]+://"; then echo "skipping $url (no URL scheme)"; continue; fi
# Check the basename. It should include something resembling a version.
base="$(basename "$url")"
#if ! echo "$base" | grep -q -E "[-_].*[0-9].*"; then echo "skipping $url (no version)"; continue; fi
if ! echo "$base" | grep -q -E "[a-zA-Z]"; then echo "skipping $url (no letter in name)"; continue; fi
if ! echo "$base" | grep -q -E "[0-9]"; then echo "skipping $url (no digit in name)"; continue; fi
if ! echo "$base" | grep -q -E "[-_\.]"; then echo "skipping $url (no dot/underscore in name)"; continue; fi
if echo "$base" | grep -q -E "[&?=%]"; then echo "skipping $url (bad character in name)"; continue; fi
if [ "${base:0:1}" = "." ]; then echo "skipping $url (starts with a dot)"; continue; fi
$(dirname $0)/copy-tarball.sh "$url"
done
echo DONE

View File

@ -0,0 +1,45 @@
# This expression returns a list of all fetchurl calls used by all
# packages reachable from release.nix.
with import ../.. { };
with lib;
let
root = removeAttrs (import ../../pkgs/top-level/release.nix { }) [ "tarball" "unstable" ];
uniqueUrls = map (x: x.file) (genericClosure {
startSet = map (file: { key = file.url; inherit file; }) urls;
operator = const [ ];
});
urls = map (drv: { url = head drv.urls; hash = drv.outputHash; type = drv.outputHashAlgo; }) fetchurlDependencies;
fetchurlDependencies = filter (drv: drv.outputHash or "" != "" && drv ? urls) dependencies;
dependencies = map (x: x.value) (genericClosure {
startSet = map keyDrv (derivationsIn' root);
operator = { key, value }: map keyDrv (immediateDependenciesOf value);
});
derivationsIn' = x:
if !canEval x then []
else if isDerivation x then optional (canEval x.drvPath) x
else if isList x then concatLists (map derivationsIn' x)
else if isAttrs x then concatLists (mapAttrsToList (n: v: derivationsIn' v) x)
else [ ];
keyDrv = drv: if canEval drv.drvPath then { key = drv.drvPath; value = drv; } else { };
immediateDependenciesOf = drv:
concatLists (mapAttrsToList (n: v: derivationsIn v) (removeAttrs drv ["meta" "passthru"]));
derivationsIn = x:
if !canEval x then []
else if isDerivation x then optional (canEval x.drvPath) x
else if isList x then concatLists (map derivationsIn x)
else [ ];
canEval = val: (builtins.tryEval val).success;
in uniqueUrls

View File

@ -31,8 +31,7 @@ GetOptions("package|p=s" => \$filter,
"maintainer|m=s" => \$maintainer, "maintainer|m=s" => \$maintainer,
"file|f=s" => \$path, "file|f=s" => \$path,
"help" => sub { showHelp() } "help" => sub { showHelp() }
) ) or exit 1;
or die("syntax: $0 ...\n");
# Evaluate Nixpkgs into an XML representation. # Evaluate Nixpkgs into an XML representation.
my $xml = `nix-env -f '$path' -qa '$filter' --xml --meta --drv-path`; my $xml = `nix-env -f '$path' -qa '$filter' --xml --meta --drv-path`;

View File

@ -1,146 +0,0 @@
/* Tool to sort attribute sets. Primarily useful for keeping
all-packages.nix tidy.
To compile:
$ strc -i ../../maintainers/scripts/sort-attrs.str -la stratego-lib
Typical invocation:
$ sglr -m -p ~/Dev/nix/src/libexpr/nix.tbl -i all-packages.nix \
| implode-asfix --lex \
| ../../maintainers/scripts/sort-attrs \
| asfix-yield
*/
module sort-attrs
imports
libstratego-lib
libstratego-sglr
strategies
no-wsp = !appl(prod([], cf(opt(layout())), no-attrs()), [])
rules
list-sep(s): [] -> []
list-sep(s): [x | xs] -> [[x | before] | <list-sep(s)> [split | after]]
where
<split-fetch-keep(s)> xs => (before, split, after)
list-sep(s): [x | xs] -> [[x | xs]]
where
<not(split-fetch-keep(s))> xs
list-sep-end(s): xs -> [<conc> (before, [split]) | <list-sep-end(s)> after]
where
<split-fetch-keep(s)> xs => (before, split, after)
list-sep-end(s): xs -> [xs]
where
<not(split-fetch-keep(s))> xs
sort-attrs:
appl(p@prod(_, _, attrs([term(cons("Attrs"))])),
[ lit("{")
, ws1
, appl(p2@list(cf(iter-star(sort("Bind")))), attrs)
, ws2
, lit("}")
]
) ->
appl(p, [lit("{"), <no-wsp>, appl(p2, <concat> attrs'), ws2, lit("}")])
where
<debug> "found it";
<attach-wsp> [ws1 | attrs] => withWSP;
<list-sep(starts-section)> withWSP => groups;
<length; debug> groups;
<map({x', x'', x''', xs', starts, starts': \[x | xs] -> [x''' | xs']
where
<remove-section-start> x => (x', starts);
<map(regularise-empty-lines); if !starts; debug; sortable-section; debug then qsort(compare-attrs) else id end> [x' | xs] => [x'' | xs'];
<[] <+ \x -> ["\n\n\n" | x]\ > starts => starts';
<prepend-layout> (starts', x'') => x'''
\ })> groups => attrs';
<debug> "did it"
attach-wsp: [a, b | cs] -> [(a, b) | <attach-wsp> cs]
attach-wsp: [] -> []
strategies
starts-section =
?x@(appl(prod([cf(layout())], cf(opt(layout())), no-attrs()), cs), attr);
<implode-string; is-substring(!"###")> cs;
!x
rules
sortable-section = ?[s]; !s; explode-string; not(fetch({x: ?x; !(x, 97); geq}))
remove-section-start:
(appl(prod([cf(layout())], cf(opt(layout())), no-attrs()), cs), attr) ->
((appl(prod([cf(layout())], cf(opt(layout())), no-attrs()), cs'), attr), starts)
where
!cs;
list-sep-end(?10); // separate into lines, keeping the \n
map(implode-string);
partition(where(is-substring(!"###"))) => (starts, rest);
<map(explode-string); concat> rest => cs'
regularise-empty-lines:
(appl(prod([cf(layout())], cf(opt(layout())), no-attrs()), cs), attr) ->
(appl(prod([cf(layout())], cf(opt(layout())), no-attrs()), cs''), attr)
where
// separate into lines, keeping the \n
// last whitespace is significant, keep
<list-sep-end(?10); split-init-last> cs => (init, last);
<regularise-empty-lines'> init => cs'; // remove whitespace-only lines
<concat> [<explode-string> "\n\n", <concat> cs', last] => cs'' // add one empty line
/* Dirty hack: *do* keep the first empty line following a non-empty line. !!! order matters */
regularise-empty-lines': [] -> []
regularise-empty-lines': [x, y | xs] -> [x, y | <regularise-empty-lines'> xs]
where
<fetch-elem(not(?10 <+ ?32))> x;
<not(fetch-elem(not(?10 <+ ?32)))> y
regularise-empty-lines': [x | xs] -> [x | <regularise-empty-lines'> xs]
where <fetch-elem(not(?10 <+ ?32))> x
regularise-empty-lines': [x | xs] -> <regularise-empty-lines'> xs
where <not(fetch-elem(not(?10 <+ ?32)))> x
prepend-layout:
(text, (appl(prod([cf(layout())], cf(opt(layout())), no-attrs()), cs), attr)) ->
(appl(prod([cf(layout())], cf(opt(layout())), no-attrs()), cs''), attr)
where
<implode-string> cs => cs';
<conc-strings; explode-string> (<concat-strings> text, cs') => cs''
compare-attrs:
x@
( (_, appl(p1@prod(_, _, attrs([term(cons("Bind"))])), [id1 | xs1]))
, (_, appl(p2@prod(_, _, attrs([term(cons("Bind"))])), [id2 | xs2]))
)
-> x
where
<string-lt> (id1, id2)
strategies
main = io-wrap(
oncetd(sort-attrs)
)

View File

@ -1 +0,0 @@
improvements to vsftpd module

12
nixos/doc/manual/README Normal file
View File

@ -0,0 +1,12 @@
To build the manual, you need Nix installed on your system (no need
for NixOS). To install Nix, follow the instructions at
https://nixos.org/nix/download.html
When you have Nix on your system, in the root directory of the project
(i.e., `nixpkgs`), run:
nix-build nixos/release.nix -A manual.x86_64-linux
When this command successfully finishes, it will tell you where the
manual got generated.

View File

@ -237,7 +237,7 @@ postgresql.package = pkgs.postgresql90;
</section> </section>
<section><title>Abstractions</title> <section xml:id="sec-module-abstractions"><title>Abstractions</title>
<para>If you find yourself repeating yourself over and over, its time <para>If you find yourself repeating yourself over and over, its time
to abstract. Take, for instance, this Apache HTTP Server configuration: to abstract. Take, for instance, this Apache HTTP Server configuration:
@ -399,7 +399,7 @@ of an expression to be spliced into a string.</para>
</section> </section>
<section><title>Modularity</title> <section xml:id="sec-modularity"><title>Modularity</title>
<para>The NixOS configuration mechanism is modular. If your <para>The NixOS configuration mechanism is modular. If your
<filename>configuration.nix</filename> becomes too big, you can split <filename>configuration.nix</filename> becomes too big, you can split
@ -443,8 +443,20 @@ Note that both <filename>configuration.nix</filename> and
define an option, NixOS will try to <emphasis>merge</emphasis> the define an option, NixOS will try to <emphasis>merge</emphasis> the
definitions. In the case of definitions. In the case of
<option>environment.systemPackages</option>, thats easy: the lists of <option>environment.systemPackages</option>, thats easy: the lists of
packages can simply be concatenated. For other types of options, a packages can simply be concatenated. The value in
merge may not be possible: for instance, if two modules define <filename>configuration.nix</filename> is merged last, so for
list-type options, it will appear at the end of the merged list. If
you want it to appear first, you can use <varname>mkBefore</varname>:
<programlisting>
boot.kernelModules = mkBefore [ "kvm-intel" ];
</programlisting>
This causes the <literal>kvm-intel</literal> kernel module to be
loaded before any other kernel modules.</para>
<para>For other types of options, a merge may not be possible. For
instance, if two modules define
<option>services.httpd.adminAddr</option>, <option>services.httpd.adminAddr</option>,
<command>nixos-rebuild</command> will give an error: <command>nixos-rebuild</command> will give an error:
@ -526,7 +538,7 @@ nix-repl> map (x: x.hostName) config.services.httpd.virtualHosts
</section> </section>
<section><title>Syntax summary</title> <section xml:id="sec-nix-syntax-summary"><title>Syntax summary</title>
<para>Below is a summary of the most important syntactic constructs in <para>Below is a summary of the most important syntactic constructs in
the Nix expression language. Its not complete. In particular, there the Nix expression language. Its not complete. In particular, there
@ -718,7 +730,7 @@ manual</link> for the rest.</para>
<!--===============================================================--> <!--===============================================================-->
<section><title>Package management</title> <section xml:id="sec-package-management"><title>Package management</title>
<para>This section describes how to add additional packages to your <para>This section describes how to add additional packages to your
system. NixOS has two distinct styles of package management: system. NixOS has two distinct styles of package management:
@ -861,7 +873,7 @@ Any package in Nixpkgs that depends on <literal>emacs</literal> will
be passed your customised instance. (However, the value be passed your customised instance. (However, the value
<literal>pkgs.emacs</literal> in <literal>pkgs.emacs</literal> in
<varname>nixpkgs.config.packageOverrides</varname> refers to the <varname>nixpkgs.config.packageOverrides</varname> refers to the
original rather than overriden instance, to prevent an infinite original rather than overridden instance, to prevent an infinite
recursion.)</para> recursion.)</para>
</section> </section>
@ -923,7 +935,7 @@ environment.systemPackages = [ (import ./my-hello.nix) ];
</programlisting> </programlisting>
where <filename>my-hello.nix</filename> contains: where <filename>my-hello.nix</filename> contains:
<programlisting> <programlisting>
with &lt;nixpkgs> {}; # bring all of Nixpkgs into scope with import &lt;nixpkgs> {}; # bring all of Nixpkgs into scope
stdenv.mkDerivation rec { stdenv.mkDerivation rec {
name = "hello-2.8"; name = "hello-2.8";
@ -1021,25 +1033,23 @@ states that a user account named <literal>alice</literal> shall exist:
<programlisting> <programlisting>
users.extraUsers.alice = users.extraUsers.alice =
{ createHome = true; { isNormalUser = true;
home = "/home/alice";
description = "Alice Foobar"; description = "Alice Foobar";
extraGroups = [ "wheel" ]; extraGroups = [ "wheel" "networkmanager" ];
isSystemUser = false;
useDefaultShell = true;
openssh.authorizedKeys.keys = [ "ssh-dss AAAAB3Nza... alice@foobar" ]; openssh.authorizedKeys.keys = [ "ssh-dss AAAAB3Nza... alice@foobar" ];
}; };
</programlisting> </programlisting>
Note that <literal>alice</literal> is a member of the Note that <literal>alice</literal> is a member of the
<literal>wheel</literal> group, which allows her to use <literal>wheel</literal> and <literal>networkmanager</literal> groups,
<command>sudo</command> to execute commands as which allows her to use <command>sudo</command> to execute commands as
<literal>root</literal>. Also note the SSH public key that allows <literal>root</literal> and to configure the network, respectively.
remote logins with the corresponding private key. Users created in Also note the SSH public key that allows remote logins with the
this way do not have a password by default, so they cannot log in via corresponding private key. Users created in this way do not have a
mechanisms that require a password. However, you can use the password by default, so they cannot log in via mechanisms that require
<command>passwd</command> program to set a password, which is retained a password. However, you can use the <command>passwd</command> program
across invocations of <command>nixos-rebuild</command>.</para> to set a password, which is retained across invocations of
<command>nixos-rebuild</command>.</para>
<para>A user ID (uid) is assigned automatically. You can also specify <para>A user ID (uid) is assigned automatically. You can also specify
a uid manually by adding a uid manually by adding
@ -1060,11 +1070,6 @@ users.extraGroups.students.gid = 1000;
As with users, the group ID (gid) is optional and will be assigned As with users, the group ID (gid) is optional and will be assigned
automatically if its missing.</para> automatically if its missing.</para>
<warning><para>Currently declarative user management is not perfect:
<command>nixos-rebuild</command> does not know how to realise certain
configuration changes. This includes removing a user or group, and
removing group membership from a user.</para></warning>
<para>In the imperative style, users and groups are managed by <para>In the imperative style, users and groups are managed by
commands such as <command>useradd</command>, commands such as <command>useradd</command>,
<command>groupmod</command> and so on. For instance, to create a user <command>groupmod</command> and so on. For instance, to create a user
@ -1172,7 +1177,7 @@ fileSystems."/".device = "/dev/mapper/crypted";
<!--===============================================================--> <!--===============================================================-->
<section><title>X Window System</title> <section xml:id="sec-x11"><title>X Window System</title>
<para>The X Window System (X11) provides the basis of NixOS graphical <para>The X Window System (X11) provides the basis of NixOS graphical
user interface. It can be enabled as follows: user interface. It can be enabled as follows:
@ -1235,7 +1240,7 @@ with other kernel modules.</para>
<para>On 64-bit systems, if you want full acceleration for 32-bit <para>On 64-bit systems, if you want full acceleration for 32-bit
programs such as Wine, you should also set the following: programs such as Wine, you should also set the following:
<programlisting> <programlisting>
service.xserver.driSupport32Bit = true; services.xserver.driSupport32Bit = true;
</programlisting> </programlisting>
</para> </para>
@ -1264,9 +1269,31 @@ services.xserver.synaptics.twoFingerScroll = true;
<!--===============================================================--> <!--===============================================================-->
<section><title>Networking</title> <section xml:id="sec-networking"><title>Networking</title>
<section><title>Secure shell access</title> <section xml:id="sec-networkmanager"><title>NetworkManager</title>
<para>To facilitate network configuration, some desktop environments
use NetworkManager. You can enable NetworkManager by setting:
<programlisting>
services.networkmanager.enable = true;
</programlisting>
Some desktop managers (e.g., GNOME) enable NetworkManager
automatically for you.</para>
<para>All users that should have permission to change network settings
must belong to the <code>networkmanager</code> group.</para>
<note><para><code>services.networkmanager</code> and
<code>services.wireless</code> can not be enabled at the same time:
you can still connect to the wireless networks using
NetworkManager.</para></note>
</section>
<section xml:id="sec-ssh"><title>Secure shell access</title>
<para>Secure shell (SSH) access to your machine can be enabled by <para>Secure shell (SSH) access to your machine can be enabled by
setting: setting:
@ -1294,7 +1321,7 @@ users.extraUsers.alice.openssh.authorizedKeys.keys =
</section> </section>
<section><title>IPv4 configuration</title> <section xml:id="sec-ipv4"><title>IPv4 configuration</title>
<para>By default, NixOS uses DHCP (specifically, <para>By default, NixOS uses DHCP (specifically,
<command>dhcpcd</command>) to automatically configure network <command>dhcpcd</command>) to automatically configure network
@ -1337,7 +1364,7 @@ provide the host name.</para>
</section> </section>
<section><title>IPv6 configuration</title> <section xml:id="sec-ipv6"><title>IPv6 configuration</title>
<para>IPv6 is enabled by default. Stateless address autoconfiguration <para>IPv6 is enabled by default. Stateless address autoconfiguration
is used to automatically assign IPv6 addresses to all interfaces. You is used to automatically assign IPv6 addresses to all interfaces. You
@ -1352,17 +1379,19 @@ networking.enableIPv6 = false;
</section> </section>
<section><title>Firewall</title> <section xml:id="sec-firewall"><title>Firewall</title>
<para>NixOS has a simple stateful firewall that blocks incoming <para>NixOS has a simple stateful firewall that blocks incoming
connections and other unexpected packets. The firewall applies to connections and other unexpected packets. The firewall applies to
both IPv4 and IPv6 traffic. It can be enabled as follows: both IPv4 and IPv6 traffic. It is enabled by default. It can be
disabled as follows:
<programlisting> <programlisting>
networking.firewall.enable = true; networking.firewall.enable = false;
</programlisting> </programlisting>
You can open specific TCP ports to the outside world: If the firewall is enabled, you can open specific TCP ports to the
outside world:
<programlisting> <programlisting>
networking.firewall.allowedTCPPorts = [ 80 443 ]; networking.firewall.allowedTCPPorts = [ 80 443 ];
@ -1384,7 +1413,12 @@ always allowed.)</para>
</section> </section>
<section><title>Wireless networks</title> <section xml:id="sec-wireless"><title>Wireless networks</title>
<para>For a desktop installation using NetworkManager (e.g., GNOME),
you just have to make sure the user is in the
<code>networkmanager</code> group and you can skip the rest of this
section on wireless networks.</para>
<para> <para>
NixOS will start wpa_supplicant for you if you enable this setting: NixOS will start wpa_supplicant for you if you enable this setting:
@ -1445,7 +1479,7 @@ networking.localCommands =
<!--===============================================================--> <!--===============================================================-->
<section><title>Linux kernel</title> <section xml:id="sec-kernel-config"><title>Linux kernel</title>
<para>You can override the Linux kernel and associated packages using <para>You can override the Linux kernel and associated packages using
the option <option>boot.kernelPackages</option>. For instance, this the option <option>boot.kernelPackages</option>. For instance, this
@ -1458,10 +1492,11 @@ are specific to the kernel version, such as the NVIDIA video drivers.
This ensures that driver packages are consistent with the This ensures that driver packages are consistent with the
kernel.</para> kernel.</para>
<para>The default Linux kernel configuration should be fine for most <para>The default Linux kernel configuration should be fine for most users. You can see the configuration of your current kernel with the following command:
users. You can see the configuration of your current kernel in <programlisting>
<filename>/run/booted-system/kernel-modules/config</filename>. If you cat /proc/config.gz | gunzip
want to change the kernel configuration, you can use the </programlisting>
If you want to change the kernel configuration, you can use the
<option>packageOverrides</option> feature (see <xref <option>packageOverrides</option> feature (see <xref
linkend="sec-customising-packages" />). For instance, to enable linkend="sec-customising-packages" />). For instance, to enable
support for the kernel debugger KGDB: support for the kernel debugger KGDB:

View File

@ -0,0 +1,242 @@
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xml:id="ch-containers">
<title>Containers</title>
<para>NixOS allows you to easily run other NixOS instances as
<emphasis>containers</emphasis>. Containers are a light-weight
approach to virtualisation that runs software in the container at the
same speed as in the host system. NixOS containers share the Nix store
of the host, making container creation very efficient.</para>
<warning><para>Currently, NixOS containers are not perfectly isolated
from the host system. This means that a user with root access to the
container can do things that affect the host. So you should not give
container root access to untrusted users.</para></warning>
<para>NixOS containers can be created in two ways: imperatively, using
the command <command>nixos-container</command>, and declaratively, by
specifying them in your <filename>configuration.nix</filename>. The
declarative approach implies that containers get upgraded along with
your host system when you run <command>nixos-rebuild</command>, which
is often not what you want. By contrast, in the imperative approach,
containers are configured and updated independently from the host
system.</para>
<section><title>Imperative container management</title>
<para>Well cover imperative container management using
<command>nixos-container</command> first. You create a container with
identifier <literal>foo</literal> as follows:
<screen>
$ nixos-container create foo
</screen>
This creates the containers root directory in
<filename>/var/lib/containers/foo</filename> and a small configuration
file in <filename>/etc/containers/foo.conf</filename>. It also builds
the containers initial system configuration and stores it in
<filename>/nix/var/nix/profiles/per-container/foo/system</filename>. You
can modify the initial configuration of the container on the command
line. For instance, to create a container that has
<command>sshd</command> running, with the given public key for
<literal>root</literal>:
<screen>
$ nixos-container create foo --config 'services.openssh.enable = true; \
users.extraUsers.root.openssh.authorizedKeys.keys = ["ssh-dss AAAAB3N…"];'
</screen>
</para>
<para>Creating a container does not start it. To start the container,
run:
<screen>
$ nixos-container start foo
</screen>
This command will return as soon as the container has booted and has
reached <literal>multi-user.target</literal>. On the host, the
container runs within a systemd unit called
<literal>container@<replaceable>container-name</replaceable>.service</literal>.
Thus, if something went wrong, you can get status info using
<command>systemctl</command>:
<screen>
$ systemctl status container@foo
</screen>
</para>
<para>If the container has started succesfully, you can log in as
root using the <command>root-login</command> operation:
<screen>
$ nixos-container root-login foo
[root@foo:~]#
</screen>
Note that only root on the host can do this (since there is no
authentication). You can also get a regular login prompt using the
<command>login</command> operation, which is available to all users on
the host:
<screen>
$ nixos-container login foo
foo login: alice
Password: ***
</screen>
With <command>nixos-container run</command>, you can execute arbitrary
commands in the container:
<screen>
$ nixos-container run foo -- uname -a
Linux foo 3.4.82 #1-NixOS SMP Thu Mar 20 14:44:05 UTC 2014 x86_64 GNU/Linux
</screen>
</para>
<para>There are several ways to change the configuration of the
container. First, on the host, you can edit
<literal>/var/lib/container/<replaceable>name</replaceable>/etc/nixos/configuration.nix</literal>,
and run
<screen>
$ nixos-container update foo
</screen>
This will build and activate the new configuration. You can also
specify a new configuration on the command line:
<screen>
$ nixos-container update foo --config 'services.httpd.enable = true; \
services.httpd.adminAddr = "foo@example.org";'
$ curl http://$(nixos-container show-ip foo)/
&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">…
</screen>
However, note that this will overwrite the containers
<filename>/etc/nixos/configuration.nix</filename>.</para>
<para>Alternatively, you can change the configuration from within the
container itself by running <command>nixos-rebuild switch</command>
inside the container. Note that the container by default does not have
a copy of the NixOS channel, so you should run <command>nix-channel
--update</command> first.</para>
<para>Containers can be stopped and started using
<literal>nixos-container stop</literal> and <literal>nixos-container
start</literal>, respectively, or by using
<command>systemctl</command> on the containers service unit. To
destroy a container, including its file system, do
<screen>
$ nixos-container destroy foo
</screen>
</para>
</section>
<section><title>Declarative container specification</title>
<para>You can also specify containers and their configuration in the
hosts <filename>configuration.nix</filename>. For example, the
following specifies that there shall be a container named
<literal>database</literal> running PostgreSQL:
<programlisting>
containers.database =
{ config =
{ config, pkgs, ... }:
{ services.postgresql.enable = true;
services.postgresql.package = pkgs.postgresql92;
};
};
</programlisting>
If you run <literal>nixos-rebuild switch</literal>, the container will
be built and started. If the container was already running, it will be
updated in place, without rebooting.</para>
<para>By default, declarative containers share the network namespace
of the host, meaning that they can listen on (privileged)
ports. However, they cannot change the network configuration. You can
give a container its own network as follows:
<programlisting>
containers.database =
{ privateNetwork = true;
hostAddress = "192.168.100.10";
localAddress = "192.168.100.11";
};
</programlisting>
This gives the container a private virtual Ethernet interface with IP
address <literal>192.168.100.11</literal>, which is hooked up to a
virtual Ethernet interface on the host with IP address
<literal>192.168.100.10</literal>. (See the next section for details
on container networking.)</para>
<para>To disable the container, just remove it from
<filename>configuration.nix</filename> and run <literal>nixos-rebuild
switch</literal>. Note that this will not delete the root directory of
the container in <literal>/var/lib/containers</literal>.</para>
</section>
<section><title>Networking</title>
<para>When you create a container using <literal>nixos-container
create</literal>, it gets it own private IPv4 address in the range
<literal>10.233.0.0/16</literal>. You can get the containers IPv4
address as follows:
<screen>
$ nixos-container show-ip foo
10.233.4.2
$ ping -c1 10.233.4.2
64 bytes from 10.233.4.2: icmp_seq=1 ttl=64 time=0.106 ms
</screen>
</para>
<para>Networking is implemented using a pair of virtual Ethernet
devices. The network interface in the container is called
<literal>eth0</literal>, while the matching interface in the host is
called <literal>ve-<replaceable>container-name</replaceable></literal>
(e.g., <literal>ve-foo</literal>). The container has its own network
namespace and the <literal>CAP_NET_ADMIN</literal> capability, so it
can perform arbitrary network configuration such as setting up
firewall rules, without affecting or having access to the hosts
network.</para>
<para>By default, containers cannot talk to the outside network. If
you want that, you should set up Network Address Translation (NAT)
rules on the host to rewrite container traffic to use your external
IP address. This can be accomplished using the following configuration
on the host:
<programlisting>
networking.nat.enable = true;
networking.nat.internalInterfaces = ["ve-+"];
networking.nat.externalInterface = "eth0";
</programlisting>
where <literal>eth0</literal> should be replaced with the desired
external interface. Note that <literal>ve-+</literal> is a wildcard
that matches all container interfaces.</para>
</section>
</chapter>

View File

@ -1,7 +1,6 @@
{ pkgs, options { pkgs, options, version, revision }:
, revision ? "master"
}:
with pkgs;
with pkgs.lib; with pkgs.lib;
let let
@ -14,17 +13,17 @@ let
declarations = map (fn: stripPrefix fn) opt.declarations; declarations = map (fn: stripPrefix fn) opt.declarations;
}); });
prefix = toString pkgs.path; prefix = toString ../../..;
stripPrefix = fn: stripPrefix = fn:
if substring 0 (stringLength prefix) fn == prefix then if substring 0 (stringLength prefix) fn == prefix then
substring (add (stringLength prefix) 1) 1000 fn substring (stringLength prefix + 1) 1000 fn
else else
fn; fn;
optionsXML = builtins.toFile "options.xml" (builtins.unsafeDiscardStringContext (builtins.toXML options'')); optionsXML = builtins.toFile "options.xml" (builtins.unsafeDiscardStringContext (builtins.toXML options''));
optionsDocBook = pkgs.runCommand "options-db.xml" {} '' optionsDocBook = runCommand "options-db.xml" {} ''
if grep /nixpkgs/nixos/modules ${optionsXML}; then if grep /nixpkgs/nixos/modules ${optionsXML}; then
echo "The manual appears to depend on the location of Nixpkgs, which is bad" echo "The manual appears to depend on the location of Nixpkgs, which is bad"
echo "since this prevents sharing via the NixOS channel. This is typically" echo "since this prevents sharing via the NixOS channel. This is typically"
@ -32,7 +31,7 @@ let
echo "for hints about the offending path)." echo "for hints about the offending path)."
exit 1 exit 1
fi fi
${pkgs.libxslt}/bin/xsltproc \ ${libxslt}/bin/xsltproc \
--stringparam revision '${revision}' \ --stringparam revision '${revision}' \
-o $out ${./options-to-docbook.xsl} ${optionsXML} -o $out ${./options-to-docbook.xsl} ${optionsXML}
''; '';
@ -40,12 +39,12 @@ let
in rec { in rec {
# Generate the NixOS manual. # Generate the NixOS manual.
manual = pkgs.stdenv.mkDerivation { manual = stdenv.mkDerivation {
name = "nixos-manual"; name = "nixos-manual";
sources = sourceFilesBySuffices ./. [".xml"]; sources = sourceFilesBySuffices ./. [".xml"];
buildInputs = [ pkgs.libxml2 pkgs.libxslt ]; buildInputs = [ libxml2 libxslt ];
xsltFlags = '' xsltFlags = ''
--param section.autolabel 1 --param section.autolabel 1
@ -60,22 +59,23 @@ in rec {
buildCommand = '' buildCommand = ''
ln -s $sources/*.xml . # */ ln -s $sources/*.xml . # */
ln -s ${optionsDocBook} options-db.xml ln -s ${optionsDocBook} options-db.xml
echo "${version}" > version
# Check the validity of the manual sources. # Check the validity of the manual sources.
xmllint --noout --nonet --xinclude --noxincludenode \ xmllint --noout --nonet --xinclude --noxincludenode \
--relaxng ${pkgs.docbook5}/xml/rng/docbook/docbook.rng \ --relaxng ${docbook5}/xml/rng/docbook/docbook.rng \
manual.xml manual.xml
# Generate the HTML manual. # Generate the HTML manual.
dst=$out/share/doc/nixos dst=$out/share/doc/nixos
ensureDir $dst mkdir -p $dst
xsltproc $xsltFlags --nonet --xinclude \ xsltproc $xsltFlags --nonet --xinclude \
--output $dst/manual.html \ --output $dst/manual.html \
${pkgs.docbook5_xsl}/xml/xsl/docbook/xhtml/docbook.xsl \ ${docbook5_xsl}/xml/xsl/docbook/xhtml/docbook.xsl \
./manual.xml ./manual.xml
mkdir -p $dst/images/callouts mkdir -p $dst/images/callouts
cp ${pkgs.docbook5_xsl}/xml/xsl/docbook/images/callouts/*.gif $dst/images/callouts/ cp ${docbook5_xsl}/xml/xsl/docbook/images/callouts/*.gif $dst/images/callouts/
cp ${./style.css} $dst/style.css cp ${./style.css} $dst/style.css
@ -87,13 +87,39 @@ in rec {
meta.description = "The NixOS manual in HTML format"; meta.description = "The NixOS manual in HTML format";
}; };
manualPDF = stdenv.mkDerivation {
name = "nixos-manual-pdf";
sources = sourceFilesBySuffices ./. [".xml"];
buildInputs = [ libxml2 libxslt dblatex tetex ];
buildCommand = ''
# TeX needs a writable font cache.
export VARTEXFONTS=$TMPDIR/texfonts
ln -s $sources/*.xml . # */
ln -s ${optionsDocBook} options-db.xml
echo "${version}" > version
dst=$out/share/doc/nixos
mkdir -p $dst
xmllint --xinclude manual.xml | dblatex -o $dst/manual.pdf - \
-P doc.collab.show=0 \
-P latex.output.revhistory=0
mkdir -p $out/nix-support
echo "doc-pdf manual $dst/manual.pdf" >> $out/nix-support/hydra-build-products
''; # */
};
# Generate the NixOS manpages. # Generate the NixOS manpages.
manpages = pkgs.stdenv.mkDerivation { manpages = stdenv.mkDerivation {
name = "nixos-manpages"; name = "nixos-manpages";
sources = sourceFilesBySuffices ./. [".xml"]; sources = sourceFilesBySuffices ./. [".xml"];
buildInputs = [ pkgs.libxml2 pkgs.libxslt ]; buildInputs = [ libxml2 libxslt ];
buildCommand = '' buildCommand = ''
ln -s $sources/*.xml . # */ ln -s $sources/*.xml . # */
@ -101,7 +127,7 @@ in rec {
# Check the validity of the manual sources. # Check the validity of the manual sources.
xmllint --noout --nonet --xinclude --noxincludenode \ xmllint --noout --nonet --xinclude --noxincludenode \
--relaxng ${pkgs.docbook5}/xml/rng/docbook/docbook.rng \ --relaxng ${docbook5}/xml/rng/docbook/docbook.rng \
./man-pages.xml ./man-pages.xml
# Generate manpages. # Generate manpages.
@ -110,7 +136,7 @@ in rec {
--param man.output.in.separate.dir 1 \ --param man.output.in.separate.dir 1 \
--param man.output.base.dir "'$out/share/man/'" \ --param man.output.base.dir "'$out/share/man/'" \
--param man.endnotes.are.numbered 0 \ --param man.endnotes.are.numbered 0 \
${pkgs.docbook5_xsl}/xml/xsl/docbook/manpages/docbook.xsl \ ${docbook5_xsl}/xml/xsl/docbook/manpages/docbook.xsl \
./man-pages.xml ./man-pages.xml
''; '';
}; };

View File

@ -1,5 +1,6 @@
<chapter xmlns="http://docbook.org/ns/docbook" <chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"> xmlns:xlink="http://www.w3.org/1999/xlink"
xml:id="ch-development">
<title>Development</title> <title>Development</title>
@ -9,7 +10,7 @@ NixOS.</para>
<!--===============================================================--> <!--===============================================================-->
<section> <section xml:id="sec-getting-sources">
<title>Getting the sources</title> <title>Getting the sources</title>
@ -38,7 +39,37 @@ This will check out the latest NixOS sources to
and the Nixpkgs sources to and the Nixpkgs sources to
<filename><replaceable>/my/sources</replaceable>/nixpkgs</filename>. <filename><replaceable>/my/sources</replaceable>/nixpkgs</filename>.
(The NixOS source tree lives in a subdirectory of the Nixpkgs (The NixOS source tree lives in a subdirectory of the Nixpkgs
repository.) If you want to rebuild your system using your (modified) repository.)</para>
<para>Its often inconvenient to develop directly on the master
branch, since if somebody has just committed (say) a change to GCC,
then the binary cache may not have caught up yet and youll have to
rebuild everything from source. So you may want to create a local
branch based on your current NixOS version:
<screen>
$ nixos-version
14.04.273.ea1952b (Baboon)
$ git checkout -b local ea1952b
</screen>
Or, to base your local branch on the latest version available in the
NixOS channel:
<screen>
$ curl -sI http://nixos.org/channels/nixos-unstable/ | grep Location
Location: http://releases.nixos.org/nixos/unstable/nixos-14.10pre43986.acaf4a6/
$ git checkout -b local acaf4a6
</screen>
You can then use <command>git rebase</command> to sync your local
branch with the upstream branch, and use <command>git
cherry-pick</command> to copy commits from your local branch to the
upstream branch.</para>
<para>If you want to rebuild your system using your (modified)
sources, you need to tell <command>nixos-rebuild</command> about them sources, you need to tell <command>nixos-rebuild</command> about them
using the <option>-I</option> flag: using the <option>-I</option> flag:
@ -74,7 +105,7 @@ in <filename>nixos/</filename> as packages.</para>
<!--===============================================================--> <!--===============================================================-->
<section> <section xml:id="sec-writing-modules">
<title>Writing NixOS modules</title> <title>Writing NixOS modules</title>
@ -188,9 +219,9 @@ commands to be executed periodically by <command>cron</command>).</para>
<example xml:id='locate-example'><title>NixOS module for the “locate” service</title> <example xml:id='locate-example'><title>NixOS module for the “locate” service</title>
<programlisting> <programlisting>
{ config, pkgs, ... }: { config, lib, pkgs, ... }:
with pkgs.lib; with lib;
let locatedb = "/var/cache/locatedb"; in let locatedb = "/var/cache/locatedb"; in
@ -494,7 +525,7 @@ module writers.</para>
<variablelist> <variablelist>
<varlistentry> <varlistentry>
<term><option>etc.environment</option></term> <term><option>environment.etc</option></term>
<listitem> <listitem>
<para>This set defines files in <filename>/etc</filename>. A <para>This set defines files in <filename>/etc</filename>. A
typical use is: typical use is:
@ -579,7 +610,7 @@ systemd.services.dhcpcd =
<!--===============================================================--> <!--===============================================================-->
<section> <section xml:id="sec-building-parts">
<title>Building specific parts of NixOS</title> <title>Building specific parts of NixOS</title>
@ -652,6 +683,37 @@ $ qemu-system-x86_64 -kernel ./kernel/bzImage -initrd ./initrd/initrd -hda /dev/
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>systemd.units.<replaceable>unit-name</replaceable>.unit</varname></term>
<listitem>
<para>This builds the unit with the specified name. Note that
since unit names contain dots
(e.g. <literal>httpd.service</literal>), you need to put them
between quotes, like this:
<screen>
$ nix-build -A 'config.systemd.units."httpd.service".unit'
</screen>
You can also test individual units, without rebuilding the whole
system, by putting them in
<filename>/run/systemd/system</filename>:
<screen>
$ cp $(nix-build -A 'config.systemd.units."httpd.service".unit')/httpd.service \
/run/systemd/system/tmp-httpd.service
$ systemctl daemon-reload
$ systemctl start tmp-httpd.service
</screen>
Note that the unit must not have the same name as any unit in
<filename>/etc/systemd/system</filename> since those take
precedence over <filename>/run/systemd/system</filename>.
Thats why the unit is installed as
<filename>tmp-httpd.service</filename> here.</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</para> </para>
@ -661,7 +723,7 @@ $ qemu-system-x86_64 -kernel ./kernel/bzImage -initrd ./initrd/initrd -hda /dev/
<!--===============================================================--> <!--===============================================================-->
<section> <section xml:id="sec-building-cd">
<title>Building your own NixOS CD</title> <title>Building your own NixOS CD</title>
@ -697,18 +759,22 @@ $ mount -o loop -t iso9660 ./result/iso/cd.iso /mnt/iso</screen>
<title>Testing the installer</title> <title>Testing the installer</title>
<para>Building, burning, and <para>Building, burning, and booting from an installation CD is rather
booting from an installation CD is rather
tedious, so here is a quick way to see if the installer works tedious, so here is a quick way to see if the installer works
properly: properly:
<screen> <screen>
$ nix-build -A config.system.build.nixos-install $ nix-build -A config.system.build.nixos-install
$ dd if=/dev/zero of=diskimage seek=2G count=0 bs=1 $ mount -t tmpfs none /mnt
$ yes | mke2fs -j diskimage
$ mount -o loop diskimage /mnt
$ ./result/bin/nixos-install</screen> $ ./result/bin/nixos-install</screen>
To start a login shell in the new NixOS installation in
<filename>/mnt</filename>:
<screen>
$ ./result/bin/nixos-install --chroot
</screen>
</para> </para>
</section> </section>
@ -717,57 +783,310 @@ $ ./result/bin/nixos-install</screen>
<!--===============================================================--> <!--===============================================================-->
<section><title>Whole-system testing using virtual machines</title> <section xml:id="sec-nixos-tests">
<para>Complete NixOS GNU/Linux systems can be tested in virtual <title>NixOS tests</title>
machines (VMs). This makes it possible to test a system upgrade or
configuration change before rebooting into it, using the
<command>nixos-rebuild build-vm</command> or <command>nixos-rebuild
build-vm-with-bootloader</command> command.</para>
<!-- The following is adapted from <para>When you add some feature to NixOS, you should write a test for
http://wiki.nixos.org/wiki/NixOS_VM_tests, by Eelco Dolstra. --> it. NixOS tests are kept in the directory <filename
<para>The <filename>tests/</filename> directory in the NixOS source xlink:href="https://github.com/NixOS/nixpkgs/tree/master/nixos/tests">nixos/tests</filename>,
tree contains several <emphasis>whole-system unit tests</emphasis>. and are executed (using Nix) by a testing framework that automatically
These tests can be run<footnote><para>NixOS tests can be run both from starts one or more virtual machines containing the NixOS system(s)
NixOS and from a non-NixOS GNU/Linux distribution, provided the Nix required for the test.</para>
package manager is installed.</para></footnote> from the NixOS source
tree as follows: <simplesect><title>Writing tests</title>
<para>A NixOS test is a Nix expression that has the following structure:
<programlisting>
import ./make-test.nix {
# Either the configuration of a single machine:
machine =
{ config, pkgs, ... }:
{ <replaceable>configuration…</replaceable>
};
# Or a set of machines:
nodes =
{ <replaceable>machine1</replaceable> =
{ config, pkgs, ... }: { <replaceable></replaceable> };
<replaceable>machine2</replaceable> =
{ config, pkgs, ... }: { <replaceable></replaceable> };
};
testScript =
''
<replaceable>Perl code…</replaceable>
'';
}
</programlisting>
The attribute <literal>testScript</literal> is a bit of Perl code that
executes the test (described below). During the test, it will start
one or more virtual machines, the configuration of which is described
by the attribute <literal>machine</literal> (if you need only one
machine in your test) or by the attribute <literal>nodes</literal> (if
you need multiple machines). For instance, <filename
xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix">login.nix</filename>
only needs a single machine to test whether users can log in on the
virtual console, whether device ownership is correctly maintained when
switching between consoles, and so on. On the other hand, <filename
xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nfs.nix">nfs.nix</filename>,
which tests NFS client and server functionality in the Linux kernel
(including whether locks are maintained across server crashes),
requires three machines: a server and two clients.</para>
<para>There are a few special NixOS configuration options for test
VMs:
<!-- FIXME: would be nice to generate this automatically. -->
<variablelist>
<varlistentry>
<term><option>virtualisation.memorySize</option></term>
<listitem><para>The memory of the VM in
megabytes.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>virtualisation.vlans</option></term>
<listitem><para>The virtual networks to which the VM is
connected. See <filename
xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nat.nix">nat.nix</filename>
for an example.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>virtualisation.writableStore</option></term>
<listitem><para>By default, the Nix store in the VM is not
writable. If you enable this option, a writable union file system
is mounted on top of the Nix store to make it appear
writable. This is necessary for tests that run Nix operations that
modify the store.</para></listitem>
</varlistentry>
</variablelist>
For more options, see the module <filename
xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/virtualisation/qemu-vm.nix">qemu-vm.nix</filename>.</para>
<para>The test script is a sequence of Perl statements that perform
various actions, such as starting VMs, executing commands in the VMs,
and so on. Each virtual machine is represented as an object stored in
the variable <literal>$<replaceable>name</replaceable></literal>,
where <replaceable>name</replaceable> is the identifier of the machine
(which is just <literal>machine</literal> if you didnt specify
multiple machines using the <literal>nodes</literal> attribute). For
instance, the following starts the machine, waits until it has
finished booting, then executes a command and checks that the output
is more-or-less correct:
<programlisting>
$machine->start;
$machine->waitForUnit("default.target");
$machine->succeed("uname") =~ /Linux/;
</programlisting>
The first line is actually unnecessary; machines are implicitly
started when you first execute an action on them (such as
<literal>waitForUnit</literal> or <literal>succeed</literal>). If you
have multiple machines, you can speed up the test by starting them in
parallel:
<programlisting>
startAll;
</programlisting>
</para>
<para>The following methods are available on machine objects:
<variablelist>
<varlistentry>
<term><methodname>start</methodname></term>
<listitem><para>Start the virtual machine. This method is
asynchronous — it does not wait for the machine to finish
booting.</para></listitem>
</varlistentry>
<varlistentry>
<term><methodname>shutdown</methodname></term>
<listitem><para>Shut down the machine, waiting for the VM to
exit.</para></listitem>
</varlistentry>
<varlistentry>
<term><methodname>crash</methodname></term>
<listitem><para>Simulate a sudden power failure, by telling the VM
to exit immediately.</para></listitem>
</varlistentry>
<varlistentry>
<term><methodname>block</methodname></term>
<listitem><para>Simulate unplugging the Ethernet cable that
connects the machine to the other machines.</para></listitem>
</varlistentry>
<varlistentry>
<term><methodname>unblock</methodname></term>
<listitem><para>Undo the effect of
<methodname>block</methodname>.</para></listitem>
</varlistentry>
<varlistentry>
<term><methodname>screenshot</methodname></term>
<listitem><para>Take a picture of the display of the virtual
machine, in PNG format. The screenshot is linked from the HTML
log.</para></listitem>
</varlistentry>
<varlistentry>
<term><methodname>sendMonitorCommand</methodname></term>
<listitem><para>Send a command to the QEMU monitor. This is rarely
used, but allows doing stuff such as attaching virtual USB disks
to a running machine.</para></listitem>
</varlistentry>
<varlistentry>
<term><methodname>sendKeys</methodname></term>
<listitem><para>Simulate pressing keys on the virtual keyboard,
e.g., <literal>sendKeys("ctrl-alt-delete")</literal>.</para></listitem>
</varlistentry>
<varlistentry>
<term><methodname>sendChars</methodname></term>
<listitem><para>Simulate typing a sequence of characters on the
virtual keyboard, e.g., <literal>sendKeys("foobar\n")</literal>
will type the string <literal>foobar</literal> followed by the
Enter key.</para></listitem>
</varlistentry>
<varlistentry>
<term><methodname>execute</methodname></term>
<listitem><para>Execute a shell command, returning a list
<literal>(<replaceable>status</replaceable>,
<replaceable>stdout</replaceable>)</literal>.</para></listitem>
</varlistentry>
<varlistentry>
<term><methodname>succeed</methodname></term>
<listitem><para>Execute a shell command, raising an exception if
the exit status is not zero, otherwise returning the standard
output.</para></listitem>
</varlistentry>
<varlistentry>
<term><methodname>fail</methodname></term>
<listitem><para>Like <methodname>succeed</methodname>, but raising
an exception if the command returns a zero status.</para></listitem>
</varlistentry>
<varlistentry>
<term><methodname>waitUntilSucceeds</methodname></term>
<listitem><para>Repeat a shell command with 1-second intervals
until it succeeds.</para></listitem>
</varlistentry>
<varlistentry>
<term><methodname>waitUntilFails</methodname></term>
<listitem><para>Repeat a shell command with 1-second intervals
until it fails.</para></listitem>
</varlistentry>
<varlistentry>
<term><methodname>waitForUnit</methodname></term>
<listitem><para>Wait until the specified systemd unit has reached
the “active” state.</para></listitem>
</varlistentry>
<varlistentry>
<term><methodname>waitForFile</methodname></term>
<listitem><para>Wait until the specified file
exists.</para></listitem>
</varlistentry>
<varlistentry>
<term><methodname>waitForOpenPort</methodname></term>
<listitem><para>Wait until a process is listening on the given TCP
port (on <literal>localhost</literal>, at least).</para></listitem>
</varlistentry>
<varlistentry>
<term><methodname>waitForClosedPort</methodname></term>
<listitem><para>Wait until nobody is listening on the given TCP
port.</para></listitem>
</varlistentry>
<varlistentry>
<term><methodname>waitForX</methodname></term>
<listitem><para>Wait until the X11 server is accepting
connections.</para></listitem>
</varlistentry>
<varlistentry>
<term><methodname>waitForWindow</methodname></term>
<listitem><para>Wait until an X11 window has appeared whose name
matches the given regular expression, e.g.,
<literal>waitForWindow(qr/Terminal/)</literal>.</para></listitem>
</varlistentry>
</variablelist>
</para>
</simplesect>
<simplesect><title>Running tests</title>
<para>You can run tests using <command>nix-build</command>. For
example, to run the test <filename
xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix">login.nix</filename>,
you just do:
<screen> <screen>
$ nix-build tests/ -A nfs.test $ nix-build '&lt;nixpkgs/nixos/tests/login.nix>'
</screen> </screen>
This performs an automated test of the NFS client and server or, if you dont want to rely on <envar>NIX_PATH</envar>:
functionality in the Linux kernel, including file locking semantics
(e.g., whether locks are maintained across server crashes). It will <screen>
first build or download all the dependencies of the test (e.g., all $ cd /my/nixpkgs/nixos/tests
packages needed to run a NixOS VM). The test is defined in <link $ nix-build login.nix
xlink:href="https://nixos.org/repos/nix/nixos/trunk/tests/nfs.nix">
<filename>tests/nfs.nix</filename></link>. If the test succeeds, running the VM test script
<command>nix-build</command> will place a symlink machine: QEMU running (pid 8841)
<filename>./result</filename> in the current directory pointing at the
location in the Nix store of the test results (e.g., screenshots, test 6 out of 6 tests succeeded
reports, and so on). In particular, a pretty-printed log of the test </screen>
is written to <filename>log.html</filename>, which can be viewed using
a web browser like this: After building/downloading all required dependencies, this will
perform a build that starts a QEMU/KVM virtual machine containing a
NixOS system. The virtual machine mounts the Nix store of the host;
this makes VM creation very fast, as no disk image needs to be
created. Afterwards, you can view a pretty-printed log of the test:
<screen> <screen>
$ firefox result/log.html $ firefox result/log.html
</screen> </screen>
</para> </para>
<para>It is also possible to run the test environment interactively, <para>It is also possible to run the test environment interactively,
allowing you to experiment with the VMs. For example: allowing you to experiment with the VMs. For example:
<screen> <screen>
$ nix-build tests/ -A nfs.driver $ nix-build login.nix -A driver
$ ./result/bin/nixos-run-vms $ ./result/bin/nixos-run-vms
</screen> </screen>
The script <command>nixos-run-vms</command> starts the three virtual The script <command>nixos-run-vms</command> starts the virtual
machines defined in the NFS test using QEMU/KVM. The root file system machines defined by test. The root file system of the VMs is created
of the VMs is created on the fly and kept across VM restarts in on the fly and kept across VM restarts in
<filename>./</filename><varname>hostname</varname><filename>.qcow2</filename>.</para> <filename>./</filename><varname>hostname</varname><filename>.qcow2</filename>.</para>
<para>Finally, the test itself can be run interactively. This is <para>Finally, the test itself can be run interactively. This is
@ -780,17 +1099,11 @@ starting VDE switch for network 1
&gt; &gt;
</screen> </screen>
Perl statements can now be typed in to start or manipulate the VMs: You can then take any Perl statement, e.g.
<screen> <screen>
&gt; startAll; &gt; startAll
(the VMs start booting) &gt; $machine->succeed("touch /tmp/foo")
&gt; $server-&gt;waitForJob("nfs-kernel-nfsd");
&gt; $client1-&gt;succeed("flock -x /data/lock -c 'sleep 100000' &amp;");
&gt; $client2-&gt;fail("flock -n -s /data/lock true");
&gt; $client1-&gt;shutdown;
(this releases client1's lock)
&gt; $client2-&gt;succeed("flock -n -s /data/lock true");
</screen> </screen>
The function <command>testScript</command> executes the entire test The function <command>testScript</command> executes the entire test
@ -798,54 +1111,7 @@ script and drops you back into the test driver command line upon its
completion. This allows you to inspect the state of the VMs after the completion. This allows you to inspect the state of the VMs after the
test (e.g. to debug the test script).</para> test (e.g. to debug the test script).</para>
<para>This and other tests are continuously run on <link </simplesect>
xlink:href="http://hydra.nixos.org/jobset/nixos/trunk">the Hydra
instance at <literal>nixos.org</literal></link>, which allows
developers to be notified of any regressions introduced by a NixOS or
Nixpkgs change.</para>
<para>The actual Nix programming interface to VM testing is in NixOS,
under <link
xlink:href="https://nixos.org/repos/nix/nixos/trunk/lib/testing.nix">
<filename>lib/testing.nix</filename></link>. This file defines a
function which takes an attribute set containing a
<literal>nixpkgs</literal> attribute (the path to a Nixpkgs checkout),
and a <literal>system</literal> attribute (the system type). It
returns an attribute set containing several utility functions, among
which the main entry point is <literal>makeTest</literal>.
</para>
<para>The <literal>makeTest</literal> function takes a function
similar to that found in <link
xlink:href="https://nixos.org/repos/nix/nixos/trunk/tests/nfs.nix">
<filename>tests/nfs.nix</filename></link> (discussed above). It
returns an attribute set containing (among others):
<variablelist>
<varlistentry>
<term><varname>test</varname></term>
<listitem><para>A derivation containing the test log as an HTML
file, as seen above, suitable for presentation in the Hydra
continuous build system.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>report</varname></term>
<listitem><para>A derivation containing a code coverage report, with
meta-data suitable for Hydra.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>driver</varname></term>
<listitem><para>A derivation containing scripts to run the VM test or
interact with the VM network interactively, as seen above.</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</section> </section>

View File

@ -1,12 +1,13 @@
<chapter xmlns="http://docbook.org/ns/docbook" <chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"> xmlns:xlink="http://www.w3.org/1999/xlink"
xml:id="ch-installation">
<title>Installing NixOS</title> <title>Installing NixOS</title>
<!--===============================================================--> <!--===============================================================-->
<section> <section xml:id="sec-obtaining">
<title>Obtaining NixOS</title> <title>Obtaining NixOS</title>
@ -50,7 +51,7 @@ running NixOS system through several other means:
<!--===============================================================--> <!--===============================================================-->
<section> <section xml:id="sec-installation">
<title>Installation</title> <title>Installation</title>
@ -208,7 +209,20 @@ $ nixos-install</screen>
a network issue while downloading binaries from the NixOS binary a network issue while downloading binaries from the NixOS binary
cache), you can just re-run <command>nixos-install</command>. cache), you can just re-run <command>nixos-install</command>.
Otherwise, fix your <filename>configuration.nix</filename> and Otherwise, fix your <filename>configuration.nix</filename> and
then re-run <command>nixos-install</command>.</para></listitem> then re-run <command>nixos-install</command>.</para>
<para>As the last step, <command>nixos-install</command> will ask
you to set the password for the <literal>root</literal> user, e.g.
<screen>
setting root password...
Enter new UNIX password: ***
Retype new UNIX password: ***
</screen>
</para>
</listitem>
<listitem><para>If everything went well: <listitem><para>If everything went well:
@ -295,8 +309,81 @@ $ reboot</screen>
}</screen> }</screen>
</example> </example>
<section xml:id="sec-uefi-installation">
<title>UEFI Installation</title>
<para>NixOS can also be installed on UEFI systems. The procedure
is by and large the same as a BIOS installation, with the following
changes:
<itemizedlist>
<listitem>
<para>You should boot the live CD in UEFI mode (consult your
specific hardware's documentation for instructions). You may find
the <link
xlink:href="http://www.rodsbooks.com/refind">rEFInd
boot manager</link> useful.</para>
</listitem>
<listitem>
<para>Instead of <command>fdisk</command>, you should use
<command>gdisk</command> to partition your disks. You will need to
have a separate partition for <filename>/boot</filename> with
partition code EF00, and it should be formatted as a
<literal>vfat</literal> filesystem.</para>
</listitem>
<listitem>
<para>You must set <option>boot.loader.gummiboot.enable</option> to
<literal>true</literal>. <command>nixos-generate-config</command>
should do this automatically for new configurations when booted in
UEFI mode.</para>
</listitem>
<listitem>
<para>After having mounted your installation partition to
<code>/mnt</code>, you must mount the <code>boot</code> partition
to <code>/mnt/boot</code>.</para>
</listitem>
<listitem>
<para>You may want to look at the options starting with
<option>boot.loader.efi</option> and <option>boot.loader.gummiboot</option>
as well.</para>
</listitem>
<listitem>
<para>To see console messages during early boot, add <literal>"fbcon"</literal>
to your <option>boot.initrd.kernelModules</option>.</para>
</listitem>
</itemizedlist>
</para>
</section> </section>
<section>
<title xml:id="sec-booting-from-usb">Booting from a USB stick</title>
<para>For systems without CD drive, the NixOS livecd can be booted from
a usb stick. For non-UEFI installations,
<link xlink:href="http://unetbootin.sourceforge.net/">unetbootin</link>
will work. For UEFI installations, you should mount the ISO, copy its contents
verbatim to your drive, then either:
<itemizedlist>
<listitem>
<para>Change the label of the disk partition to the label of the ISO
(visible with the blkid command), or</para>
</listitem>
<listitem>
<para>Edit <filename>loader/entries/nixos-livecd.conf</filename> on the drive
and change the <literal>root=</literal> field in the <literal>options</literal>
line to point to your drive (see the documentation on <literal>root=</literal>
in <link xlink:href="https://www.kernel.org/doc/Documentation/kernel-parameters.txt">
the kernel documentation</link> for more details).</para>
</listitem>
</itemizedlist>
</para>
</section>
</section>
<!--===============================================================--> <!--===============================================================-->
@ -369,9 +456,23 @@ $ nixos-rebuild build-vm
$ ./result/bin/run-*-vm $ ./result/bin/run-*-vm
</screen> </screen>
The VM does not have use any data from your host system, so your The VM does not have any data from your host system, so your existing
existing user accounts and home directories will not be user accounts and home directories will not be available. You can
available.</para> forward ports on the host to the guest. For instance, the following
will forward host port 2222 to guest port 22 (SSH):
<screen>
$ QEMU_NET_OPTS="hostfwd=tcp::2222-:22" ./result/bin/run-*-vm
</screen>
allowing you to log in via SSH (assuming you have set the appropriate
passwords or SSH authorized keys):
<screen>
$ ssh -p 2222 localhost
</screen>
</para>
</section> </section>
@ -392,7 +493,7 @@ been built. These channels are:
<itemizedlist> <itemizedlist>
<listitem> <listitem>
<para>Stable channels, such as <literal <para>Stable channels, such as <literal
xlink:href="http://nixos.org/channels/nixos-13.10">nixos-13.10</literal>. xlink:href="http://nixos.org/channels/nixos-14.04">nixos-14.04</literal>.
These only get conservative bug fixes and package upgrades. For These only get conservative bug fixes and package upgrades. For
instance, a channel update may cause the Linux kernel on your instance, a channel update may cause the Linux kernel on your
system to be upgraded from 3.4.66 to 3.4.67 (a minor bug fix), but system to be upgraded from 3.4.66 to 3.4.67 (a minor bug fix), but
@ -418,8 +519,8 @@ appliances.)</para>
<para>When you first install NixOS, youre automatically subscribed to <para>When you first install NixOS, youre automatically subscribed to
the NixOS channel that corresponds to your installation source. For the NixOS channel that corresponds to your installation source. For
instance, if you installed from a 13.10 ISO, you will be subscribed to instance, if you installed from a 14.04 ISO, you will be subscribed to
the <literal>nixos-13.10</literal> channel. To see which NixOS the <literal>nixos-14.04</literal> channel. To see which NixOS
channel youre subscribed to, run the following as root: channel youre subscribed to, run the following as root:
<screen> <screen>
@ -434,10 +535,10 @@ $ nix-channel --add http://nixos.org/channels/<replaceable>channel-name</replace
</screen> </screen>
(Be sure to include the <literal>nixos</literal> parameter at the (Be sure to include the <literal>nixos</literal> parameter at the
end.) For instance, to use the NixOS 13.10 stable channel: end.) For instance, to use the NixOS 14.04 stable channel:
<screen> <screen>
$ nix-channel --add http://nixos.org/channels/nixos-13.10 nixos $ nix-channel --add http://nixos.org/channels/nixos-14.04 nixos
</screen> </screen>
But it you want to live on the bleeding edge: But it you want to live on the bleeding edge:

View File

@ -42,6 +42,9 @@ the following steps:
and generates a GRUB configuration file that boots into the NixOS and generates a GRUB configuration file that boots into the NixOS
configuration just installed.</para></listitem> configuration just installed.</para></listitem>
<listitem><para>It prompts you for a password for the root
account.</para></listitem>
</itemizedlist> </itemizedlist>
</para> </para>

View File

@ -5,25 +5,7 @@
<info> <info>
<title>NixOS Manual</title> <title>NixOS Manual</title>
<subtitle>Version <xi:include href="version" parse="text" /></subtitle>
<author>
<personname>
<firstname>Eelco</firstname>
<surname>Dolstra</surname>
</personname>
</author>
<author>
<personname>
<firstname>Nicolas</firstname>
<surname>Pierron</surname>
</personname>
</author>
<copyright>
<year>2007-2013</year>
<holder>Eelco Dolstra</holder>
</copyright>
</info> </info>
@ -53,10 +35,14 @@
<xi:include href="running.xml" /> <xi:include href="running.xml" />
<!-- <xi:include href="userconfiguration.xml" /> --> <!-- <xi:include href="userconfiguration.xml" /> -->
<xi:include href="troubleshooting.xml" /> <xi:include href="troubleshooting.xml" />
<xi:include href="containers.xml" />
<xi:include href="development.xml" /> <xi:include href="development.xml" />
<chapter xml:id="ch-options">
<title>List of options</title> <xi:include href="release-notes.xml" />
<appendix xml:id="ch-options">
<title>Configuration options</title>
<xi:include href="options-db.xml" /> <xi:include href="options-db.xml" />
</chapter> </appendix>
</book> </book>

View File

@ -18,14 +18,12 @@
<variablelist> <variablelist>
<xsl:for-each select="attrs"> <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, '*', '_'), '&lt;', '_'), '>', '_'), '?', '_'))" />
<varlistentry> <varlistentry>
<term> <term xlink:href="#{$id}">
<xsl:attribute name="xml:id"><xsl:value-of select="$id"/></xsl:attribute>
<option> <option>
<xsl:for-each select="attr[@name = 'name']/string"> <xsl:value-of select="attr[@name = 'name']/string/@value" />
<xsl:value-of select="@value" />
<xsl:if test="position() != last()">.</xsl:if>
</xsl:for-each>
</option> </option>
</term> </term>
@ -204,4 +202,10 @@
</simplelist> </simplelist>
</xsl:template> </xsl:template>
<xsl:template match="function">
<xsl:text>λ</xsl:text>
</xsl:template>
</xsl:stylesheet> </xsl:stylesheet>

View File

@ -0,0 +1,198 @@
<appendix xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xml:id="ch-release-notes">
<title>Release notes</title>
<!--==================================================================-->
<section xml:id="sec-release-14.10">
<title>Release 14.10 (“Caterpillar”, 2014/10/??)</title>
<para>When upgrading from a previous release, please be aware of the
following incompatible changes:
<itemizedlist>
<listitem><para>The host side of a container virtual Ethernet pair
is now called <literal>ve-<replaceable>container-name</replaceable></literal>
rather than <literal>c-<replaceable>container-name</replaceable></literal>.</para></listitem>
</itemizedlist>
</para>
</section>
<!--==================================================================-->
<section xml:id="sec-release-14.04">
<title>Release 14.04 (“Baboon”, 2014/04/30)</title>
<para>This is the second stable release branch of NixOS. In addition
to numerous new and upgraded packages and modules, this release has
the following highlights:
<itemizedlist>
<listitem><para>Installation on UEFI systems is now supported. See
<xref linkend="sec-uefi-installation"/> for
details.</para></listitem>
<listitem><para>Systemd has been updated to version 212, which has
<link xlink:href="http://cgit.freedesktop.org/systemd/systemd/plain/NEWS?id=v212">numerous
improvements</link>. NixOS now automatically starts systemd user
instances when you log in. You can define global user units through
the <option>systemd.unit.*</option> options.</para></listitem>
<listitem><para>NixOS is now based on Glibc 2.19 and GCC
4.8.</para></listitem>
<listitem><para>The default Linux kernel has been updated to
3.12.</para></listitem>
<listitem><para>KDE has been updated to 4.12.</para></listitem>
<listitem><para>GNOME 3.10 experimental support has been added.</para></listitem>
<listitem><para>Nix has been updated to 1.7 (<link
xlink:href="http://nixos.org/nix/manual/#ssec-relnotes-1.7">details</link>).</para></listitem>
<listitem><para>NixOS now supports fully declarative management of
users and groups. If you set <option>users.mutableUsers</option> to
<literal>false</literal>, then the contents of
<filename>/etc/passwd</filename> and <filename>/etc/group</filename>
will be <link
xlink:href="https://www.usenix.org/legacy/event/lisa02/tech/full_papers/traugott/traugott_html/">congruent</link>
to your NixOS configuration. For instance, if you remove a user from
<option>users.extraUsers</option> and run
<command>nixos-rebuild</command>, the user account will cease to
exist. Also, imperative commands for managing users and groups, such
as <command>useradd</command>, are no longer available. If
<option>users.mutableUsers</option> is <literal>true</literal> (the
default), then behaviour is unchanged from NixOS
13.10.</para></listitem>
<listitem><para>NixOS now has basic container support, meaning you
can easily run a NixOS instance as a container in a NixOS host
system. These containers are suitable for testing and
experimentation but not production use, since theyre not fully
isolated from the host. See <xref linkend="ch-containers"/> for
details.</para></listitem>
<listitem><para>Systemd units provided by packages can now be
overridden from the NixOS configuration. For instance, if a package
<literal>foo</literal> provides systemd units, you can say:
<programlisting>
systemd.packages = [ pkgs.foo ];
</programlisting>
to enable those units. You can then set or override unit options in
the usual way, e.g.
<programlisting>
systemd.services.foo.wantedBy = [ "multi-user.target" ];
systemd.services.foo.serviceConfig.MemoryLimit = "512M";
</programlisting>
</para></listitem>
</itemizedlist>
</para>
<para>When upgrading from a previous release, please be aware of the
following incompatible changes:
<itemizedlist>
<listitem><para>Nixpkgs no longer exposes unfree packages by
default. If your NixOS configuration requires unfree packages from
Nixpkgs, you need to enable support for them explicitly by setting:
<programlisting>
nixpkgs.config.allowUnfree = true;
</programlisting>
Otherwise, you get an error message such as:
<screen>
error: package nvidia-x11-331.49-3.12.17 in ‘…/nvidia-x11/default.nix:56
has an unfree license, refusing to evaluate
</screen>
</para></listitem>
<listitem><para>The Adobe Flash player is no longer enabled by
default in the Firefox and Chromium wrappers. To enable it, you must
set:
<programlisting>
nixpkgs.config.allowUnfree = true;
nixpkgs.config.firefox.enableAdobeFlash = true; # for Firefox
nixpkgs.config.chromium.enableAdobeFlash = true; # for Chromium
</programlisting>
</para></listitem>
<listitem><para>The firewall is now enabled by default. If you dont
want this, you need to disable it explicitly:
<programlisting>
networking.firewall.enable = false;
</programlisting>
</para></listitem>
<listitem><para>The option
<option>boot.loader.grub.memtest86</option> has been renamed to
<option>boot.loader.grub.memtest86.enable</option>.</para></listitem>
<listitem><para>The <literal>mysql55</literal> service has been
merged into the <literal>mysql</literal> service, which no longer
sets a default for the option
<option>services.mysql.package</option>.</para></listitem>
<listitem><para>Package variants are now differentiated by suffixing
the name, rather than the version. For instance,
<filename>sqlite-3.8.4.3-interactive</filename> is now called
<filename>sqlite-interactive-3.8.4.3</filename>. This ensures that
<literal>nix-env -i sqlite</literal> is unambiguous, and that
<literal>nix-env -u</literal> wont “upgrade”
<literal>sqlite</literal> to <literal>sqlite-interactive</literal>
or vice versa. Notably, this change affects the Firefox wrapper
(which provides plugins), as it is now called
<literal>firefox-wrapper</literal>. So when using
<command>nix-env</command>, you should do <literal>nix-env -e
firefox; nix-env -i firefox-wrapper</literal> if you want to keep
using the wrapper. This change does not affect declarative package
management, since attribute names like
<literal>pkgs.firefoxWrapper</literal> were already
unambiguous.</para></listitem>
<listitem><para>The symlink <filename>/etc/ca-bundle.crt</filename>
is gone. Programs should instead use the environment variable
<envar>OPENSSL_X509_CERT_FILE</envar> (which points to
<filename>/etc/ssl/certs/ca-bundle.crt</filename>).</para></listitem>
</itemizedlist>
</para>
</section>
<!--==================================================================-->
<section xml:id="sec-release-13.10">
<title>Release 13.10 (“Aardvark”, 2013/10/31)</title>
<para>This is the first stable release branch of NixOS.</para>
</section>
</appendix>

View File

@ -11,7 +11,7 @@ service manager.</para>
<!--===============================================================--> <!--===============================================================-->
<section><title>Service management</title> <section xml:id="sec-systemctl"><title>Service management</title>
<para>In NixOS, all system services are started and monitored using <para>In NixOS, all system services are started and monitored using
the systemd program. Systemd is the “init” process of the system the systemd program. Systemd is the “init” process of the system
@ -92,7 +92,7 @@ necessary).</para>
<!--===============================================================--> <!--===============================================================-->
<section><title>Rebooting and shutting down</title> <section xml:id="sec-rebooting"><title>Rebooting and shutting down</title>
<para>The system can be shut down (and automatically powered off) by <para>The system can be shut down (and automatically powered off) by
doing: doing:
@ -134,7 +134,7 @@ authentication.</para>
<!--===============================================================--> <!--===============================================================-->
<section><title>User sessions</title> <section xml:id="sec-user-sessions"><title>User sessions</title>
<para>Systemd keeps track of all users who are logged into the system <para>Systemd keeps track of all users who are logged into the system
(e.g. on a virtual console or remotely via SSH). The command (e.g. on a virtual console or remotely via SSH). The command
@ -185,7 +185,7 @@ $ loginctl terminate-session c3
<!--===============================================================--> <!--===============================================================-->
<section><title>Control groups</title> <section xml:id="sec-cgroups"><title>Control groups</title>
<para>To keep track of the processes in a running system, systemd uses <para>To keep track of the processes in a running system, systemd uses
<emphasis>control groups</emphasis> (cgroups). A control group is a <emphasis>control groups</emphasis> (cgroups). A control group is a
@ -258,7 +258,7 @@ usage.</para>
<!--===============================================================--> <!--===============================================================-->
<section><title>Logging</title> <section xml:id="sec-logging"><title>Logging</title>
<para>System-wide logging is provided by systemds <para>System-wide logging is provided by systemds
<emphasis>journal</emphasis>, which subsumes traditional logging <emphasis>journal</emphasis>, which subsumes traditional logging
@ -308,7 +308,7 @@ groups. All users have a private journal that can be read using
<!--===============================================================--> <!--===============================================================-->
<section><title>Cleaning up the Nix store</title> <section xml:id="sec-nix-gc"><title>Cleaning up the Nix store</title>
<para>Nix has a purely functional model, meaning that packages are <para>Nix has a purely functional model, meaning that packages are
never upgraded in place. Instead new versions of packages end up in a never upgraded in place. Instead new versions of packages end up in a

View File

@ -1,12 +1,13 @@
<chapter xmlns="http://docbook.org/ns/docbook" <chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"> xmlns:xlink="http://www.w3.org/1999/xlink"
xml:id="ch-troubleshooting">
<title>Troubleshooting</title> <title>Troubleshooting</title>
<!--===============================================================--> <!--===============================================================-->
<section><title>Boot problems</title> <section xml:id="sec-boot-problems"><title>Boot problems</title>
<para>If NixOS fails to boot, there are a number of kernel command <para>If NixOS fails to boot, there are a number of kernel command
line parameters that may help you to identify or fix the issue. You line parameters that may help you to identify or fix the issue. You
@ -69,7 +70,7 @@ unless something is very wrong.)</para>
<!--===============================================================--> <!--===============================================================-->
<section><title>Maintenance mode</title> <section xml:id="sec-maintenance-mode"><title>Maintenance mode</title>
<para>You can enter rescue mode by running: <para>You can enter rescue mode by running:
@ -85,7 +86,7 @@ just exit from the rescue shell.</para>
<!--===============================================================--> <!--===============================================================-->
<section><title>Rolling back configuration changes</title> <section xml:id="sec-rollback"><title>Rolling back configuration changes</title>
<para>After running <command>nixos-rebuild</command> to switch to a <para>After running <command>nixos-rebuild</command> to switch to a
new configuration, you may find that the new configuration doesnt new configuration, you may find that the new configuration doesnt
@ -131,7 +132,7 @@ lrwxrwxrwx 1 root root 78 Aug 12 13:54 /nix/var/nix/profiles/system-268-link ->
<!--===============================================================--> <!--===============================================================-->
<section><title>Nix store corruption</title> <section xml:id="sec-nix-store-corruption"><title>Nix store corruption</title>
<para>After a system crash, its possible for files in the Nix store <para>After a system crash, its possible for files in the Nix store
to become corrupted. (For instance, the Ext4 file system has the to become corrupted. (For instance, the Ext4 file system has the
@ -166,7 +167,7 @@ binary cache; otherwise, they cannot be repaired.</para>
<!--===============================================================--> <!--===============================================================-->
<section><title>Nix network issues</title> <section xml:id="sec-nix-network-issues"><title>Nix network issues</title>
<para>Nix uses a so-called <emphasis>binary cache</emphasis> to <para>Nix uses a so-called <emphasis>binary cache</emphasis> to
optimise building a package from source into downloading it as a optimise building a package from source into downloading it as a

View File

@ -68,8 +68,8 @@ rec {
# the first interface (i.e. the first network in its # the first interface (i.e. the first network in its
# virtualisation.vlans option). # virtualisation.vlans option).
networking.extraHosts = flip concatMapStrings machines networking.extraHosts = flip concatMapStrings machines
(m: let config = (getAttr m nodes).config; in (m': let config = (getAttr m' nodes).config; in
optionalString (config.networking.primaryIPAddress != "") optionalString (m.first != m' && config.networking.primaryIPAddress != "")
("${config.networking.primaryIPAddress} " + ("${config.networking.primaryIPAddress} " +
"${config.networking.hostName}\n")); "${config.networking.hostName}\n"));

View File

@ -8,6 +8,7 @@
, extraArgs ? {} , extraArgs ? {}
, modules , modules
, check ? true , check ? true
, prefix ? []
}: }:
let extraArgs_ = extraArgs; pkgs_ = pkgs; system_ = system; in let extraArgs_ = extraArgs; pkgs_ = pkgs; system_ = system; in
@ -17,6 +18,7 @@ rec {
# Merge the option definitions in all modules, forming the full # Merge the option definitions in all modules, forming the full
# system configuration. # system configuration.
inherit (pkgs.lib.evalModules { inherit (pkgs.lib.evalModules {
inherit prefix;
modules = modules ++ baseModules; modules = modules ++ baseModules;
args = extraArgs; args = extraArgs;
check = check && options.environment.checkConfigurationOptions.value; check = check && options.environment.checkConfigurationOptions.value;
@ -24,10 +26,15 @@ rec {
# These are the extra arguments passed to every module. In # These are the extra arguments passed to every module. In
# particular, Nixpkgs is passed through the "pkgs" argument. # particular, Nixpkgs is passed through the "pkgs" argument.
# FIXME: we enable config.allowUnfree to make packages like
# nvidia-x11 available. This isn't a problem because if the user has
# nixpkgs.config.allowUnfree = false, then evaluation will fail on
# the 64-bit package anyway. However, it would be cleaner to respect
# nixpkgs.config here.
extraArgs = extraArgs_ // { extraArgs = extraArgs_ // {
inherit pkgs modules baseModules; inherit pkgs modules baseModules;
modulesPath = ../modules; modulesPath = ../modules;
pkgs_i686 = import ./nixpkgs.nix { system = "i686-linux"; }; pkgs_i686 = import ./nixpkgs.nix { system = "i686-linux"; config.allowUnfree = true; };
utils = import ./utils.nix pkgs; utils = import ./utils.nix pkgs;
}; };
@ -48,10 +55,10 @@ rec {
let let
system = if nixpkgsOptions.system != "" then nixpkgsOptions.system else system_; system = if nixpkgsOptions.system != "" then nixpkgsOptions.system else system_;
nixpkgsOptions = (import ./eval-config.nix { nixpkgsOptions = (import ./eval-config.nix {
inherit system extraArgs modules; inherit system extraArgs modules prefix;
# For efficiency, leave out most NixOS modules; they don't # For efficiency, leave out most NixOS modules; they don't
# define nixpkgs.config, so it's pointless to evaluate them. # define nixpkgs.config, so it's pointless to evaluate them.
baseModules = [ ../modules/misc/nixpkgs.nix ]; baseModules = [ ../modules/misc/nixpkgs.nix ../modules/config/no-x-libs.nix ];
pkgs = import ./nixpkgs.nix { system = system_; config = {}; }; pkgs = import ./nixpkgs.nix { system = system_; config = {}; };
check = false; check = false;
}).config.nixpkgs; }).config.nixpkgs;

View File

@ -78,7 +78,7 @@ done
cat pathlist | sed -e 's/=\(.*\)=\(.*\)=/\\=\1=\2\\=/' | tee pathlist.safer cat pathlist | sed -e 's/=\(.*\)=\(.*\)=/\\=\1=\2\\=/' | tee pathlist.safer
ensureDir $out/iso mkdir -p $out/iso
genCommand="genisoimage -iso-level 4 -r -J $bootFlags -hide-rr-moved -graft-points -path-list pathlist.safer ${volumeID:+-V $volumeID}" genCommand="genisoimage -iso-level 4 -r -J $bootFlags -hide-rr-moved -graft-points -path-list pathlist.safer ${volumeID:+-V $volumeID}"
if test -z "$compressImage"; then if test -z "$compressImage"; then
$genCommand -o $out/iso/$isoName $genCommand -o $out/iso/$isoName
@ -87,5 +87,5 @@ else
fi fi
ensureDir $out/nix-support mkdir -p $out/nix-support
echo $system > $out/nix-support/system echo $system > $out/nix-support/system

View File

@ -48,11 +48,11 @@ for ((n = 0; n < ${#objects[*]}; n++)); do
fi fi
done done
ensureDir $out/tarball mkdir -p $out/tarball
tar cvJf $out/tarball/$fileName.tar.xz * tar cvJf $out/tarball/$fileName.tar.xz *
ensureDir $out/nix-support mkdir -p $out/nix-support
echo $system > $out/nix-support/system echo $system > $out/nix-support/system
echo "file system-tarball $out/tarball/$fileName.tar.xz" > $out/nix-support/hydra-build-products echo "file system-tarball $out/tarball/$fileName.tar.xz" > $out/nix-support/hydra-build-products

View File

@ -495,7 +495,9 @@ sub waitForX {
my ($self, $regexp) = @_; my ($self, $regexp) = @_;
$self->nest("waiting for the X11 server", sub { $self->nest("waiting for the X11 server", sub {
retry sub { retry sub {
my ($status, $out) = $self->execute("xwininfo -root > /dev/null 2>&1"); my ($status, $out) = $self->execute("journalctl -b SYSLOG_IDENTIFIER=systemd | grep 'session opened'");
return 0 if $status != 0;
($status, $out) = $self->execute("xwininfo -root > /dev/null 2>&1");
return 1 if $status == 0; return 1 if $status == 0;
} }
}); });

View File

@ -9,8 +9,8 @@
<xsl:template match="logfile"> <xsl:template match="logfile">
<html> <html>
<head> <head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script> <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js"></script> <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js"></script>
<script type="text/javascript" src="treebits.js" /> <script type="text/javascript" src="treebits.js" />
<link rel="stylesheet" href="logfile.css" type="text/css" /> <link rel="stylesheet" href="logfile.css" type="text/css" />
<title>Log File</title> <title>Log File</title>

View File

@ -52,12 +52,12 @@ sub createMachine {
my ($args) = @_; my ($args) = @_;
my $vm = Machine->new({%{$args}, log => $log, redirectSerial => ($ENV{USE_SERIAL} // "0") ne "1"}); my $vm = Machine->new({%{$args}, log => $log, redirectSerial => ($ENV{USE_SERIAL} // "0") ne "1"});
$vms{$vm->name} = $vm; $vms{$vm->name} = $vm;
$context .= "my \$" . $vm->name . " = \$vms{'" . $vm->name . "'}; ";
return $vm; return $vm;
} }
foreach my $vmScript (@ARGV) { foreach my $vmScript (@ARGV) {
my $vm = createMachine({startCommand => $vmScript}); my $vm = createMachine({startCommand => $vmScript});
$context .= "my \$" . $vm->name . " = \$vms{'" . $vm->name . "'}; ";
} }
@ -144,6 +144,13 @@ sub runTests {
} }
}); });
$log->nest("syncing", sub {
foreach my $vm (values %vms) {
next unless $vm->isUp();
$vm->execute("sync");
}
});
if ($nrTests != 0) { if ($nrTests != 0) {
$log->log("$nrSucceeded out of $nrTests tests succeeded", $log->log("$nrSucceeded out of $nrTests tests succeeded",
($nrSucceeded < $nrTests ? { error => 1 } : { })); ($nrSucceeded < $nrTests ? { error => 1 } : { }));

View File

@ -37,7 +37,7 @@ rec {
# `driver' is the script that runs the network. # `driver' is the script that runs the network.
runTests = driver: runTests = driver:
stdenv.mkDerivation { stdenv.mkDerivation {
name = "vm-test-run"; name = "vm-test-run-${driver.testName}";
requiredSystemFeatures = [ "kvm" "nixos-test" ]; requiredSystemFeatures = [ "kvm" "nixos-test" ];
@ -67,68 +67,20 @@ rec {
}; };
# Generate a coverage report from the coverage data produced by makeTest =
# runTests. { testScript, makeCoverageReport ? false, name ? "unnamed", ... } @ t:
makeReport = x: runCommand "report" { buildInputs = [rsync]; }
''
mkdir -p $TMPDIR/gcov/
for d in ${x}/coverage-data/*; do let
echo "doing $d" testDriverName = "nixos-test-driver-${name}";
[ -n "$(ls -A "$d")" ] || continue
for i in $(cd $d/nix/store && ls); do
if ! test -e $TMPDIR/gcov/nix/store/$i; then
echo "copying $i"
mkdir -p $TMPDIR/gcov/$(echo $i | cut -c34-)
rsync -rv /nix/store/$i/.build/* $TMPDIR/gcov/
fi
done
chmod -R u+w $TMPDIR/gcov
find $TMPDIR/gcov -name "*.gcda" -exec rm {} \;
for i in $(cd $d/nix/store && ls); do
rsync -rv $d/nix/store/$i/.build/* $TMPDIR/gcov/
done
find $TMPDIR/gcov -name "*.gcda" -exec chmod 644 {} \;
echo "producing info..."
${pkgs.lcov}/bin/geninfo --ignore-errors source,gcov $TMPDIR/gcov --output-file $TMPDIR/app.info
cat $TMPDIR/app.info >> $TMPDIR/full.info
done
echo "making report..."
mkdir -p $out/coverage
${pkgs.lcov}/bin/genhtml --show-details $TMPDIR/full.info -o $out/coverage
cp $TMPDIR/full.info $out/coverage/
mkdir -p $out/nix-support
cat ${x}/nix-support/hydra-build-products >> $out/nix-support/hydra-build-products
echo "report coverage $out/coverage" >> $out/nix-support/hydra-build-products
[ ! -e ${x}/nix-support/failed ] || touch $out/nix-support/failed
''; # */
makeTest = testFun: complete (call testFun);
makeTests = testsFun: lib.mapAttrs (name: complete) (call testsFun);
apply = makeTest; # compatibility
call = f: f { inherit pkgs system; };
complete = t: t // rec {
nodes = buildVirtualNetwork ( nodes = buildVirtualNetwork (
if t ? nodes then t.nodes else t.nodes or (if t ? machine then { machine = t.machine; } else { }));
if t ? machine then { machine = t.machine; }
else { } );
testScript = testScript' =
# Call the test script with the computed nodes. # Call the test script with the computed nodes.
if builtins.isFunction t.testScript if builtins.isFunction testScript
then t.testScript { inherit nodes; } then testScript { inherit nodes; }
else t.testScript; else testScript;
vlans = map (m: m.config.virtualisation.vlans) (lib.attrValues nodes); vlans = map (m: m.config.virtualisation.vlans) (lib.attrValues nodes);
@ -137,10 +89,11 @@ rec {
# Generate onvenience wrappers for running the test driver # Generate onvenience wrappers for running the test driver
# interactively with the specified network, and for starting the # interactively with the specified network, and for starting the
# VMs from the command line. # VMs from the command line.
driver = runCommand "nixos-test-driver" driver = runCommand testDriverName
{ buildInputs = [ makeWrapper]; { buildInputs = [ makeWrapper];
inherit testScript; testScript = testScript';
preferLocalBuild = true; preferLocalBuild = true;
testName = name;
} }
'' ''
mkdir -p $out/bin mkdir -p $out/bin
@ -162,8 +115,9 @@ rec {
test = runTests driver; test = runTests driver;
report = makeReport test; report = releaseTools.gcovReport { coverageRuns = [ test ]; };
};
in (if makeCoverageReport then report else test) // { inherit nodes driver test; };
runInMachine = runInMachine =
@ -193,7 +147,7 @@ rec {
exit $? exit $?
''; '';
testscript = '' testScript = ''
startAll; startAll;
$client->waitForUnit("multi-user.target"); $client->waitForUnit("multi-user.target");
${preBuild} ${preBuild}
@ -206,7 +160,7 @@ rec {
${coreutils}/bin/mkdir $out ${coreutils}/bin/mkdir $out
${coreutils}/bin/mkdir -p vm-state-client/xchg ${coreutils}/bin/mkdir -p vm-state-client/xchg
export > vm-state-client/xchg/saved-env export > vm-state-client/xchg/saved-env
export tests='${testscript}' export tests='${testScript}'
${testDriver}/bin/nixos-test-driver ${vm.config.system.build.vm}/bin/run-*-vm ${testDriver}/bin/nixos-test-driver ${vm.config.system.build.vm}/bin/run-*-vm
''; # */ ''; # */
@ -244,6 +198,6 @@ rec {
} // args); } // args);
simpleTest = as: (makeTest ({ ... }: as)).test; simpleTest = as: (makeTest as).test;
} }

View File

@ -0,0 +1,5 @@
{ modulesPath, ...}:
{
imports = [ "${modulesPath}/virtualisation/amazon-config.nix" ];
services.journald.rateLimitBurst = 0;
}

View File

@ -0,0 +1,5 @@
{ config, pkgs, ...}:
{
imports = [ ./amazon-base-config.nix ];
ec2.hvm = true;
}

View File

@ -0,0 +1,33 @@
{ config, pkgs, lib, ...}:
let
cloudUtils = pkgs.fetchurl {
url = "https://launchpad.net/cloud-utils/trunk/0.27/+download/cloud-utils-0.27.tar.gz";
sha256 = "16shlmg36lidp614km41y6qk3xccil02f5n3r4wf6d1zr5n4v8vd";
};
growpart = pkgs.stdenv.mkDerivation {
name = "growpart";
src = cloudUtils;
buildPhase = ''
cp bin/growpart $out
sed -i 's|awk|gawk|' $out
sed -i 's|sed|gnused|' $out
'';
dontInstall = true;
dontPatchShebangs = true;
};
in
{
imports = [ ./amazon-base-config.nix ];
ec2.hvm = true;
boot.loader.grub.device = lib.mkOverride 0 "nodev";
boot.initrd.extraUtilsCommands = ''
cp -v ${pkgs.gawk}/bin/gawk $out/bin/gawk
cp -v ${pkgs.gnused}/bin/sed $out/bin/gnused
cp -v ${pkgs.utillinux}/sbin/sfdisk $out/bin/sfdisk
cp -v ${growpart} $out/bin/growpart
'';
boot.initrd.postDeviceCommands = ''
[ -e /dev/xvda ] && [ -e /dev/xvda1 ] && TMPDIR=/run sh $(type -P growpart) /dev/xvda 1
'';
}

View File

@ -8,15 +8,17 @@ import nixops.util
from nixops import deployment from nixops import deployment
from boto.ec2.blockdevicemapping import BlockDeviceMapping, BlockDeviceType from boto.ec2.blockdevicemapping import BlockDeviceMapping, BlockDeviceType
import boto.ec2 import boto.ec2
from nixops.statefile import StateFile, get_default_state_file
parser = argparse.ArgumentParser(description='Create an EBS-backed NixOS AMI') parser = argparse.ArgumentParser(description='Create an EBS-backed NixOS AMI')
parser.add_argument('--region', dest='region', required=True, help='EC2 region to create the image in') parser.add_argument('--region', dest='region', required=True, help='EC2 region to create the image in')
parser.add_argument('--channel', dest='channel', default="13.10", help='Channel to use')
parser.add_argument('--keep', dest='keep', action='store_true', help='Keep NixOps machine after use') parser.add_argument('--keep', dest='keep', action='store_true', help='Keep NixOps machine after use')
parser.add_argument('--hvm', dest='hvm', action='store_true', help='Create HVM image') parser.add_argument('--hvm', dest='hvm', action='store_true', help='Create HVM image')
parser.add_argument('--key', dest='key_name', action='store_true', help='Keypair used for HVM instance creation', default="rob") parser.add_argument('--key', dest='key_name', action='store_true', help='Keypair used for HVM instance creation', default="rob")
args = parser.parse_args() args = parser.parse_args()
instance_type = "cc1.4xlarge" if args.hvm else "m1.small" instance_type = "m3.medium" if args.hvm else "m1.small"
ebs_size = 8 if args.hvm else 20 ebs_size = 8 if args.hvm else 20
@ -37,11 +39,11 @@ f.write('''{{
'''.format(args.region, ebs_size)) '''.format(args.region, ebs_size))
f.close() f.close()
db = deployment.open_database(deployment.get_default_state_file()) db = StateFile(get_default_state_file())
try: try:
depl = deployment.open_deployment(db, "ebs-creator") depl = db.open_deployment("ebs-creator")
except Exception: except Exception:
depl = deployment.create_deployment(db) depl = db.create_deployment()
depl.name = "ebs-creator" depl.name = "ebs-creator"
depl.auto_response = "y" depl.auto_response = "y"
depl.nix_exprs = [os.path.abspath("./ebs-creator.nix"), os.path.abspath("./ebs-creator-config.nix")] depl.nix_exprs = [os.path.abspath("./ebs-creator.nix"), os.path.abspath("./ebs-creator-config.nix")]
@ -50,7 +52,6 @@ depl.deploy(allow_reboot=True)
m = depl.machines['machine'] m = depl.machines['machine']
# Do the installation. # Do the installation.
device="/dev/xvdg" device="/dev/xvdg"
if args.hvm: if args.hvm:
@ -64,23 +65,27 @@ m.run_command("mkdir -p /mnt")
m.run_command("mount {0} /mnt".format(device)) m.run_command("mount {0} /mnt".format(device))
m.run_command("touch /mnt/.ebs") m.run_command("touch /mnt/.ebs")
m.run_command("mkdir -p /mnt/etc/nixos") m.run_command("mkdir -p /mnt/etc/nixos")
m.run_command("nix-channel --add http://nixos.org/channels/nixos-unstable")
m.run_command("nix-channel --add http://nixos.org/channels/nixos-{} nixos".format(args.channel))
m.run_command("nix-channel --update") m.run_command("nix-channel --update")
m.run_command("nixos-rebuild switch")
version = m.run_command("nixos-version", capture_stdout=True).replace('"', '').rstrip() version = m.run_command("nix-instantiate --eval-only -A lib.nixpkgsVersion '<nixpkgs>'", capture_stdout=True).split(' ')[0].replace('"','').strip()
print >> sys.stderr, "NixOS version is {0}".format(version) print >> sys.stderr, "NixOS version is {0}".format(version)
m.upload_file("./amazon-base-config.nix", "/mnt/etc/nixos/configuration.nix")
m.run_command("nixos-install")
if args.hvm: if args.hvm:
m.run_command('cp /mnt/nix/store/*-grub-0.97*/lib/grub/i386-pc/* /mnt/boot/grub') m.upload_file("./amazon-base-config.nix", "/mnt/etc/nixos/amazon-base-config.nix")
m.run_command('sed -i "s|hd0|hd0,0|" /mnt/boot/grub/menu.lst') m.upload_file("./amazon-hvm-config.nix", "/mnt/etc/nixos/configuration.nix")
m.upload_file("./amazon-hvm-install-config.nix", "/mnt/etc/nixos/amazon-hvm-install-config.nix")
m.run_command("NIXOS_CONFIG=/etc/nixos/amazon-hvm-install-config.nix nixos-install")
m.run_command('nix-env -iA nixos.pkgs.grub')
m.run_command('cp /nix/store/*-grub-0.97*/lib/grub/i386-pc/* /mnt/boot/grub')
m.run_command('echo "(hd1) /dev/xvdg" > device.map') m.run_command('echo "(hd1) /dev/xvdg" > device.map')
m.run_command('echo -e "root (hd1,0)\nsetup (hd1)" | grub --device-map=device.map --batch') m.run_command('echo -e "root (hd1,0)\nsetup (hd1)" | grub --device-map=device.map --batch')
else:
m.upload_file("./amazon-base-config.nix", "/mnt/etc/nixos/configuration.nix")
m.run_command("nixos-install")
m.run_command("umount /mnt") m.run_command("umount /mnt")
if args.hvm: if args.hvm:
ami_name = "nixos-{0}-x86_64-ebs-hvm".format(version) ami_name = "nixos-{0}-x86_64-ebs-hvm".format(version)
description = "NixOS {0} (x86_64; EBS root; hvm)".format(version) description = "NixOS {0} (x86_64; EBS root; hvm)".format(version)
@ -98,7 +103,7 @@ def check():
m.connect() m.connect()
volume = m._conn.get_all_volumes([], filters={'attachment.instance-id': m.resource_id, 'attachment.device': "/dev/sdg"})[0] volume = m._conn.get_all_volumes([], filters={'attachment.instance-id': m.resource_id, 'attachment.device': "/dev/sdg"})[0]
if args.hvm: if args.hvm:
instance = m._conn.run_instances( image_id="ami-6a9e4503" instance = m._conn.run_instances( image_id="ami-5f491f36"
, instance_type=instance_type , instance_type=instance_type
, key_name=args.key_name , key_name=args.key_name
, placement=m.zone , placement=m.zone
@ -185,7 +190,7 @@ f.write(
'''.format(args.region, ami_id, instance_type)) '''.format(args.region, ami_id, instance_type))
f.close() f.close()
test_depl = deployment.create_deployment(db) test_depl = db.create_deployment()
test_depl.auto_response = "y" test_depl.auto_response = "y"
test_depl.name = "ebs-creator-test" test_depl.name = "ebs-creator-test"
test_depl.nix_exprs = [os.path.abspath("./ebs-test.nix")] test_depl.nix_exprs = [os.path.abspath("./ebs-test.nix")]
@ -202,7 +207,7 @@ f = open("{0}.{1}.ami-id".format(args.region, image_type), "w")
f.write("{0}".format(ami_id)) f.write("{0}".format(ami_id))
f.close() f.close()
for dest in [ 'us-east-1', 'us-west-1', 'us-west-2', 'eu-west-1']: for dest in [ 'us-east-1', 'us-west-1', 'us-west-2', 'eu-west-1', 'ap-southeast-1', 'ap-southeast-2', 'ap-northeast-1', 'sa-east-1']:
if args.region != dest: if args.region != dest:
print >> sys.stderr, "copying image from region {0} to {1}".format(args.region, dest) print >> sys.stderr, "copying image from region {0} to {1}".format(args.region, dest)
conn = boto.ec2.connect_to_region(dest) conn = boto.ec2.connect_to_region(dest)

View File

@ -1,9 +1,8 @@
#! /bin/sh -e #! /bin/sh -e
nixos=$(nix-instantiate --find-file nixos)
export NIXOS_CONFIG=$(dirname $(readlink -f $0))/amazon-base-config.nix export NIXOS_CONFIG=$(dirname $(readlink -f $0))/amazon-base-config.nix
version=$(nix-instantiate --eval-only '<nixos>' -A config.system.nixosVersion | sed s/'"'//g) version=$(nix-instantiate --eval-only '<nixpkgs/nixos>' -A config.system.nixosVersion | sed s/'"'//g)
echo "NixOS version is $version" echo "NixOS version is $version"
buildAndUploadFor() { buildAndUploadFor() {
@ -11,13 +10,13 @@ buildAndUploadFor() {
arch="$2" arch="$2"
echo "building $system image..." echo "building $system image..."
nix-build '<nixos>' \ nix-build '<nixpkgs/nixos>' \
-A config.system.build.amazonImage --argstr system "$system" -o ec2-ami -A config.system.build.amazonImage --argstr system "$system" -o ec2-ami
ec2-bundle-image -i ./ec2-ami/nixos.img --user "$AWS_ACCOUNT" --arch "$arch" \ ec2-bundle-image -i ./ec2-ami/nixos.img --user "$AWS_ACCOUNT" --arch "$arch" \
-c "$EC2_CERT" -k "$EC2_PRIVATE_KEY" -c "$EC2_CERT" -k "$EC2_PRIVATE_KEY"
for region in eu-west-1 us-east-1 us-west-1 us-west-2; do for region in eu-west-1; do
echo "uploading $system image for $region..." echo "uploading $system image for $region..."
name=nixos-$version-$arch-s3 name=nixos-$version-$arch-s3

View File

@ -4,10 +4,11 @@
machine = machine =
{ config, pkgs, resources, ... }: { config, pkgs, resources, ... }:
{ deployment.targetEnv = "ec2"; { deployment.targetEnv = "ec2";
deployment.ec2.instanceType = "m1.large"; deployment.ec2.instanceType = "c3.large";
deployment.ec2.securityGroups = [ "admin" ]; deployment.ec2.securityGroups = [ "admin" ];
deployment.ec2.ebsBoot = false; deployment.ec2.ebsBoot = false;
deployment.ec2.keyPair = resources.ec2KeyPairs.keypair.name; deployment.ec2.keyPair = resources.ec2KeyPairs.keypair.name;
deployment.ec2.zone = "us-east-1e";
environment.systemPackages = [ pkgs.parted ]; environment.systemPackages = [ pkgs.parted ];
}; };
} }

View File

@ -0,0 +1,14 @@
#! /bin/sh -e
export NIX_PATH=nixpkgs=../../../..
export NIXOS_CONFIG=$(dirname $(readlink -f $0))/../../../modules/virtualisation/google-compute-image.nix
export TIMESTAMP=$(date +%Y%m%d%H%M)
nix-build '<nixpkgs/nixos>' \
-A config.system.build.googleComputeImage --argstr system x86_64-linux -o gce --option extra-binary-caches http://hydra.nixos.org -j 10
img=$(echo gce/*.tar.gz)
if ! gsutil ls gs://nixos/$(basename $img); then
gsutil cp $img gs://nixos/$(basename $img)
fi
gcutil addimage $(basename $img .raw.tar.gz | sed 's|\.|-|' | sed 's|_|-|') gs://nixos/$(basename $img)

View File

@ -1,6 +1,6 @@
{ config, pkgs, ... }: { config, lib, pkgs, ... }:
with pkgs.lib; with lib;
{ {
@ -25,7 +25,7 @@ with pkgs.lib;
config = mkIf config.fonts.enableCoreFonts { config = mkIf config.fonts.enableCoreFonts {
fonts.extraFonts = [ pkgs.corefonts ]; fonts.fonts = [ pkgs.corefonts ];
}; };

View File

@ -1,6 +1,6 @@
{ config, pkgs, ... }: { config, lib, pkgs, ... }:
with pkgs.lib; with lib;
{ {

View File

@ -1,6 +1,6 @@
{ config, pkgs, ... }: { config, lib, pkgs, ... }:
with pkgs.lib; with lib;
let let

View File

@ -1,6 +1,6 @@
{ config, pkgs, ... }: { config, lib, pkgs, ... }:
with pkgs.lib; with lib;
{ {
@ -10,20 +10,27 @@ with pkgs.lib;
# TODO: find another name for it. # TODO: find another name for it.
fonts = mkOption { fonts = mkOption {
default = [ type = types.listOf types.path;
# - the user's .fonts directory example = [ pkgs.dejavu_fonts ];
"~/.fonts" description = "List of primary font paths.";
# - the user's current profile apply = list: list ++
[ # - the user's current profile
"~/.nix-profile/lib/X11/fonts" "~/.nix-profile/lib/X11/fonts"
"~/.nix-profile/share/fonts" "~/.nix-profile/share/fonts"
# - the default profile # - the default profile
"/nix/var/nix/profiles/default/lib/X11/fonts" "/nix/var/nix/profiles/default/lib/X11/fonts"
"/nix/var/nix/profiles/default/share/fonts" "/nix/var/nix/profiles/default/share/fonts"
]; ];
description = "List of primary font paths."; };
apply = list: list ++ [
# - a few statically built locations };
pkgs.xorg.fontbhttf
};
config = {
fonts.fonts =
[ pkgs.xorg.fontbhttf
pkgs.xorg.fontbhlucidatypewriter100dpi pkgs.xorg.fontbhlucidatypewriter100dpi
pkgs.xorg.fontbhlucidatypewriter75dpi pkgs.xorg.fontbhlucidatypewriter75dpi
pkgs.ttf_bitstream_vera pkgs.ttf_bitstream_vera
@ -32,17 +39,7 @@ with pkgs.lib;
pkgs.xorg.fontbh100dpi pkgs.xorg.fontbh100dpi
pkgs.xorg.fontmiscmisc pkgs.xorg.fontmiscmisc
pkgs.xorg.fontcursormisc pkgs.xorg.fontcursormisc
] ];
++ config.fonts.extraFonts;
};
extraFonts = mkOption {
default = [];
example = [ pkgs.dejavu_fonts ];
description = "List of packages with additional fonts.";
};
};
}; };

View File

@ -1,6 +1,6 @@
{ config, pkgs, ... }: { config, lib, pkgs, ... }:
with pkgs.lib; with lib;
{ {
@ -25,7 +25,7 @@ with pkgs.lib;
config = mkIf config.fonts.enableGhostscriptFonts { config = mkIf config.fonts.enableGhostscriptFonts {
fonts.extraFonts = [ "${pkgs.ghostscript}/share/ghostscript/fonts" ]; fonts.fonts = [ "${pkgs.ghostscript}/share/ghostscript/fonts" ];
}; };

View File

@ -1,6 +1,6 @@
{ config, pkgs, ... }: { config, lib, pkgs, ... }:
with pkgs.lib; with lib;
{ {
options = { options = {
@ -36,7 +36,7 @@ with pkgs.lib;
# GNU lsh. # GNU lsh.
services.openssh.enable = false; services.openssh.enable = false;
services.lshd.enable = true; services.lshd.enable = true;
services.xserver.startOpenSSHAgent = false; programs.ssh.startAgent = false;
services.xserver.startGnuPGAgent = true; services.xserver.startGnuPGAgent = true;
# TODO: GNU dico. # TODO: GNU dico.

View File

@ -1,6 +1,6 @@
{ config, pkgs, ... }: { config, lib, pkgs, ... }:
with pkgs.lib; with lib;
let let
@ -53,7 +53,11 @@ in
}; };
consoleKeyMap = mkOption { consoleKeyMap = mkOption {
type = types.str; type = mkOptionType {
name = "string or path";
check = t: (isString t || types.path.check t);
};
default = "us"; default = "us";
example = "fr"; example = "fr";
description = '' description = ''
@ -72,7 +76,12 @@ in
environment.systemPackages = [ glibcLocales ]; environment.systemPackages = [ glibcLocales ];
environment.variables.LANG = config.i18n.defaultLocale; environment.sessionVariables =
{ LANG = config.i18n.defaultLocale;
LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive";
};
systemd.globalEnvironment.LOCALE_ARCHIVE = "${glibcLocales}/lib/locale/locale-archive";
# /etc/locale.conf is used by systemd. # /etc/locale.conf is used by systemd.
environment.etc = singleton environment.etc = singleton

View File

@ -1,6 +1,6 @@
{ config, pkgs, ... }: { config, lib, pkgs, ... }:
with pkgs.lib; with lib;
let let
@ -32,12 +32,12 @@ in
kdc = mkOption { kdc = mkOption {
default = "kerberos.mit.edu"; default = "kerberos.mit.edu";
description = "Kerberos Domain Controller"; description = "Kerberos Domain Controller.";
}; };
kerberosAdminServer = mkOption { kerberosAdminServer = mkOption {
default = "kerberos.mit.edu"; default = "kerberos.mit.edu";
description = "Kerberos Admin Server"; description = "Kerberos Admin Server.";
}; };
}; };

View File

@ -1,7 +1,7 @@
{ config, pkgs, ... }: { config, lib, pkgs, ... }:
with pkgs.lib;
with pkgs; with pkgs;
with lib;
let let
@ -217,9 +217,7 @@ in
systemd.services = mkIf cfg.daemon.enable { systemd.services = mkIf cfg.daemon.enable {
nslcd = { nslcd = {
wantedBy = [ "nss-user-lookup.target" ]; wantedBy = [ "multi-user.target" ];
before = [ "nss-user-lookup.target" ];
after = [ "network.target" ];
preStart = '' preStart = ''
mkdir -p /run/nslcd mkdir -p /run/nslcd

View File

@ -1,8 +1,8 @@
# /etc files related to networking, such as /etc/services. # /etc files related to networking, such as /etc/services.
{ config, pkgs, ... }: { config, lib, pkgs, ... }:
with pkgs.lib; with lib;
let let
@ -14,7 +14,7 @@ in
options = { options = {
networking.extraHosts = pkgs.lib.mkOption { networking.extraHosts = lib.mkOption {
type = types.lines; type = types.lines;
default = ""; default = "";
example = "192.168.0.1 lanlocalhost"; example = "192.168.0.1 lanlocalhost";
@ -23,7 +23,7 @@ in
''; '';
}; };
networking.dnsSingleRequest = pkgs.lib.mkOption { networking.dnsSingleRequest = lib.mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = '' description = ''

View File

@ -1,6 +1,9 @@
{ config, pkgs, ... }: # This module gets rid of all dependencies on X11 client libraries
# (including fontconfig).
with pkgs.lib; { config, lib, pkgs, ... }:
with lib;
{ {
options = { options = {
@ -8,18 +11,22 @@ with pkgs.lib;
type = types.bool; type = types.bool;
default = false; default = false;
description = '' description = ''
Switch off the options in the default configuration that require X libraries. Switch off the options in the default configuration that
Currently this includes: ssh X11 forwarding, dbus, fonts.enableCoreFonts, require X11 libraries. This includes client-side font
fonts.enableFontConfig configuration and SSH forwarding of X11 authentication
in. Thus, you probably do not want to enable this option if
you want to run X11 programs on this machine via SSH.
''; '';
}; };
}; };
config = mkIf config.environment.noXlibs { config = mkIf config.environment.noXlibs {
programs.ssh.setXAuthLocation = false; programs.ssh.setXAuthLocation = false;
fonts = { security.pam.services.su.forwardXAuth = lib.mkForce false;
enableCoreFonts = false;
enableFontConfig = false; fonts.enableFontConfig = false;
};
nixpkgs.config.packageOverrides = pkgs:
{ dbus = pkgs.dbus.override { useX11 = false; }; };
}; };
} }

View File

@ -1,8 +1,8 @@
# Configuration for the Name Service Switch (/etc/nsswitch.conf). # Configuration for the Name Service Switch (/etc/nsswitch.conf).
{ config, pkgs, ... }: { config, lib, pkgs, ... }:
with pkgs.lib; with lib;
let let

View File

@ -1,6 +1,6 @@
{ config, pkgs, ... }: { config, lib, pkgs, ... }:
with pkgs.lib; with lib;
let let
@ -65,14 +65,7 @@ in
config = mkIf cfg.enable { config = mkIf cfg.enable {
# Enable the ACPI daemon. Not sure whether this is essential. # FIXME: Implement powersave governor for sandy bridge or later Intel CPUs
services.acpid.enable = true;
boot.kernelModules =
[ "acpi_cpufreq" "powernow-k8" "cpufreq_performance" "cpufreq_powersave" "cpufreq_ondemand"
"cpufreq_conservative"
];
powerManagement.cpuFreqGovernor = mkDefault "ondemand"; powerManagement.cpuFreqGovernor = mkDefault "ondemand";
powerManagement.scsiLinkPolicy = mkDefault "min_power"; powerManagement.scsiLinkPolicy = mkDefault "min_power";

View File

@ -1,24 +1,26 @@
{ config, pkgs, ... }: { config, lib, pkgs, ... }:
with pkgs.lib;
with pkgs; with pkgs;
with lib;
let let
cfg = config.hardware.pulseaudio; cfg = config.hardware.pulseaudio;
systemWide = cfg.enable && cfg.systemWide;
nonSystemWide = cfg.enable && !cfg.systemWide;
uid = config.ids.uids.pulseaudio; uid = config.ids.uids.pulseaudio;
gid = config.ids.gids.pulseaudio; gid = config.ids.gids.pulseaudio;
pulseRuntimePath = "/var/run/pulse"; stateDir = "/run/pulse";
# Create pulse/client.conf even if PulseAudio is disabled so # Create pulse/client.conf even if PulseAudio is disabled so
# that we can disable the autospawn feature in programs that # that we can disable the autospawn feature in programs that
# are built with PulseAudio support (like KDE). # are built with PulseAudio support (like KDE).
clientConf = writeText "client.conf" '' clientConf = writeText "client.conf" ''
autospawn=${if (cfg.enable && !cfg.systemWide) then "yes" else "no"} autospawn=${if nonSystemWide then "yes" else "no"}
${optionalString (cfg.enable && !cfg.systemWide) ${optionalString nonSystemWide "daemon-binary=${cfg.package}/bin/pulseaudio"}
"daemon-binary=${cfg.package}/bin/pulseaudio"}
''; '';
# Write an /etc/asound.conf that causes all ALSA applications to # Write an /etc/asound.conf that causes all ALSA applications to
@ -68,7 +70,7 @@ in {
configFile = mkOption { configFile = mkOption {
type = types.uniq types.path; type = types.uniq types.path;
default = "${pulseaudio}/etc/pulse/default.pa"; default = "${cfg.package}/etc/pulse/default.pa";
description = '' description = ''
The path to the configuration the PulseAudio server The path to the configuration the PulseAudio server
should use. By default, the "default.pa" configuration should use. By default, the "default.pa" configuration
@ -77,15 +79,26 @@ in {
}; };
package = mkOption { package = mkOption {
type = types.path; type = types.package;
default = pulseaudio; default = pulseaudioFull;
example = literalExample "pulseaudio.override { jackaudioSupport = true; }"; example = literalExample "pulseaudioFull";
description = '' description = ''
The PulseAudio derivation to use. This can be used to enable The PulseAudio derivation to use. This can be used to disable
features (such as JACK support) that are not enabled in the features (such as JACK support, Bluetooth) that are enabled in the
default PulseAudio in Nixpkgs. pulseaudioFull package in Nixpkgs.
''; '';
}; };
daemon = {
logLevel = mkOption {
type = types.str;
default = "notice";
description = ''
The log level that the system-wide pulseaudio daemon should use,
if activated.
'';
};
};
}; };
}; };
@ -111,38 +124,37 @@ in {
security.rtkit.enable = true; security.rtkit.enable = true;
}) })
(mkIf (cfg.enable && !cfg.systemWide) { (mkIf nonSystemWide {
environment.etc = singleton { environment.etc = singleton {
target = "pulse/default.pa"; target = "pulse/default.pa";
source = cfg.configFile; source = cfg.configFile;
}; };
}) })
(mkIf (cfg.enable && cfg.systemWide) { (mkIf systemWide {
users.extraUsers.pulse = { users.extraUsers.pulse = {
# For some reason, PulseAudio wants UID == GID. # For some reason, PulseAudio wants UID == GID.
uid = assert uid == gid; uid; uid = assert uid == gid; uid;
group = "pulse"; group = "pulse";
extraGroups = [ "audio" ]; extraGroups = [ "audio" ];
description = "PulseAudio system service user"; description = "PulseAudio system service user";
home = pulseRuntimePath;
}; };
users.extraGroups.pulse.gid = gid; users.extraGroups.pulse.gid = gid;
systemd.services.pulseaudio = { systemd.services.pulseaudio = {
description = "PulseAudio system-wide server"; description = "PulseAudio System-Wide Server";
wantedBy = [ "sound.target" ]; wantedBy = [ "sound.target" ];
before = [ "sound.target" ]; before = [ "sound.target" ];
path = [ cfg.package ]; environment.PULSE_RUNTIME_PATH = stateDir;
environment.PULSE_RUNTIME_PATH = pulseRuntimePath;
preStart = '' preStart = ''
mkdir -p --mode 755 ${pulseRuntimePath} mkdir -p --mode 755 ${stateDir}
chown -R pulse:pulse ${pulseRuntimePath} chown -R pulse:pulse ${stateDir}
'';
script = ''
exec pulseaudio --system -n --file="${cfg.configFile}"
''; '';
serviceConfig = {
ExecStart = "${cfg.package}/bin/pulseaudio -D --log-level=${cfg.daemon.logLevel} --system --use-pid-file -n --file=${cfg.configFile}";
PIDFile = "${stateDir}/pid";
};
}; };
}) })
]; ];

View File

@ -1,9 +1,9 @@
# This module defines a global environment configuration and # This module defines a global environment configuration and
# a common configuration for all shells. # a common configuration for all shells.
{ config, pkgs, ... }: { config, lib, pkgs, ... }:
with pkgs.lib; with lib;
let let
@ -19,6 +19,7 @@ in
default = {}; default = {};
description = '' description = ''
A set of environment variables used in the global environment. A set of environment variables used in the global environment.
These variables will be set on shell initialisation.
The value of each variable can be either a string or a list of The value of each variable can be either a string or a list of
strings. The latter is concatenated, interspersed with colon strings. The latter is concatenated, interspersed with colon
characters. characters.
@ -31,9 +32,9 @@ in
res = (head defs').value; res = (head defs').value;
in in
if isList res then concatLists (getValues defs') if isList res then concatLists (getValues defs')
else if builtins.lessThan 1 (length defs') then else if lessThan 1 (length defs') then
throw "The option `${showOption loc}' is defined multiple times, in ${showFiles (getFiles defs)}." throw "The option `${showOption loc}' is defined multiple times, in ${showFiles (getFiles defs)}."
else if !builtins.isString res then else if !isString res then
throw "The option `${showOption loc}' does not have a string value, in ${showFiles (getFiles defs)}." throw "The option `${showOption loc}' does not have a string value, in ${showFiles (getFiles defs)}."
else res; else res;
}); });
@ -148,6 +149,12 @@ in
system.build.binsh = pkgs.bashInteractive; system.build.binsh = pkgs.bashInteractive;
# Set session variables in the shell as well. This is usually
# unnecessary, but it allows changes to session variables to take
# effect without restarting the session (e.g. by opening a new
# terminal instead of logging out of X11).
environment.variables = config.environment.sessionVariables;
environment.etc."shells".text = environment.etc."shells".text =
'' ''
${concatStringsSep "\n" cfg.shells} ${concatStringsSep "\n" cfg.shells}

View File

@ -1,7 +1,7 @@
{ config, pkgs, utils, ... }: { config, lib, pkgs, utils, ... }:
with pkgs.lib;
with utils; with utils;
with lib;
{ {
@ -106,6 +106,7 @@ with utils;
if [ ! -e "${sw.device}" ]; then if [ ! -e "${sw.device}" ]; then
fallocate -l ${toString sw.size}M "${sw.device}" || fallocate -l ${toString sw.size}M "${sw.device}" ||
dd if=/dev/zero of="${sw.device}" bs=1M count=${toString sw.size} dd if=/dev/zero of="${sw.device}" bs=1M count=${toString sw.size}
chmod 0600 ${sw.device}
mkswap ${sw.device} mkswap ${sw.device}
fi fi
''; '';

View File

@ -1,13 +1,17 @@
{ config, pkgs, ... }: { config, lib, pkgs, ... }:
with pkgs.lib; with lib;
let let
sysctlOption = mkOptionType { sysctlOption = mkOptionType {
name = "sysctl option value"; name = "sysctl option value";
check = x: builtins.isBool x || builtins.isString x || builtins.isInt x; check = val:
merge = args: defs: (last defs).value; # FIXME: hacky way to allow overriding in configuration.nix. let
checkType = x: isBool x || isString x || isInt x || isNull x;
in
checkType val || (val._type or "" == "override" && checkType val.content);
merge = loc: defs: mergeOneOption loc (filterOverrides defs);
}; };
in in
@ -29,8 +33,9 @@ in
<manvolnum>8</manvolnum></citerefentry>. Note that sysctl <manvolnum>8</manvolnum></citerefentry>. Note that sysctl
parameters names must be enclosed in quotes parameters names must be enclosed in quotes
(e.g. <literal>"vm.swappiness"</literal> instead of (e.g. <literal>"vm.swappiness"</literal> instead of
<literal>vm.swappiness</literal>). The value of each parameter <literal>vm.swappiness</literal>). The value of each
may be a string, integer or Boolean. parameter may be a string, integer, boolean, or null
(signifying the option will not appear at all).
''; '';
}; };
@ -39,19 +44,13 @@ in
config = { config = {
environment.etc."sysctl.d/nixos.conf".text = environment.etc."sysctl.d/nixos.conf".text =
concatStrings (mapAttrsToList (n: v: "${n}=${if v == false then "0" else toString v}\n") config.boot.kernel.sysctl); concatStrings (mapAttrsToList (n: v:
optionalString (v != null) "${n}=${if v == false then "0" else toString v}\n"
) config.boot.kernel.sysctl);
systemd.services.systemd-sysctl = systemd.services.systemd-sysctl =
{ description = "Apply Kernel Variables"; { wantedBy = [ "multi-user.target" ];
before = [ "sysinit.target" "shutdown.target" ];
wantedBy = [ "sysinit.target" "multi-user.target" ];
restartTriggers = [ config.environment.etc."sysctl.d/nixos.conf".source ]; restartTriggers = [ config.environment.etc."sysctl.d/nixos.conf".source ];
unitConfig.DefaultDependencies = false; # needed to prevent a cycle
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStart = "${config.systemd.package}/lib/systemd/systemd-sysctl";
};
}; };
# Enable hardlink and symlink restrictions. See # Enable hardlink and symlink restrictions. See
@ -62,8 +61,9 @@ in
# Hide kernel pointers (e.g. in /proc/modules) for unprivileged # Hide kernel pointers (e.g. in /proc/modules) for unprivileged
# users as these make it easier to exploit kernel vulnerabilities. # users as these make it easier to exploit kernel vulnerabilities.
boot.kernel.sysctl."kernel.kptr_restrict" = 1; #
# Removed under grsecurity.
boot.kernel.sysctl."kernel.kptr_restrict" =
if config.security.grsecurity.enable then null else 1;
}; };
} }

View File

@ -0,0 +1,56 @@
# This module defines a system-wide environment that will be
# initialised by pam_env (that is, not only in shells).
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.environment;
in
{
options = {
environment.sessionVariables = mkOption {
default = {};
description = ''
A set of environment variables used in the global environment.
These variables will be set by PAM.
The value of each variable can be either a string or a list of
strings. The latter is concatenated, interspersed with colon
characters.
'';
type = types.attrsOf (mkOptionType {
name = "a string or a list of strings";
merge = loc: defs:
let
defs' = filterOverrides defs;
res = (head defs').value;
in
if isList res then concatLists (getValues defs')
else if lessThan 1 (length defs') then
throw "The option `${showOption loc}' is defined multiple times, in ${showFiles (getFiles defs)}."
else if !isString res then
throw "The option `${showOption loc}' does not have a string value, in ${showFiles (getFiles defs)}."
else res;
});
apply = mapAttrs (n: v: if isList v then concatStringsSep ":" v else v);
};
};
config = {
system.build.pamEnvironment = pkgs.writeText "pam-environment"
''
${concatStringsSep "\n" (
(mapAttrsToList (n: v: ''${n}="${concatStringsSep ":" v}"'')
(zipAttrsWith (const concatLists) ([ (mapAttrs (n: v: [ v ]) cfg.sessionVariables) ]))))}
'';
};
}

View File

@ -1,9 +1,9 @@
# This module defines the packages that appear in # This module defines the packages that appear in
# /run/current-system/sw. # /run/current-system/sw.
{ config, pkgs, ... }: { config, lib, pkgs, ... }:
with pkgs.lib; with lib;
let let
@ -46,6 +46,7 @@ let
pkgs.rsync pkgs.rsync
pkgs.strace pkgs.strace
pkgs.sysvtools pkgs.sysvtools
pkgs.su
pkgs.time pkgs.time
pkgs.usbutils pkgs.usbutils
pkgs.utillinux pkgs.utillinux
@ -109,6 +110,7 @@ in
"/man" "/man"
"/sbin" "/sbin"
"/share/emacs" "/share/emacs"
"/share/vim-plugins"
"/share/org" "/share/org"
"/share/info" "/share/info"
"/share/terminfo" "/share/terminfo"
@ -134,6 +136,10 @@ in
if [ -x $out/bin/glib-compile-schemas -a -w $out/share/glib-2.0/schemas ]; then if [ -x $out/bin/glib-compile-schemas -a -w $out/share/glib-2.0/schemas ]; then
$out/bin/glib-compile-schemas $out/share/glib-2.0/schemas $out/bin/glib-compile-schemas $out/share/glib-2.0/schemas
fi fi
if [ -x $out/bin/update-desktop-database -a -w $out/share/applications ]; then
$out/bin/update-desktop-database $out/share/applications
fi
''; '';
}; };

View File

@ -1,6 +1,12 @@
{ config, pkgs, ... }: { config, lib, pkgs, ... }:
with pkgs.lib; with lib;
let
tzdir = "${pkgs.tzdata}/share/zoneinfo";
in
{ {
options = { options = {
@ -24,10 +30,14 @@ with pkgs.lib;
config = { config = {
environment.variables.TZDIR = "/etc/zoneinfo"; environment.sessionVariables.TZDIR = "/etc/zoneinfo";
environment.variables.TZ = config.time.timeZone;
environment.etc.localtime.source = "${pkgs.tzdata}/share/zoneinfo/${config.time.timeZone}"; systemd.globalEnvironment.TZDIR = tzdir;
environment.etc.localtime =
{ source = "${tzdir}/${config.time.timeZone}";
mode = "direct-symlink";
};
environment.etc.zoneinfo.source = "${pkgs.tzdata}/share/zoneinfo"; environment.etc.zoneinfo.source = "${pkgs.tzdata}/share/zoneinfo";

View File

@ -1,6 +1,6 @@
{ config, pkgs, ... }: { config, lib, pkgs, ... }:
with pkgs.lib; with lib;
# unixODBC drivers (this solution is not perfect.. Because the user has to # unixODBC drivers (this solution is not perfect.. Because the user has to
# ask the admin to add a driver.. but it's simple and works # ask the admin to add a driver.. but it's simple and works
@ -27,7 +27,7 @@ with pkgs.lib;
environment.etc."odbcinst.ini".text = environment.etc."odbcinst.ini".text =
let inis = config.environment.unixODBCDrivers; let inis = config.environment.unixODBCDrivers;
in pkgs.lib.concatStringsSep "\n" inis; in lib.concatStringsSep "\n" inis;
}; };

View File

@ -0,0 +1,239 @@
use strict;
use File::Path qw(make_path);
use File::Slurp;
use JSON;
make_path("/var/lib/nixos", { mode => 0755 });
# Functions for allocating free GIDs/UIDs. FIXME: respect ID ranges in
# /etc/login.defs.
sub allocId {
my ($used, $idMin, $idMax, $up, $getid) = @_;
my $id = $up ? $idMin : $idMax;
while ($id >= $idMin && $id <= $idMax) {
if (!$used->{$id} && !defined &$getid($id)) {
$used->{$id} = 1;
return $id;
}
$used->{$id} = 1;
if ($up) { $id++; } else { $id--; }
}
die "$0: out of free UIDs or GIDs\n";
}
my (%gidsUsed, %uidsUsed);
sub allocGid {
return allocId(\%gidsUsed, 400, 499, 0, sub { my ($gid) = @_; getgrgid($gid) });
}
sub allocUid {
my ($isSystemUser) = @_;
my ($min, $max, $up) = $isSystemUser ? (400, 499, 0) : (1000, 29999, 1);
return allocId(\%uidsUsed, $min, $max, $up, sub { my ($uid) = @_; getpwuid($uid) });
}
# Read the declared users/groups.
my $spec = decode_json(read_file($ARGV[0]));
# Don't allocate UIDs/GIDs that are already in use.
foreach my $g (@{$spec->{groups}}) {
$gidsUsed{$g->{gid}} = 1 if defined $g->{gid};
}
foreach my $u (@{$spec->{groups}}) {
$uidsUsed{$u->{u}} = 1 if defined $u->{uid};
}
# Read the current /etc/group.
sub parseGroup {
chomp;
my @f = split(':', $_, -4);
my $gid = $f[2] eq "" ? undef : int($f[2]);
$gidsUsed{$gid} = 1 if defined $gid;
return ($f[0], { name => $f[0], password => $f[1], gid => $gid, members => $f[3] });
}
my %groupsCur = -f "/etc/group" ? map { parseGroup } read_file("/etc/group") : ();
# Read the current /etc/passwd.
sub parseUser {
chomp;
my @f = split(':', $_, -7);
my $uid = $f[2] eq "" ? undef : int($f[2]);
$uidsUsed{$uid} = 1 if defined $uid;
return ($f[0], { name => $f[0], fakePassword => $f[1], uid => $uid,
gid => $f[3], description => $f[4], home => $f[5], shell => $f[6] });
}
my %usersCur = -f "/etc/passwd" ? map { parseUser } read_file("/etc/passwd") : ();
# Read the groups that were created declaratively (i.e. not by groups)
# in the past. These must be removed if they are no longer in the
# current spec.
my $declGroupsFile = "/var/lib/nixos/declarative-groups";
my %declGroups;
$declGroups{$_} = 1 foreach split / /, -e $declGroupsFile ? read_file($declGroupsFile) : "";
# Idem for the users.
my $declUsersFile = "/var/lib/nixos/declarative-users";
my %declUsers;
$declUsers{$_} = 1 foreach split / /, -e $declUsersFile ? read_file($declUsersFile) : "";
# Generate a new /etc/group containing the declared groups.
my %groupsOut;
foreach my $g (@{$spec->{groups}}) {
my $name = $g->{name};
my $existing = $groupsCur{$name};
my %members = map { ($_, 1) } @{$g->{members}};
if (defined $existing) {
$g->{gid} = $existing->{gid} if !defined $g->{gid};
if ($g->{gid} != $existing->{gid}) {
warn "warning: not applying GID change of group $name\n";
$g->{gid} = $existing->{gid};
}
$g->{password} = $existing->{password}; # do we want this?
if ($spec->{mutableUsers}) {
# Merge in non-declarative group members.
foreach my $uname (split /,/, $existing->{members} // "") {
$members{$uname} = 1 if !defined $declUsers{$uname};
}
}
} else {
$g->{gid} = allocGid if !defined $g->{gid};
$g->{password} = "x";
}
$g->{members} = join ",", sort(keys(%members));
$groupsOut{$name} = $g;
}
# Update the persistent list of declarative groups.
write_file($declGroupsFile, join(" ", sort(keys %groupsOut)));
# Merge in the existing /etc/group.
foreach my $name (keys %groupsCur) {
my $g = $groupsCur{$name};
next if defined $groupsOut{$name};
if (!$spec->{mutableUsers} || defined $declGroups{$name}) {
print STDERR "removing group $name\n";
} else {
$groupsOut{$name} = $g;
}
}
# Rewrite /etc/group. FIXME: acquire lock.
my @lines = map { join(":", $_->{name}, $_->{password}, $_->{gid}, $_->{members}) . "\n" }
(sort { $a->{gid} <=> $b->{gid} } values(%groupsOut));
write_file("/etc/group.tmp", @lines);
rename("/etc/group.tmp", "/etc/group") or die;
system("nscd --invalidate group");
# Generate a new /etc/passwd containing the declared users.
my %usersOut;
foreach my $u (@{$spec->{users}}) {
my $name = $u->{name};
# Resolve the gid of the user.
if ($u->{group} =~ /^[0-9]$/) {
$u->{gid} = $u->{group};
} elsif (defined $groupsOut{$u->{group}}) {
$u->{gid} = $groupsOut{$u->{group}}->{gid} // die;
} else {
warn "warning: user $name has unknown group $u->{group}\n";
$u->{gid} = 65534;
}
my $existing = $usersCur{$name};
if (defined $existing) {
$u->{uid} = $existing->{uid} if !defined $u->{uid};
if ($u->{uid} != $existing->{uid}) {
warn "warning: not applying UID change of user $name\n";
$u->{uid} = $existing->{uid};
}
} else {
$u->{uid} = allocUid($u->{isSystemUser}) if !defined $u->{uid};
# Create a home directory.
if ($u->{createHome}) {
make_path($u->{home}, { mode => 0700 }) if ! -e $u->{home};
chown $u->{uid}, $u->{gid}, $u->{home};
}
}
if (defined $u->{passwordFile}) {
if (-e $u->{passwordFile}) {
$u->{hashedPassword} = read_file($u->{passwordFile});
chomp $u->{hashedPassword};
} else {
warn "warning: password file $u->{passwordFile} does not exist\n";
}
}
$u->{fakePassword} = $existing->{fakePassword} // "x";
$usersOut{$name} = $u;
}
# Update the persistent list of declarative users.
write_file($declUsersFile, join(" ", sort(keys %usersOut)));
# Merge in the existing /etc/passwd.
foreach my $name (keys %usersCur) {
my $u = $usersCur{$name};
next if defined $usersOut{$name};
if (!$spec->{mutableUsers} || defined $declUsers{$name}) {
print STDERR "removing user $name\n";
} else {
$usersOut{$name} = $u;
}
}
# Rewrite /etc/passwd. FIXME: acquire lock.
@lines = map { join(":", $_->{name}, $_->{fakePassword}, $_->{uid}, $_->{gid}, $_->{description}, $_->{home}, $_->{shell}) . "\n" }
(sort { $a->{uid} <=> $b->{uid} } (values %usersOut));
write_file("/etc/passwd.tmp", @lines);
rename("/etc/passwd.tmp", "/etc/passwd") or die;
system("nscd --invalidate passwd");
# Rewrite /etc/shadow to add new accounts or remove dead ones.
my @shadowNew;
my %shadowSeen;
foreach my $line (-f "/etc/shadow" ? read_file("/etc/shadow") : ()) {
chomp $line;
my ($name, $password, @rest) = split(':', $line, -9);
my $u = $usersOut{$name};;
next if !defined $u;
$password = $u->{hashedPassword} if defined $u->{hashedPassword} && !$spec->{mutableUsers}; # FIXME
push @shadowNew, join(":", $name, $password, @rest) . "\n";
$shadowSeen{$name} = 1;
}
foreach my $u (values %usersOut) {
next if defined $shadowSeen{$u->{name}};
my $password = "!";
$password = $u->{hashedPassword} if defined $u->{hashedPassword};
# FIXME: set correct value for sp_lstchg.
push @shadowNew, join(":", $u->{name}, $password, "1::::::") . "\n";
}
write_file("/etc/shadow.tmp", { perms => 0600 }, @shadowNew);
rename("/etc/shadow.tmp", "/etc/shadow") or die;
# Call chpasswd to apply password. FIXME: generate the hashes directly
# and merge into the /etc/shadow updating above.
foreach my $u (@{$spec->{users}}) {
if (defined $u->{password}) {
my $pid = open(PW, "| chpasswd") or die;
print PW "$u->{name}:$u->{password}\n";
close PW or die "unable to change password of user $u->{name}: $?\n";
}
}

View File

@ -1,11 +1,29 @@
{pkgs, config, ...}: { config, lib, pkgs, ... }:
with pkgs.lib; with lib;
let let
ids = config.ids; ids = config.ids;
users = config.users; cfg = config.users;
passwordDescription = ''
The options <literal>hashedPassword</literal>,
<literal>password</literal> and <literal>passwordFile</literal>
controls what password is set for the user.
<literal>hashedPassword</literal> overrides both
<literal>password</literal> and <literal>passwordFile</literal>.
<literal>password</literal> overrides <literal>passwordFile</literal>.
If none of these three options are set, no password is assigned to
the user, and the user will not be able to do password logins.
If the option <literal>users.mutableUsers</literal> is true, the
password defined in one of the three options will only be set when
the user is created for the first time. After that, you are free to
change the password with the ordinary user management commands. If
<literal>users.mutableUsers</literal> is false, you cannot change
user passwords, they will always be set according to the password
options.
'';
userOpts = { name, config, ... }: { userOpts = { name, config, ... }: {
@ -13,7 +31,10 @@ let
name = mkOption { name = mkOption {
type = types.str; type = types.str;
description = "The name of the user account. If undefined, the name of the attribute set will be used."; description = ''
The name of the user account. If undefined, the name of the
attribute set will be used.
'';
}; };
description = mkOption { description = mkOption {
@ -28,9 +49,40 @@ let
}; };
uid = mkOption { uid = mkOption {
type = with types; uniq (nullOr int); type = with types; nullOr int;
default = null; default = null;
description = "The account UID. If undefined, NixOS will select a free UID."; description = ''
The account UID. If the UID is null, a free UID is picked on
activation.
'';
};
isSystemUser = mkOption {
type = types.bool;
default = false;
description = ''
Indicates if the user is a system user or not. This option
only has an effect if <option>uid</option> is
<option>null</option>, in which case it determines whether
the user's UID is allocated in the range for system users
(below 500) or in the range for normal users (starting at
1000).
'';
};
isNormalUser = mkOption {
type = types.bool;
default = false;
description = ''
Indicates whether this is an account for a real user. This
automatically sets <option>group</option> to
<literal>users</literal>, <option>createHome</option> to
<literal>true</literal>, <option>home</option> to
<filename>/home/<replaceable>username</replaceable></filename>,
<option>useDefaultShell</option> to <literal>true</literal>,
and <option>isSystemUser</option> to
<literal>false</literal>.
'';
}; };
group = mkOption { group = mkOption {
@ -60,56 +112,69 @@ let
createHome = mkOption { createHome = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = "If true, the home directory will be created automatically."; description = ''
If true, the home directory will be created automatically. If this
option is true and the home directory already exists but is not
owned by the user, directory owner and group will be changed to
match the user.
'';
}; };
useDefaultShell = mkOption { useDefaultShell = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = "If true, the user's shell will be set to <literal>users.defaultUserShell</literal>."; description = ''
If true, the user's shell will be set to
<literal>cfg.defaultUserShell</literal>.
'';
};
hashedPassword = mkOption {
type = with types; uniq (nullOr str);
default = null;
description = ''
Specifies the (hashed) password for the user.
${passwordDescription}
'';
}; };
password = mkOption { password = mkOption {
type = with types; uniq (nullOr str); type = with types; uniq (nullOr str);
default = null; default = null;
description = '' description = ''
The user's password. If undefined, no password is set for Specifies the (clear text) password for the user.
the user. Warning: do not set confidential information here Warning: do not set confidential information here
because it is world-readable in the Nix store. This option because it is world-readable in the Nix store. This option
should only be used for public accounts such as should only be used for public accounts.
<literal>guest</literal>. ${passwordDescription}
''; '';
}; };
isSystemUser = mkOption { passwordFile = mkOption {
type = types.bool; type = with types; uniq (nullOr string);
default = true; default = null;
description = "Indicates if the user is a system user or not.";
};
createUser = mkOption {
type = types.bool;
default = true;
description = '' description = ''
Indicates if the user should be created automatically as a local user. The path to a file that contains the user's password. The password
Set this to false if the user for instance is an LDAP user. NixOS will file is read on each system activation. The file should contain
then not modify any of the basic properties for the user account. exactly one line, which should be the password in an encrypted form
that is suitable for the <literal>chpasswd -e</literal> command.
${passwordDescription}
''; '';
}; };
isAlias = mkOption {
type = types.bool;
default = false;
description = "If true, the UID of this user is not required to be unique and can thus alias another user.";
}; };
}; config = mkMerge
[ { name = mkDefault name;
config = { shell = mkIf config.useDefaultShell (mkDefault cfg.defaultUserShell);
name = mkDefault name; }
uid = mkDefault (attrByPath [name] null ids.uids); (mkIf config.isNormalUser {
shell = mkIf config.useDefaultShell (mkDefault users.defaultUserShell); group = mkDefault "users";
}; createHome = mkDefault true;
home = mkDefault "/home/${name}";
useDefaultShell = mkDefault true;
isSystemUser = mkDefault false;
})
];
}; };
@ -119,41 +184,102 @@ let
name = mkOption { name = mkOption {
type = types.str; type = types.str;
description = "The name of the group. If undefined, the name of the attribute set will be used."; description = ''
The name of the group. If undefined, the name of the attribute set
will be used.
'';
}; };
gid = mkOption { gid = mkOption {
type = with types; uniq (nullOr int); type = with types; nullOr int;
default = null; default = null;
description = "The GID of the group. If undefined, NixOS will select a free GID."; description = ''
The group GID. If the GID is null, a free GID is picked on
activation.
'';
};
members = mkOption {
type = with types; listOf string;
default = [];
description = ''
The user names of the group members, added to the
<literal>/etc/group</literal> file.
'';
}; };
}; };
config = { config = {
name = mkDefault name; name = mkDefault name;
gid = mkDefault (attrByPath [name] null ids.gids);
}; };
}; };
# Note: the 'X' in front of the password is to distinguish between idsAreUnique = set: idAttr: !(fold (name: args@{ dup, acc }:
# having an empty password, and not having a password.
serializedUser = u: "${u.name}\n${u.description}\n${if u.uid != null then toString u.uid else ""}\n${u.group}\n${toString (concatStringsSep "," u.extraGroups)}\n${u.home}\n${u.shell}\n${toString u.createHome}\n${if u.password != null then "X" + u.password else ""}\n${toString u.isSystemUser}\n${toString u.createUser}\n${toString u.isAlias}\n";
usersFile = pkgs.writeText "users" (
let let
p = partition (u: u.isAlias) (attrValues config.users.extraUsers); id = builtins.toString (builtins.getAttr idAttr (builtins.getAttr name set));
in concatStrings (map serializedUser p.wrong ++ map serializedUser p.right)); exists = builtins.hasAttr id acc;
newAcc = acc // (builtins.listToAttrs [ { name = id; value = true; } ]);
in if dup then args else if exists
then builtins.trace "Duplicate ${idAttr} ${id}" { dup = true; acc = null; }
else { dup = false; acc = newAcc; }
) { dup = false; acc = {}; } (builtins.attrNames set)).dup;
in uidsAreUnique = idsAreUnique (filterAttrs (n: u: u.uid != null) cfg.extraUsers) "uid";
gidsAreUnique = idsAreUnique (filterAttrs (n: g: g.gid != null) cfg.extraGroups) "gid";
{ spec = builtins.toFile "users-groups.json" (builtins.toJSON {
inherit (cfg) mutableUsers;
users = mapAttrsToList (n: u:
{ inherit (u)
name uid group description home shell createHome isSystemUser
password passwordFile hashedPassword;
}) cfg.extraUsers;
groups = mapAttrsToList (n: g:
{ inherit (g) name gid;
members = mapAttrsToList (n: u: u.name) (
filterAttrs (n: u: elem g.name u.extraGroups) cfg.extraUsers
);
}) cfg.extraGroups;
});
in {
###### interface ###### interface
options = { options = {
users.mutableUsers = mkOption {
type = types.bool;
default = true;
description = ''
If true, you are free to add new users and groups to the system
with the ordinary <literal>useradd</literal> and
<literal>groupadd</literal> commands. On system activation, the
existing contents of the <literal>/etc/passwd</literal> and
<literal>/etc/group</literal> files will be merged with the
contents generated from the <literal>users.extraUsers</literal> and
<literal>users.extraGroups</literal> options. If
<literal>mutableUsers</literal> is false, the contents of the user and
group files will simply be replaced on system activation. This also
holds for the user passwords; if this option is false, all changed
passwords will be reset according to the
<literal>users.extraUsers</literal> configuration on activation. If
this option is true, the initial password for a user will be set
according to <literal>users.extraUsers</literal>, but existing passwords
will not be changed.
'';
};
users.enforceIdUniqueness = mkOption {
type = types.bool;
default = true;
description = ''
Whether to require that no two users/groups share the same uid/gid.
'';
};
users.extraUsers = mkOption { users.extraUsers = mkOption {
default = {}; default = {};
type = types.loaOf types.optionSet; type = types.loaOf types.optionSet;
@ -188,6 +314,26 @@ in
options = [ groupOpts ]; options = [ groupOpts ];
}; };
security.initialRootPassword = mkOption {
type = types.str;
default = "!";
example = "";
description = ''
The (hashed) password for the root account set on initial
installation. The empty string denotes that root can login
locally without a password (but not via remote services such
as SSH, or indirectly via <command>su</command> or
<command>sudo</command>). The string <literal>!</literal>
prevents root from logging in using a password.
Note that setting this option sets
<literal>users.extraUsers.root.hashedPassword</literal>.
Also, if <literal>users.mutableUsers</literal> is false
you cannot change the root password manually, so in that case
the name of this option is a bit misleading, since it will define
the root password beyond the user initialisation phase.
'';
};
}; };
@ -197,128 +343,59 @@ in
users.extraUsers = { users.extraUsers = {
root = { root = {
uid = ids.uids.root;
description = "System administrator"; description = "System administrator";
home = "/root"; home = "/root";
shell = config.users.defaultUserShell; shell = mkDefault cfg.defaultUserShell;
group = "root"; group = "root";
extraGroups = [ "grsecurity" ];
hashedPassword = mkDefault config.security.initialRootPassword;
}; };
nobody = { nobody = {
uid = ids.uids.nobody;
description = "Unprivileged account (don't use!)"; description = "Unprivileged account (don't use!)";
group = "nogroup";
}; };
}; };
users.extraGroups = { users.extraGroups = {
root = { }; root.gid = ids.gids.root;
wheel = { }; wheel.gid = ids.gids.wheel;
disk = { }; disk.gid = ids.gids.disk;
kmem = { }; kmem.gid = ids.gids.kmem;
tty = { }; tty.gid = ids.gids.tty;
floppy = { }; floppy.gid = ids.gids.floppy;
uucp = { }; uucp.gid = ids.gids.uucp;
lp = { }; lp.gid = ids.gids.lp;
cdrom = { }; cdrom.gid = ids.gids.cdrom;
tape = { }; tape.gid = ids.gids.tape;
audio = { }; audio.gid = ids.gids.audio;
video = { }; video.gid = ids.gids.video;
dialout = { }; dialout.gid = ids.gids.dialout;
nogroup = { }; nogroup.gid = ids.gids.nogroup;
users = { }; users.gid = ids.gids.users;
nixbld = { }; nixbld.gid = ids.gids.nixbld;
utmp = { }; utmp.gid = ids.gids.utmp;
adm = { }; # expected by journald adm.gid = ids.gids.adm;
grsecurity.gid = ids.gids.grsecurity;
}; };
system.activationScripts.rootPasswd = stringAfter [ "etc" ] system.activationScripts.users = stringAfter [ "etc" ]
'' ''
# If there is no password file yet, create a root account with an ${pkgs.perl}/bin/perl -w \
# empty password. -I${pkgs.perlPackages.FileSlurp}/lib/perl5/site_perl \
if ! test -e /etc/passwd; then -I${pkgs.perlPackages.JSON}/lib/perl5/site_perl \
rootHome=/root ${./update-users-groups.pl} ${spec}
touch /etc/passwd; chmod 0644 /etc/passwd
touch /etc/group; chmod 0644 /etc/group
touch /etc/shadow; chmod 0600 /etc/shadow
# Can't use useradd, since it complains that it doesn't know us
# (bootstrap problem!).
echo "root:x:0:0:System administrator:$rootHome:${config.users.defaultUserShell}" >> /etc/passwd
echo "root::::::::" >> /etc/shadow
fi
''; '';
system.activationScripts.users = stringAfter [ "groups" ] # for backwards compatibility
'' system.activationScripts.groups = stringAfter [ "users" ] "";
echo "updating users..."
cat ${usersFile} | while true; do assertions = [
read name || break { assertion = !cfg.enforceIdUniqueness || (uidsAreUnique && gidsAreUnique);
read description message = "UIDs and GIDs must be unique!";
read uid
read group
read extraGroups
read home
read shell
read createHome
read password
read isSystemUser
read createUser
read isAlias
if [ -z "$createUser" ]; then
continue
fi
if ! curEnt=$(getent passwd "$name"); then
useradd ''${isSystemUser:+--system} \
--comment "$description" \
''${uid:+--uid $uid} \
--gid "$group" \
--groups "$extraGroups" \
--home "$home" \
--shell "$shell" \
''${createHome:+--create-home} \
''${isAlias:+--non-unique} \
"$name"
if test "''${password:0:1}" = 'X'; then
(echo "''${password:1}"; echo "''${password:1}") | ${pkgs.shadow}/bin/passwd "$name"
fi
else
#echo "updating user $name..."
oldIFS="$IFS"; IFS=:; set -- $curEnt; IFS="$oldIFS"
prevUid=$3
prevHome=$6
# Don't change the home directory if it's the same to prevent
# unnecessary warnings about logged in users.
if test "$prevHome" = "$home"; then unset home; fi
usermod \
--comment "$description" \
--gid "$group" \
--groups "$extraGroups" \
''${home:+--home "$home"} \
--shell "$shell" \
"$name"
fi
done
'';
system.activationScripts.groups = stringAfter [ "rootPasswd" "binsh" "etc" "var" ]
''
echo "updating groups..."
createGroup() {
name="$1"
gid="$2"
if ! curEnt=$(getent group "$name"); then
groupadd --system \
''${gid:+--gid $gid} \
"$name"
fi
} }
];
${flip concatMapStrings (attrValues config.users.extraGroups) (g: ''
createGroup '${g.name}' '${toString g.gid}'
'')}
'';
}; };

View File

@ -0,0 +1,138 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.zramSwap;
devices = map (nr: "zram${toString nr}") (range 0 (cfg.numDevices - 1));
modprobe = "${config.system.sbin.modprobe}/sbin/modprobe";
in
{
###### interface
options = {
zramSwap = {
enable = mkOption {
default = false;
type = types.bool;
description = ''
Enable in-memory compressed swap space provided by the zram kernel
module. It is recommended to enable only for kernel 3.14 or higher.
'';
};
numDevices = mkOption {
default = 4;
type = types.int;
description = ''
Number of zram swap devices to create. It should be equal to the
number of CPU cores your system has.
'';
};
memoryPercent = mkOption {
default = 50;
type = types.int;
description = ''
Maximum amount of memory that can be used by the zram swap devices
(as a percentage of your total memory). Defaults to 1/2 of your total
RAM.
'';
};
priority = mkOption {
default = 5;
type = types.int;
description = ''
Priority of the zram swap devices. It should be a number higher than
the priority of your disk-based swap devices (so that the system will
fill the zram swap devices before falling back to disk swap).
'';
};
};
};
config = mkIf cfg.enable {
system.requiredKernelConfig = with config.lib.kernelConfig; [
(isModule "ZRAM")
];
# Disabling this for the moment, as it would create and mkswap devices twice,
# once in stage 2 boot, and again when the zram-reloader service starts.
# boot.kernelModules = [ "zram" ];
boot.extraModprobeConfig = ''
options zram num_devices=${toString cfg.numDevices}
'';
services.udev.extraRules = ''
KERNEL=="zram[0-9]*", ENV{SYSTEMD_WANTS}="zram-init-%k.service", TAG+="systemd"
'';
systemd.services =
let
createZramInitService = dev:
nameValuePair "zram-init-${dev}" {
description = "Init swap on zram-based device ${dev}";
bindsTo = [ "dev-${dev}.swap" ];
after = [ "dev-${dev}.device" "zram-reloader.service" ];
requires = [ "dev-${dev}.device" "zram-reloader.service" ];
before = [ "dev-${dev}.swap" ];
requiredBy = [ "dev-${dev}.swap" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStop = "${pkgs.stdenv.shell} -c 'echo 1 > /sys/class/block/${dev}/reset'";
};
script = ''
set -u
set -o pipefail
PATH=${pkgs.procps}/bin:${pkgs.gnugrep}/bin:${pkgs.gnused}/bin
# Calculate memory to use for zram
totalmem=$(free | grep -e "^Mem:" | sed -e 's/^Mem: *//' -e 's/ *.*//')
mem=$(((totalmem * ${toString cfg.memoryPercent} / 100 / ${toString cfg.numDevices}) * 1024))
echo $mem > /sys/class/block/${dev}/disksize
${pkgs.utillinux}/sbin/mkswap /dev/${dev}
'';
restartIfChanged = false;
};
in listToAttrs ((map createZramInitService devices) ++ [(nameValuePair "zram-reloader"
{
description = "Reload zram kernel module when number of devices changes";
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStartPre = "${modprobe} -r zram";
ExecStart = "${modprobe} zram";
ExecStop = "${modprobe} -r zram";
};
restartTriggers = [ cfg.numDevices ];
restartIfChanged = true;
})]);
swapDevices =
let
useZramSwap = dev:
{
device = "/dev/${dev}";
priority = cfg.priority;
};
in map useZramSwap devices;
};
}

View File

@ -1,6 +1,6 @@
{ config, pkgs, ... }: { config, lib, pkgs, ... }:
with pkgs.lib; with lib;
{ {

View File

@ -1,6 +1,6 @@
{ config, pkgs, ... }: { config, lib, pkgs, ... }:
with pkgs.lib; with lib;
{ {

View File

@ -1,6 +1,6 @@
{ config, pkgs, ... }: { config, lib, pkgs, ... }:
with pkgs.lib; with lib;
{ {

View File

@ -1,4 +1,6 @@
{pkgs, config, ...}: { config, lib, pkgs, ... }:
with lib;
let kernelVersion = config.boot.kernelPackages.kernel.version; in let kernelVersion = config.boot.kernelPackages.kernel.version; in
@ -8,9 +10,9 @@ let kernelVersion = config.boot.kernelPackages.kernel.version; in
options = { options = {
networking.enableB43Firmware = pkgs.lib.mkOption { networking.enableB43Firmware = mkOption {
default = false; default = false;
type = pkgs.lib.types.bool; type = types.bool;
description = '' description = ''
Turn on this option if you want firmware for the NICs supported by the b43 module. Turn on this option if you want firmware for the NICs supported by the b43 module.
''; '';
@ -21,11 +23,11 @@ let kernelVersion = config.boot.kernelPackages.kernel.version; in
###### implementation ###### implementation
config = pkgs.lib.mkIf config.networking.enableB43Firmware { config = mkIf config.networking.enableB43Firmware {
assertions = [ { assertions = singleton
assertion = builtins.lessThan 0 (builtins.compareVersions kernelVersion "3.2"); { assertion = lessThan 0 (builtins.compareVersions kernelVersion "3.2");
message = "b43 firmware for kernels older than 3.2 not packaged yet!"; message = "b43 firmware for kernels older than 3.2 not packaged yet!";
} ]; };
hardware.firmware = [ pkgs.b43Firmware_5_1_138 ]; hardware.firmware = [ pkgs.b43Firmware_5_1_138 ];
}; };

View File

@ -1,4 +1,4 @@
{ config, pkgs, ... }: { config, pkgs, lib, ... }:
{ {
@ -6,9 +6,9 @@
options = { options = {
networking.enableIntel2100BGFirmware = pkgs.lib.mkOption { networking.enableIntel2100BGFirmware = lib.mkOption {
default = false; default = false;
type = pkgs.lib.types.bool; type = lib.types.bool;
description = '' description = ''
Turn on this option if you want firmware for the Intel Turn on this option if you want firmware for the Intel
PRO/Wireless 2100BG to be loaded automatically. This is PRO/Wireless 2100BG to be loaded automatically. This is
@ -21,7 +21,7 @@
###### implementation ###### implementation
config = pkgs.lib.mkIf config.networking.enableIntel2100BGFirmware { config = lib.mkIf config.networking.enableIntel2100BGFirmware {
hardware.enableAllFirmware = true; hardware.enableAllFirmware = true;

View File

@ -1,4 +1,4 @@
{ config, pkgs, ... }: { config, pkgs, lib, ... }:
{ {
@ -6,9 +6,9 @@
options = { options = {
networking.enableIntel2200BGFirmware = pkgs.lib.mkOption { networking.enableIntel2200BGFirmware = lib.mkOption {
default = false; default = false;
type = pkgs.lib.types.bool; type = lib.types.bool;
description = '' description = ''
Turn on this option if you want firmware for the Intel Turn on this option if you want firmware for the Intel
PRO/Wireless 2200BG to be loaded automatically. This is PRO/Wireless 2200BG to be loaded automatically. This is
@ -21,7 +21,7 @@
###### implementation ###### implementation
config = pkgs.lib.mkIf config.networking.enableIntel2200BGFirmware { config = lib.mkIf config.networking.enableIntel2200BGFirmware {
hardware.enableAllFirmware = true; hardware.enableAllFirmware = true;

View File

@ -1,4 +1,4 @@
{ config, pkgs, ... }: { config, pkgs, lib, ... }:
{ {
@ -6,9 +6,9 @@
options = { options = {
networking.enableIntel3945ABGFirmware = pkgs.lib.mkOption { networking.enableIntel3945ABGFirmware = lib.mkOption {
default = false; default = false;
type = pkgs.lib.types.bool; type = lib.types.bool;
description = '' description = ''
This option enables automatic loading of the firmware for the Intel This option enables automatic loading of the firmware for the Intel
PRO/Wireless 3945ABG. PRO/Wireless 3945ABG.
@ -20,7 +20,7 @@
###### implementation ###### implementation
config = pkgs.lib.mkIf config.networking.enableIntel3945ABGFirmware { config = lib.mkIf config.networking.enableIntel3945ABGFirmware {
hardware.enableAllFirmware = true; hardware.enableAllFirmware = true;

View File

@ -1,4 +1,4 @@
{pkgs, config, ...}: {pkgs, config, lib, ...}:
{ {
@ -6,9 +6,9 @@
options = { options = {
networking.enableRalinkFirmware = pkgs.lib.mkOption { networking.enableRalinkFirmware = lib.mkOption {
default = false; default = false;
type = pkgs.lib.types.bool; type = lib.types.bool;
description = '' description = ''
Turn on this option if you want firmware for the RT73 NIC. Turn on this option if you want firmware for the RT73 NIC.
''; '';
@ -19,7 +19,7 @@
###### implementation ###### implementation
config = pkgs.lib.mkIf config.networking.enableRalinkFirmware { config = lib.mkIf config.networking.enableRalinkFirmware {
hardware.enableAllFirmware = true; hardware.enableAllFirmware = true;
}; };

View File

@ -1,4 +1,4 @@
{pkgs, config, ...}: {pkgs, config, lib, ...}:
{ {
@ -6,9 +6,9 @@
options = { options = {
networking.enableRTL8192cFirmware = pkgs.lib.mkOption { networking.enableRTL8192cFirmware = lib.mkOption {
default = false; default = false;
type = pkgs.lib.types.bool; type = lib.types.bool;
description = '' description = ''
Turn on this option if you want firmware for the RTL8192c (and related) NICs. Turn on this option if you want firmware for the RTL8192c (and related) NICs.
''; '';
@ -19,7 +19,7 @@
###### implementation ###### implementation
config = pkgs.lib.mkIf config.networking.enableRTL8192cFirmware { config = lib.mkIf config.networking.enableRTL8192cFirmware {
hardware.enableAllFirmware = true; hardware.enableAllFirmware = true;
}; };

View File

@ -1,9 +1,9 @@
{pkgs, config, ...}: {lib, config, ...}:
{ {
hardware = { hardware = {
pcmcia = { pcmcia = {
firmware = [ (pkgs.lib.cleanSource ./firmware) ]; firmware = [ (lib.cleanSource ./firmware) ];
}; };
}; };
} }

View File

@ -0,0 +1,125 @@
{ config, lib, pkgs, pkgs_i686, ... }:
with lib;
let
cfg = config.hardware.opengl;
kernelPackages = config.boot.kernelPackages;
videoDrivers = config.services.xserver.videoDrivers;
makePackage = p: p.buildEnv {
name = "mesa-drivers+txc-${p.mesa_drivers.version}";
paths =
[ p.mesa_drivers
p.mesa_noglu # mainly for libGL
(if cfg.s3tcSupport then p.libtxc_dxtn else p.libtxc_dxtn_s2tc)
p.udev
];
};
in
{
options = {
hardware.opengl.enable = mkOption {
description = "Whether this configuration requires OpenGL.";
type = types.bool;
default = false;
internal = true;
};
hardware.opengl.driSupport = mkOption {
type = types.bool;
default = true;
description = ''
Whether to enable accelerated OpenGL rendering through the
Direct Rendering Interface (DRI).
'';
};
hardware.opengl.driSupport32Bit = mkOption {
type = types.bool;
default = false;
description = ''
On 64-bit systems, whether to support Direct Rendering for
32-bit applications (such as Wine). This is currently only
supported for the <literal>nvidia</literal> driver and for
<literal>Mesa</literal>.
'';
};
hardware.opengl.s3tcSupport = mkOption {
type = types.bool;
default = false;
description = ''
Make S3TC(S3 Texture Compression) via libtxc_dxtn available
to OpenGL drivers instead of the patent-free S2TC replacement.
Using this library may require a patent license depending on your location.
'';
};
hardware.opengl.package = mkOption {
type = types.package;
internal = true;
description = ''
The package that provides the OpenGL implementation.
'';
};
hardware.opengl.package32 = mkOption {
type = types.package;
internal = true;
description = ''
The package that provides the 32-bit OpenGL implementation on
64-bit systems. Used when <option>driSupport32Bit</option> is
set.
'';
};
};
config = mkIf cfg.enable {
assertions = lib.singleton {
assertion = cfg.driSupport32Bit -> pkgs.stdenv.isx86_64;
message = "Option driSupport32Bit only makes sense on a 64-bit system.";
};
system.activationScripts.setup-opengl =
''
ln -sfn ${cfg.package} /run/opengl-driver
${if pkgs.stdenv.isi686 then ''
ln -sfn opengl-driver /run/opengl-driver-32
'' else if cfg.driSupport32Bit then ''
ln -sfn ${cfg.package32} /run/opengl-driver-32
'' else ''
rm -f /run/opengl-driver-32
''}
'';
environment.sessionVariables.LD_LIBRARY_PATH =
[ "/run/opengl-driver/lib" "/run/opengl-driver-32/lib" ];
# FIXME: move this into card-specific modules.
hardware.opengl.package = mkDefault
(if elem "ati_unfree" videoDrivers then
kernelPackages.ati_drivers_x11
else
makePackage pkgs);
hardware.opengl.package32 = mkDefault (makePackage pkgs_i686);
boot.extraModulePackages =
optional (elem "virtualbox" videoDrivers) kernelPackages.virtualboxGuestAdditions ++
optional (elem "ati_unfree" videoDrivers) kernelPackages.ati_drivers_x11;
environment.etc =
optionalAttrs (elem "ati_unfree" videoDrivers) {
"ati".source = "${kernelPackages.ati_drivers_x11}/etc/ati";
};
};
}

View File

@ -1,6 +1,6 @@
{ config, pkgs, ... }: { config, lib, pkgs, ... }:
with pkgs.lib; with lib;
let let

View File

@ -0,0 +1,49 @@
{ config, lib, pkgs, ... }:
let kernel = config.boot.kernelPackages; in
with lib;
{
options = {
hardware.bumblebee.enable = mkOption {
default = false;
type = types.bool;
description = ''
Enable the bumblebee daemon to manage Optimus hybrid video cards.
This should power off secondary GPU until its use is requested
by running an application with optirun.
Only nvidia driver is supported so far.
'';
};
hardware.bumblebee.group = mkOption {
default = "wheel";
example = "video";
type = types.uniq types.str;
description = ''Group for bumblebee socket'';
};
};
config = mkIf config.hardware.bumblebee.enable {
boot.blacklistedKernelModules = [ "nouveau" "nvidia" ];
boot.kernelModules = [ "bbswitch" ];
boot.extraModulePackages = [ kernel.bbswitch kernel.nvidia_x11 ];
environment.systemPackages = [ pkgs.bumblebee ];
systemd.services.bumblebeed = {
description = "Bumblebee Hybrid Graphics Switcher";
wantedBy = [ "display-manager.service" ];
script = "bumblebeed --use-syslog -g ${config.hardware.bumblebee.group}";
path = [ kernel.bbswitch pkgs.bumblebee ];
serviceConfig = {
Restart = "always";
RestartSec = 60;
CPUSchedulingPolicy = "idle";
};
environment.LD_LIBRARY_PATH="/run/opengl-driver/lib/";
environment.MODULE_DIR="/run/current-system/kernel-modules/lib/modules/";
};
};
}

View File

@ -0,0 +1,54 @@
# This module provides the proprietary NVIDIA X11 / OpenGL drivers.
{ config, lib, pkgs, pkgs_i686, ... }:
with lib;
let
drivers = config.services.xserver.videoDrivers;
# FIXME: should introduce an option like
# hardware.video.nvidia.package for overriding the default NVIDIA
# driver.
enabled = elem "nvidia" drivers || elem "nvidiaLegacy173" drivers || elem "nvidiaLegacy304" drivers;
nvidia_x11 =
if elem "nvidia" drivers then
config.boot.kernelPackages.nvidia_x11
else if elem "nvidiaLegacy173" drivers then
config.boot.kernelPackages.nvidia_x11_legacy173
else if elem "nvidiaLegacy304" drivers then
config.boot.kernelPackages.nvidia_x11_legacy304
else throw "impossible";
in
{
config = mkIf enabled {
services.xserver.drivers = singleton
{ name = "nvidia"; modules = [ nvidia_x11 ]; libPath = [ nvidia_x11 ]; };
services.xserver.screenSection =
''
Option "RandRRotation" "on"
'';
hardware.opengl.package = nvidia_x11;
hardware.opengl.package32 = pkgs_i686.linuxPackages.nvidia_x11.override { libsOnly = true; kernel = null; };
environment.systemPackages = [ nvidia_x11 ];
boot.extraModulePackages = [ nvidia_x11 ];
boot.blacklistedKernelModules = [ "nouveau" "nvidiafb" ];
services.acpid.enable = true;
environment.etc."OpenCL/vendors/nvidia.icd".source = "${nvidia_x11}/lib/vendors/nvidia.icd";
};
}

Some files were not shown because too many files have changed in this diff Show More