Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: NixOS/nixpkgs
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 664ff4069cb8
Choose a base ref
...
head repository: NixOS/nixpkgs
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: beba8e9c4474
Choose a head ref

Commits on Sep 26, 2016

  1. Copy the full SHA
    37f0aaf View commit details

Commits on Nov 16, 2016

  1. MAR1D: init at 0.2.0

    Radvendii committed Nov 16, 2016
    Copy the full SHA
    7c955ab View commit details

Commits on Dec 15, 2016

  1. irods: init at 4.2.0

    bzizou committed Dec 15, 2016
    Copy the full SHA
    146985e View commit details

Commits on Mar 6, 2017

  1. cloud-init: 0.7.6 -> 0.7.9

    phile314 committed Mar 6, 2017
    Copy the full SHA
    2e4d0ff View commit details
  2. Copy the full SHA
    a0f4a72 View commit details

Commits on Mar 16, 2017

  1. Copy the full SHA
    c2b0cb5 View commit details

Commits on Apr 11, 2017

  1. Copy the full SHA
    9a12461 View commit details

Commits on Apr 12, 2017

  1. pytestcov: 2.3.1 -> 2.4.0

    johbo committed Apr 12, 2017
    Copy the full SHA
    ab8bcd0 View commit details
  2. freezegun: 0.3.5 -> 0.3.8

    johbo committed Apr 12, 2017
    Copy the full SHA
    3c65b4a View commit details
  3. pytest_xdist: 1.8 -> 1.14

    johbo committed Apr 12, 2017
    Copy the full SHA
    a189f8c View commit details
  4. qt4: enable gtk2 by default

    abbradar committed Apr 12, 2017
    Copy the full SHA
    b525898 View commit details

Commits on Apr 18, 2017

  1. Copy the full SHA
    ce4ff6b View commit details
  2. Copy the full SHA
    46a36d8 View commit details

Commits on Apr 20, 2017

  1. Revert "Remove spurious call to patchPhase."

    This reverts commit 9a12461.
    phile314 committed Apr 20, 2017
    Copy the full SHA
    a03ff82 View commit details
  2. Copy the full SHA
    59ca1f6 View commit details

Commits on Apr 21, 2017

  1. Copy the full SHA
    5083a75 View commit details
  2. Copy the full SHA
    27e05f9 View commit details
  3. madonctl: init at 0.1.0

    matthiasbeyer committed Apr 21, 2017
    Copy the full SHA
    d6caa6b View commit details

Commits on Apr 23, 2017

  1. quakespasm: init at 0.92.1

    Mathäus Sander committed Apr 23, 2017
    Copy the full SHA
    bbf114c View commit details

Commits on Apr 25, 2017

  1. Copy the full SHA
    e9adf38 View commit details
  2. Copy the full SHA
    34436df View commit details
  3. Copy the full SHA
    3eee6ea View commit details
  4. llvm-3.9: Fix cross compilation

    It's now possible to cross compile llvm:
    
    `nix-build -E '(import ./. { crossSystem = import ./platform.nix; }).pkgs.llvm'`
    expipiplus1 committed Apr 25, 2017
    Copy the full SHA
    12bbc63 View commit details
  5. LLVM-3.9: Fix RPATH in cross compile builds

    This error was cause by multiple-outputs.sh not setting
    NIX_CROSS_LDFLAGS
    expipiplus1 committed Apr 25, 2017
    Copy the full SHA
    fea424f View commit details
  6. Copy the full SHA
    bad5ca0 View commit details

Commits on Apr 26, 2017

  1. root: 6.08.02 -> 6.09.02

    This also fixes breakage on darwin due to LLVM4.0 migration.
    
    I had to enable opengl because otherwise macOS build is broken.
    See root commit 23f8871c7 ('Do not include OpenGL directly but use our
    TGLIncludes for that purpose.')
    
    I've enabled xml because TUnfold depends on it.
    veprbl committed Apr 26, 2017

    Verified

    This commit was signed with the committer’s verified signature.
    veprbl Dmitry Kalinkin
    Copy the full SHA
    be9c0e8 View commit details

Commits on Apr 28, 2017

  1. xen service: fix xen-bridge not setting the configured netmask

    The xen-bridge service accepts the option prefixLength, but does not
    use it to set the actual netmask on the bridge. This commit makes
    it set the correct netmask.
    Michał Pałka committed Apr 28, 2017
    Copy the full SHA
    2fcb871 View commit details

Commits on Apr 29, 2017

  1. llvm: Add the LLVM OpenMP components

    Needed to build an executable that uses OpenMP with clang. This
    includes a header file and a library that clang will link into an
    executable whose source makes use of ‘omp‘ pragmas.
    acowley committed Apr 29, 2017
    Copy the full SHA
    0059131 View commit details
  2. Copy the full SHA
    86e1604 View commit details
  3. LLVM-3.9: disable shared libraries in cross builds

    The current cc-wrapper script seems to have trouble setting the rpath
    correctly. Hopefully #25047 will fix this.
    expipiplus1 committed Apr 29, 2017
    Copy the full SHA
    7b7ffc4 View commit details
  4. LLVM-3.9: formatting

    expipiplus1 committed Apr 29, 2017
    Copy the full SHA
    ad778a6 View commit details

Commits on Apr 30, 2017

  1. Copy the full SHA
    66f7398 View commit details
  2. cloud-print-connector: init at unstable-2017-01-19

    This adds a fairly basic build for just the binaries for the Google
    Cloud Print CUPS connector (gcp-cups-connector), and gcp-connector-util
    to set it up in the first place. In the future I would like to
    streamline the configuration more and make gcp-cups-connector a
    proper NixOS service - as right now it must be run by hand.
    Hodapp87 committed Apr 30, 2017
    Copy the full SHA
    cc4f861 View commit details
  3. Copy the full SHA
    cdebfa8 View commit details
  4. virtualbox: 5.1.18 -> 5.1.22

    bachp committed Apr 30, 2017
    Copy the full SHA
    c4a4860 View commit details

Commits on May 1, 2017

  1. crashplan: 4.8.0 -> 4.8.2

    jerith666 committed May 1, 2017

    Unverified

    This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
    Copy the full SHA
    66b40ad View commit details
  2. Unverified

    This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
    Copy the full SHA
    2188a8b View commit details
  3. Verified

    This commit was signed with the committer’s verified signature.
    rasendubi Oleksii Shmalko
    Copy the full SHA
    f5bed28 View commit details
  4. gimp: fix all plugins build

    avnik committed May 1, 2017
    Copy the full SHA
    94d909a View commit details
  5. 3
    Copy the full SHA
    df5d588 View commit details
  6. Merge pull request #25205 from orivej/rsp

    Fix parsing @args.rsp compiler arguments
    7c6f434c authored May 1, 2017
    Copy the full SHA
    f3b45f8 View commit details
  7. Merge pull request #24827 from johbo/trytond-dependencies

    Trytond dependencies updates
    7c6f434c authored May 1, 2017
    Copy the full SHA
    2dd3511 View commit details
  8. openal-soft: move cmake to nativeBuildInputs

    This allows cross-compiling it.
    lheckemann committed May 1, 2017
    Copy the full SHA
    6130dfd View commit details
  9. Copy the full SHA
    4338f09 View commit details

Commits on May 2, 2017

  1. sherpa: fix for llvm 4

    veprbl committed May 2, 2017

    Verified

    This commit was signed with the committer’s verified signature.
    veprbl Dmitry Kalinkin
    Copy the full SHA
    a7b4b84 View commit details
  2. Copy the full SHA
    8452e06 View commit details
  3. purescript: remove pinned dependencies in hackage2nix config

    The dependencies were added for purescript 0.10.7 and are no longer needed since
    the override is gone.
    themoritz committed May 2, 2017
    Copy the full SHA
    473a9be View commit details
  4. far2l: add .desktop file

    Volth committed May 2, 2017
    Copy the full SHA
    42e1796 View commit details
  5. Merge branch 'master' into staging

    There's been a very large rebuild on master, unfortunately.
    pytestcov conflict: I'm not really sure what should be propagated.
    vcunat committed May 2, 2017
    3

    Verified

    This commit was signed with the committer’s verified signature.
    vcunat Vladimír Čunát
    Copy the full SHA
    1bcd56b View commit details
  6. draftsight: init at 2017-SP1

    DraftSight is "a professional-grade 2D design and drafting solution
    that lets you create, edit, view and markup any kind of 2D drawing."
    It is available as a binary .deb package for Linux. This package jumps
    through the necessary hoops to make it run properly.
    Hodapp87 committed May 2, 2017
    Copy the full SHA
    7680f83 View commit details
Showing 2,928 changed files with 99,804 additions and 97,956 deletions.
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -11,3 +11,4 @@
* System: (NixOS: `nixos-version`, Ubuntu/Fedora: `lsb_release -a`, ...)
* Nix version: (run `nix-env --version`)
* Nixpkgs version: (run `nix-instantiate --eval '<nixpkgs>' -A lib.nixpkgsVersion`)
* Sandboxing enabled: (run `grep build-use-sandbox /etc/nix/nix.conf`)
1 change: 1 addition & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@
- [ ] NixOS
- [ ] macOS
- [ ] Linux
- [ ] Tested via one or more NixOS test(s) if existing and applicable for the change (look inside [nixos/tests](https://github.com/NixOS/nixpkgs/blob/master/nixos/tests))
- [ ] Tested compilation of all pkgs that depend on this change using `nix-shell -p nox --run "nox-review wip"`
- [ ] Tested execution of all binary files (usually in `./result/bin/`)
- [ ] Fits [CONTRIBUTING.md](https://github.com/NixOS/nixpkgs/blob/master/.github/CONTRIBUTING.md).
4 changes: 1 addition & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -26,6 +26,4 @@ env:
- GITHUB_TOKEN=5edaaf1017f691ed34e7f80878f8f5fbd071603f

notifications:
email:
on_success: never
on_failure: change
email: false
215 changes: 214 additions & 1 deletion doc/configuration.xml
Original file line number Diff line number Diff line change
@@ -227,7 +227,7 @@ packages via <literal>packageOverrides</literal></title>

<para>You can define a function called
<varname>packageOverrides</varname> in your local
<filename>~/.config/nixpkgs/config.nix</filename> to overide nix packages. It
<filename>~/.config/nixpkgs/config.nix</filename> to override nix packages. It
must be a function that takes pkgs as an argument and return modified
set of packages.

@@ -243,5 +243,218 @@ set of packages.

</section>

<section xml:id="sec-declarative-package-management">
<title>Declarative Package Management</title>

<section xml:id="sec-building-environment">
<title>Build an environment</title>

<para>
Using <literal>packageOverrides</literal>, it is possible to manage
packages declaratively. This means that we can list all of our desired
packages within a declarative Nix expression. For example, to have
<literal>aspell</literal>, <literal>bc</literal>,
<literal>ffmpeg</literal>, <literal>coreutils</literal>,
<literal>gdb</literal>, <literal>nixUnstable</literal>,
<literal>emscripten</literal>, <literal>jq</literal>,
<literal>nox</literal>, and <literal>silver-searcher</literal>, we could
use the following in <filename>~/.config/nixpkgs/config.nix</filename>:
</para>

<screen>
{
packageOverrides = pkgs: with pkgs; {
myPackages = pkgs.buildEnv {
name = "my-packages";
paths = [ aspell bc coreutils gdb ffmpeg nixUnstable emscripten jq nox silver-searcher ];
};
};
}
</screen>

<para>
To install it into our environment, you can just run <literal>nix-env -iA
nixpkgs.myPackages</literal>. If you want to load the packages to be built
from a working copy of <literal>nixpkgs</literal> you just run
<literal>nix-env -f. -iA myPackages</literal>. To explore what's been
installed, just look through <filename>~/.nix-profile/</filename>. You can
see that a lot of stuff has been installed. Some of this stuff is useful
some of it isn't. Let's tell Nixpkgs to only link the stuff that we want:
</para>

<screen>
{
packageOverrides = pkgs: with pkgs; {
myPackages = pkgs.buildEnv {
name = "my-packages";
paths = [ aspell bc coreutils gdb ffmpeg nixUnstable emscripten jq nox silver-searcher ];
pathsToLink = [ "/share" "/bin" ];
};
};
}
</screen>

<para>
<literal>pathsToLink</literal> tells Nixpkgs to only link the paths listed
which gets rid of the extra stuff in the profile.
<filename>/bin</filename> and <filename>/share</filename> are good
defaults for a user environment, getting rid of the clutter. If you are
running on Nix on MacOS, you may want to add another path as well,
<filename>/Applications</filename>, that makes GUI apps available.
</para>

</section>

<section xml:id="sec-getting-documentation">
<title>Getting documentation</title>

<para>
After building that new environment, look through
<filename>~/.nix-profile</filename> to make sure everything is there that
we wanted. Discerning readers will note that some files are missing. Look
inside <filename>~/.nix-profile/share/man/man1/</filename> to verify this.
There are no man pages for any of the Nix tools! This is because some
packages like Nix have multiple outputs for things like documentation (see
section 4). Let's make Nix install those as well.
</para>

<screen>
{
packageOverrides = pkgs: with pkgs; {
myPackages = pkgs.buildEnv {
name = "my-packages";
paths = [ aspell bc coreutils ffmpeg nixUnstable emscripten jq nox silver-searcher ];
pathsToLink = [ "/share/man" "/share/doc" /bin" ];
extraOutputsToInstall = [ "man" "doc" ];
};
};
}
</screen>

<para>
This provides us with some useful documentation for using our packages.
However, if we actually want those manpages to be detected by man, we need
to set up our environment. This can also be managed within Nix
expressions.
</para>

<screen>
{
packageOverrides = pkgs: with pkgs; rec {
myProfile = writeText "my-profile" ''
export PATH=$HOME/.nix-profile/bin:/nix/var/nix/profiles/default/bin:/sbin:/bin:/usr/sbin:/usr/bin
export MANPATH=$HOME/.nix-profile/share/man:/nix/var/nix/profiles/default/share/man:/usr/share/man
'';
myPackages = pkgs.buildEnv {
name = "my-packages";
paths = [
(runCommand "profile" {} ''
mkdir -p $out/etc/profile.d
cp ${myProfile} $out/etc/profile.d/my-profile.sh
'')
aspell
bc
coreutils
ffmpeg
man
nixUnstable
emscripten
jq
nox
silver-searcher
];
pathsToLink = [ "/share/man" "/share/doc" /bin" "/etc" ];
extraOutputsToInstall = [ "man" "doc" ];
};
};
}
</screen>

<para>
For this to work fully, you must also have this script sourced when you
are logged in. Try adding something like this to your
<filename>~/.profile</filename> file:
</para>

<screen>
#!/bin/sh
if [ -d $HOME/.nix-profile/etc/profile.d ]; then
for i in $HOME/.nix-profile/etc/profile.d/*.sh; do
if [ -r $i ]; then
. $i
fi
done
fi
</screen>

<para>
Now just run <literal>source $HOME/.profile</literal> and you can starting
loading man pages from your environent.
</para>

</section>

<section xml:id="sec-gnu-info-setup">
<title>GNU info setup</title>

<para>
Configuring GNU info is a little bit trickier than man pages. To work
correctly, info needs a database to be generated. This can be done with
some small modifications to our environment scripts.
</para>

<screen>
{
packageOverrides = pkgs: with pkgs; rec {
myProfile = writeText "my-profile" ''
export PATH=$HOME/.nix-profile/bin:/nix/var/nix/profiles/default/bin:/sbin:/bin:/usr/sbin:/usr/bin
export MANPATH=$HOME/.nix-profile/share/man:/nix/var/nix/profiles/default/share/man:/usr/share/man
export INFOPATH=$HOME/.nix-profile/share/info:/nix/var/nix/profiles/default/share/info:/usr/share/info
'';
myPackages = pkgs.buildEnv {
name = "my-packages";
paths = [
(runCommand "profile" {} ''
mkdir -p $out/etc/profile.d
cp ${myProfile} $out/etc/profile.d/my-profile.sh
'')
aspell
bc
coreutils
ffmpeg
man
nixUnstable
emscripten
jq
nox
silver-searcher
texinfoInteractive
];
pathsToLink = [ "/share/man" "/share/doc" "/share/info" "/bin" "/etc" ];
extraOutputsToInstall = [ "man" "doc" "info" ];
postBuild = ''
if [ -x $out/bin/install-info -a -w $out/share/info ]; then
shopt -s nullglob
for i in $out/share/info/*.info $out/share/info/*.info.gz; do
$out/bin/install-info $i $out/share/info/dir
done
fi
'';
};
};
}
</screen>

<para>
<literal>postBuild</literal> tells Nixpkgs to run a command after building
the environment. In this case, <literal>install-info</literal> adds the
installed info pages to <literal>dir</literal> which is GNU info's default
root node. Note that <literal>texinfoInteractive</literal> is added to the
environment to give the <literal>install-info</literal> command.
</para>

</section>

</section>

</chapter>
72 changes: 52 additions & 20 deletions doc/cross-compilation.xml
Original file line number Diff line number Diff line change
@@ -30,15 +30,16 @@
<section>
<title>Platform parameters</title>
<para>
The three GNU Autoconf platforms, <wordasword>build</wordasword>, <wordasword>host</wordasword>, and <wordasword>cross</wordasword>, are historically the result of much confusion.
The three GNU Autoconf platforms, <wordasword>build</wordasword>, <wordasword>host</wordasword>, and <wordasword>target</wordasword>, are historically the result of much confusion.
<link xlink:href="https://gcc.gnu.org/onlinedocs/gccint/Configure-Terms.html" /> clears this up somewhat but there is more to be said.
An important advice to get out the way is, unless you are packaging a compiler or other build tool, just worry about the build and host platforms.
Dealing with just two platforms usually better matches people's preconceptions, and in this case is completely correct.
</para>
<para>
In Nixpkgs, these three platforms are defined as attribute sets under the names <literal>buildPlatform</literal>, <literal>hostPlatform</literal>, and <literal>targetPlatform</literal>.
All three are always defined at the top level, so one can get at them just like a dependency in a function that is imported with <literal>callPackage</literal>:
<programlisting>{ stdenv, buildPlatform, hostPlatform, fooDep, barDep, .. }: ...</programlisting>
All three are always defined as attributes in the standard environment, and at the top level. That means one can get at them just like a dependency in a function that is imported with <literal>callPackage</literal>:
<programlisting>{ stdenv, buildPlatform, hostPlatform, fooDep, barDep, .. }: ...buildPlatform...</programlisting>, or just off <varname>stdenv</varname>:
<programlisting>{ stdenv, fooDep, barDep, .. }: ...stdenv.buildPlatform...</programlisting>.
</para>
<variablelist>
<varlistentry>
@@ -62,8 +63,8 @@
The "target platform" is black sheep.
The other two intrinsically apply to all compiled software—or any build process with a notion of "build-time" followed by "run-time".
The target platform only applies to programming tools, and even then only is a good for for some of them.
Briefly, GCC, Binutils, GHC, and certain other tools are written in such a way such that a single build can only compiler code for a single platform.
Thus, when building them, one must think ahead about what platforms they wish to use the tool to produce machine code for, and build binaries for each.
Briefly, GCC, Binutils, GHC, and certain other tools are written in such a way such that a single build can only compile code for a single platform.
Thus, when building them, one must think ahead about which platforms they wish to use the tool to produce machine code for, and build binaries for each.
</para>
<para>
There is no fundamental need to think about the target ahead of time like this.
@@ -79,13 +80,9 @@
</listitem>
</varlistentry>
</variablelist>
<note><para>
If you dig around nixpkgs, you may notice there is also <varname>stdenv.cross</varname>.
This field defined as <varname>hostPlatform</varname> when the host and build platforms differ, but otherwise not defined at all.
This field is obsolete and will soon disappear—please do not use it.
</para></note>
<para>
The exact scheme these fields is a bit ill-defined due to a long and convoluted evolution, but this is slowly being cleaned up.
The exact schema these fields follow is a bit ill-defined due to a long and convoluted evolution, but this is slowly being cleaned up.
You can see examples of ones used in practice in <literal>lib.systems.examples</literal>; note how they are not all very consistent.
For now, here are few fields can count on them containing:
</para>
<variablelist>
@@ -118,8 +115,27 @@
This is a nix representation of a parsed LLVM target triple with white-listed components.
This can be specified directly, or actually parsed from the <varname>config</varname>.
[Technically, only one need be specified and the others can be inferred, though the precision of inference may not be very good.]
See <literal>lib.systems.parse</literal> for the exact representation, along with some <literal>is*</literal>predicates.
These predicates are superior to the ones in <varname>stdenv</varname> as they aren't tied to the build platform (host, as previously discussed, would be a saner default).
See <literal>lib.systems.parse</literal> for the exact representation.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>libc</varname></term>
<listitem>
<para>
This is a string identifying the standard C library used.
Valid identifiers include "glibc" for GNU libc, "libSystem" for Darwin's Libsystem, and "uclibc" for µClibc.
It should probably be refactored to use the module system, like <varname>parse</varname>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>is*</varname></term>
<listitem>
<para>
These predicates are defined in <literal>lib.systems.inspect</literal>, and slapped on every platform.
They are superior to the ones in <varname>stdenv</varname> as they force the user to be explicit about which platform they are inspecting.
Please use these instead of those.
</para>
</listitem>
</varlistentry>
@@ -128,7 +144,7 @@
<listitem>
<para>
This is, quite frankly, a dumping ground of ad-hoc settings (it's an attribute set).
See <literal>lib.systems.platforms</literal> for examples—there's hopefully one in there that will work verbatim for each platform one is working.
See <literal>lib.systems.platforms</literal> for examples—there's hopefully one in there that will work verbatim for each platform that is working.
Please help us triage these flags and give them better homes!
</para>
</listitem>
@@ -158,10 +174,10 @@
The depending package's target platform is unconstrained by the sliding window principle, which makes sense in that one can in principle build cross compilers targeting arbitrary platforms.
</para></note>
<para>
How does this work in practice? Nixpkgs is now structured so that build-time dependencies are taken from from <varname>buildPackages</varname>, whereas run-time dependencies are taken from the top level attribute set.
How does this work in practice? Nixpkgs is now structured so that build-time dependencies are taken from <varname>buildPackages</varname>, whereas run-time dependencies are taken from the top level attribute set.
For example, <varname>buildPackages.gcc</varname> should be used at build time, while <varname>gcc</varname> should be used at run time.
Now, for most of Nixpkgs's history, there was no <varname>buildPackages</varname>, and most packages have not been refactored to use it explicitly.
Instead, one can use the four attributes used for specifying dependencies as documented in <link linkend="ssec-stdenv-attributes" />.
Instead, one can use the four attributes used for specifying dependencies as documented in <xref linkend="ssec-stdenv-attributes"/>.
We "splice" together the run-time and build-time package sets with <varname>callPackage</varname>, and then <varname>mkDerivation</varname> for each of four attributes pulls the right derivation out.
This splicing can be skipped when not cross compiling as the package sets are the same, but is a bit slow for cross compiling.
Because of this, a best-of-both-worlds solution is in the works with no splicing or explicit access of <varname>buildPackages</varname> needed.
@@ -184,11 +200,27 @@
More information needs to moved from the old wiki, especially <link xlink:href="https://nixos.org/wiki/CrossCompiling" />, for this section.
</para></note>
<para>
Many sources (manual, wiki, etc) probably mention passing <varname>system</varname>, <varname>platform</varname>, and, optionally, <varname>crossSystem</varname> to nixpkgs:
<literal>import &lt;nixpkgs&gt; { system = ..; platform = ..; crossSystem = ..; }</literal>.
<varname>system</varname> and <varname>platform</varname> together determine the system on which packages are built, and <varname>crossSystem</varname> specifies the platform on which packages are ultimately intended to run, if it is different.
This still works, but with more recent changes, one can alternatively pass <varname>localSystem</varname>, containing <varname>system</varname> and <varname>platform</varname>, for symmetry.
Nixpkgs can be instantiated with <varname>localSystem</varname> alone, in which case there is no cross compiling and everything is built by and for that system,
or also with <varname>crossSystem</varname>, in which case packages run on the latter, but all building happens on the former.
Both parameters take the same schema as the 3 (build, host, and target) platforms defined in the previous section.
As mentioned above, <literal>lib.systems.examples</literal> has some platforms which are used as arguments for these parameters in practice.
You can use them programmatically, or on the command line like <command>nix-build &lt;nixpkgs&gt; --arg crossSystem '(import &lt;nixpkgs/lib&gt;).systems.examples.fooBarBaz'</command>.
</para>
<para>
While one is free to pass both parameters in full, there's a lot of logic to fill in missing fields.
As discussed in the previous section, only one of <varname>system</varname>, <varname>config</varname>, and <varname>parsed</varname> is needed to infer the other two.
Additionally, <varname>libc</varname> will be inferred from <varname>parse</varname>.
Finally, <literal>localSystem.system</literal> is also <emphasis>impurely</emphasis> inferred based on the platform evaluation occurs.
This means it is often not necessary to pass <varname>localSystem</varname> at all, as in the command-line example in the previous paragraph.
</para>
<note>
<para>
Many sources (manual, wiki, etc) probably mention passing <varname>system</varname>, <varname>platform</varname>, along with the optional <varname>crossSystem</varname> to nixpkgs:
<literal>import &lt;nixpkgs&gt; { system = ..; platform = ..; crossSystem = ..; }</literal>.
Passing those two instead of <varname>localSystem</varname> is still supported for compatibility, but is discouraged.
Indeed, much of the inference we do for these parameters is motivated by compatibility as much as convenience.
</para>
</note>
<para>
One would think that <varname>localSystem</varname> and <varname>crossSystem</varname> overlap horribly with the three <varname>*Platforms</varname> (<varname>buildPlatform</varname>, <varname>hostPlatform,</varname> and <varname>targetPlatform</varname>; see <varname>stage.nix</varname> or the manual).
Actually, those identifiers are purposefully not used here to draw a subtle but important distinction:
2 changes: 1 addition & 1 deletion doc/default.nix
Original file line number Diff line number Diff line change
@@ -26,7 +26,7 @@ pkgs.stdenv.mkDerivation {
extraHeader = ''xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" '';
in ''
{
pandoc '${inputFile}' -w docbook ${lib.optionalString useChapters "--chapters"} \
pandoc '${inputFile}' -w docbook ${lib.optionalString useChapters "--top-level-division=chapter"} \
--smart \
| sed -e 's|<ulink url=|<link xlink:href=|' \
-e 's|</ulink>|</link>|' \
2 changes: 1 addition & 1 deletion doc/functions.xml
Original file line number Diff line number Diff line change
@@ -70,7 +70,7 @@

<para>
In the above example, the <varname>separateDebugInfo</varname> attribute is
overriden to be true, thus building debug info for
overridden to be true, thus building debug info for
<varname>helloWithDebug</varname>, while all other attributes will be
retained from the original <varname>hello</varname> package.
</para>
364 changes: 231 additions & 133 deletions doc/languages-frameworks/beam.xml

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions doc/languages-frameworks/go.xml
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ standard Go programs.
deis = buildGoPackage rec {
name = "deis-${version}";
version = "1.13.0";

goPackagePath = "github.com/deis/deis"; <co xml:id='ex-buildGoPackage-1' />
subPackages = [ "client" ]; <co xml:id='ex-buildGoPackage-2' />

@@ -130,6 +130,9 @@ the following arguments are of special significance to the function:

</para>

<para>To extract dependency information from a Go package in automated way use <link xlink:href="https://github.com/kamilchm/go2nix">go2nix</link>.
It can produce complete derivation and <varname>goDeps</varname> file for Go programs.</para>

<para>
<varname>buildGoPackage</varname> produces <xref linkend='chap-multiple-output' xrefstyle="select: title" />
where <varname>bin</varname> includes program binaries. You can test build a Go binary as follows:
@@ -160,7 +163,4 @@ done
</screen>
</para>

<para>To extract dependency information from a Go package in automated way use <link xlink:href="https://github.com/kamilchm/go2nix">go2nix</link>.
It can produce complete derivation and <varname>goDeps</varname> file for Go programs.</para>
</section>

28 changes: 25 additions & 3 deletions doc/languages-frameworks/python.md
Original file line number Diff line number Diff line change
@@ -580,7 +580,7 @@ running `nix-shell` with the following `shell.nix`
with import <nixpkgs> {};
(python3.buildEnv.override {
extraLibs = with python3Packages; [ numpy requests2 ];
extraLibs = with python3Packages; [ numpy requests ];
}).env
```

@@ -622,7 +622,7 @@ attribute. The `shell.nix` file from the previous section can thus be also writt
```nix
with import <nixpkgs> {};
(python33.withPackages (ps: [ps.numpy ps.requests2])).env
(python33.withPackages (ps: [ps.numpy ps.requests])).env
```

In contrast to `python.buildEnv`, `python.withPackages` does not support the more advanced options
@@ -710,7 +710,7 @@ nix-env -if build.nix
```
Now you can use the Python interpreter, as well as the extra packages that you added to the environment.

#### Environment defined in `~/.nixpkgs/config.nix`
#### Environment defined in `~/.config/nixpkgs/config.nix`

If you prefer to, you could also add the environment as a package override to the Nixpkgs set.
```nix
@@ -923,6 +923,28 @@ If you need to change a package's attribute(s) from `configuration.nix` you coul

If you are using the `bepasty-server` package somewhere, for example in `systemPackages` or indirectly from `services.bepasty`, then a `nixos-rebuild switch` will rebuild the system but with the `bepasty-server` package using a different `src` attribute. This way one can modify `python` based software/libraries easily. Using `self` and `super` one can also alter dependencies (`buildInputs`) between the old state (`self`) and new state (`super`).

### How to override a Python package using overlays?

To alter a python package using overlays, you would use the following approach:

```nix
self: super:
rec {
python = super.python.override {
packageOverrides = python-self: python-super: {
bepasty-server = python-super.bepasty-server.overrideAttrs ( oldAttrs: {
src = self.pkgs.fetchgit {
url = "https://github.com/bepasty/bepasty-server";
sha256 = "9ziqshmsf0rjvdhhca55sm0x8jz76fsf2q4rwh4m6lpcf8wr0nps";
rev = "e2516e8cf4f2afb5185337073607eb9e84a61d2d";
};
});
};
};
pythonPackages = python.pkgs;
}
```

## Contributing

### Contributing guidelines
68 changes: 46 additions & 22 deletions doc/languages-frameworks/qt.xml
Original file line number Diff line number Diff line change
@@ -2,31 +2,55 @@
xmlns:xlink="http://www.w3.org/1999/xlink"
xml:id="sec-language-qt">

<title>Qt and KDE</title>

<para>Qt is a comprehensive desktop and mobile application development toolkit for C++. Legacy support is available for Qt 3 and Qt 4, but all current development uses Qt 5. The Qt 5 packages in Nixpkgs are updated frequently to take advantage of new features, but older versions are typically retained to support packages that may not be compatible with the latest version. When packaging applications and libraries for Nixpkgs, it is important to ensure that compatible versions of Qt 5 are used throughout; this consideration motivates the tools described below.</para>

<section xml:id="ssec-qt-libraries"><title>Libraries</title>

<para>Libraries that depend on Qt 5 should be built with each available version to avoid linking a dependent package against incompatible versions of Qt 5. (Although Qt 5 maintains backward ABI compatibility, linking against multiple versions at once is generally not possible; at best it will lead to runtime faults.) Packages that provide libraries should be added to the top-level function <varname>mkLibsForQt5</varname>, which is used to build a set of libraries for every Qt 5 version. The <varname>callPackage</varname> provided in this scope will ensure that only one Qt version will be used throughout the dependency tree. Dependencies should be imported unqualified, i.e. <literal>qtbase</literal> not <literal>qt5.qtbase</literal>, so that <varname>callPackage</varname> can do its work. <emphasis>Do not</emphasis> import a package set such as <literal>qt5</literal> or <literal>libsForQt5</literal> into your package; although it may work fine in the moment, it could well break at the next Qt update.</para>

<para>If a library does not support a particular version of Qt 5, it is best to mark it as broken by setting its <literal>meta.broken</literal> attribute. A package may be marked broken for certain versions by testing the <literal>qtbase.version</literal> attribute, which will always give the current Qt 5 version.</para>
<title>Qt</title>

<para>
Qt is a comprehensive desktop and mobile application development toolkit for C++.
Legacy support is available for Qt 3 and Qt 4, but all current development uses Qt 5.
The Qt 5 packages in Nixpkgs are updated frequently to take advantage of new features,
but older versions are typically retained until their support window ends.
The most important consideration in packaging Qt-based software is ensuring that each package and all its dependencies use the same version of Qt 5;
this consideration motivates most of the tools described below.
</para>

<section xml:id="ssec-qt-libraries"><title>Packaging Libraries for Nixpkgs</title>

<para>
Whenever possible, libraries that use Qt 5 should be built with each available version.
Packages providing libraries should be added to the top-level function <varname>mkLibsForQt5</varname>,
which is used to build a set of libraries for every Qt 5 version.
A special <varname>callPackage</varname> function is used in this scope to ensure that the entire dependency tree uses the same Qt 5 version.
Import dependencies unqualified, i.e., <literal>qtbase</literal> not <literal>qt5.qtbase</literal>.
<emphasis>Do not</emphasis> import a package set such as <literal>qt5</literal> or <literal>libsForQt5</literal>.
</para>

<para>
If a library does not support a particular version of Qt 5, it is best to mark it as broken by setting its <literal>meta.broken</literal> attribute.
A package may be marked broken for certain versions by testing the <literal>qtbase.version</literal> attribute, which will always give the current Qt 5 version.
</para>

</section>

<section xml:id="ssec-qt-applications"><title>Applications</title>

<para>Applications generally do not need to be built with every Qt version because they do not provide any libraries for dependent packages to link against. The primary consideration is merely ensuring that the application itself and its dependencies are linked against only one version of Qt. To call your application expression, use <literal>libsForQt5.callPackage</literal> instead of <literal>callPackage</literal>. Dependencies should be imported unqualified, i.e. <literal>qtbase</literal> not <literal>qt5.qtbase</literal>. <emphasis>Do not</emphasis> import a package set such as <literal>qt5</literal> or <literal>libsForQt5</literal> into your package; although it may work fine in the moment, it could well break at the next Qt update.</para>

<para>It is generally best to build an application package against the <varname>libsForQt5</varname> library set. In case a package does not build with the latest Qt version, it is possible to pick a set pinned to a particular version, e.g. <varname>libsForQt55</varname> for Qt 5.5, if that is the latest version the package supports.</para>

<para>Qt-based applications require that several paths be set at runtime. This is accomplished by wrapping the provided executables in a package with <literal>wrapQtProgram</literal> or <literal>makeQtWrapper</literal> during the <literal>postFixup</literal> phase. To use the wrapper generators, add <literal>makeQtWrapper</literal> to <literal>nativeBuildInputs</literal>. The wrapper generators support the same options as <literal>wrapProgram</literal> and <literal>makeWrapper</literal> respectively. It is usually only necessary to generate wrappers for programs intended to be invoked by the user.</para>

</section>

<section xml:id="ssec-qt-kde"><title>KDE</title>

<para>The KDE Frameworks are a set of libraries for Qt 5 which form the basis of the Plasma desktop environment and the KDE Applications suite. Packaging a Frameworks-based library does not require any steps beyond those described above for general Qt-based libraries. Frameworks-based applications should not use <literal>makeQtWrapper</literal>; instead, use <literal>kdeWrapper</literal> to create the necessary wrappers: <literal>kdeWrapper { unwrapped = <replaceable>expr</replaceable>; targets = <replaceable>exes</replaceable>; }</literal>, where <replaceable>expr</replaceable> is the un-wrapped package expression and <replaceable>exes</replaceable> is a list of strings giving the relative paths to programs in the package which should be wrapped.</para>
<section xml:id="ssec-qt-applications"><title>Packaging Applications for Nixpkgs</title>

<para>
Call your application expression using <literal>libsForQt5.callPackage</literal> instead of <literal>callPackage</literal>.
Import dependencies unqualified, i.e., <literal>qtbase</literal> not <literal>qt5.qtbase</literal>.
<emphasis>Do not</emphasis> import a package set such as <literal>qt5</literal> or <literal>libsForQt5</literal>.
</para>

<para>
Qt 5 maintains strict backward compatibility, so it is generally best to build an application package against the latest version using the <varname>libsForQt5</varname> library set.
In case a package does not build with the latest Qt version, it is possible to pick a set pinned to a particular version, e.g. <varname>libsForQt55</varname> for Qt 5.5, if that is the latest version the package supports.
If a package must be pinned to an older Qt version, be sure to file a bug upstream;
because Qt is strictly backwards-compatible, any incompatibility is by definition a bug in the application.
</para>

<para>
When testing applications in Nixpkgs, it is a common practice to build the package with <literal>nix-build</literal> and run it using the created symbolic link.
This will not work with Qt applications, however, because they have many hard runtime requirements that can only be guaranteed if the package is actually installed.
To test a Qt application, install it with <literal>nix-env</literal> or run it inside <literal>nix-shell</literal>.
</para>

</section>

2 changes: 1 addition & 1 deletion doc/languages-frameworks/ruby.xml
Original file line number Diff line number Diff line change
@@ -46,7 +46,7 @@ bundlerEnv rec {
so it has all the libraries necessary for <literal>sensu</literal> in its paths. The second one can be used to make derivations from custom Ruby scripts which have
<filename>Gemfile</filename>s with their dependencies specified. It is a derivation with <command>ruby</command> wrapped so it can find all the needed dependencies.
For example, to make a derivation <literal>my-script</literal> for a <filename>my-script.rb</filename> (which should be placed in <filename>bin</filename>) you should
run <command>bundix</command> as specified above and then use <literal>bundlerEnv</literal> lile this:</para>
run <command>bundix</command> as specified above and then use <literal>bundlerEnv</literal> like this:</para>

<programlisting>
<![CDATA[let env = bundlerEnv {
41 changes: 37 additions & 4 deletions doc/languages-frameworks/vim.md
Original file line number Diff line number Diff line change
@@ -8,15 +8,48 @@ date: 2016-06-25
You'll get a vim(-your-suffix) in PATH also loading the plugins you want.
Loading can be deferred; see examples.

VAM (=vim-addon-manager) and Pathogen plugin managers are supported.
Vundle, NeoBundle could be your turn.
Vim packages, VAM (=vim-addon-manager) and Pathogen are supported to load
packages.

## dependencies by Vim plugins
## Custom configuration

Adding custom .vimrc lines can be done using the following code:

```
vim_configurable.customize {
name = "vim-with-plugins";
vimrcConfig.customRC = ''
set hidden
'';
}
```

## Vim packages

To store you plugins in Vim packages the following example can be used:

```
vim_configurable.customize {
vimrcConfig.packages.myVimPackage = with pkgs.vimPlugins; {
# loaded on launch
start = [ youcompleteme fugitive ];
# manually loadable by calling `:packadd $plugin-name`
opt = [ phpCompletion elm-vim ];
# To automatically load a plugin when opening a filetype, add vimrc lines like:
# autocmd FileType php :packadd phpCompletion
}
};
```

## VAM

### dependencies by Vim plugins

VAM introduced .json files supporting dependencies without versioning
assuming that "using latest version" is ok most of the time.

## HOWTO
### Example

First create a vim-scripts file having one plugin name per line. Example:

2 changes: 1 addition & 1 deletion doc/overlays.xml
Original file line number Diff line number Diff line change
@@ -78,7 +78,7 @@ self: super:
<para>The first argument, usually named <varname>self</varname>, corresponds to the final package
set. You should use this set for the dependencies of all packages specified in your
overlay. For example, all the dependencies of <varname>rr</varname> in the example above come
from <varname>self</varname>, as well as the overriden dependencies used in the
from <varname>self</varname>, as well as the overridden dependencies used in the
<varname>boost</varname> override.</para>

<para>The second argument, usually named <varname>super</varname>,
136 changes: 136 additions & 0 deletions doc/package-notes.xml
Original file line number Diff line number Diff line change
@@ -516,4 +516,140 @@ to your configuration, rebuild, and run the game with

</section>

<section xml:id="sec-emacs">

<title>Emacs</title>

<section xml:id="sec-emacs-config">

<title>Configuring Emacs</title>

<para>
The Emacs package comes with some extra helpers to make it easier to
configure. <varname>emacsWithPackages</varname> allows you to manage
packages from ELPA. This means that you will not have to install
that packages from within Emacs. For instance, if you wanted to use
<literal>company</literal>, <literal>counsel</literal>,
<literal>flycheck</literal>, <literal>ivy</literal>,
<literal>magit</literal>, <literal>projectile</literal>, and
<literal>use-package</literal> you could use this as a
<filename>~/.config/nixpkgs/config.nix</filename> override:
</para>

<screen>
{
packageOverrides = pkgs: with pkgs; {
myEmacs = emacsWithPackages (epkgs: (with epkgs.melpaStablePackages; [
company
counsel
flycheck
ivy
magit
projectile
use-package
]));
}
}
</screen>

<para>
You can install it like any other packages via <command>nix-env -iA
myEmacs</command>. However, this will only install those packages.
It will not <literal>configure</literal> them for us. To do this, we
need to provide a configuration file. Luckily, it is possible to do
this from within Nix! By modifying the above example, we can make
Emacs load a custom config file. The key is to create a package that
provide a <filename>default.el</filename> file in
<filename>/share/emacs/site-start/</filename>. Emacs knows to load
this file automatically when it starts.
</para>

<screen>
{
packageOverrides = pkgs: with pkgs; rec {
myEmacsConfig = writeText "default.el" ''
;; initialize package

(require 'package)
(package-initialize 'noactivate)
(eval-when-compile
(require 'use-package))

;; load some packages

(use-package company
:bind ("&lt;C-tab&gt;" . company-complete)
:diminish company-mode
:commands (company-mode global-company-mode)
:defer 1
:config
(global-company-mode))

(use-package counsel
:commands (counsel-descbinds)
:bind (([remap execute-extended-command] . counsel-M-x)
("C-x C-f" . counsel-find-file)
("C-c g" . counsel-git)
("C-c j" . counsel-git-grep)
("C-c k" . counsel-ag)
("C-x l" . counsel-locate)
("M-y" . counsel-yank-pop)))

(use-package flycheck
:defer 2
:config (global-flycheck-mode))

(use-package ivy
:defer 1
:bind (("C-c C-r" . ivy-resume)
("C-x C-b" . ivy-switch-buffer)
:map ivy-minibuffer-map
("C-j" . ivy-call))
:diminish ivy-mode
:commands ivy-mode
:config
(ivy-mode 1))

(use-package magit
:defer
:if (executable-find "git")
:bind (("C-x g" . magit-status)
("C-x G" . magit-dispatch-popup))
:init
(setq magit-completing-read-function 'ivy-completing-read))

(use-package projectile
:commands projectile-mode
:bind-keymap ("C-c p" . projectile-command-map)
:defer 5
:config
(projectile-global-mode))
'';
myEmacs = emacsWithPackages (epkgs: (with epkgs.melpaStablePackages; [
(runCommand "default.el" {} ''
mkdir -p $out/share/emacs/site-lisp
cp ${myEmacsConfig} $out/share/emacs/site-lisp/default.el
'')
company
counsel
flycheck
ivy
magit
projectile
use-package
]));
};
}
</screen>

<para>
This provides a fairly full Emacs start file. It will load in
addition to the user's presonal config. You can always disable it by
passing <command>-q</command> to the Emacs command.
</para>

</section>

</section>

</chapter>
2 changes: 1 addition & 1 deletion doc/reviewing-contributions.xml
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@
<para>The high change rate of nixpkgs make any pull request that is open for
long enough subject to conflicts that will require extra work from the
submitter or the merger. Reviewing pull requests in a timely manner and being
responsive to the comments is the key to avoid these. Github provides sort
responsive to the comments is the key to avoid these. GitHub provides sort
filters that can be used to see the <link
xlink:href="https://github.com/NixOS/nixpkgs/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-desc">most
recently</link> and the <link
30 changes: 23 additions & 7 deletions doc/stdenv.xml
Original file line number Diff line number Diff line change
@@ -318,7 +318,13 @@ containing some shell commands to be executed, or by redefining the
shell function
<varname><replaceable>name</replaceable>Phase</varname>. The former
is convenient to override a phase from the derivation, while the
latter is convenient from a build script.</para>
latter is convenient from a build script.

However, typically one only wants to <emphasis>add</emphasis> some
commands to a phase, e.g. by defining <literal>postInstall</literal>
or <literal>preFixup</literal>, as skipping some of the default actions
may have unexpected consequences.
</para>


<section xml:id="ssec-controlling-phases"><title>Controlling
@@ -634,6 +640,16 @@ script) if it exists.</para>
true.</para></listitem>
</varlistentry>

<varlistentry>
<term><varname>configurePlatforms</varname></term>
<listitem><para>
By default, when cross compiling, the configure script has <option>--build=...</option> and <option>--host=...</option> passed.
Packages can instead pass <literal>[ "build" "host" "target" ]</literal> or a subset to control exactly which platform flags are passed.
Compilers and other tools should use this to also pass the target platform, for example.
Note eventually these will be passed when in native builds too, to improve determinism: build-time guessing, as is done today, is a risk of impurity.
</para></listitem>
</varlistentry>

<varlistentry>
<term><varname>preConfigure</varname></term>
<listitem><para>Hook executed at the start of the configure
@@ -1156,15 +1172,15 @@ makeWrapper $out/bin/foo $wrapperfile --prefix PATH : ${lib.makeBinPath [ hello
<term><option>--replace</option>
<replaceable>s1</replaceable>
<replaceable>s2</replaceable></term>
<listitem><para>Replace every occurence of the string
<listitem><para>Replace every occurrence of the string
<replaceable>s1</replaceable> by
<replaceable>s2</replaceable>.</para></listitem>
</varlistentry>

<varlistentry>
<term><option>--subst-var</option>
<replaceable>varName</replaceable></term>
<listitem><para>Replace every occurence of
<listitem><para>Replace every occurrence of
<literal>@<replaceable>varName</replaceable>@</literal> by
the contents of the environment variable
<replaceable>varName</replaceable>. This is useful for
@@ -1177,7 +1193,7 @@ makeWrapper $out/bin/foo $wrapperfile --prefix PATH : ${lib.makeBinPath [ hello
<term><option>--subst-var-by</option>
<replaceable>varName</replaceable>
<replaceable>s</replaceable></term>
<listitem><para>Replace every occurence of
<listitem><para>Replace every occurrence of
<literal>@<replaceable>varName</replaceable>@</literal> by
the string <replaceable>s</replaceable>.</para></listitem>
</varlistentry>
@@ -1225,7 +1241,7 @@ substitute ./foo.in ./foo.out \
<term><function>substituteAll</function>
<replaceable>infile</replaceable>
<replaceable>outfile</replaceable></term>
<listitem><para>Replaces every occurence of
<listitem><para>Replaces every occurrence of
<literal>@<replaceable>varName</replaceable>@</literal>, where
<replaceable>varName</replaceable> is any environment variable, in
<replaceable>infile</replaceable>, writing the result to
@@ -1528,7 +1544,7 @@ bin/blib.a(bios_console.o): In function `bios_handle_cup':
depends on such a format string, it will need to be worked around.
</para>

<para>Addtionally, some warnings are enabled which might trigger build
<para>Additionally, some warnings are enabled which might trigger build
failures if compiler warnings are treated as errors in the package build.
In this case, set <option>NIX_CFLAGS_COMPILE</option> to
<option>-Wno-error=warning-type</option>.</para>
@@ -1558,7 +1574,7 @@ fcntl2.h:50:4: error: call to '__open_missing_mode' declared with attribute erro
<term><varname>pic</varname></term>
<listitem>
<para>Adds the <option>-fPIC</option> compiler options. This options adds
support for position independant code in shared libraries and thus making
support for position independent code in shared libraries and thus making
ASLR possible.</para>
<para>Most notably, the Linux kernel, kernel modules and other code
not running in an operating system environment like boot loaders won't
18 changes: 18 additions & 0 deletions lib/customisation.nix
Original file line number Diff line number Diff line change
@@ -51,6 +51,24 @@ rec {
else { }));


/* `makeOverridable` takes a function from attribute set to attribute set and
injects `override` attibute which can be used to override arguments of
the function.
nix-repl> x = {a, b}: { result = a + b; }
nix-repl> y = lib.makeOverridable x { a = 1; b = 2; }
nix-repl> y
{ override = «lambda»; overrideDerivation = «lambda»; result = 3; }
nix-repl> y.override { a = 10; }
{ override = «lambda»; overrideDerivation = «lambda»; result = 12; }
Please refer to "Nixpkgs Contributors Guide" section
"<pkg>.overrideDerivation" to learn about `overrideDerivation` and caveats
related to its use.
*/
makeOverridable = f: origArgs:
let
ff = f origArgs;
24 changes: 24 additions & 0 deletions lib/debug.nix
Original file line number Diff line number Diff line change
@@ -20,8 +20,32 @@ rec {
traceXMLValMarked = str: x: trace (str + builtins.toXML x) x;

# strict trace functions (traced structure is fully evaluated and printed)

/* `builtins.trace`, but the value is `builtins.deepSeq`ed first. */
traceSeq = x: y: trace (builtins.deepSeq x x) y;

/* Like `traceSeq`, but only down to depth n.
* This is very useful because lots of `traceSeq` usages
* lead to an infinite recursion.
*/
traceSeqN = depth: x: y: with lib;
let snip = v: if isList v then noQuotes "[…]" v
else if isAttrs v then noQuotes "{…}" v
else v;
noQuotes = str: v: { __pretty = const str; val = v; };
modify = n: fn: v: if (n == 0) then fn v
else if isList v then map (modify (n - 1) fn) v
else if isAttrs v then mapAttrs
(const (modify (n - 1) fn)) v
else v;
in trace (generators.toPretty { allowPrettyValues = true; }
(modify depth snip x)) y;

/* `traceSeq`, but the same value is traced and returned */
traceValSeq = v: traceVal (builtins.deepSeq v v);
/* `traceValSeq` but with fixed depth */
traceValSeqN = depth: v: traceSeqN depth v v;


# this can help debug your code as well - designed to not produce thousands of lines
traceShowVal = x: trace (showVal x) x;
8 changes: 5 additions & 3 deletions lib/default.nix
Original file line number Diff line number Diff line change
@@ -5,8 +5,9 @@
*/
let

# trivial, often used functions
# often used, or depending on very little
trivial = import ./trivial.nix;
fixedPoints = import ./fixed-points.nix;

# datatypes
attrsets = import ./attrsets.nix;
@@ -42,7 +43,7 @@ let
filesystem = import ./filesystem.nix;

in
{ inherit trivial
{ inherit trivial fixedPoints
attrsets lists strings stringsWithDeps
customisation maintainers meta sources
modules options types
@@ -55,6 +56,7 @@ in
}
# !!! don't include everything at top-level; perhaps only the most
# commonly used functions.
// trivial // lists // strings // stringsWithDeps // attrsets // sources
// trivial // fixedPoints
// lists // strings // stringsWithDeps // attrsets // sources
// options // types // meta // debug // misc // modules
// customisation
8 changes: 8 additions & 0 deletions lib/deprecated.nix
Original file line number Diff line number Diff line change
@@ -423,4 +423,12 @@ rec {
else if isInt x then "int"
else "string";

/* deprecated:
For historical reasons, imap has an index starting at 1.
But for consistency with the rest of the library we want an index
starting at zero.
*/
imap = imap1;
}
78 changes: 78 additions & 0 deletions lib/fixed-points.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
rec {
# Compute the fixed point of the given function `f`, which is usually an
# attribute set that expects its final, non-recursive representation as an
# argument:
#
# f = self: { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; }
#
# Nix evaluates this recursion until all references to `self` have been
# resolved. At that point, the final result is returned and `f x = x` holds:
#
# nix-repl> fix f
# { bar = "bar"; foo = "foo"; foobar = "foobar"; }
#
# Type: fix :: (a -> a) -> a
#
# See https://en.wikipedia.org/wiki/Fixed-point_combinator for further
# details.
fix = f: let x = f x; in x;

# A variant of `fix` that records the original recursive attribute set in the
# result. This is useful in combination with the `extends` function to
# implement deep overriding. See pkgs/development/haskell-modules/default.nix
# for a concrete example.
fix' = f: let x = f x // { __unfix__ = f; }; in x;

# Modify the contents of an explicitly recursive attribute set in a way that
# honors `self`-references. This is accomplished with a function
#
# g = self: super: { foo = super.foo + " + "; }
#
# that has access to the unmodified input (`super`) as well as the final
# non-recursive representation of the attribute set (`self`). `extends`
# differs from the native `//` operator insofar as that it's applied *before*
# references to `self` are resolved:
#
# nix-repl> fix (extends g f)
# { bar = "bar"; foo = "foo + "; foobar = "foo + bar"; }
#
# The name of the function is inspired by object-oriented inheritance, i.e.
# think of it as an infix operator `g extends f` that mimics the syntax from
# Java. It may seem counter-intuitive to have the "base class" as the second
# argument, but it's nice this way if several uses of `extends` are cascaded.
extends = f: rattrs: self: let super = rattrs self; in super // f self super;

# Compose two extending functions of the type expected by 'extends'
# into one where changes made in the first are available in the
# 'super' of the second
composeExtensions =
f: g: self: super:
let fApplied = f self super;
super' = super // fApplied;
in fApplied // g self super';

# Create an overridable, recursive attribute set. For example:
#
# nix-repl> obj = makeExtensible (self: { })
#
# nix-repl> obj
# { __unfix__ = «lambda»; extend = «lambda»; }
#
# nix-repl> obj = obj.extend (self: super: { foo = "foo"; })
#
# nix-repl> obj
# { __unfix__ = «lambda»; extend = «lambda»; foo = "foo"; }
#
# nix-repl> obj = obj.extend (self: super: { foo = super.foo + " + "; bar = "bar"; foobar = self.foo + self.bar; })
#
# nix-repl> obj
# { __unfix__ = «lambda»; bar = "bar"; extend = «lambda»; foo = "foo + "; foobar = "foo + bar"; }
makeExtensible = makeExtensibleWithCustomName "extend";

# Same as `makeExtensible` but the name of the extending attribute is
# customized.
makeExtensibleWithCustomName = extenderName: rattrs:
fix' rattrs // {
${extenderName} = f: makeExtensibleWithCustomName extenderName (extends f rattrs);
};
}
37 changes: 37 additions & 0 deletions lib/generators.nix
Original file line number Diff line number Diff line change
@@ -90,4 +90,41 @@ rec {
* parsers as well.
*/
toYAML = {}@args: toJSON args;

/* Pretty print a value, akin to `builtins.trace`.
* Should probably be a builtin as well.
*/
toPretty = {
/* If this option is true, attrsets like { __pretty = fn; val = …; }
will use fn to convert val to a pretty printed representation.
(This means fn is type Val -> String.) */
allowPrettyValues ? false
}@args: v: with builtins;
if isInt v then toString v
else if isBool v then (if v == true then "true" else "false")
else if isString v then "\"" + v + "\""
else if null == v then "null"
else if isFunction v then
let fna = functionArgs v;
showFnas = concatStringsSep "," (libAttr.mapAttrsToList
(name: hasDefVal: if hasDefVal then "(${name})" else name)
fna);
in if fna == {} then "<λ>"
else "<λ:{${showFnas}}>"
else if isList v then "[ "
+ libStr.concatMapStringsSep " " (toPretty args) v
+ " ]"
else if isAttrs v then
# apply pretty values if allowed
if attrNames v == [ "__pretty" "val" ] && allowPrettyValues
then v.__pretty v.val
# TODO: there is probably a better representation?
else if v ? type && v.type == "derivation" then "<δ>"
else "{ "
+ libStr.concatStringsSep " " (libAttr.mapAttrsToList
(name: value:
"${toPretty args name} = ${toPretty args value};") v)
+ " }"
else "toPretty: should never happen (v = ${v})";

}
5 changes: 5 additions & 0 deletions lib/licenses.nix
Original file line number Diff line number Diff line change
@@ -45,6 +45,11 @@ lib.mapAttrs (n: v: v // { shortName = n; }) rec {
fullName = "Apple Public Source License 2.0";
};

arphicpl = {
fullName = "Arphic Public License";
url = https://www.freedesktop.org/wiki/Arphic_Public_License/;
};

artistic1 = spdx {
spdxId = "Artistic-1.0";
fullName = "Artistic License 1.0";
22 changes: 18 additions & 4 deletions lib/lists.nix
Original file line number Diff line number Diff line change
@@ -77,15 +77,21 @@ rec {
*/
foldl' = builtins.foldl' or foldl;

/* Map with index
/* Map with index starting from 0
FIXME(zimbatm): why does this start to count at 1?
Example:
imap0 (i: v: "${v}-${toString i}") ["a" "b"]
=> [ "a-0" "b-1" ]
*/
imap0 = f: list: genList (n: f n (elemAt list n)) (length list);

/* Map with index starting from 1
Example:
imap (i: v: "${v}-${toString i}") ["a" "b"]
imap1 (i: v: "${v}-${toString i}") ["a" "b"]
=> [ "a-1" "b-2" ]
*/
imap = f: list: genList (n: f (n + 1) (elemAt list n)) (length list);
imap1 = f: list: genList (n: f (n + 1) (elemAt list n)) (length list);

/* Map and concatenate the result.
@@ -471,4 +477,12 @@ rec {
*/
subtractLists = e: filter (x: !(elem x e));

/* Test if two lists have no common element.
It should be slightly more efficient than (intersectLists a b == [])
*/
mutuallyExclusive = a: b:
(builtins.length a) == 0 ||
(!(builtins.elem (builtins.head a) b) &&
mutuallyExclusive (builtins.tail a) b);

}
50 changes: 48 additions & 2 deletions lib/maintainers.nix
Original file line number Diff line number Diff line change
@@ -16,6 +16,7 @@
acowley = "Anthony Cowley <acowley@gmail.com>";
adelbertc = "Adelbert Chang <adelbertc@gmail.com>";
adev = "Adrien Devresse <adev@adev.name>";
adisbladis = "Adam Hose <adis@blad.is>";
Adjective-Object = "Maxwell Huang-Hobbs <mhuan13@gmail.com>";
adnelson = "Allen Nelson <ithinkican@gmail.com>";
adolfogc = "Adolfo E. García Castro <adolfo.garcia.cr@gmail.com>";
@@ -42,7 +43,9 @@
andrewrk = "Andrew Kelley <superjoe30@gmail.com>";
andsild = "Anders Sildnes <andsild@gmail.com>";
aneeshusa = "Aneesh Agrawal <aneeshusa@gmail.com>";
ankhers = "Justin Wood <justin.k.wood@gmail.com>";
antono = "Antono Vasiljev <self@antono.info>";
apeschar = "Albert Peschar <albert@peschar.net>";
apeyroux = "Alexandre Peyroux <alex@px.io>";
ardumont = "Antoine R. Dumont <eniotna.t@gmail.com>";
aristid = "Aristid Breitkreuz <aristidb@gmail.com>";
@@ -60,6 +63,7 @@
bachp = "Pascal Bach <pascal.bach@nextrem.ch>";
badi = "Badi' Abdul-Wahid <abdulwahidc@gmail.com>";
balajisivaraman = "Balaji Sivaraman<sivaraman.balaji@gmail.com>";
barrucadu = "Michael Walker <mike@barrucadu.co.uk>";
basvandijk = "Bas van Dijk <v.dijk.bas@gmail.com>";
Baughn = "Svein Ove Aas <sveina@gmail.com>";
bcarrell = "Brandon Carrell <brandoncarrell@gmail.com>";
@@ -70,6 +74,7 @@
benwbooth = "Ben Booth <benwbooth@gmail.com>";
berdario = "Dario Bertini <berdario@gmail.com>";
bergey = "Daniel Bergey <bergey@teallabs.org>";
bhipple = "Benjamin Hipple <bhipple@protonmail.com>";
bjg = "Brian Gough <bjg@gnu.org>";
bjornfor = "Bjørn Forsman <bjorn.forsman@gmail.com>";
bluescreen303 = "Mathijs Kwik <mathijs@bluescreen303.nl>";
@@ -97,6 +102,7 @@
chris-martin = "Chris Martin <ch.martin@gmail.com>";
chrisjefferson = "Christopher Jefferson <chris@bubblescope.net>";
christopherpoole = "Christopher Mark Poole <mail@christopherpoole.net>";
ciil = "Simon Lackerbauer <simon@lackerbauer.com>";
ckampka = "Christian Kampka <christian@kampka.net>";
cko = "Christine Koppelt <christine.koppelt@gmail.com>";
cleverca22 = "Michael Bishop <cleverca22@gmail.com>";
@@ -130,34 +136,40 @@
deepfire = "Kosyrev Serge <_deepfire@feelingofgreen.ru>";
demin-dmitriy = "Dmitriy Demin <demindf@gmail.com>";
DerGuteMoritz = "Moritz Heidkamp <moritz@twoticketsplease.de>";
dermetfan = "Robin Stumm <serverkorken@gmail.com>";
DerTim1 = "Tim Digel <tim.digel@active-group.de>";
desiderius = "Didier J. Devroye <didier@devroye.name>";
devhell = "devhell <\"^\"@regexmail.net>";
dezgeg = "Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>";
dfoxfranke = "Daniel Fox Franke <dfoxfranke@gmail.com>";
dgonyeo = "Derek Gonyeo <derek@gonyeo.com>";
dipinhora = "Dipin Hora <dipinhora+github@gmail.com>";
disassembler = "Samuel Leathers <disasm@gmail.com>";
dmalikov = "Dmitry Malikov <malikov.d.y@gmail.com>";
DmitryTsygankov = "Dmitry Tsygankov <dmitry.tsygankov@gmail.com>";
dmjio = "David Johnson <djohnson.m@gmail.com>";
dochang = "Desmond O. Chang <dochang@gmail.com>";
domenkozar = "Domen Kozar <domen@dev.si>";
dotlambda = "Robert Schütz <rschuetz17@gmail.com>";
doublec = "Chris Double <chris.double@double.co.nz>";
dpaetzel = "David Pätzel <david.a.paetzel@gmail.com>";
drets = "Dmytro Rets <dmitryrets@gmail.com>";
drewkett = "Andrew Burkett <burkett.andrew@gmail.com>";
dsferruzza = "David Sferruzza <david.sferruzza@gmail.com>";
dtzWill = "Will Dietz <nix@wdtz.org>";
dywedir = "Vladyslav M. <dywedir@protonmail.ch>";
e-user = "Alexander Kahl <nixos@sodosopa.io>";
ebzzry = "Rommel Martinez <ebzzry@gmail.com>";
edanaher = "Evan Danaher <nixos@edanaher.net>";
edef = "edef <edef@edef.eu>";
ederoyd46 = "Matthew Brown <matt@ederoyd.co.uk>";
eduarrrd = "Eduard Bachmakov <e.bachmakov@gmail.com>";
edwtjo = "Edward Tjörnhammar <ed@cflags.cc>";
eelco = "Eelco Dolstra <eelco.dolstra@logicblox.com>";
ehegnes = "Eric Hegnes <eric.hegnes@gmail.com>";
ehmry = "Emery Hemingway <emery@vfemail.net>";
eikek = "Eike Kettner <eike.kettner@posteo.de>";
ekleog = "Leo Gaspard <leo@gaspard.io>";
elasticdog = "Aaron Bull Schaefer <aaron@elasticdog.com>";
eleanor = "Dejan Lukan <dejan@proteansec.com>";
elitak = "Eric Litak <elitak@gmail.com>";
@@ -173,7 +185,9 @@
exlevan = "Alexey Levan <exlevan@gmail.com>";
expipiplus1 = "Joe Hermaszewski <nix@monoid.al>";
fadenb = "Tristan Helmich <tristan.helmich+nixos@gmail.com>";
fare = "Francois-Rene Rideau <fahree@gmail.com>";
falsifian = "James Cook <james.cook@utoronto.ca>";
florianjacob = "Florian Jacob <projects+nixos@florianjacob.de>";
flosse = "Markus Kohlhase <mail@markus-kohlhase.de>";
fluffynukeit = "Daniel Austin <dan@fluffynukeit.com>";
fmthoma = "Franz Thoma <f.m.thoma@googlemail.com>";
@@ -194,6 +208,7 @@
garrison = "Jim Garrison <jim@garrison.cc>";
gavin = "Gavin Rogers <gavin@praxeology.co.uk>";
gebner = "Gabriel Ebner <gebner@gebner.org>";
georgewhewell = "George Whewell <georgerw@gmail.com>";
gilligan = "Tobias Pflug <tobias.pflug@gmail.com>";
giogadi = "Luis G. Torres <lgtorres42@gmail.com>";
gleber = "Gleb Peregud <gleber.p@gmail.com>";
@@ -204,6 +219,7 @@
goodrone = "Andrew Trachenko <goodrone@gmail.com>";
gpyh = "Yacine Hmito <yacine.hmito@gmail.com>";
grahamc = "Graham Christensen <graham@grahamc.com>";
grburst = "Julius Elias <grburst@openmailbox.org>";
gridaphobe = "Eric Seidel <eric@seidel.io>";
guibert = "David Guibert <david.guibert@gmail.com>";
guillaumekoenig = "Guillaume Koenig <guillaume.edward.koenig@gmail.com>";
@@ -212,11 +228,14 @@
havvy = "Ryan Scheel <ryan.havvy@gmail.com>";
hbunke = "Hendrik Bunke <bunke.hendrik@gmail.com>";
hce = "Hans-Christian Esperer <hc@hcesperer.org>";
hectorj = "Hector Jusforgues <hector.jusforgues+nixos@gmail.com>";
heel = "Sergii Paryzhskyi <parizhskiy@gmail.com>";
henrytill = "Henry Till <henrytill@gmail.com>";
hhm = "hhm <heehooman+nixpkgs@gmail.com>";
hinton = "Tom Hinton <t@larkery.com>";
hodapp = "Chris Hodapp <hodapp87@gmail.com>";
hrdinka = "Christoph Hrdinka <c.nix@hrdinka.at>";
htr = "Hugo Tavares Reis <hugo@linux.com>";
iand675 = "Ian Duncan <ian@iankduncan.com>";
ianwookim = "Ian-Woo Kim <ianwookim@gmail.com>";
igsha = "Igor Sharonov <igor.sharonov@gmail.com>";
@@ -225,6 +244,7 @@
ivan-tkatchev = "Ivan Tkatchev <tkatchev@gmail.com>";
j-keck = "Jürgen Keck <jhyphenkeck@gmail.com>";
jagajaga = "Arseniy Seroka <ars.seroka@gmail.com>";
jammerful = "jammerful <jammerful@gmail.com>";
jansol = "Jan Solanti <jan.solanti@paivola.fi>";
javaguirre = "Javier Aguirre <contacto@javaguirre.net>";
jb55 = "William Casarin <bill@casarin.me>";
@@ -235,30 +255,35 @@
jensbin = "Jens Binkert <jensbin@protonmail.com>";
jerith666 = "Matt McHenry <github@matt.mchenryfamily.org>";
jfb = "James Felix Black <james@yamtime.com>";
jfrankenau = "Johannes Frankenau <johannes@frankenau.net>";
jgeerds = "Jascha Geerds <jascha@jgeerds.name>";
jgertm = "Tim Jaeger <jger.tm@gmail.com>";
jgillich = "Jakob Gillich <jakob@gillich.me>";
jhhuh = "Ji-Haeng Huh <jhhuh.note@gmail.com>";
jirkamarsik = "Jirka Marsik <jiri.marsik89@gmail.com>";
jlesquembre = "José Luis Lafuente <jl@lafuente.me>";
jluttine = "Jaakko Luttinen <jaakko.luttinen@iki.fi>";
joachifm = "Joachim Fasting <joachifm@fastmail.fm>";
joamaki = "Jussi Maki <joamaki@gmail.com>";
joelmo = "Joel Moberg <joel.moberg@gmail.com>";
joelteon = "Joel Taylor <me@joelt.io>";
johbo = "Johannes Bornhold <johannes@bornhold.name>";
johnramsden = "John Ramsden <johnramsden@riseup.net>";
joko = "Ioannis Koutras <ioannis.koutras@gmail.com>";
jonafato = "Jon Banafato <jon@jonafato.com>";
jpbernardy = "Jean-Philippe Bernardy <jeanphilippe.bernardy@gmail.com>";
jpierre03 = "Jean-Pierre PRUNARET <nix@prunetwork.fr>";
jpotier = "Martin Potier <jpo.contributes.to.nixos@marvid.fr>";
jraygauthier = "Raymond Gauthier <jraygauthier@gmail.com>";
jtojnar = "Jan Tojnar <jtojnar@gmail.com>";
juliendehos = "Julien Dehos <dehos@lisic.univ-littoral.fr>";
jwiegley = "John Wiegley <johnw@newartisans.com>";
jwilberding = "Jordan Wilberding <jwilberding@afiniate.com>";
jzellner = "Jeff Zellner <jeffz@eml.cc>";
kaiha = "Kai Harries <kai.harries@gmail.com>";
kamilchm = "Kamil Chmielewski <kamil.chm@gmail.com>";
kampfschlaefer = "Arnold Krille <arnold@arnoldarts.de>";
kentjames = "James Kent <jameschristopherkent@gmail.com";
kevincox = "Kevin Cox <kevincox@kevincox.ca>";
khumba = "Bryan Gardiner <bog@khumba.net>";
KibaFox = "Kiba Fox <kiba.fox@foxypossibilities.com>";
@@ -292,9 +317,12 @@
lsix = "Lancelot SIX <lsix@lancelotsix.com>";
lucas8 = "Luc Chabassier <luc.linux@mailoo.org>";
ludo = "Ludovic Courtès <ludo@gnu.org>";
lufia = "Kyohei Kadota <lufia@lufia.org>";
luispedro = "Luis Pedro Coelho <luis@luispedro.org>";
lukego = "Luke Gorrie <luke@snabb.co>";
lw = "Sergey Sofeychuk <lw@fmap.me>";
lyt = "Tim Liou <wheatdoge@gmail.com>";
m3tti = "Mathaeus Sander <mathaeus.peter.sander@gmail.com>";
ma27 = "Maximilian Bosch <maximilian@mbosch.me>";
madjar = "Georges Dubus <georges.dubus@compiletoi.net>";
magnetophon = "Bart Brouns <bart@magnetophon.nl>";
@@ -327,6 +355,7 @@
michaelpj = "Michael Peyton Jones <michaelpj@gmail.com>";
michalrus = "Michal Rus <m@michalrus.com>";
michelk = "Michel Kuhlmann <michel@kuhlmanns.info>";
midchildan = "midchildan <midchildan+nix@gmail.com>";
mikefaille = "Michaël Faille <michael@faille.io>";
miltador = "Vasiliy Solovey <miltador@yandex.ua>";
mimadrid = "Miguel Madrid <mimadrid@ucm.es>";
@@ -349,6 +378,7 @@
msackman = "Matthew Sackman <matthew@wellquite.org>";
mschristiansen = "Mikkel Christiansen <mikkel@rheosystems.com>";
msteen = "Matthijs Steen <emailmatthijs@gmail.com>";
mt-caret = "Masayuki Takeda <mtakeda.enigsol@gmail.com>";
mtreskin = "Max Treskin <zerthurd@gmail.com>";
mudri = "James Wood <lamudri@gmail.com>";
muflax = "Stefan Dorn <mail@muflax.com>";
@@ -357,11 +387,12 @@
nand0p = "Fernando Jose Pando <nando@hex7.com>";
Nate-Devv = "Nathan Moore <natedevv@gmail.com>";
nathan-gs = "Nathan Bijnens <nathan@nathan.gs>";
nckx = "Tobias Geerinckx-Rice <tobias.geerinckx.rice@gmail.com>";
nckx = "Tobias Geerinckx-Rice <github@tobias.gr>";
ndowens = "Nathan Owens <ndowens04@gmail.com>";
neeasade = "Nathan Isom <nathanisom27@gmail.com>";
nequissimus = "Tim Steinbach <tim@nequissimus.com>";
nfjinjing = "Jinjing Wang <nfjinjing@gmail.com>";
nh2 = "Niklas Hambüchen <mail@nh2.me>";
nhooyr = "Anmol Sethi <anmol@aubble.com>";
nickhu = "Nick Hu <me@nickhu.co.uk>";
nicknovitski = "Nick Novitski <nixpkgs@nicknovitski.com>";
@@ -381,6 +412,7 @@
okasu = "Okasu <oka.sux@gmail.com>";
olcai = "Erik Timan <dev@timan.info>";
olejorgenb = "Ole Jørgen Brønner <olejorgenb@yahoo.no>";
olynch = "Owen Lynch <owen@olynch.me>";
orbekk = "KJ Ørbekk <kjetil.orbekk@gmail.com>";
orbitz = "Malcolm Matalka <mmatalka@gmail.com>";
orivej = "Orivej Desh <orivej@gmx.fr>";
@@ -442,24 +474,27 @@
relrod = "Ricky Elrod <ricky@elrod.me>";
renzo = "Renzo Carbonara <renzocarbonara@gmail.com>";
retrry = "Tadas Barzdžius <retrry@gmail.com>";
rht = "rht <rhtbot@protonmail.com>";
rick68 = "Wei-Ming Yang <rick68@gmail.com>";
rickynils = "Rickard Nilsson <rickynils@gmail.com>";
ris = "Robert Scott <code@humanleg.org.uk>";
rlupton20 = "Richard Lupton <richard.lupton@gmail.com>";
rnhmjoj = "Michele Guerini Rocco <micheleguerinirocco@me.com>";
rob = "Rob Vermaas <rob.vermaas@gmail.com>";
robberer = "Longrin Wischnewski <robberer@freakmail.de>";
robbinch = "Robbin C. <robbinch33@gmail.com>";
roberth = "Robert Hensing <nixpkgs@roberthensing.nl>";
robgssp = "Rob Glossop <robgssp@gmail.com>";
roblabla = "Robin Lambertz <robinlambertz+dev@gmail.com>";
roconnor = "Russell O'Connor <roconnor@theorem.ca>";
romildo = "José Romildo Malaquias <malaquias@gmail.com>";
rongcuid = "Rongcui Dong <rongcuid@outlook.com>";
ronny = "Ronny Pfannschmidt <nixos@ronnypfannschmidt.de>";
rszibele = "Richard Szibele <richard@szibele.com>";
rtreffer = "Rene Treffer <treffer+nixos@measite.de>";
rushmorem = "Rushmore Mushambi <rushmore@webenchanter.com>";
rvl = "Rodney Lorrimar <dev+nix@rodney.id.au>";
rvlander = "Gaëtan André <rvlander@gaetanandre.eu>";
rvolosatovs = "Roman Volosatovs <rvolosatovs@riseup.net";
ryanartecona = "Ryan Artecona <ryanartecona@gmail.com>";
ryansydnor = "Ryan Sydnor <ryan.t.sydnor@gmail.com>";
ryantm = "Ryan Mulligan <ryan@ryantm.com>";
@@ -507,6 +542,7 @@
steveej = "Stefan Junker <mail@stefanjunker.de>";
SuprDewd = "Bjarki Ágúst Guðmundsson <suprdewd@gmail.com>";
swarren83 = "Shawn Warren <shawn.w.warren@gmail.com>";
swflint = "Samuel W. Flint <swflint@flintfam.org>";
swistak35 = "Rafał Łasocha <me@swistak35.com>";
szczyp = "Szczyp <qb@szczyp.com>";
sztupi = "Attila Sztupak <attila.sztupak@gmail.com>";
@@ -530,17 +566,20 @@
tokudan = "Daniel Frank <git@danielfrank.net>";
tomberek = "Thomas Bereknyei <tomberek@gmail.com>";
travisbhartwell = "Travis B. Hartwell <nafai@travishartwell.net>";
trevorj = "Trevor Joynson <nix@trevor.joynson.io>";
trino = "Hubert Mühlhans <muehlhans.hubert@ekodia.de>";
tstrobel = "Thomas Strobel <4ZKTUB6TEP74PYJOPWIR013S2AV29YUBW5F9ZH2F4D5UMJUJ6S@hash.domains>";
ttuegel = "Thomas Tuegel <ttuegel@mailbox.org>";
tv = "Tomislav Viljetić <tv@shackspace.de>";
tvestelind = "Tomas Vestelind <tomas.vestelind@fripost.org>";
tvorog = "Marsel Zaripov <marszaripov@gmail.com>";
tweber = "Thorsten Weber <tw+nixpkgs@360vier.de>";
twey = "James ‘Twey’ Kay <twey@twey.co.uk>";
uralbash = "Svintsov Dmitry <root@uralbash.ru>";
utdemir = "Utku Demir <me@utdemir.com>";
#urkud = "Yury G. Kudryashov <urkud+nix@ya.ru>"; inactive since 2012
uwap = "uwap <me@uwap.name>";
vaibhavsagar = "Vaibhav Sagar <vaibhavsagar@gmail.com>";
vandenoever = "Jos van den Oever <jos@vandenoever.info>";
vanzef = "Ivan Solyankin <vanzef@gmail.com>";
vbgl = "Vincent Laporte <Vincent.Laporte@gmail.com>";
@@ -554,10 +593,13 @@
vklquevs = "vklquevs <vklquevs@gmail.com>";
vlstill = "Vladimír Štill <xstill@fi.muni.cz>";
vmandela = "Venkateswara Rao Mandela <venkat.mandela@gmail.com>";
vmchale = "Vanessa McHale <tmchale@wisc.edu>";
valeriangalliat = "Valérian Galliat <val@codejam.info>";
volhovm = "Mikhail Volkhov <volhovm.cs@gmail.com>";
volth = "Jaroslavas Pocepko <jaroslavas@volth.com>";
vozz = "Oliver Hunt <oliver.huntuk@gmail.com>";
vrthra = "Rahul Gopinath <rahul@gopinath.org>";
vyp = "vyp <elisp.vim@gmail.com>";
wedens = "wedens <kirill.wedens@gmail.com>";
willtim = "Tim Philip Williams <tim.williams.public@gmail.com>";
winden = "Antonio Vargas Gonzalez <windenntw@gmail.com>";
@@ -574,13 +616,17 @@
yarr = "Dmitry V. <savraz@gmail.com>";
yochai = "Yochai <yochai@titat.info>";
yorickvp = "Yorick van Pelt <yorickvanpelt@gmail.com>";
yuriaisaka = "Yuri Aisaka <yuri.aisaka+nix@gmail.com>";
yurrriq = "Eric Bailey <eric@ericb.me>";
z77z = "Marco Maggesi <maggesi@math.unifi.it>";
zagy = "Christian Zagrodnick <cz@flyingcircus.io>";
zalakain = "Unai Zalakain <contact@unaizalakain.info>";
zarelit = "David Costa <david@zarel.net>";
zauberpony = "Elmar Athmer <elmar@athmer.org>";
zef = "Zef Hemel <zef@zef.me>";
zimbatm = "zimbatm <zimbatm@zimbatm.com>";
zohl = "Al Zohali <zohl@fmap.me>";
zoomulator = "Kim Simmons <zoomulator@gmail.com>";
zraexy = "David Mell <zraexy@gmail.com>";
zx2c4 = "Jason A. Donenfeld <Jason@zx2c4.com>";
}
5 changes: 5 additions & 0 deletions lib/meta.nix
Original file line number Diff line number Diff line change
@@ -17,6 +17,11 @@ rec {
drv // { meta = (drv.meta or {}) // newAttrs; };


/* Disable Hydra builds of given derivation.
*/
dontDistribute = drv: addMetaAttrs { hydraPlatforms = []; } drv;


/* Change the symbolic name of a package for presentation purposes
(i.e., so that nix-env users can tell them apart).
*/
2 changes: 1 addition & 1 deletion lib/modules.nix
Original file line number Diff line number Diff line change
@@ -98,7 +98,7 @@ rec {
/* Close a set of modules under the ‘imports’ relation. */
closeModules = modules: args:
let
toClosureList = file: parentKey: imap (n: x:
toClosureList = file: parentKey: imap1 (n: x:
if isAttrs x || isFunction x then
let key = "${parentKey}:anon-${toString n}"; in
unifyModuleSyntax file key (unpackSubmodule (applyIfFunction key) x args)
11 changes: 8 additions & 3 deletions lib/strings.nix
Original file line number Diff line number Diff line change
@@ -33,7 +33,7 @@ rec {
concatImapStrings (pos: x: "${toString pos}-${x}") ["foo" "bar"]
=> "1-foo2-bar"
*/
concatImapStrings = f: list: concatStrings (lib.imap f list);
concatImapStrings = f: list: concatStrings (lib.imap1 f list);

/* Place an element between each element of a list
@@ -70,7 +70,7 @@ rec {
concatImapStringsSep "-" (pos: x: toString (x / pos)) [ 6 6 6 ]
=> "6-3-2"
*/
concatImapStringsSep = sep: f: list: concatStringsSep sep (lib.imap f list);
concatImapStringsSep = sep: f: list: concatStringsSep sep (lib.imap1 f list);

/* Construct a Unix-style search path consisting of each `subDir"
directory of the given list of packages.
@@ -438,8 +438,13 @@ rec {
=> true
isStorePath pkgs.python
=> true
isStorePath [] || isStorePath 42 || isStorePath {} || …
=> false
*/
isStorePath = x: builtins.substring 0 1 (toString x) == "/" && dirOf (builtins.toPath x) == builtins.storeDir;
isStorePath = x:
builtins.isString x
&& builtins.substring 0 1 (toString x) == "/"
&& dirOf (builtins.toPath x) == builtins.storeDir;

/* Convert string to int
Obviously, it is a bit hacky to use fromJSON that way.
13 changes: 12 additions & 1 deletion lib/systems/default.nix
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
let inherit (import ../attrsets.nix) mapAttrs; in

rec {
doubles = import ./doubles.nix;
parse = import ./parse.nix;
inspect = import ./inspect.nix;
platforms = import ./platforms.nix;
examples = import ./examples.nix;

# Elaborate a `localSystem` or `crossSystem` so that it contains everything
# necessary.
@@ -18,6 +22,13 @@ rec {
config = parse.tripleFromSystem final.parsed;
# Just a guess, based on `system`
platform = platforms.selectBySystem final.system;
} // args;
libc =
/**/ if final.isDarwin then "libSystem"
else if final.isMinGW then "msvcrt"
else if final.isLinux then "glibc"
# TODO(@Ericson2314) think more about other operating systems
else "native/impure";
} // mapAttrs (n: v: v final.parsed) inspect.predicates
// args;
in final;
}
38 changes: 20 additions & 18 deletions lib/systems/doubles.nix
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
let lists = import ../lists.nix; in
let parse = import ./parse.nix; in
let inherit (import ../attrsets.nix) matchAttrs; in

let
lists = import ../lists.nix;
parse = import ./parse.nix;
inherit (import ./inspect.nix) predicates;
inherit (import ../attrsets.nix) matchAttrs;

all = [
"aarch64-linux"
"armv5tel-linux" "armv6l-linux" "armv7l-linux"
@@ -25,20 +26,21 @@ in rec {
allBut = platforms: lists.filter (x: !(builtins.elem x platforms)) all;
none = [];

arm = filterDoubles (matchAttrs { cpu = { family = "arm"; bits = 32; }; });
i686 = filterDoubles parse.isi686;
mips = filterDoubles (matchAttrs { cpu = { family = "mips"; }; });
x86_64 = filterDoubles parse.isx86_64;

cygwin = filterDoubles parse.isCygwin;
darwin = filterDoubles parse.isDarwin;
freebsd = filterDoubles (matchAttrs { kernel = parse.kernels.freebsd; });
gnu = filterDoubles (matchAttrs { kernel = parse.kernels.linux; abi = parse.abis.gnu; }); # Should be better
illumos = filterDoubles (matchAttrs { kernel = parse.kernels.solaris; });
linux = filterDoubles parse.isLinux;
netbsd = filterDoubles (matchAttrs { kernel = parse.kernels.netbsd; });
openbsd = filterDoubles (matchAttrs { kernel = parse.kernels.openbsd; });
unix = filterDoubles parse.isUnix;
arm = filterDoubles predicates.isArm32;
i686 = filterDoubles predicates.isi686;
mips = filterDoubles predicates.isMips;
x86_64 = filterDoubles predicates.isx86_64;

cygwin = filterDoubles predicates.isCygwin;
darwin = filterDoubles predicates.isDarwin;
freebsd = filterDoubles predicates.isFreeBSD;
# Should be better, but MinGW is unclear, and HURD is bit-rotted.
gnu = filterDoubles (matchAttrs { kernel = parse.kernels.linux; abi = parse.abis.gnu; });
illumos = filterDoubles predicates.isSunOS;
linux = filterDoubles predicates.isLinux;
netbsd = filterDoubles predicates.isNetBSD;
openbsd = filterDoubles predicates.isOpenBSD;
unix = filterDoubles predicates.isUnix;

mesaPlatforms = ["i686-linux" "x86_64-linux" "x86_64-darwin" "armv5tel-linux" "armv6l-linux" "armv7l-linux" "aarch64-linux"];
}
130 changes: 130 additions & 0 deletions lib/systems/examples.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# These can be passed to nixpkgs as either the `localSystem` or
# `crossSystem`. They are put here for user convenience, but also used by cross
# tests and linux cross stdenv building, so handle with care!

let platforms = import ./platforms.nix; in

rec {
#
# Linux
#

sheevaplug = rec {
config = "armv5tel-unknown-linux-gnueabi";
bigEndian = false;
arch = "armv5tel";
float = "soft";
withTLS = true;
libc = "glibc";
platform = platforms.sheevaplug;
openssl.system = "linux-generic32";
inherit (platform) gcc;
};

raspberryPi = rec {
config = "armv6l-unknown-linux-gnueabihf";
bigEndian = false;
arch = "armv6l";
float = "hard";
fpu = "vfp";
withTLS = true;
libc = "glibc";
platform = platforms.raspberrypi;
openssl.system = "linux-generic32";
inherit (platform) gcc;
};

armv7l-hf-multiplatform = rec {
config = "arm-unknown-linux-gnueabihf";
bigEndian = false;
arch = "armv7-a";
float = "hard";
fpu = "vfpv3-d16";
withTLS = true;
libc = "glibc";
platform = platforms.armv7l-hf-multiplatform;
openssl.system = "linux-generic32";
inherit (platform) gcc;
};

aarch64-multiplatform = rec {
config = "aarch64-unknown-linux-gnu";
bigEndian = false;
arch = "aarch64";
withTLS = true;
libc = "glibc";
platform = platforms.aarch64-multiplatform;
inherit (platform) gcc;
};

scaleway-c1 = armv7l-hf-multiplatform // rec {
platform = platforms.scaleway-c1;
inherit (platform) gcc;
inherit (gcc) fpu;
};

pogoplug4 = rec {
arch = "armv5tel";
config = "armv5tel-softfloat-linux-gnueabi";
float = "soft";

platform = platforms.pogoplug4;

inherit (platform) gcc;
libc = "glibc";

withTLS = true;
openssl.system = "linux-generic32";
};

fuloongminipc = rec {
config = "mips64el-unknown-linux-gnu";
bigEndian = false;
arch = "mips";
float = "hard";
withTLS = true;
libc = "glibc";
platform = platforms.fuloong2f_n32;
openssl.system = "linux-generic32";
inherit (platform) gcc;
};

#
# Darwin
#

iphone64 = {
config = "aarch64-apple-darwin14";
arch = "arm64";
libc = "libSystem";
platform = {};
};

iphone32 = {
config = "arm-apple-darwin10";
arch = "armv7-a";
libc = "libSystem";
platform = {};
};

#
# Windows
#

# 32 bit mingw-w64
mingw32 = {
config = "i686-pc-mingw32";
arch = "x86"; # Irrelevant
libc = "msvcrt"; # This distinguishes the mingw (non posix) toolchain
platform = {};
};

# 64 bit mingw-w64
mingwW64 = {
# That's the triplet they use in the mingw-w64 docs.
config = "x86_64-pc-mingw32";
arch = "x86_64"; # Irrelevant
libc = "msvcrt"; # This distinguishes the mingw (non posix) toolchain
platform = {};
};
}
43 changes: 43 additions & 0 deletions lib/systems/inspect.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
with import ./parse.nix;
with import ../attrsets.nix;
with import ../lists.nix;

rec {
patterns = rec {
"32bit" = { cpu = { bits = 32; }; };
"64bit" = { cpu = { bits = 64; }; };
i686 = { cpu = cpuTypes.i686; };
x86_64 = { cpu = cpuTypes.x86_64; };
PowerPC = { cpu = cpuTypes.powerpc; };
x86 = { cpu = { family = "x86"; }; };
Arm = { cpu = { family = "arm"; }; };
Mips = { cpu = { family = "mips"; }; };
BigEndian = { cpu = { significantByte = significantBytes.bigEndian; }; };
LittleEndian = { cpu = { significantByte = significantBytes.littleEndian; }; };

BSD = { kernel = { families = { inherit (kernelFamilies) bsd; }; }; };
Unix = [ BSD Darwin Linux SunOS Hurd Cygwin ];

Darwin = { kernel = kernels.darwin; };
Linux = { kernel = kernels.linux; };
SunOS = { kernel = kernels.solaris; };
FreeBSD = { kernel = kernels.freebsd; };
Hurd = { kernel = kernels.hurd; };
NetBSD = { kernel = kernels.netbsd; };
OpenBSD = { kernel = kernels.openbsd; };
Windows = { kernel = kernels.windows; };
Cygwin = { kernel = kernels.windows; abi = abis.cygnus; };
MinGW = { kernel = kernels.windows; abi = abis.gnu; };

Arm32 = recursiveUpdate Arm patterns."32bit";
Arm64 = recursiveUpdate Arm patterns."64bit";
};

matchAnyAttrs = patterns:
if builtins.isList patterns then attrs: any (pattern: matchAttrs pattern attrs) patterns
else matchAttrs patterns;

predicates = mapAttrs'
(name: value: nameValuePair ("is" + name) (matchAnyAttrs value))
patterns;
}
53 changes: 23 additions & 30 deletions lib/systems/parse.nix
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@
with import ../lists.nix;
with import ../types.nix;
with import ../attrsets.nix;
with (import ./inspect.nix).predicates;

let
lib = import ../default.nix;
@@ -43,7 +44,7 @@ rec {
i686 = { bits = 32; significantByte = littleEndian; family = "x86"; };
x86_64 = { bits = 64; significantByte = littleEndian; family = "x86"; };
mips64el = { bits = 32; significantByte = littleEndian; family = "mips"; };
powerpc = { bits = 32; significantByte = bigEndian; family = "powerpc"; };
powerpc = { bits = 32; significantByte = bigEndian; family = "power"; };
};

isVendor = isType "vendor";
@@ -67,22 +68,25 @@ rec {
isKernelFamily = isType "kernel-family";
kernelFamilies = setTypes "kernel-family" {
bsd = {};
unix = {};
};

isKernel = x: isType "kernel" x;
kernels = with execFormats; with kernelFamilies; setTypesAssert "kernel"
(x: isExecFormat x.execFormat && all isKernelFamily (attrValues x.families))
{
darwin = { execFormat = macho; families = { inherit unix; }; };
freebsd = { execFormat = elf; families = { inherit unix bsd; }; };
linux = { execFormat = elf; families = { inherit unix; }; };
netbsd = { execFormat = elf; families = { inherit unix bsd; }; };
none = { execFormat = unknown; families = { inherit unix; }; };
openbsd = { execFormat = elf; families = { inherit unix bsd; }; };
solaris = { execFormat = elf; families = { inherit unix; }; };
darwin = { execFormat = macho; families = { }; };
freebsd = { execFormat = elf; families = { inherit bsd; }; };
hurd = { execFormat = elf; families = { }; };
linux = { execFormat = elf; families = { }; };
netbsd = { execFormat = elf; families = { inherit bsd; }; };
none = { execFormat = unknown; families = { }; };
openbsd = { execFormat = elf; families = { inherit bsd; }; };
solaris = { execFormat = elf; families = { }; };
windows = { execFormat = pe; families = { }; };
} // { # aliases
# TODO(@Ericson2314): Handle these Darwin version suffixes more generally.
darwin10 = kernels.darwin;
darwin14 = kernels.darwin;
win32 = kernels.windows;
};

@@ -106,23 +110,12 @@ rec {
inherit cpu vendor kernel abi;
};

is64Bit = matchAttrs { cpu = { bits = 64; }; };
is32Bit = matchAttrs { cpu = { bits = 32; }; };
isi686 = matchAttrs { cpu = cpuTypes.i686; };
isx86_64 = matchAttrs { cpu = cpuTypes.x86_64; };

isDarwin = matchAttrs { kernel = kernels.darwin; };
isLinux = matchAttrs { kernel = kernels.linux; };
isUnix = matchAttrs { kernel = { families = { inherit (kernelFamilies) unix; }; }; };
isWindows = matchAttrs { kernel = kernels.windows; };
isCygwin = matchAttrs { kernel = kernels.windows; abi = abis.cygnus; };
isMinGW = matchAttrs { kernel = kernels.windows; abi = abis.gnu; };


mkSkeletonFromList = l: {
"2" = # We only do 2-part hacks for things Nix already supports
if elemAt l 1 == "cygwin"
then { cpu = elemAt l 0; kernel = "windows"; abi = "cygnus"; }
then { cpu = elemAt l 0; kernel = "windows"; abi = "cygnus"; }
else if elemAt l 1 == "gnu"
then { cpu = elemAt l 0; kernel = "hurd"; abi = "gnu"; }
else { cpu = elemAt l 0; kernel = elemAt l 1; };
"3" = # Awkwards hacks, beware!
if elemAt l 1 == "apple"
@@ -150,27 +143,27 @@ rec {
getKernel = name: kernels.${name} or (throw "Unknown kernel: ${name}");
getAbi = name: abis.${name} or (throw "Unknown ABI: ${name}");

system = rec {
parsed = rec {
cpu = getCpu args.cpu;
vendor =
/**/ if args ? vendor then getVendor args.vendor
else if isDarwin system then vendors.apple
else if isWindows system then vendors.pc
else if isDarwin parsed then vendors.apple
else if isWindows parsed then vendors.pc
else vendors.unknown;
kernel = getKernel args.kernel;
abi =
/**/ if args ? abi then getAbi args.abi
else if isLinux system then abis.gnu
else if isWindows system then abis.gnu
else if isLinux parsed then abis.gnu
else if isWindows parsed then abis.gnu
else abis.unknown;
};

in mkSystem system;
in mkSystem parsed;

mkSystemFromString = s: mkSystemFromSkeleton (mkSkeletonFromList (lib.splitString "-" s));

doubleFromSystem = { cpu, vendor, kernel, abi, ... }:
if vendor == kernels.windows && abi == abis.cygnus
if abi == abis.cygnus
then "${cpu.name}-cygwin"
else "${cpu.name}-${kernel.name}";

9 changes: 8 additions & 1 deletion lib/systems/platforms.nix
Original file line number Diff line number Diff line change
@@ -255,6 +255,10 @@ rec {
arch = "armv6";
fpu = "vfp";
float = "hard";
# TODO(@Ericson2314) what is this and is it a good idea? It was
# used in some cross compilation examples but not others.
#
# abi = "aapcs-linux";
};
};

@@ -460,7 +464,10 @@ rec {
'';
kernelTarget = "vmlinux";
uboot = null;
gcc.arch = "loongson2f";
gcc = {
arch = "loongson2f";
abi = "n32";
};
};

beaglebone = armv7l-hf-multiplatform // {
219 changes: 145 additions & 74 deletions lib/tests.nix → lib/tests/misc.nix
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# to run these tests:
# nix-instantiate --eval --strict nixpkgs/lib/tests.nix
# nix-instantiate --eval --strict nixpkgs/lib/tests/misc.nix
# if the resulting list is empty, all tests passed
let inherit (builtins) add; in
with import ./default.nix;
with import ../default.nix;

runTests {


# TRIVIAL

testId = {
expr = id 1;
expected = 1;
@@ -33,6 +35,18 @@ runTests {
expected = {a = "a";};
};

testComposeExtensions = {
expr = let obj = makeExtensible (self: { foo = self.bar; });
f = self: super: { bar = false; baz = true; };
g = self: super: { bar = super.baz or false; };
f_o_g = composeExtensions f g;
composed = obj.extend f_o_g;
in composed.foo;
expected = true;
};

# STRINGS

testConcatMapStrings = {
expr = concatMapStrings (x: x + ";") ["a" "b" "c"];
expected = "a;b;c;";
@@ -43,6 +57,69 @@ runTests {
expected = "a,b,c";
};

testSplitStringsSimple = {
expr = strings.splitString "." "a.b.c.d";
expected = [ "a" "b" "c" "d" ];
};

testSplitStringsEmpty = {
expr = strings.splitString "." "a..b";
expected = [ "a" "" "b" ];
};

testSplitStringsOne = {
expr = strings.splitString ":" "a.b";
expected = [ "a.b" ];
};

testSplitStringsNone = {
expr = strings.splitString "." "";
expected = [ "" ];
};

testSplitStringsFirstEmpty = {
expr = strings.splitString "/" "/a/b/c";
expected = [ "" "a" "b" "c" ];
};

testSplitStringsLastEmpty = {
expr = strings.splitString ":" "2001:db8:0:0042::8a2e:370:";
expected = [ "2001" "db8" "0" "0042" "" "8a2e" "370" "" ];
};

testIsStorePath = {
expr =
let goodPath =
"${builtins.storeDir}/d945ibfx9x185xf04b890y4f9g3cbb63-python-2.7.11";
in {
storePath = isStorePath goodPath;
storePathAppendix = isStorePath
"${goodPath}/bin/python";
nonAbsolute = isStorePath (concatStrings (tail (stringToCharacters goodPath)));
asPath = isStorePath (builtins.toPath goodPath);
otherPath = isStorePath "/something/else";
otherVals = {
attrset = isStorePath {};
list = isStorePath [];
int = isStorePath 42;
};
};
expected = {
storePath = true;
storePathAppendix = false;
nonAbsolute = false;
asPath = true;
otherPath = false;
otherVals = {
attrset = false;
list = false;
int = false;
};
};
};

# LISTS

testFilter = {
expr = filter (x: x != "a") ["a" "b" "c" "a"];
expected = ["b" "c"];
@@ -93,45 +170,6 @@ runTests {
expected = { a = [ 2 3 ]; b = [7]; c = [8];};
};

testOverridableDelayableArgsTest = {
expr =
let res1 = defaultOverridableDelayableArgs id {};
res2 = defaultOverridableDelayableArgs id { a = 7; };
res3 = let x = defaultOverridableDelayableArgs id { a = 7; };
in (x.merge) { b = 10; };
res4 = let x = defaultOverridableDelayableArgs id { a = 7; };
in (x.merge) ( x: { b = 10; });
res5 = let x = defaultOverridableDelayableArgs id { a = 7; };
in (x.merge) ( x: { a = add x.a 3; });
res6 = let x = defaultOverridableDelayableArgs id { a = 7; mergeAttrBy = { a = add; }; };
y = x.merge {};
in (y.merge) { a = 10; };

resRem7 = res6.replace (a: removeAttrs a ["a"]);

resReplace6 = let x = defaultOverridableDelayableArgs id { a = 7; mergeAttrBy = { a = add; }; };
x2 = x.merge { a = 20; }; # now we have 27
in (x2.replace) { a = 10; }; # and override the value by 10

# fixed tests (delayed args): (when using them add some comments, please)
resFixed1 =
let x = defaultOverridableDelayableArgs id ( x: { a = 7; c = x.fixed.b; });
y = x.merge (x: { name = "name-${builtins.toString x.fixed.c}"; });
in (y.merge) { b = 10; };
strip = attrs: removeAttrs attrs ["merge" "replace"];
in all id
[ ((strip res1) == { })
((strip res2) == { a = 7; })
((strip res3) == { a = 7; b = 10; })
((strip res4) == { a = 7; b = 10; })
((strip res5) == { a = 10; })
((strip res6) == { a = 17; })
((strip resRem7) == {})
((strip resFixed1) == { a = 7; b = 10; c =10; name = "name-10"; })
];
expected = true;
};

testSort = {
expr = sort builtins.lessThan [ 40 2 30 42 ];
expected = [2 30 40 42];
@@ -158,9 +196,9 @@ runTests {
};


/* Generator tests */
# these tests assume attributes are converted to lists
# in alphabetical order
# GENERATORS
# these tests assume attributes are converted to lists
# in alphabetical order

testMkKeyValueDefault = {
expr = generators.mkKeyValueDefault ":" "f:oo" "bar";
@@ -247,43 +285,76 @@ runTests {
expected = builtins.toJSON val;
};

testSplitStringsSimple = {
expr = strings.splitString "." "a.b.c.d";
expected = [ "a" "b" "c" "d" ];
testToPretty = {
expr = mapAttrs (const (generators.toPretty {})) rec {
int = 42;
bool = true;
string = "fnord";
null_ = null;
function = x: x;
functionArgs = { arg ? 4, foo }: arg;
list = [ 3 4 function [ false ] ];
attrs = { foo = null; "foo bar" = "baz"; };
drv = derivation { name = "test"; system = builtins.currentSystem; };
};
expected = rec {
int = "42";
bool = "true";
string = "\"fnord\"";
null_ = "null";
function = "<λ>";
functionArgs = "<λ:{(arg),foo}>";
list = "[ 3 4 ${function} [ false ] ]";
attrs = "{ \"foo\" = null; \"foo bar\" = \"baz\"; }";
drv = "<δ>";
};
};

testSplitStringsEmpty = {
expr = strings.splitString "." "a..b";
expected = [ "a" "" "b" ];
testToPrettyAllowPrettyValues = {
expr = generators.toPretty { allowPrettyValues = true; }
{ __pretty = v: "«" + v + "»"; val = "foo"; };
expected = "«foo»";
};

testSplitStringsOne = {
expr = strings.splitString ":" "a.b";
expected = [ "a.b" ];
};

testSplitStringsNone = {
expr = strings.splitString "." "";
expected = [ "" ];
};
# MISC

testSplitStringsFirstEmpty = {
expr = strings.splitString "/" "/a/b/c";
expected = [ "" "a" "b" "c" ];
};
testOverridableDelayableArgsTest = {
expr =
let res1 = defaultOverridableDelayableArgs id {};
res2 = defaultOverridableDelayableArgs id { a = 7; };
res3 = let x = defaultOverridableDelayableArgs id { a = 7; };
in (x.merge) { b = 10; };
res4 = let x = defaultOverridableDelayableArgs id { a = 7; };
in (x.merge) ( x: { b = 10; });
res5 = let x = defaultOverridableDelayableArgs id { a = 7; };
in (x.merge) ( x: { a = builtins.add x.a 3; });
res6 = let x = defaultOverridableDelayableArgs id { a = 7; mergeAttrBy = { a = builtins.add; }; };
y = x.merge {};
in (y.merge) { a = 10; };

testSplitStringsLastEmpty = {
expr = strings.splitString ":" "2001:db8:0:0042::8a2e:370:";
expected = [ "2001" "db8" "0" "0042" "" "8a2e" "370" "" ];
};
resRem7 = res6.replace (a: removeAttrs a ["a"]);

testComposeExtensions = {
expr = let obj = makeExtensible (self: { foo = self.bar; });
f = self: super: { bar = false; baz = true; };
g = self: super: { bar = super.baz or false; };
f_o_g = composeExtensions f g;
composed = obj.extend f_o_g;
in composed.foo;
resReplace6 = let x = defaultOverridableDelayableArgs id { a = 7; mergeAttrBy = { a = builtins.add; }; };
x2 = x.merge { a = 20; }; # now we have 27
in (x2.replace) { a = 10; }; # and override the value by 10

# fixed tests (delayed args): (when using them add some comments, please)
resFixed1 =
let x = defaultOverridableDelayableArgs id ( x: { a = 7; c = x.fixed.b; });
y = x.merge (x: { name = "name-${builtins.toString x.fixed.c}"; });
in (y.merge) { b = 10; };
strip = attrs: removeAttrs attrs ["merge" "replace"];
in all id
[ ((strip res1) == { })
((strip res2) == { a = 7; })
((strip res3) == { a = 7; b = 10; })
((strip res4) == { a = 7; b = 10; })
((strip res5) == { a = 10; })
((strip res6) == { a = 17; })
((strip resRem7) == {})
((strip resFixed1) == { a = 7; b = 10; c =10; name = "name-10"; })
];
expected = true;
};

58 changes: 25 additions & 33 deletions lib/tests/release.nix
Original file line number Diff line number Diff line change
@@ -1,40 +1,32 @@
{ nixpkgs ? { outPath = (import ../.).cleanSource ../..; revCount = 1234; shortRev = "abcdef"; }
, # The platforms for which we build Nixpkgs.
supportedSystems ? [ builtins.currentSystem ]
, # Strip most of attributes when evaluating to spare memory usage
scrubJobs ? true
}:
{ pkgs ? import ((import ../.).cleanSource ../..) {} }:

with import ../../pkgs/top-level/release-lib.nix { inherit supportedSystems scrubJobs; };
with lib;
pkgs.stdenv.mkDerivation {
name = "nixpkgs-lib-tests";
buildInputs = [ pkgs.nix ];
NIX_PATH="nixpkgs=${pkgs.path}";

{
systems = import ./systems.nix { inherit lib assertTrue; };
buildCommand = ''
datadir="${pkgs.nix}/share"
export TEST_ROOT=$(pwd)/test-tmp
export NIX_BUILD_HOOK=
export NIX_CONF_DIR=$TEST_ROOT/etc
export NIX_DB_DIR=$TEST_ROOT/db
export NIX_LOCALSTATE_DIR=$TEST_ROOT/var
export NIX_LOG_DIR=$TEST_ROOT/var/log/nix
export NIX_MANIFESTS_DIR=$TEST_ROOT/var/nix/manifests
export NIX_STATE_DIR=$TEST_ROOT/var/nix
export NIX_STORE_DIR=$TEST_ROOT/store
export PAGER=cat
cacheDir=$TEST_ROOT/binary-cache
nix-store --init
moduleSystem = pkgs.stdenv.mkDerivation {
name = "nixpkgs-lib-tests";
buildInputs = [ pkgs.nix ];
NIX_PATH="nixpkgs=${nixpkgs}";
cd ${pkgs.path}/lib/tests
./modules.sh
buildCommand = ''
datadir="${pkgs.nix}/share"
export TEST_ROOT=$(pwd)/test-tmp
export NIX_BUILD_HOOK=
export NIX_CONF_DIR=$TEST_ROOT/etc
export NIX_DB_DIR=$TEST_ROOT/db
export NIX_LOCALSTATE_DIR=$TEST_ROOT/var
export NIX_LOG_DIR=$TEST_ROOT/var/log/nix
export NIX_MANIFESTS_DIR=$TEST_ROOT/var/nix/manifests
export NIX_STATE_DIR=$TEST_ROOT/var/nix
export NIX_STORE_DIR=$TEST_ROOT/store
export PAGER=cat
cacheDir=$TEST_ROOT/binary-cache
nix-store --init
[[ "$(nix-instantiate --eval --strict misc.nix)" == "[ ]" ]]
cd ${nixpkgs}/lib/tests
./modules.sh
[[ "$(nix-instantiate --eval --strict systems.nix)" == "[ ]" ]]
touch $out
'';
};
touch $out
'';
}
14 changes: 7 additions & 7 deletions lib/tests/systems.nix
Original file line number Diff line number Diff line change
@@ -5,13 +5,13 @@
# calculating the lists anyway?". The answer is one can mindlessly update these
# tests as new platforms become supported, and then just give the diff a quick
# sanity check before committing :).
{ lib, assertTrue }:

with lib.systems.doubles;

let mseteq = x: y: lib.sort lib.lessThan x == lib.sort lib.lessThan y; in

{
let
lib = import ../default.nix;
mseteq = x: y: {
expr = lib.sort lib.lessThan x;
expected = lib.sort lib.lessThan y;
};
in with lib.systems.doubles; lib.runTests {
all = assertTrue (mseteq all (linux ++ darwin ++ cygwin ++ freebsd ++ openbsd ++ netbsd ++ illumos));

arm = assertTrue (mseteq arm [ "armv5tel-linux" "armv6l-linux" "armv7l-linux" ]);
76 changes: 0 additions & 76 deletions lib/trivial.nix
Original file line number Diff line number Diff line change
@@ -43,82 +43,6 @@ rec {
*/
mergeAttrs = x: y: x // y;


# Compute the fixed point of the given function `f`, which is usually an
# attribute set that expects its final, non-recursive representation as an
# argument:
#
# f = self: { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; }
#
# Nix evaluates this recursion until all references to `self` have been
# resolved. At that point, the final result is returned and `f x = x` holds:
#
# nix-repl> fix f
# { bar = "bar"; foo = "foo"; foobar = "foobar"; }
#
# See https://en.wikipedia.org/wiki/Fixed-point_combinator for further
# details.
fix = f: let x = f x; in x;

# A variant of `fix` that records the original recursive attribute set in the
# result. This is useful in combination with the `extends` function to
# implement deep overriding. See pkgs/development/haskell-modules/default.nix
# for a concrete example.
fix' = f: let x = f x // { __unfix__ = f; }; in x;

# Modify the contents of an explicitly recursive attribute set in a way that
# honors `self`-references. This is accomplished with a function
#
# g = self: super: { foo = super.foo + " + "; }
#
# that has access to the unmodified input (`super`) as well as the final
# non-recursive representation of the attribute set (`self`). `extends`
# differs from the native `//` operator insofar as that it's applied *before*
# references to `self` are resolved:
#
# nix-repl> fix (extends g f)
# { bar = "bar"; foo = "foo + "; foobar = "foo + bar"; }
#
# The name of the function is inspired by object-oriented inheritance, i.e.
# think of it as an infix operator `g extends f` that mimics the syntax from
# Java. It may seem counter-intuitive to have the "base class" as the second
# argument, but it's nice this way if several uses of `extends` are cascaded.
extends = f: rattrs: self: let super = rattrs self; in super // f self super;

# Compose two extending functions of the type expected by 'extends'
# into one where changes made in the first are available in the
# 'super' of the second
composeExtensions =
f: g: self: super:
let fApplied = f self super;
super' = super // fApplied;
in fApplied // g self super';

# Create an overridable, recursive attribute set. For example:
#
# nix-repl> obj = makeExtensible (self: { })
#
# nix-repl> obj
# { __unfix__ = «lambda»; extend = «lambda»; }
#
# nix-repl> obj = obj.extend (self: super: { foo = "foo"; })
#
# nix-repl> obj
# { __unfix__ = «lambda»; extend = «lambda»; foo = "foo"; }
#
# nix-repl> obj = obj.extend (self: super: { foo = super.foo + " + "; bar = "bar"; foobar = self.foo + self.bar; })
#
# nix-repl> obj
# { __unfix__ = «lambda»; bar = "bar"; extend = «lambda»; foo = "foo + "; foobar = "foo + bar"; }
makeExtensible = makeExtensibleWithCustomName "extend";

# Same as `makeExtensible` but the name of the extending attribute is
# customized.
makeExtensibleWithCustomName = extenderName: rattrs:
fix' rattrs // {
${extenderName} = f: makeExtensibleWithCustomName extenderName (extends f rattrs);
};

# Flip the order of the arguments of a binary function.
flip = f: a: b: f b a;

17 changes: 13 additions & 4 deletions lib/types.nix
Original file line number Diff line number Diff line change
@@ -92,6 +92,8 @@ rec {
};


# When adding new types don't forget to document them in
# nixos/doc/manual/development/option-types.xml!
types = rec {

unspecified = mkOptionType {
@@ -177,9 +179,9 @@ rec {
description = "list of ${elemType.description}s";
check = isList;
merge = loc: defs:
map (x: x.value) (filter (x: x ? value) (concatLists (imap (n: def:
map (x: x.value) (filter (x: x ? value) (concatLists (imap1 (n: def:
if isList def.value then
imap (m: def':
imap1 (m: def':
(mergeDefinitions
(loc ++ ["[definition ${toString n}-entry ${toString m}]"])
elemType
@@ -218,7 +220,7 @@ rec {
if isList def.value then
{ inherit (def) file;
value = listToAttrs (
imap (elemIdx: elem:
imap1 (elemIdx: elem:
{ name = elem.name or "unnamed-${toString defIdx}.${toString elemIdx}";
value = elem;
}) def.value);
@@ -231,7 +233,7 @@ rec {
name = "loaOf";
description = "list or attribute set of ${elemType.description}s";
check = x: isList x || isAttrs x;
merge = loc: defs: attrOnly.merge loc (imap convertIfList defs);
merge = loc: defs: attrOnly.merge loc (imap1 convertIfList defs);
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name?>"]);
getSubModules = elemType.getSubModules;
substSubModules = m: loaOf (elemType.substSubModules m);
@@ -257,6 +259,7 @@ rec {
functor = (defaultFunctor name) // { wrapped = elemType; };
};

# Value of given type but with no merging (i.e. `uniq list`s are not concatenated).
uniq = elemType: mkOptionType rec {
name = "uniq";
inherit (elemType) description check;
@@ -267,6 +270,7 @@ rec {
functor = (defaultFunctor name) // { wrapped = elemType; };
};

# Null or value of ...
nullOr = elemType: mkOptionType rec {
name = "nullOr";
description = "null or ${elemType.description}";
@@ -283,6 +287,7 @@ rec {
functor = (defaultFunctor name) // { wrapped = elemType; };
};

# A submodule (like typed attribute set). See NixOS manual.
submodule = opts:
let
opts' = toList opts;
@@ -314,6 +319,7 @@ rec {
};
};

# A value from a set of allowed ones.
enum = values:
let
show = v:
@@ -329,6 +335,7 @@ rec {
functor = (defaultFunctor name) // { payload = values; binOp = a: b: unique (a ++ b); };
};

# Either value of type `t1` or `t2`.
either = t1: t2: mkOptionType rec {
name = "either";
description = "${t1.description} or ${t2.description}";
@@ -352,6 +359,8 @@ rec {
functor = (defaultFunctor name) // { wrapped = [ t1 t2 ]; };
};

# Either value of type `finalType` or `coercedType`, the latter is
# converted to `finalType` using `coerceFunc`.
coercedTo = coercedType: coerceFunc: finalType:
assert coercedType.getSubModules == null;
mkOptionType rec {
2 changes: 1 addition & 1 deletion maintainers/scripts/gnome.sh
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@ GNOME_FTP="ftp.gnome.org/pub/GNOME/sources"

# projects that don't follow the GNOME major versioning, or that we don't want to
# programmatically update
NO_GNOME_MAJOR="gtkhtml gdm"
NO_GNOME_MAJOR="ghex gtkhtml gdm"

usage() {
echo "Usage: $0 gnome_dir <show project>|<update project>|<update-all> [major.minor]" >&2
345 changes: 100 additions & 245 deletions maintainers/scripts/rebuild-amount.sh
Original file line number Diff line number Diff line change
@@ -1,260 +1,115 @@
#!/bin/sh

usage () {
echo 1>&2 "
usage:
$0
[--git commit..commit | --git commit]
[--svn rev:rev | --svn rev]
[--path path[:path]*]
[--help]
This program is used to investigate how any changes inside your nixpkgs
repository may hurt. With these kind of information you may choose wisely
where you should commit your changes.
This program adapts it-self to your versionning system to avoid too much
effort on your Internet bandwidth. If you need to check more than one
commits / revisions, you may use the following commands:
--git remotes/trunk..master
--svn 17670:17677
Check the differences between each commit separating the first and the
last commit.
--path /etc/nixos/nixpkgs:/tmp/nixpkgs_1:/tmp/nixpkgs_2
Check the differences between multiple directories containing different
versions of nixpkgs.
All these options exist with one commit / revision argument. Such options
are used to compare your \$NIXPKGS path with the specified version.
If you omit to mention any other commit / revision, then your \$NIXPKGS path
is compared with its last update. This command is useful to test code from
a dirty repository.
"

exit 1;
}

#####################
# Process Arguments #
#####################

: ${NIXPKGS=/etc/nixos/nixpkgs/}

vcs=""
gitCommits=""
svnRevisions=""
pathLocations=""
verbose=false

argfun=""
for arg; do
if test -z "$argfun"; then
case $arg in
--git) vcs="git"; argfun="set_gitCommits";;
--svn) vcs="svn"; argfun="set_svnRevisions";;
--path) vcs="path"; argfun="set_pathLocations";;
--verbose) verbose=true;;
--help) usage;;
*) usage;;
esac
else
case $argfun in
set_*)
var=$(echo $argfun | sed 's,^set_,,')
eval $var=$arg
;;
esac
argfun=""
fi
done

if $verbose; then
set -x
else
set +x
#!/usr/bin/env bash
set -e

if [ "$#" != 1 ] && [ "$#" != 2 ]; then
cat <<-EOF
Usage: $0 commit-spec [commit-spec]
You need to be in a git-controlled nixpkgs tree.
The current state of the tree will be used if the second commit is missing.
EOF
exit 1
fi

############################
# Find the repository type #
############################
# A slightly hacky way to get the config.
parallel="$(echo 'config.rebuild-amount.parallel or false' | nix-repl . 2>/dev/null \
| grep -v '^\(nix-repl.*\)\?$' | tail -n 1 || true)"

if test -z "$vcs"; then
if test -x "$NIXPKGS/.git"; then
if git --git-dir="$NIXPKGS/.git" branch > /dev/null 2>&1; then
vcs="git"
gitCommits=$(git --git-dir="$NIXPKGS/.git" log -n 1 --pretty=format:%H 2> /dev/null)
fi
elif test -x "$NIXPKGS/.svn"; then
cd "$NIXPKGS"
if svn info > /dev/null 2>&1; then
vcs="svn";
svnRevisions=$(svn info | sed -n 's,Revision: ,,p')
fi
cd -
else
usage
fi
fi
echo "Estimating rebuild amount by counting changed Hydra jobs."

###############################
# Define a storage directory. #
###############################
toRemove=()

pkgListDir=""
exitCode=1
cleanup(){
test -e "$pkgListDir" && rm -rf "$pkgListDir"
exit $exitCode;
cleanup() {
rm -rf "${toRemove[@]}"
}

trap cleanup EXIT SIGINT SIGQUIT ERR

pkgListDir=$(mktemp --tmpdir -d rebuild-amount-XXXXXXXX)
vcsDir="$pkgListDir/.vcs"

###########################
# Versionning for Dummies #
###########################

path_init() {
if test "${pathLocations#*:}" = "$pathLocations"; then
pathLocations="$NIXPKGS:$pathLocations"
fi
pathLocations="${pathLocations}:"
MKTEMP='mktemp --tmpdir nix-rebuild-amount-XXXXXXXX'

nixexpr() {
cat <<-EONIX
let
lib = import $1/lib;
hydraJobs = import $1/pkgs/top-level/release.nix
# Compromise: accuracy vs. resources needed for evaluation.
{ supportedSystems = cfg.systems or [ "x86_64-linux" "x86_64-darwin" ]; };
cfg = (import $1 {}).config.rebuild-amount or {};
recurseIntoAttrs = attrs: attrs // { recurseForDerivations = true; };
# hydraJobs leaves recurseForDerivations as empty attrmaps;
# that would break nix-env and we also need to recurse everywhere.
tweak = lib.mapAttrs
(name: val:
if name == "recurseForDerivations" then true
else if lib.isAttrs val && val.type or null != "derivation"
then recurseIntoAttrs (tweak val)
else val
);
# Some of these contain explicit references to platform(s) we want to avoid;
# some even (transitively) depend on ~/.nixpkgs/config.nix (!)
blacklist = [
"tarball" "metrics" "manual"
"darwin-tested" "unstable" "stdenvBootstrapTools"
"moduleSystem" "lib-tests" # these just confuse the output
];
in
tweak (builtins.removeAttrs hydraJobs blacklist)
EONIX
}

path_getNext() {
pathLoc="${pathLocations%%:*}"
pathLocations="${pathLocations#*:}"
# Output packages in tree $2 that weren't in $1.
# Changing the output hash or name is taken as a change.
# Extra nix-env parameters can be in $3
newPkgs() {
# We use files instead of pipes, as running multiple nix-env processes
# could eat too much memory for a standard 4GiB machine.
local -a list
for i in 1 2; do
local l="$($MKTEMP)"
list[$i]="$l"
toRemove+=("$l")

local expr="$($MKTEMP)"
toRemove+=("$expr")
nixexpr "${!i}" > "$expr"

nix-env -f "$expr" -qaP --no-name --out-path --show-trace $3 \
| sort > "${list[$i]}" &

if [ "$parallel" != "true" ]; then
wait
fi
done

wait
comm -13 "${list[@]}"
}

path_setPath() {
path="$pathLoc"
}

path_setName() {
name=$(echo "$pathLoc" | tr '/' '_')
}

################
# Git Commands #
################

git_init() {
git clone "$NIXPKGS/.git" "$vcsDir" > /dev/null 2>&1
if echo "gitCommits" | grep -c "\.\." > /dev/null 2>&1; then
gitCommits=$(git --git-dir="$vcsDir/.git" log --reverse --pretty=format:%H $gitCommits 2> /dev/null)
else
pathLocations="$vcsDir:$NIXPKGS"
vcs="path"
path_init
fi
}

git_getNext() {
git --git-dir="$vcsDir/.git" checkout $(echo "$gitCommits" | head -n 1) > /dev/null 2>&1
gitCommits=$(echo "$gitCommits" | sed '1 d')
}

git_setPath() {
path="$vcsDir"
}

git_setName() {
name=$(git --git-dir="$vcsDir/.git" log -n 1 --pretty=format:%H 2> /dev/null)
}

#######################
# Subversion Commands #
#######################

svn_init() {
cp -r "$NIXPKGS" "$vcsDir" > /dev/null 2>&1
if echo "svnRevisions" | grep -c ":" > /dev/null 2>&1; then
svnRevisions=$(seq ${svnRevisions%:*} ${svnRevisions#*:})
else
pathLocations="$vcsDir:$NIXPKGS"
vcs="path"
path_init
fi
}

svn_getNext() {
cd "$vcsDir"
svn checkout $(echo "$svnRevisions" | head -n 1) > /dev/null 2>&1
cd -
svnRevisions=$(echo "$svnRevisions" | sed '1 d')
}

svn_setPath() {
path="$vcsDir"
}

svn_setName() {
name=$(svn info 2> /dev/null | sed -n 's,Revision: ,,p')
}

####################
# Logical Commands #
####################

init () { ${vcs}_init; }
getNext () { ${vcs}_getNext; }
setPath () { ${vcs}_setPath; }
setName () { ${vcs}_setName; }


#####################
# Check for Rebuild #
#####################

# Generate the list of all derivations that could be build from a nixpkgs
# respository. This list of derivation hashes is compared with previous
# lists and a brief summary is produced on the output.

compareNames () {
nb=$(diff -y --suppress-common-lines --speed-large-files "$pkgListDir/$1.drvs" "$pkgListDir/$2.drvs" 2> /dev/null | wc -l)
echo "$1 -> $2: $nb"
}

echo "Please wait, this may take some minutes ..."

init
first=""
oldPrev=""

prev=""
curr=""

while true; do
getNext
setPath # set path=...
setName # set name=...
curr="$name"

test -z "$curr" && break || true

nix-instantiate "$path" > "$pkgListDir/$curr.drvs" > /dev/null 2>&1 || true

if test -n "$prev"; then
compareNames "$prev" "$curr"
else
echo "Number of package to rebuild:"
first="$curr"
fi
oldPrev="$prev"
prev="$curr"
# Prepare nixpkgs trees.
declare -a tree
for i in 1 2; do
if [ -n "${!i}" ]; then # use the given commit
dir="$($MKTEMP -d)"
tree[$i]="$dir"
toRemove+=("$dir")

git clone --shared --no-checkout --quiet . "${tree[$i]}"
(cd "${tree[$i]}" && git checkout --quiet "${!i}")
else #use the current tree
tree[$i]="$(pwd)"
fi
done

if test "$first" != "$oldPrev"; then
echo "Number of package to rebuild (first -> last):"
compareNames "$first" "$curr"
fi
newlist="$($MKTEMP)"
toRemove+=("$newlist")
# Notes:
# - the evaluation is done on x86_64-linux, like on Hydra.
# - using $newlist file so that newPkgs() isn't in a sub-shell (because of toRemove)
newPkgs "${tree[1]}" "${tree[2]}" '--argstr system "x86_64-linux"' > "$newlist"

# Hacky: keep only the last word of each attribute path and sort.
sed -n 's/\([^. ]*\.\)*\([^. ]*\) .*$/\2/p' < "$newlist" \
| sort | uniq -c

exitCode=0
243 changes: 243 additions & 0 deletions maintainers/scripts/update-python-libraries
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
#! /usr/bin/env nix-shell
#! nix-shell -i python3 -p 'python3.withPackages(ps: with ps; [ requests toolz ])'

"""
Update a Python package expression by passing in the `.nix` file, or the directory containing it.
You can pass in multiple files or paths.

You'll likely want to use
``
$ ./update-python-libraries ../../pkgs/development/python-modules/*
``
to update all libraries in that folder.
"""

import argparse
import logging
import os
import re
import requests
import toolz

INDEX = "https://pypi.io/pypi"
"""url of PyPI"""

EXTENSIONS = ['tar.gz', 'tar.bz2', 'tar', 'zip', '.whl']
"""Permitted file extensions. These are evaluated from left to right and the first occurance is returned."""

import logging
logging.basicConfig(level=logging.INFO)


def _get_values(attribute, text):
"""Match attribute in text and return all matches.

:returns: List of matches.
"""
regex = '{}\s+=\s+"(.*)";'.format(attribute)
regex = re.compile(regex)
values = regex.findall(text)
return values

def _get_unique_value(attribute, text):
"""Match attribute in text and return unique match.

:returns: Single match.
"""
values = _get_values(attribute, text)
n = len(values)
if n > 1:
raise ValueError("found too many values for {}".format(attribute))
elif n == 1:
return values[0]
else:
raise ValueError("no value found for {}".format(attribute))

def _get_line_and_value(attribute, text):
"""Match attribute in text. Return the line and the value of the attribute."""
regex = '({}\s+=\s+"(.*)";)'.format(attribute)
regex = re.compile(regex)
value = regex.findall(text)
n = len(value)
if n > 1:
raise ValueError("found too many values for {}".format(attribute))
elif n == 1:
return value[0]
else:
raise ValueError("no value found for {}".format(attribute))


def _replace_value(attribute, value, text):
"""Search and replace value of attribute in text."""
old_line, old_value = _get_line_and_value(attribute, text)
new_line = old_line.replace(old_value, value)
new_text = text.replace(old_line, new_line)
return new_text

def _fetch_page(url):
r = requests.get(url)
if r.status_code == requests.codes.ok:
return r.json()
else:
raise ValueError("request for {} failed".format(url))

def _get_latest_version_pypi(package, extension):
"""Get latest version and hash from PyPI."""
url = "{}/{}/json".format(INDEX, package)
json = _fetch_page(url)

version = json['info']['version']
for release in json['releases'][version]:
if release['filename'].endswith(extension):
# TODO: In case of wheel we need to do further checks!
sha256 = release['digests']['sha256']
break
else:
sha256 = None
return version, sha256


def _get_latest_version_github(package, extension):
raise ValueError("updating from GitHub is not yet supported.")


FETCHERS = {
'fetchFromGitHub' : _get_latest_version_github,
'fetchPypi' : _get_latest_version_pypi,
'fetchurl' : _get_latest_version_pypi,
}


DEFAULT_SETUPTOOLS_EXTENSION = 'tar.gz'


FORMATS = {
'setuptools' : DEFAULT_SETUPTOOLS_EXTENSION,
'wheel' : 'whl'
}

def _determine_fetcher(text):
# Count occurences of fetchers.
nfetchers = sum(text.count('src = {}'.format(fetcher)) for fetcher in FETCHERS.keys())
if nfetchers == 0:
raise ValueError("no fetcher.")
elif nfetchers > 1:
raise ValueError("multiple fetchers.")
else:
# Then we check which fetcher to use.
for fetcher in FETCHERS.keys():
if 'src = {}'.format(fetcher) in text:
return fetcher


def _determine_extension(text, fetcher):
"""Determine what extension is used in the expression.

If we use:
- fetchPypi, we check if format is specified.
- fetchurl, we determine the extension from the url.
- fetchFromGitHub we simply use `.tar.gz`.
"""
if fetcher == 'fetchPypi':
try:
format = _get_unique_value('format', text)
except ValueError as e:
format = None # format was not given

try:
extension = _get_unique_value('extension', text)
except ValueError as e:
extension = None # extension was not given

if extension is None:
if format is None:
format = 'setuptools'
extension = FORMATS[format]

elif fetcher == 'fetchurl':
url = _get_unique_value('url', text)
extension = os.path.splitext(url)[1]
if 'pypi' not in url:
raise ValueError('url does not point to PyPI.')

elif fetcher == 'fetchFromGitHub':
raise ValueError('updating from GitHub is not yet implemented.')

return extension


def _update_package(path):



# Read the expression
with open(path, 'r') as f:
text = f.read()

# Determine pname.
pname = _get_unique_value('pname', text)

# Determine version.
version = _get_unique_value('version', text)

# First we check how many fetchers are mentioned.
fetcher = _determine_fetcher(text)

extension = _determine_extension(text, fetcher)

new_version, new_sha256 = _get_latest_version_pypi(pname, extension)

if new_version == version:
logging.info("Path {}: no update available for {}.".format(path, pname))
return False
if not new_sha256:
raise ValueError("no file available for {}.".format(pname))

text = _replace_value('version', new_version, text)
text = _replace_value('sha256', new_sha256, text)

with open(path, 'w') as f:
f.write(text)

logging.info("Path {}: updated {} from {} to {}".format(path, pname, version, new_version))

return True


def _update(path):

# We need to read and modify a Nix expression.
if os.path.isdir(path):
path = os.path.join(path, 'default.nix')

# If a default.nix does not exist, we quit.
if not os.path.isfile(path):
logging.info("Path {}: does not exist.".format(path))
return False

# If file is not a Nix expression, we quit.
if not path.endswith(".nix"):
logging.info("Path {}: does not end with `.nix`.".format(path))
return False

try:
return _update_package(path)
except ValueError as e:
logging.warning("Path {}: {}".format(path, e))
return False

def main():

parser = argparse.ArgumentParser()
parser.add_argument('package', type=str, nargs='+')

args = parser.parse_args()

packages = map(os.path.abspath, args.package)

count = list(map(_update, packages))

logging.info("{} package(s) updated".format(sum(count)))

if __name__ == '__main__':
main()
2 changes: 1 addition & 1 deletion nixos/doc/manual/administration/imperative-containers.xml
Original file line number Diff line number Diff line change
@@ -57,7 +57,7 @@ Thus, if something went wrong, you can get status info using

</para>

<para>If the container has started succesfully, you can log in as
<para>If the container has started successfully, you can log in as
root using the <command>root-login</command> operation:

<screen>
7 changes: 7 additions & 0 deletions nixos/doc/manual/configuration/x-windows.xml
Original file line number Diff line number Diff line change
@@ -45,6 +45,13 @@ services.xserver.displayManager.lightdm.enable = true;
</programlisting>
</para>

<para>You can set the keyboard layout (and optionally the layout variant):
<programlisting>
services.xserver.layout = "de";
services.xserver.xkbVariant = "neo";
</programlisting>
</para>

<para>The X server is started automatically at boot time. If you
don’t want this to happen, you can set:
<programlisting>
Loading