diff options
Diffstat (limited to 'doc')
-rw-r--r-- | doc/doc-support/lib-function-locations.nix | 4 | ||||
-rw-r--r-- | doc/functions.xml | 1 | ||||
-rw-r--r-- | doc/functions/ocitools.xml | 76 | ||||
-rw-r--r-- | doc/languages-frameworks/python.section.md | 19 | ||||
-rw-r--r-- | doc/languages-frameworks/ruby.section.md | 365 | ||||
-rw-r--r-- | doc/package-specific-user-notes.xml | 4 | ||||
-rw-r--r-- | doc/stdenv.xml | 43 |
7 files changed, 507 insertions, 5 deletions
diff --git a/doc/doc-support/lib-function-locations.nix b/doc/doc-support/lib-function-locations.nix index ae7036e46264..68edd2709854 100644 --- a/doc/doc-support/lib-function-locations.nix +++ b/doc/doc-support/lib-function-locations.nix @@ -14,10 +14,10 @@ let builtins.map (subsetname: { subsetname = subsetname; - functions = libDefPos toplib."${subsetname}"; + functions = libDefPos toplib.${subsetname}; }) (builtins.filter - (name: builtins.isAttrs toplib."${name}") + (name: builtins.isAttrs toplib.${name}) (builtins.attrNames toplib)); nixpkgsLib = pkgs.lib; diff --git a/doc/functions.xml b/doc/functions.xml index 3b60f46d81da..96bd95958eae 100644 --- a/doc/functions.xml +++ b/doc/functions.xml @@ -20,4 +20,5 @@ <xi:include href="functions/appimagetools.xml" /> <xi:include href="functions/prefer-remote-fetch.xml" /> <xi:include href="functions/nix-gitignore.xml" /> + <xi:include href="functions/ocitools.xml" /> </chapter> diff --git a/doc/functions/ocitools.xml b/doc/functions/ocitools.xml new file mode 100644 index 000000000000..163bee2382e6 --- /dev/null +++ b/doc/functions/ocitools.xml @@ -0,0 +1,76 @@ +<section xmlns="http://docbook.org/ns/docbook" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:xi="http://www.w3.org/2001/XInclude" + xml:id="sec-pkgs-ociTools"> + <title>pkgs.ociTools</title> + + <para> + <varname>pkgs.ociTools</varname> is a set of functions for creating + containers according to the + <link xlink:href="https://github.com/opencontainers/runtime-spec">OCI + container specification v1.0.0</link>. Beyond that it makes no assumptions + about the container runner you choose to use to run the created container. + </para> + + <section xml:id="ssec-pkgs-ociTools-buildContainer"> + <title>buildContainer</title> + + <para> + This function creates a simple OCI container that runs a single command + inside of it. An OCI container consists of a <varname>config.json</varname> + and a rootfs directory.The nix store of the container will contain all + referenced dependencies of the given command. + </para> + + <para> + The parameters of <varname>buildContainer</varname> with an example value + are described below: + </para> + + <example xml:id='ex-ociTools-buildContainer'> + <title>Build Container</title> +<programlisting> +buildContainer { + args = [ (with pkgs; writeScript "run.sh" '' + #!${bash}/bin/bash + ${coreutils}/bin/exec ${bash}/bin/bash + '').outPath ]; <co xml:id='ex-ociTools-buildContainer-1' /> + + mounts = { + "/data" = { + type = "none"; + source = "/var/lib/mydata"; + options = [ "bind" ]; + }; + };<co xml:id='ex-ociTools-buildContainer-2' /> + + readonly = false; <co xml:id='ex-ociTools-buildContainer-3' /> +} + + </programlisting> + <calloutlist> + <callout arearefs='ex-ociTools-buildContainer-1'> + <para> + <varname>args</varname> specifies a set of arguments to run inside the container. + This is the only required argument for <varname>buildContainer</varname>. + All referenced packages inside the derivation will be made available + inside the container + </para> + </callout> + <callout arearefs='ex-ociTools-buildContainer-2'> + <para> + <varname>mounts</varname> specifies additional mount points chosen by the + user. By default only a minimal set of necessary filesystems are mounted + into the container (e.g procfs, cgroupfs) + </para> + </callout> + <callout arearefs='ex-ociTools-buildContainer-3'> + <para> + <varname>readonly</varname> makes the container's rootfs read-only if it is set to true. + The default value is false <literal>false</literal>. + </para> + </callout> + </calloutlist> + </example> + </section> +</section> diff --git a/doc/languages-frameworks/python.section.md b/doc/languages-frameworks/python.section.md index 4963c97a6c9a..88dc42ebc6c2 100644 --- a/doc/languages-frameworks/python.section.md +++ b/doc/languages-frameworks/python.section.md @@ -540,7 +540,8 @@ and the aliases #### `buildPythonPackage` function The `buildPythonPackage` function is implemented in -`pkgs/development/interpreters/python/build-python-package.nix` +`pkgs/development/interpreters/python/mk-python-derivation` +using setup hooks. The following is an example: ```nix @@ -797,6 +798,22 @@ such as `ignoreCollisions = true` or `postBuild`. If you need them, you have to Python 2 namespace packages may provide `__init__.py` that collide. In that case `python.buildEnv` should be used with `ignoreCollisions = true`. +#### Setup hooks + +The following are setup hooks specifically for Python packages. Most of these are +used in `buildPythonPackage`. + +- `flitBuildHook` to build a wheel using `flit`. +- `pipBuildHook` to build a wheel using `pip` and PEP 517. Note a build system (e.g. `setuptools` or `flit`) should still be added as `nativeBuildInput`. +- `pipInstallHook` to install wheels. +- `pytestCheckHook` to run tests with `pytest`. +- `pythonCatchConflictsHook` to check whether a Python package is not already existing. +- `pythonImportsCheckHook` to check whether importing the listed modules works. +- `pythonRemoveBinBytecode` to remove bytecode from the `/bin` folder. +- `setuptoolsBuildHook` to build a wheel using `setuptools`. +- `setuptoolsCheckHook` to run tests with `python setup.py test`. +- `wheelUnpackHook` to move a wheel to the correct folder so it can be installed with the `pipInstallHook`. + ### Development mode Development or editable mode is supported. To develop Python packages diff --git a/doc/languages-frameworks/ruby.section.md b/doc/languages-frameworks/ruby.section.md new file mode 100644 index 000000000000..e4c4ffce0432 --- /dev/null +++ b/doc/languages-frameworks/ruby.section.md @@ -0,0 +1,365 @@ +--- +title: Ruby +author: Michael Fellinger +date: 2019-05-23 +--- + +# Ruby + +## User Guide + +### Using Ruby + +#### Overview + +Several versions of Ruby interpreters are available on Nix, as well as over 250 gems and many applications written in Ruby. +The attribute `ruby` refers to the default Ruby interpreter, which is currently +MRI 2.5. It's also possible to refer to specific versions, e.g. `ruby_2_6`, `jruby`, or `mruby`. + +In the nixpkgs tree, Ruby packages can be found throughout, depending on what +they do, and are called from the main package set. Ruby gems, however are +separate sets, and there's one default set for each interpreter (currently MRI +only). + +There are two main approaches for using Ruby with gems. +One is to use a specifically locked `Gemfile` for an application that has very strict dependencies. +The other is to depend on the common gems, which we'll explain further down, and +rely on them being updated regularly. + +The interpreters have common attributes, namely `gems`, and `withPackages`. So +you can refer to `ruby.gems.nokogiri`, or `ruby_2_5.gems.nokogiri` to get the +Nokogiri gem already compiled and ready to use. + +Since not all gems have executables like `nokogiri`, it's usually more +convenient to use the `withPackages` function like this: +`ruby.withPackages (p: with p; [ nokogiri ])`. This will also make sure that the +Ruby in your environment will be able to find the gem and it can be used in your +Ruby code (for example via `ruby` or `irb` executables) via `require "nokogiri"` +as usual. + +#### Temporary Ruby environment with `nix-shell` + +Rather than having a single Ruby environment shared by all Ruby +development projects on a system, Nix allows you to create separate +environments per project. `nix-shell` gives you the possibility to +temporarily load another environment akin to a combined `chruby` or +`rvm` and `bundle exec`. + +There are two methods for loading a shell with Ruby packages. The first and +recommended method is to create an environment with `ruby.withPackages` and load +that. + +```shell +nix-shell -p "ruby.withPackages (ps: with ps; [ nokogiri pry ])" +``` + +The other method, which is not recommended, is to create an environment and list +all the packages directly. + +```shell +nix-shell -p ruby.gems.nokogiri ruby.gems.pry +``` + +Again, it's possible to launch the interpreter from the shell. The Ruby +interpreter has the attribute `gems` which contains all Ruby gems for that +specific interpreter. + +##### Load environment from `.nix` expression + +As explained in the Nix manual, `nix-shell` can also load an expression from a +`.nix` file. Say we want to have Ruby 2.5, `nokogori`, and `pry`. Consider a +`shell.nix` file with: + +```nix +with import <nixpkgs> {}; +ruby.withPackages (ps: with ps; [ nokogiri pry ]) +``` + +What's happening here? + +1. We begin with importing the Nix Packages collections. `import <nixpkgs>` + imports the `<nixpkgs>` function, `{}` calls it and the `with` statement + brings all attributes of `nixpkgs` in the local scope. These attributes form + the main package set. +2. Then we create a Ruby environment with the `withPackages` function. +3. The `withPackages` function expects us to provide a function as an argument + that takes the set of all ruby gems and returns a list of packages to include + in the environment. Here, we select the packages `nokogiri` and `pry` from + the package set. + +##### Execute command with `--run` + +A convenient flag for `nix-shell` is `--run`. It executes a command in the +`nix-shell`. We can e.g. directly open a `pry` REPL: + +```shell +nix-shell -p "ruby.withPackages (ps: with ps; [ nokogiri pry ])" --run "pry" +``` + +Or immediately require `nokogiri` in pry: + +```shell +nix-shell -p "ruby.withPackages (ps: with ps; [ nokogiri pry ])" --run "pry -rnokogiri" +``` + +Or run a script using this environment: + +```shell +nix-shell -p "ruby.withPackages (ps: with ps; [ nokogiri pry ])" --run "ruby example.rb" +``` + +##### Using `nix-shell` as shebang + +In fact, for the last case, there is a more convenient method. You can add a +[shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)) to your script +specifying which dependencies `nix-shell` needs. With the following shebang, you +can just execute `./example.rb`, and it will run with all dependencies. + +```ruby +#! /usr/bin/env nix-shell +#! nix-shell -i ruby -p "ruby.withPackages (ps: with ps; [ nokogiri rest-client ])" + +require 'nokogiri' +require 'rest-client' + +body = RestClient.get('http://example.com').body +puts Nokogiri::HTML(body).at('h1').text +``` + +### Developing with Ruby + +#### Using an existing Gemfile + +In most cases, you'll already have a `Gemfile.lock` listing all your dependencies. +This can be used to generate a `gemset.nix` which is used to fetch the gems and +combine them into a single environment. +The reason why you need to have a separate file for this, is that Nix requires +you to have a checksum for each input to your build. +Since the `Gemfile.lock` that `bundler` generates doesn't provide us with +checksums, we have to first download each gem, calculate its SHA256, and store +it in this separate file. + +So the steps from having just a `Gemfile` to a `gemset.nix` are: + +```shell +bundle lock +bundix +``` + +If you already have a `Gemfile.lock`, you can simply run `bundix` and it will +work the same. + +To update the gems in your `Gemfile.lock`, you may use the `bundix -l` flag, +which will create a new `Gemfile.lock` in case the `Gemfile` has a more recent +time of modification. + +Once the `gemset.nix` is generated, it can be used in a +`bundlerEnv` derivation. Here is an example you could use for your `shell.nix`: + +```nix +# ... +let + gems = bundlerEnv { + name = "gems-for-some-project"; + gemdir = ./.; + }; +in mkShell { buildInputs = [ gems gems.wrappedRuby ]; } +``` + +With this file in your directory, you can run `nix-shell` to build and use the gems. +The important parts here are `bundlerEnv` and `wrappedRuby`. + +The `bundlerEnv` is a wrapper over all the gems in your gemset. This means that +all the `/lib` and `/bin` directories will be available, and the executables of +all gems (even of indirect dependencies) will end up in your `$PATH`. +The `wrappedRuby` provides you with all executables that come with Ruby itself, +but wrapped so they can easily find the gems in your gemset. + +One common issue that you might have is that you have Ruby 2.6, but also +`bundler` in your gemset. That leads to a conflict for `/bin/bundle` and +`/bin/bundler`. You can resolve this by wrapping either your Ruby or your gems +in a `lowPrio` call. So in order to give the `bundler` from your gemset +priority, it would be used like this: + +```nix +# ... +mkShell { buildInputs = [ gems (lowPrio gems.wrappedRuby) ]; } +``` + + +#### Gem-specific configurations and workarounds + +In some cases, especially if the gem has native extensions, you might need to +modify the way the gem is built. + +This is done via a common configuration file that includes all of the +workarounds for each gem. + +This file lives at `/pkgs/development/ruby-modules/gem-config/default.nix`, +since it already contains a lot of entries, it should be pretty easy to add the +modifications you need for your needs. + +In the meanwhile, or if the modification is for a private gem, you can also add +the configuration to only your own environment. + +Two places that allow this modification are the `ruby` derivation, or `bundlerEnv`. + +Here's the `ruby` one: + +```nix +{ pg_version ? "10", pkgs ? import <nixpkgs> { } }: +let + myRuby = pkgs.ruby.override { + defaultGemConfig = pkgs.defaultGemConfig // { + pg = attrs: { + buildFlags = + [ "--with-pg-config=${pkgs."postgresql_${pg_version}"}/bin/pg_config" ]; + }; + }; + }; +in myRuby.withPackages (ps: with ps; [ pg ]) +``` + +And an example with `bundlerEnv`: + +```nix +{ pg_version ? "10", pkgs ? import <nixpkgs> { } }: +let + gems = pkgs.bundlerEnv { + name = "gems-for-some-project"; + gemdir = ./.; + gemConfig = pkgs.defaultGemConfig // { + pg = attrs: { + buildFlags = + [ "--with-pg-config=${pkgs."postgresql_${pg_version}"}/bin/pg_config" ]; + }; + }; + }; +in mkShell { buildInputs = [ gems gems.wrappedRuby ]; } +``` + +And finally via overlays: + +```nix +{ pg_version ? "10" }: +let + pkgs = import <nixpkgs> { + overlays = [ + (self: super: { + defaultGemConfig = super.defaultGemConfig // { + pg = attrs: { + buildFlags = [ + "--with-pg-config=${ + pkgs."postgresql_${pg_version}" + }/bin/pg_config" + ]; + }; + }; + }) + ]; + }; +in pkgs.ruby.withPackages (ps: with ps; [ pg ]) +``` + +Then we can get whichever postgresql version we desire and the `pg` gem will +always reference it correctly: + +```shell +$ nix-shell --argstr pg_version 9_4 --run 'ruby -rpg -e "puts PG.library_version"' +90421 + +$ nix-shell --run 'ruby -rpg -e "puts PG.library_version"' +100007 +``` + +Of course for this use-case one could also use overlays since the configuration +for `pg` depends on the `postgresql` alias, but for demonstration purposes this +has to suffice. + +#### Adding a gem to the default gemset + +Now that you know how to get a working Ruby environment with Nix, it's time to +go forward and start actually developing with Ruby. +We will first have a look at how Ruby gems are packaged on Nix. Then, we will +look at how you can use development mode with your code. + +All gems in the standard set are automatically generated from a single +`Gemfile`. The dependency resolution is done with `bundler` and makes it more +likely that all gems are compatible to each other. + +In order to add a new gem to nixpkgs, you can put it into the +`/pkgs/development/ruby-modules/with-packages/Gemfile` and run +`./maintainers/scripts/update-ruby-packages`. + +To test that it works, you can then try using the gem with: + +```shell +NIX_PATH=nixpkgs=$PWD nix-shell -p "ruby.withPackages (ps: with ps; [ name-of-your-gem ])" +``` + +#### Packaging applications + +A common task is to add a ruby executable to nixpkgs, popular examples would be +`chef`, `jekyll`, or `sass`. A good way to do that is to use the `bundlerApp` +function, that allows you to make a package that only exposes the listed +executables, otherwise the package may cause conflicts through common paths like +`bin/rake` or `bin/bundler` that aren't meant to be used. + +The absolute easiest way to do that is to write a +`Gemfile` along these lines: + +```ruby +source 'https://rubygems.org' do + gem 'mdl' +end +``` + +If you want to package a specific version, you can use the standard Gemfile +syntax for that, e.g. `gem 'mdl', '0.5.0'`, but if you want the latest stable +version anyway, it's easier to update by simply running the `bundle lock` and +`bundix` steps again. + +Now you can also also make a `default.nix` that looks like this: + +```nix +{ lib, bundlerApp }: + +bundlerApp { + pname = "mdl"; + gemdir = ./.; + exes = [ "mdl" ]; +} +``` + +All that's left to do is to generate the corresponding `Gemfile.lock` and +`gemset.nix` as described above in the `Using an existing Gemfile` section. + +##### Packaging executables that require wrapping + +Sometimes your app will depend on other executables at runtime, and tries to +find it through the `PATH` environment variable. + +In this case, you can provide a `postBuild` hook to `bundlerApp` that wraps the +gem in another script that prefixes the `PATH`. + +Of course you could also make a custom `gemConfig` if you know exactly how to +patch it, but it's usually much easier to maintain with a simple wrapper so the +patch doesn't have to be adjusted for each version. + +Here's another example: + +```nix +{ lib, bundlerApp, makeWrapper, git, gnutar, gzip }: + +bundlerApp { + pname = "r10k"; + gemdir = ./.; + exes = [ "r10k" ]; + + buildInputs = [ makeWrapper ]; + + postBuild = '' + wrapProgram $out/bin/r10k --prefix PATH : ${lib.makeBinPath [ git gnutar gzip ]} + ''; +} +``` diff --git a/doc/package-specific-user-notes.xml b/doc/package-specific-user-notes.xml index 196c760251f0..a176f4d13959 100644 --- a/doc/package-specific-user-notes.xml +++ b/doc/package-specific-user-notes.xml @@ -6,7 +6,7 @@ answer some of the frequently asked questions related to Nixpkgs use. - Some useful information related to package use + Some useful information related to package use can be found in <link linkend="chap-package-notes">package-specific development notes</link>. </para> @@ -196,7 +196,7 @@ overrides = self: super: rec { haskell-mode = self.melpaPackages.haskell-mode; ... }; -((emacsPackagesNgGen emacs).overrideScope' overrides).emacsWithPackages (p: with p; [ +((emacsPackagesGen emacs).overrideScope' overrides).emacsWithPackages (p: with p; [ # here both these package will use haskell-mode of our own choice ghc-mod dante diff --git a/doc/stdenv.xml b/doc/stdenv.xml index fe5929656565..15a13ba49e8e 100644 --- a/doc/stdenv.xml +++ b/doc/stdenv.xml @@ -2716,6 +2716,49 @@ nativeBuildInputs = [ breakpointHook ]; </varlistentry> <varlistentry> <term> + installShellFiles + </term> + <listitem> + <para> + This hook helps with installing manpages and shell completion files. It + exposes 2 shell functions <literal>installManPage</literal> and + <literal>installShellCompletion</literal> that can be used from your + <literal>postInstall</literal> hook. + </para> + <para> + The <literal>installManPage</literal> function takes one or more paths + to manpages to install. The manpages must have a section suffix, and may + optionally be compressed (with <literal>.gz</literal> suffix). This + function will place them into the correct directory. + </para> + <para> + The <literal>installShellCompletion</literal> function takes one or more + paths to shell completion files. By default it will autodetect the shell + type from the completion file extension, but you may also specify it by + passing one of <literal>--bash</literal>, <literal>--fish</literal>, or + <literal>--zsh</literal>. These flags apply to all paths listed after + them (up until another shell flag is given). Each path may also have a + custom installation name provided by providing a flag <literal>--name + NAME</literal> before the path. If this flag is not provided, zsh + completions will be renamed automatically such that + <literal>foobar.zsh</literal> becomes <literal>_foobar</literal>. +<programlisting> +nativeBuildInputs = [ installShellFiles ]; +postInstall = '' + installManPage doc/foobar.1 doc/barfoo.3 + # explicit behavior + installShellCompletion --bash --name foobar.bash share/completions.bash + installShellCompletion --fish --name foobar.fish share/completions.fish + installShellCompletion --zsh --name _foobar share/completions.zsh + # implicit behavior + installShellCompletion share/completions/foobar.{bash,fish,zsh} +''; +</programlisting> + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> libiconv, libintl </term> <listitem> |