···5353To [backport a change into a release branch](https://nixos.org/nixpkgs/manual/#submitting-changes-stable-release-branches):
545455551. Take note of the commit in which the change was introduced into `master`.
5656-2. Check out the target _release branch_, e.g. `release-19.09`. Do not use a _channel branch_ like `nixos-19.09` or `nixpkgs-19.09`.
5656+2. Check out the target _release branch_, e.g. `release-20.03`. Do not use a _channel branch_ like `nixos-20.03` or `nixpkgs-20.03`.
57573. Use `git cherry-pick -x <original commit>`.
5858-4. Open your backport PR. Make sure to select the release branch (e.g. `release-19.09`) as the target branch of the PR, and link to the PR in which the original change was made to `master`.
5858+4. Open your backport PR. Make sure to select the release branch (e.g. `release-20.03`) as the target branch of the PR, and link to the PR in which the original change was made to `master`.
59596060## Reviewing contributions
6161
+2-2
README.md
···4545system, [Hydra](https://hydra.nixos.org/).
46464747* [Continuous package builds for unstable/master](https://hydra.nixos.org/jobset/nixos/trunk-combined)
4848-* [Continuous package builds for the NixOS 19.09 release](https://hydra.nixos.org/jobset/nixos/release-19.09)
4848+* [Continuous package builds for the NixOS 20.03 release](https://hydra.nixos.org/jobset/nixos/release-20.03)
4949* [Tests for unstable/master](https://hydra.nixos.org/job/nixos/trunk-combined/tested#tabs-constituents)
5050-* [Tests for the NixOS 19.09 release](https://hydra.nixos.org/job/nixos/release-19.09/tested#tabs-constituents)
5050+* [Tests for the NixOS 20.03 release](https://hydra.nixos.org/job/nixos/release-20.03/tested#tabs-constituents)
51515252Artifacts successfully built with Hydra are published to cache at
5353https://cache.nixos.org/. When successful build and test criteria are
···412412413413 meta = with lib; {
414414 description = "A pythonic wrapper around FFTW, the FFT library, presenting a unified interface for all the supported transforms";
415415- homepage = http://hgomersall.github.com/pyFFTW;
415415+ homepage = "http://hgomersall.github.com/pyFFTW";
416416 license = with licenses; [ bsd2 bsd3 ];
417417 maintainers = with maintainers; [ fridh ];
418418 };
+2-2
doc/languages-frameworks/ruby.xml
···32323333 meta = with lib; {
3434 description = "A monitoring framework that aims to be simple, malleable, and scalable";
3535- homepage = http://sensuapp.org/;
3535+ homepage = "http://sensuapp.org/";
3636 license = with licenses; mit;
3737 maintainers = with maintainers; [ theuni ];
3838 platforms = platforms.unix;
···69697070 meta = with lib; {
7171 description = "Tool and libraries for maintaining Ruby gems.";
7272- homepage = https://github.com/nyarly/corundum;
7272+ homepage = "https://github.com/nyarly/corundum";
7373 license = licenses.mit;
7474 maintainers = [ maintainers.nyarly ];
7575 platforms = platforms.unix;
-27
doc/languages-frameworks/texlive.xml
···149149]]></programlisting>
150150 </para>
151151 </section>
152152-153153- <section xml:id="sec-language-texlive-known-problems">
154154- <title>Known problems</title>
155155-156156- <itemizedlist>
157157- <listitem>
158158- <para>
159159- Some tools are still missing, e.g. luajittex;
160160- </para>
161161- </listitem>
162162- <listitem>
163163- <para>
164164- some apps aren't packaged/tested yet (asymptote, biber, etc.);
165165- </para>
166166- </listitem>
167167- <listitem>
168168- <para>
169169- feature/bug: when a package is rejected by <varname>pkgFilter</varname>, its dependencies are still propagated;
170170- </para>
171171- </listitem>
172172- <listitem>
173173- <para>
174174- in case of any bugs or feature requests, file a github issue or better a pull request and /cc @vcunat.
175175- </para>
176176- </listitem>
177177- </itemizedlist>
178178- </section>
179152</section>
···190190 The function <function>fetchurl</function> now has support for two different kinds of mirroring of files. First, it has support for <emphasis>content-addressable mirrors</emphasis>. For example, given the <function>fetchurl</function> call
191191<programlisting>
192192fetchurl {
193193- url = http://releases.mozilla.org/<replaceable>...</replaceable>/firefox-2.0.0.6-source.tar.bz2;
193193+ url = "http://releases.mozilla.org/<replaceable>...</replaceable>/firefox-2.0.0.6-source.tar.bz2";
194194 sha1 = "eb72f55e4a8bf08e8c6ef227c0ade3d068ba1082";
195195}</programlisting>
196196 <function>fetchurl</function> will first try to download this file from <link
···1414 <para>
1515 <emphasis>Stable channels</emphasis>, such as
1616 <literal
1717- xlink:href="https://nixos.org/channels/nixos-19.09">nixos-19.09</literal>.
1717+ xlink:href="https://nixos.org/channels/nixos-20.03">nixos-20.03</literal>.
1818 These only get conservative bug fixes and package upgrades. For instance,
1919 a channel update may cause the Linux kernel on your system to be upgraded
2020 from 4.19.34 to 4.19.38 (a minor bug fix), but not from
···3838 <para>
3939 <emphasis>Small channels</emphasis>, such as
4040 <literal
4141- xlink:href="https://nixos.org/channels/nixos-19.09-small">nixos-19.09-small</literal>
4141+ xlink:href="https://nixos.org/channels/nixos-20.03-small">nixos-20.03-small</literal>
4242 or
4343 <literal
4444 xlink:href="https://nixos.org/channels/nixos-unstable-small">nixos-unstable-small</literal>.
···6363 <para>
6464 When you first install NixOS, you’re automatically subscribed to the NixOS
6565 channel that corresponds to your installation source. For instance, if you
6666- installed from a 19.09 ISO, you will be subscribed to the
6767- <literal>nixos-19.09</literal> channel. To see which NixOS channel you’re
6666+ installed from a 20.03 ISO, you will be subscribed to the
6767+ <literal>nixos-20.03</literal> channel. To see which NixOS channel you’re
6868 subscribed to, run the following as root:
6969<screen>
7070# nix-channel --list | grep nixos
···7575# nix-channel --add https://nixos.org/channels/<replaceable>channel-name</replaceable> nixos
7676</screen>
7777 (Be sure to include the <literal>nixos</literal> parameter at the end.) For
7878- instance, to use the NixOS 19.09 stable channel:
7878+ instance, to use the NixOS 20.03 stable channel:
7979<screen>
8080-# nix-channel --add https://nixos.org/channels/nixos-19.09 nixos
8080+# nix-channel --add https://nixos.org/channels/nixos-20.03 nixos
8181</screen>
8282 If you have a server, you may want to use the “small” channel instead:
8383<screen>
8484-# nix-channel --add https://nixos.org/channels/nixos-19.09-small nixos
8484+# nix-channel --add https://nixos.org/channels/nixos-20.03-small nixos
8585</screen>
8686 And if you want to live on the bleeding edge:
8787<screen>
···132132 kernel, initrd or kernel modules.
133133 You can also specify a channel explicitly, e.g.
134134<programlisting>
135135-<xref linkend="opt-system.autoUpgrade.channel"/> = https://nixos.org/channels/nixos-19.09;
135135+<xref linkend="opt-system.autoUpgrade.channel"/> = https://nixos.org/channels/nixos-20.03;
136136</programlisting>
137137 </para>
138138 </section>
···180180 ) )
181181 {
182182 # we need e.g. brcmfmac43602-pcie.bin
183183- push @imports, "<nixpkgs/nixos/modules/hardware/network/broadcom-43xx.nix>";
183183+ push @imports, "(modulesPath + \"/hardware/network/broadcom-43xx.nix\")";
184184 }
185185186186 # Can't rely on $module here, since the module may not be loaded
···279279280280# Likewise for QEMU.
281281if ($virt eq "qemu" || $virt eq "kvm" || $virt eq "bochs") {
282282- push @imports, "<nixpkgs/nixos/modules/profiles/qemu-guest.nix>";
282282+ push @imports, "(modulesPath + \"/profiles/qemu-guest.nix\")";
283283}
284284285285# Also for Hyper-V.
···296296297297# Provide firmware for devices that are not detected by this script,
298298# unless we're in a VM/container.
299299-push @imports, "<nixpkgs/nixos/modules/installer/scan/not-detected.nix>"
299299+push @imports, "(modulesPath + \"/installer/scan/not-detected.nix\")"
300300 if $virt eq "none";
301301302302···549549# Do not modify this file! It was generated by ‘nixos-generate-config’
550550# and may be overwritten by future invocations. Please make changes
551551# to /etc/nixos/configuration.nix instead.
552552-{ config, lib, pkgs, ... }:
552552+{ config, lib, pkgs, modulesPath, ... }:
553553554554{
555555 imports =${\multiLineList(" ", @imports)};
···7788{
99 meta = {
1010- maintainers = [ maintainers.joachifm ];
1010+ maintainers = [ maintainers.joachifm maintainers.emily ];
1111 };
12121313 boot.kernelPackages = mkDefault pkgs.linuxPackages_hardened;
···21212222 security.lockKernelModules = mkDefault true;
23232424- security.allowUserNamespaces = mkDefault false;
2525-2624 security.protectKernelImage = mkDefault true;
27252826 security.allowSimultaneousMultithreading = mkDefault false;
···3735 # Slab/slub sanity checks, redzoning, and poisoning
3836 "slub_debug=FZP"
39374040- # Disable slab merging to make certain heap overflow attacks harder
4141- "slab_nomerge"
4242-4338 # Overwrite free'd memory
4439 "page_poison=1"
4545-4646- # Disable legacy virtual syscalls
4747- "vsyscall=none"
48404941 # Enable page allocator randomization
5042 "page_alloc.shuffle=1"
···8274 # (e.g., parent/child)
8375 boot.kernel.sysctl."kernel.yama.ptrace_scope" = mkOverride 500 1;
84768585- # Restrict access to kernel ring buffer (information leaks)
8686- boot.kernel.sysctl."kernel.dmesg_restrict" = mkDefault true;
8787-8877 # Hide kptrs even for processes with CAP_SYSLOG
8978 boot.kernel.sysctl."kernel.kptr_restrict" = mkOverride 500 2;
90799191- # Unprivileged access to bpf() has been used for privilege escalation in
9292- # the past
9393- boot.kernel.sysctl."kernel.unprivileged_bpf_disabled" = mkDefault true;
9494-9580 # Disable bpf() JIT (to eliminate spray attacks)
9681 boot.kernel.sysctl."net.core.bpf_jit_enable" = mkDefault false;
97829898- # ... or at least apply some hardening to it
9999- boot.kernel.sysctl."net.core.bpf_jit_harden" = mkDefault true;
100100-101101- # Raise ASLR entropy for 64bit & 32bit, respectively.
102102- #
103103- # Note: mmap_rnd_compat_bits may not exist on 64bit.
104104- boot.kernel.sysctl."vm.mmap_rnd_bits" = mkDefault 32;
105105- boot.kernel.sysctl."vm.mmap_rnd_compat_bits" = mkDefault 16;
106106-107107- # Allowing users to mmap() memory starting at virtual address 0 can turn a
108108- # NULL dereference bug in the kernel into code execution with elevated
109109- # privilege. Mitigate by enforcing a minimum base addr beyond the NULL memory
110110- # space. This breaks applications that require mapping the 0 page, such as
111111- # dosemu or running 16bit applications under wine. It also breaks older
112112- # versions of qemu.
113113- #
114114- # The value is taken from the KSPP recommendations (Debian uses 4096).
115115- boot.kernel.sysctl."vm.mmap_min_addr" = mkDefault 65536;
116116-11783 # Disable ftrace debugging
11884 boot.kernel.sysctl."kernel.ftrace_enabled" = mkDefault false;
11985···140106 # Ignore outgoing ICMP redirects (this is ipv4 only)
141107 boot.kernel.sysctl."net.ipv4.conf.all.send_redirects" = mkDefault false;
142108 boot.kernel.sysctl."net.ipv4.conf.default.send_redirects" = mkDefault false;
143143-144144- # Restrict userfaultfd syscalls to processes with the SYS_PTRACE capability
145145- boot.kernel.sysctl."vm.unprivileged_userfaultfd" = mkDefault false;
146109}
+6-1
nixos/modules/security/acme.nix
···343343344344 # Test that existing cert is older than new cert
345345 KEY=${spath}/certificates/${keyName}.key
346346+ KEY_CHANGED=no
346347 if [ -e $KEY -a $KEY -nt key.pem ]; then
348348+ KEY_CHANGED=yes
347349 cp -p ${spath}/certificates/${keyName}.key key.pem
348350 cp -p ${spath}/certificates/${keyName}.crt fullchain.pem
349351 cp -p ${spath}/certificates/${keyName}.issuer.crt chain.pem
···354356 chmod ${fileMode} *.pem
355357 chown '${data.user}:${data.group}' *.pem
356358357357- ${data.postRun}
359359+ if [ "$KEY_CHANGED" = "yes" ]; then
360360+ : # noop in case postRun is empty
361361+ ${data.postRun}
362362+ fi
358363 '';
359364 in
360365 "+${script}";
+1-1
nixos/modules/services/databases/cockroachdb.nix
···153153 defaultText = "pkgs.cockroachdb";
154154 description = ''
155155 The CockroachDB derivation to use for running the service.
156156-156156+157157 This would primarily be useful to enable Enterprise Edition features
158158 in your own custom CockroachDB build (Nixpkgs CockroachDB binaries
159159 only contain open source features and open source code).
···33let
4455 inherit (lib) mkEnableOption mkForce mkIf mkMerge mkOption optionalAttrs recursiveUpdate types;
66+ inherit (lib) concatMapStringsSep flatten mapAttrs mapAttrs' mapAttrsToList nameValuePair concatMapStringSep;
6777- cfg = config.services.dokuwiki;
88+ eachSite = config.services.dokuwiki;
8999- user = config.services.nginx.user;
1010+ user = "dokuwiki";
1011 group = config.services.nginx.group;
11121212- dokuwikiAclAuthConfig = pkgs.writeText "acl.auth.php" ''
1313+ dokuwikiAclAuthConfig = cfg: pkgs.writeText "acl.auth.php" ''
1314 # acl.auth.php
1415 # <?php exit()?>
1516 #
···1819 ${toString cfg.acl}
1920 '';
20212121- dokuwikiLocalConfig = pkgs.writeText "local.php" ''
2222+ dokuwikiLocalConfig = cfg: pkgs.writeText "local.php" ''
2223 <?php
2324 $conf['savedir'] = '${cfg.stateDir}';
2425 $conf['superuser'] = '${toString cfg.superUser}';
2526 $conf['useacl'] = '${toString cfg.aclUse}';
2727+ $conf['disableactions'] = '${cfg.disableActions}';
2628 ${toString cfg.extraConfig}
2729 '';
28302929- dokuwikiPluginsLocalConfig = pkgs.writeText "plugins.local.php" ''
3131+ dokuwikiPluginsLocalConfig = cfg: pkgs.writeText "plugins.local.php" ''
3032 <?php
3133 ${cfg.pluginsConfig}
3234 '';
33353434-in
3535-{
3636- options.services.dokuwiki = {
3737- enable = mkEnableOption "DokuWiki web application.";
3636+ pkg = hostName: cfg: pkgs.stdenv.mkDerivation rec {
3737+ pname = "dokuwiki-${hostName}";
3838+ version = src.version;
3939+ src = cfg.package;
38403939- hostName = mkOption {
4040- type = types.str;
4141- default = "localhost";
4242- description = "FQDN for the instance.";
4343- };
4141+ installPhase = ''
4242+ mkdir -p $out
4343+ cp -r * $out/
44444545- stateDir = mkOption {
4646- type = types.path;
4747- default = "/var/lib/dokuwiki/data";
4848- description = "Location of the dokuwiki state directory.";
4949- };
4545+ # symlink the dokuwiki config
4646+ ln -s ${dokuwikiLocalConfig cfg} $out/share/dokuwiki/local.php
50475151- acl = mkOption {
5252- type = types.nullOr types.lines;
5353- default = null;
5454- example = "* @ALL 8";
5555- description = ''
5656- Access Control Lists: see <link xlink:href="https://www.dokuwiki.org/acl"/>
5757- Mutually exclusive with services.dokuwiki.aclFile
5858- Set this to a value other than null to take precedence over aclFile option.
5959- '';
6060- };
4848+ # symlink plugins config
4949+ ln -s ${dokuwikiPluginsLocalConfig cfg} $out/share/dokuwiki/plugins.local.php
5050+5151+ # symlink acl
5252+ ln -s ${dokuwikiAclAuthConfig cfg} $out/share/dokuwiki/acl.auth.php
5353+5454+ # symlink additional plugin(s) and templates(s)
5555+ ${concatMapStringsSep "\n" (template: "ln -s ${template} $out/share/dokuwiki/lib/tpl/${template.name}") cfg.templates}
5656+ ${concatMapStringsSep "\n" (plugin: "ln -s ${plugin} $out/share/dokuwiki/lib/plugins/${plugin.name}") cfg.plugins}
5757+ '';
5858+ };
61596262- aclFile = mkOption {
6363- type = types.nullOr types.path;
6464- default = null;
6565- description = ''
6666- Location of the dokuwiki acl rules. Mutually exclusive with services.dokuwiki.acl
6767- Mutually exclusive with services.dokuwiki.acl which is preferred.
6868- Consult documentation <link xlink:href="https://www.dokuwiki.org/acl"/> for further instructions.
6969- Example: <link xlink:href="https://github.com/splitbrain/dokuwiki/blob/master/conf/acl.auth.php.dist"/>
7070- '';
7171- };
6060+ siteOpts = { config, lib, name, ...}: {
6161+ options = {
6262+ enable = mkEnableOption "DokuWiki web application.";
72637373- aclUse = mkOption {
7474- type = types.bool;
7575- default = true;
7676- description = ''
7777- Necessary for users to log in into the system.
7878- Also limits anonymous users. When disabled,
7979- everyone is able to create and edit content.
8080- '';
8181- };
6464+ package = mkOption {
6565+ type = types.package;
6666+ default = pkgs.dokuwiki;
6767+ description = "Which dokuwiki package to use.";
6868+ };
82698383- pluginsConfig = mkOption {
8484- type = types.lines;
8585- default = ''
8686- $plugins['authad'] = 0;
8787- $plugins['authldap'] = 0;
8888- $plugins['authmysql'] = 0;
8989- $plugins['authpgsql'] = 0;
9090- '';
9191- description = ''
9292- List of the dokuwiki (un)loaded plugins.
9393- '';
9494- };
7070+ hostName = mkOption {
7171+ type = types.str;
7272+ default = "localhost";
7373+ description = "FQDN for the instance.";
7474+ };
95759696- superUser = mkOption {
9797- type = types.nullOr types.str;
9898- default = "@admin";
9999- description = ''
100100- You can set either a username, a list of usernames (“admin1,admin2”),
101101- or the name of a group by prepending an @ char to the groupname
102102- Consult documentation <link xlink:href="https://www.dokuwiki.org/config:superuser"/> for further instructions.
103103- '';
104104- };
7676+ stateDir = mkOption {
7777+ type = types.path;
7878+ default = "/var/lib/dokuwiki/${name}/data";
7979+ description = "Location of the dokuwiki state directory.";
8080+ };
10581106106- usersFile = mkOption {
107107- type = types.nullOr types.path;
108108- default = null;
109109- description = ''
110110- Location of the dokuwiki users file. List of users. Format:
111111- login:passwordhash:Real Name:email:groups,comma,separated
112112- Create passwordHash easily by using:$ mkpasswd -5 password `pwgen 8 1`
113113- Example: <link xlink:href="https://github.com/splitbrain/dokuwiki/blob/master/conf/users.auth.php.dist"/>
8282+ acl = mkOption {
8383+ type = types.nullOr types.lines;
8484+ default = null;
8585+ example = "* @ALL 8";
8686+ description = ''
8787+ Access Control Lists: see <link xlink:href="https://www.dokuwiki.org/acl"/>
8888+ Mutually exclusive with services.dokuwiki.aclFile
8989+ Set this to a value other than null to take precedence over aclFile option.
9090+9191+ Warning: Consider using aclFile instead if you do not
9292+ want to store the ACL in the world-readable Nix store.
11493 '';
115115- };
9494+ };
9595+9696+ aclFile = mkOption {
9797+ type = with types; nullOr str;
9898+ default = if (config.aclUse && config.acl == null) then "/var/lib/dokuwiki/${name}/users.auth.php" else null;
9999+ description = ''
100100+ Location of the dokuwiki acl rules. Mutually exclusive with services.dokuwiki.acl
101101+ Mutually exclusive with services.dokuwiki.acl which is preferred.
102102+ Consult documentation <link xlink:href="https://www.dokuwiki.org/acl"/> for further instructions.
103103+ Example: <link xlink:href="https://github.com/splitbrain/dokuwiki/blob/master/conf/acl.auth.php.dist"/>
104104+ '';
105105+ example = "/var/lib/dokuwiki/${name}/acl.auth.php";
106106+ };
116107117117- extraConfig = mkOption {
118118- type = types.nullOr types.lines;
119119- default = null;
120120- example = ''
121121- $conf['title'] = 'My Wiki';
122122- $conf['userewrite'] = 1;
123123- '';
124124- description = ''
125125- DokuWiki configuration. Refer to
126126- <link xlink:href="https://www.dokuwiki.org/config"/>
127127- for details on supported values.
128128- '';
129129- };
108108+ aclUse = mkOption {
109109+ type = types.bool;
110110+ default = true;
111111+ description = ''
112112+ Necessary for users to log in into the system.
113113+ Also limits anonymous users. When disabled,
114114+ everyone is able to create and edit content.
115115+ '';
116116+ };
117117+118118+ pluginsConfig = mkOption {
119119+ type = types.lines;
120120+ default = ''
121121+ $plugins['authad'] = 0;
122122+ $plugins['authldap'] = 0;
123123+ $plugins['authmysql'] = 0;
124124+ $plugins['authpgsql'] = 0;
125125+ '';
126126+ description = ''
127127+ List of the dokuwiki (un)loaded plugins.
128128+ '';
129129+ };
130130+131131+ superUser = mkOption {
132132+ type = types.nullOr types.str;
133133+ default = "@admin";
134134+ description = ''
135135+ You can set either a username, a list of usernames (“admin1,admin2”),
136136+ or the name of a group by prepending an @ char to the groupname
137137+ Consult documentation <link xlink:href="https://www.dokuwiki.org/config:superuser"/> for further instructions.
138138+ '';
139139+ };
130140131131- poolConfig = mkOption {
132132- type = with types; attrsOf (oneOf [ str int bool ]);
133133- default = {
134134- "pm" = "dynamic";
135135- "pm.max_children" = 32;
136136- "pm.start_servers" = 2;
137137- "pm.min_spare_servers" = 2;
138138- "pm.max_spare_servers" = 4;
139139- "pm.max_requests" = 500;
141141+ usersFile = mkOption {
142142+ type = with types; nullOr str;
143143+ default = if config.aclUse then "/var/lib/dokuwiki/${name}/users.auth.php" else null;
144144+ description = ''
145145+ Location of the dokuwiki users file. List of users. Format:
146146+ login:passwordhash:Real Name:email:groups,comma,separated
147147+ Create passwordHash easily by using:$ mkpasswd -5 password `pwgen 8 1`
148148+ Example: <link xlink:href="https://github.com/splitbrain/dokuwiki/blob/master/conf/users.auth.php.dist"/>
149149+ '';
150150+ example = "/var/lib/dokuwiki/${name}/users.auth.php";
140151 };
141141- description = ''
142142- Options for the dokuwiki PHP pool. See the documentation on <literal>php-fpm.conf</literal>
143143- for details on configuration directives.
144144- '';
145145- };
146152147147- nginx = mkOption {
148148- type = types.submodule (
149149- recursiveUpdate
150150- (import ../web-servers/nginx/vhost-options.nix { inherit config lib; })
151151- {
152152- # Enable encryption by default,
153153- options.forceSSL.default = true;
154154- options.enableACME.default = true;
155155- }
156156- );
157157- default = {forceSSL = true; enableACME = true;};
158158- example = {
159159- serverAliases = [
160160- "wiki.\${config.networking.domain}"
161161- ];
162162- enableACME = false;
153153+ disableActions = mkOption {
154154+ type = types.nullOr types.str;
155155+ default = "";
156156+ example = "search,register";
157157+ description = ''
158158+ Disable individual action modes. Refer to
159159+ <link xlink:href="https://www.dokuwiki.org/config:action_modes"/>
160160+ for details on supported values.
161161+ '';
163162 };
164164- description = ''
165165- With this option, you can customize the nginx virtualHost which already has sensible defaults for DokuWiki.
166166- '';
163163+164164+ extraConfig = mkOption {
165165+ type = types.nullOr types.lines;
166166+ default = null;
167167+ example = ''
168168+ $conf['title'] = 'My Wiki';
169169+ $conf['userewrite'] = 1;
170170+ '';
171171+ description = ''
172172+ DokuWiki configuration. Refer to
173173+ <link xlink:href="https://www.dokuwiki.org/config"/>
174174+ for details on supported values.
175175+ '';
176176+ };
177177+178178+ plugins = mkOption {
179179+ type = types.listOf types.path;
180180+ default = [];
181181+ description = ''
182182+ List of path(s) to respective plugin(s) which are copied from the 'plugin' directory.
183183+ <note><para>These plugins need to be packaged before use, see example.</para></note>
184184+ '';
185185+ example = ''
186186+ # Let's package the icalevents plugin
187187+ plugin-icalevents = pkgs.stdenv.mkDerivation {
188188+ name = "icalevents";
189189+ # Download the plugin from the dokuwiki site
190190+ src = pkgs.fetchurl {
191191+ url = https://github.com/real-or-random/dokuwiki-plugin-icalevents/releases/download/2017-06-16/dokuwiki-plugin-icalevents-2017-06-16.zip;
192192+ sha256 = "e40ed7dd6bbe7fe3363bbbecb4de481d5e42385b5a0f62f6a6ce6bf3a1f9dfa8";
193193+ };
194194+ sourceRoot = ".";
195195+ # We need unzip to build this package
196196+ buildInputs = [ pkgs.unzip ];
197197+ # Installing simply means copying all files to the output directory
198198+ installPhase = "mkdir -p $out; cp -R * $out/";
199199+ };
200200+201201+ # And then pass this theme to the plugin list like this:
202202+ plugins = [ plugin-icalevents ];
203203+ '';
204204+ };
205205+206206+ templates = mkOption {
207207+ type = types.listOf types.path;
208208+ default = [];
209209+ description = ''
210210+ List of path(s) to respective template(s) which are copied from the 'tpl' directory.
211211+ <note><para>These templates need to be packaged before use, see example.</para></note>
212212+ '';
213213+ example = ''
214214+ # Let's package the bootstrap3 theme
215215+ template-bootstrap3 = pkgs.stdenv.mkDerivation {
216216+ name = "bootstrap3";
217217+ # Download the theme from the dokuwiki site
218218+ src = pkgs.fetchurl {
219219+ url = https://github.com/giterlizzi/dokuwiki-template-bootstrap3/archive/v2019-05-22.zip;
220220+ sha256 = "4de5ff31d54dd61bbccaf092c9e74c1af3a4c53e07aa59f60457a8f00cfb23a6";
221221+ };
222222+ # We need unzip to build this package
223223+ buildInputs = [ pkgs.unzip ];
224224+ # Installing simply means copying all files to the output directory
225225+ installPhase = "mkdir -p $out; cp -R * $out/";
226226+ };
227227+228228+ # And then pass this theme to the template list like this:
229229+ templates = [ template-bootstrap3 ];
230230+ '';
231231+ };
232232+233233+ poolConfig = mkOption {
234234+ type = with types; attrsOf (oneOf [ str int bool ]);
235235+ default = {
236236+ "pm" = "dynamic";
237237+ "pm.max_children" = 32;
238238+ "pm.start_servers" = 2;
239239+ "pm.min_spare_servers" = 2;
240240+ "pm.max_spare_servers" = 4;
241241+ "pm.max_requests" = 500;
242242+ };
243243+ description = ''
244244+ Options for the dokuwiki PHP pool. See the documentation on <literal>php-fpm.conf</literal>
245245+ for details on configuration directives.
246246+ '';
247247+ };
248248+249249+ nginx = mkOption {
250250+ type = types.submodule (
251251+ recursiveUpdate
252252+ (import ../web-servers/nginx/vhost-options.nix { inherit config lib; })
253253+ {
254254+ # Enable encryption by default,
255255+ options.forceSSL.default = true;
256256+ options.enableACME.default = true;
257257+ }
258258+ );
259259+ default = {forceSSL = true; enableACME = true;};
260260+ example = {
261261+ serverAliases = [
262262+ "wiki.\${config.networking.domain}"
263263+ ];
264264+ enableACME = false;
265265+ };
266266+ description = ''
267267+ With this option, you can customize the nginx virtualHost which already has sensible defaults for DokuWiki.
268268+ '';
269269+ };
270270+ };
271271+ };
272272+in
273273+{
274274+ # interface
275275+ options = {
276276+ services.dokuwiki = mkOption {
277277+ type = types.attrsOf (types.submodule siteOpts);
278278+ default = {};
279279+ description = "Sepcification of one or more dokuwiki sites to service.";
167280 };
168281 };
169282170283 # implementation
171284172172- config = mkIf cfg.enable {
285285+ config = mkIf (eachSite != {}) {
173286174174- warnings = mkIf (cfg.superUser == null) ["Not setting services.dokuwiki.superUser will impair your ability to administer DokuWiki"];
287287+ warnings = mapAttrsToList (hostName: cfg: mkIf (cfg.superUser == null) "Not setting services.dokuwiki.${hostName} superUser will impair your ability to administer DokuWiki") eachSite;
175288176176- assertions = [
177177- {
178178- assertion = cfg.aclUse -> (cfg.acl != null || cfg.aclFile != null);
179179- message = "Either services.dokuwiki.acl or services.dokuwiki.aclFile is mandatory when aclUse is true";
180180- }
181181- {
182182- assertion = cfg.usersFile != null -> cfg.aclUse != false;
183183- message = "services.dokuwiki.aclUse must be true when usersFile is not null";
184184- }
185185- ];
289289+ assertions = flatten (mapAttrsToList (hostName: cfg:
290290+ [{
291291+ assertion = cfg.aclUse -> (cfg.acl != null || cfg.aclFile != null);
292292+ message = "Either services.dokuwiki.${hostName}.acl or services.dokuwiki.${hostName}.aclFile is mandatory if aclUse true";
293293+ }
294294+ {
295295+ assertion = cfg.usersFile != null -> cfg.aclUse != false;
296296+ message = "services.dokuwiki.${hostName}.aclUse must must be true if usersFile is not null";
297297+ }
298298+ ]) eachSite);
186299187187- services.phpfpm.pools.dokuwiki = {
188188- inherit user;
189189- inherit group;
190190- phpEnv = {
191191- DOKUWIKI_LOCAL_CONFIG = "${dokuwikiLocalConfig}";
192192- DOKUWIKI_PLUGINS_LOCAL_CONFIG = "${dokuwikiPluginsLocalConfig}";
193193- } //optionalAttrs (cfg.usersFile != null) {
194194- DOKUWIKI_USERS_AUTH_CONFIG = "${cfg.usersFile}";
195195- } //optionalAttrs (cfg.aclUse) {
196196- DOKUWIKI_ACL_AUTH_CONFIG = if (cfg.acl != null) then "${dokuwikiAclAuthConfig}" else "${toString cfg.aclFile}";
197197- };
198198-199199- settings = {
200200- "listen.mode" = "0660";
201201- "listen.owner" = user;
202202- "listen.group" = group;
203203- } // cfg.poolConfig;
204204- };
300300+ services.phpfpm.pools = mapAttrs' (hostName: cfg: (
301301+ nameValuePair "dokuwiki-${hostName}" {
302302+ inherit user;
303303+ inherit group;
304304+ phpEnv = {
305305+ DOKUWIKI_LOCAL_CONFIG = "${dokuwikiLocalConfig cfg}";
306306+ DOKUWIKI_PLUGINS_LOCAL_CONFIG = "${dokuwikiPluginsLocalConfig cfg}";
307307+ } // optionalAttrs (cfg.usersFile != null) {
308308+ DOKUWIKI_USERS_AUTH_CONFIG = "${cfg.usersFile}";
309309+ } //optionalAttrs (cfg.aclUse) {
310310+ DOKUWIKI_ACL_AUTH_CONFIG = if (cfg.acl != null) then "${dokuwikiAclAuthConfig cfg}" else "${toString cfg.aclFile}";
311311+ };
312312+313313+ settings = {
314314+ "listen.mode" = "0660";
315315+ "listen.owner" = user;
316316+ "listen.group" = group;
317317+ } // cfg.poolConfig;
318318+ })) eachSite;
205319206320 services.nginx = {
207321 enable = true;
208208-209209- virtualHosts = {
210210- ${cfg.hostName} = mkMerge [ cfg.nginx {
211211- root = mkForce "${pkgs.dokuwiki}/share/dokuwiki/";
212212- extraConfig = "fastcgi_param HTTPS on;";
322322+ virtualHosts = mapAttrs (hostName: cfg: mkMerge [ cfg.nginx {
323323+ root = mkForce "${pkg hostName cfg}/share/dokuwiki";
324324+ extraConfig = "fastcgi_param HTTPS on;";
213325214214- locations."~ /(conf/|bin/|inc/|install.php)" = {
215215- extraConfig = "deny all;";
216216- };
326326+ locations."~ /(conf/|bin/|inc/|install.php)" = {
327327+ extraConfig = "deny all;";
328328+ };
217329218218- locations."~ ^/data/" = {
219219- root = "${cfg.stateDir}";
220220- extraConfig = "internal;";
221221- };
330330+ locations."~ ^/data/" = {
331331+ root = "${cfg.stateDir}";
332332+ extraConfig = "internal;";
333333+ };
222334223223- locations."~ ^/lib.*\.(js|css|gif|png|ico|jpg|jpeg)$" = {
224224- extraConfig = "expires 365d;";
225225- };
335335+ locations."~ ^/lib.*\.(js|css|gif|png|ico|jpg|jpeg)$" = {
336336+ extraConfig = "expires 365d;";
337337+ };
226338227227- locations."/" = {
228228- priority = 1;
229229- index = "doku.php";
230230- extraConfig = ''try_files $uri $uri/ @dokuwiki;'';
231231- };
339339+ locations."/" = {
340340+ priority = 1;
341341+ index = "doku.php";
342342+ extraConfig = ''try_files $uri $uri/ @dokuwiki;'';
343343+ };
232344233233- locations."@dokuwiki" = {
234234- extraConfig = ''
345345+ locations."@dokuwiki" = {
346346+ extraConfig = ''
235347 # rewrites "doku.php/" out of the URLs if you set the userwrite setting to .htaccess in dokuwiki config page
236348 rewrite ^/_media/(.*) /lib/exe/fetch.php?media=$1 last;
237349 rewrite ^/_detail/(.*) /lib/exe/detail.php?media=$1 last;
238350 rewrite ^/_export/([^/]+)/(.*) /doku.php?do=export_$1&id=$2 last;
239351 rewrite ^/(.*) /doku.php?id=$1&$args last;
240240- '';
241241- };
352352+ '';
353353+ };
242354243243- locations."~ \.php$" = {
244244- extraConfig = ''
355355+ locations."~ \.php$" = {
356356+ extraConfig = ''
245357 try_files $uri $uri/ /doku.php;
246358 include ${pkgs.nginx}/conf/fastcgi_params;
247359 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
248360 fastcgi_param REDIRECT_STATUS 200;
249249- fastcgi_pass unix:${config.services.phpfpm.pools.dokuwiki.socket};
361361+ fastcgi_pass unix:${config.services.phpfpm.pools."dokuwiki-${hostName}".socket};
250362 fastcgi_param HTTPS on;
251251- '';
252252- };
253253- }];
254254- };
255255-363363+ '';
364364+ };
365365+ }]) eachSite;
256366 };
257367258258- systemd.tmpfiles.rules = [
368368+ systemd.tmpfiles.rules = flatten (mapAttrsToList (hostName: cfg: [
259369 "d ${cfg.stateDir}/attic 0750 ${user} ${group} - -"
260370 "d ${cfg.stateDir}/cache 0750 ${user} ${group} - -"
261371 "d ${cfg.stateDir}/index 0750 ${user} ${group} - -"
···266376 "d ${cfg.stateDir}/meta 0750 ${user} ${group} - -"
267377 "d ${cfg.stateDir}/pages 0750 ${user} ${group} - -"
268378 "d ${cfg.stateDir}/tmp 0750 ${user} ${group} - -"
269269- ];
379379+ ] ++ lib.optional (cfg.aclFile != null) "C ${cfg.aclFile} 0640 ${user} ${group} - ${pkg hostName cfg}/share/dokuwiki/conf/acl.auth.php.dist"
380380+ ++ lib.optional (cfg.usersFile != null) "C ${cfg.usersFile} 0640 ${user} ${group} - ${pkg hostName cfg}/share/dokuwiki/conf/users.auth.php.dist"
381381+ ) eachSite);
270382383383+ users.users.${user} = {
384384+ group = group;
385385+ isSystemUser = true;
386386+ };
271387 };
272388}
+2-2
nixos/modules/services/web-apps/wordpress.nix
···105105 name = "embed-pdf-viewer-plugin";
106106 # Download the theme from the wordpress site
107107 src = pkgs.fetchurl {
108108- url = https://downloads.wordpress.org/plugin/embed-pdf-viewer.2.0.3.zip;
108108+ url = "https://downloads.wordpress.org/plugin/embed-pdf-viewer.2.0.3.zip";
109109 sha256 = "1rhba5h5fjlhy8p05zf0p14c9iagfh96y91r36ni0rmk6y891lyd";
110110 };
111111 # We need unzip to build this package
···132132 name = "responsive-theme";
133133 # Download the theme from the wordpress site
134134 src = pkgs.fetchurl {
135135- url = https://downloads.wordpress.org/theme/responsive.3.14.zip;
135135+ url = "https://downloads.wordpress.org/theme/responsive.3.14.zip";
136136 sha256 = "0rjwm811f4aa4q43r77zxlpklyb85q08f9c8ns2akcarrvj5ydx3";
137137 };
138138 # We need unzip to build this package
+7-7
nixos/modules/system/boot/systemd.nix
···894894 "sysctl.d/50-coredump.conf".source = "${systemd}/example/sysctl.d/50-coredump.conf";
895895 "sysctl.d/50-default.conf".source = "${systemd}/example/sysctl.d/50-default.conf";
896896897897+ "tmpfiles.d/00-nixos.conf".text = ''
898898+ # This file is created automatically and should not be modified.
899899+ # Please change the option ‘systemd.tmpfiles.rules’ instead.
900900+901901+ ${concatStringsSep "\n" cfg.tmpfiles.rules}
902902+ '';
903903+897904 "tmpfiles.d/home.conf".source = "${systemd}/example/tmpfiles.d/home.conf";
898905 "tmpfiles.d/journal-nocow.conf".source = "${systemd}/example/tmpfiles.d/journal-nocow.conf";
899906 "tmpfiles.d/portables.conf".source = "${systemd}/example/tmpfiles.d/portables.conf";
···905912 "tmpfiles.d/tmp.conf".source = "${systemd}/example/tmpfiles.d/tmp.conf";
906913 "tmpfiles.d/var.conf".source = "${systemd}/example/tmpfiles.d/var.conf";
907914 "tmpfiles.d/x11.conf".source = "${systemd}/example/tmpfiles.d/x11.conf";
908908-909909- "tmpfiles.d/nixos.conf".text = ''
910910- # This file is created automatically and should not be modified.
911911- # Please change the option ‘systemd.tmpfiles.rules’ instead.
912912-913913- ${concatStringsSep "\n" cfg.tmpfiles.rules}
914914- '';
915915916916 "systemd/system-generators" = { source = hooks "generators" cfg.generators; };
917917 "systemd/system-shutdown" = { source = hooks "shutdown" cfg.shutdown; };
+16-2
nixos/modules/virtualisation/containers.nix
···463463 A specification of the desired configuration of this
464464 container, as a NixOS module.
465465 '';
466466- type = lib.mkOptionType {
466466+ type = let
467467+ confPkgs = if config.pkgs == null then pkgs else config.pkgs;
468468+ in lib.mkOptionType {
467469 name = "Toplevel NixOS config";
468468- merge = loc: defs: (import ../../lib/eval-config.nix {
470470+ merge = loc: defs: (import (confPkgs.path + "/nixos/lib/eval-config.nix") {
469471 inherit system;
472472+ pkgs = confPkgs;
473473+ baseModules = import (confPkgs.path + "/nixos/modules/module-list.nix");
474474+ inherit (confPkgs) lib;
470475 modules =
471476 let
472477 extraConfig = {
···512517 Grant additional capabilities to the container. See the
513518 capabilities(7) and systemd-nspawn(1) man pages for more
514519 information.
520520+ '';
521521+ };
522522+523523+ pkgs = mkOption {
524524+ type = types.nullOr types.attrs;
525525+ default = null;
526526+ example = literalExample "pkgs";
527527+ description = ''
528528+ Customise which nixpkgs to use for this container.
515529 '';
516530 };
517531
···11# This performs a full 'end-to-end' test of a multi-node CockroachDB cluster
22# using the built-in 'cockroach workload' command, to simulate a semi-realistic
33# test load. It generally takes anywhere from 3-5 minutes to run and 1-2GB of
44-# RAM (though each of 3 workers gets 1GB allocated)
44+# RAM (though each of 3 workers gets 2GB allocated)
55#
66# CockroachDB requires synchronized system clocks within a small error window
77# (~500ms by default) on each node in order to maintain a multi-node cluster.
···55555656 {
5757 # Bank/TPC-C benchmarks take some memory to complete
5858- virtualisation.memorySize = 1024;
5858+ virtualisation.memorySize = 2048;
59596060 # Install the KVM PTP "Virtualized Clock" driver. This allows a /dev/ptp0
6161 # device to appear as a reference clock, synchronized to the host clock.
···8888 services.cockroachdb.listen.address = myAddr;
8989 services.cockroachdb.join = lib.mkIf (joinNode != null) joinNode;
90909191+ systemd.services.chronyd.unitConfig.ConditionPathExists = "/dev/ptp0";
9292+9193 # Hold startup until Chrony has performed its first measurement (which
9294 # will probably result in a full timeskip, thanks to makestep)
9395 systemd.services.cockroachdb.preStart = ''
···9597 '';
9698 };
97999898-in import ./make-test.nix ({ pkgs, ...} : {
100100+in import ./make-test-python.nix ({ pkgs, ...} : {
99101 name = "cockroachdb";
100102 meta.maintainers = with pkgs.stdenv.lib.maintainers;
101103 [ thoughtpolice ];
···110112 # there's otherwise no way to guarantee that node1 will start before the others try
111113 # to join it.
112114 testScript = ''
113113- $node1->start;
114114- $node1->waitForUnit("cockroachdb");
115115-116116- $node2->start;
117117- $node2->waitForUnit("cockroachdb");
118118-119119- $node3->start;
120120- $node3->waitForUnit("cockroachdb");
121121-122122- $node1->mustSucceed("cockroach sql --host=192.168.1.1 --insecure -e 'SHOW ALL CLUSTER SETTINGS' 2>&1");
123123- $node1->mustSucceed("cockroach workload init bank 'postgresql://root\@192.168.1.1:26257?sslmode=disable'");
124124- $node1->mustSucceed("cockroach workload run bank --duration=1m 'postgresql://root\@192.168.1.1:26257?sslmode=disable'");
115115+ for node in node1, node2, node3:
116116+ node.start()
117117+ node.wait_for_unit("cockroachdb")
118118+ node1.succeed(
119119+ "cockroach sql --host=192.168.1.1 --insecure -e 'SHOW ALL CLUSTER SETTINGS' 2>&1",
120120+ "cockroach workload init bank 'postgresql://root@192.168.1.1:26257?sslmode=disable'",
121121+ "cockroach workload run bank --duration=1m 'postgresql://root@192.168.1.1:26257?sslmode=disable'",
122122+ )
125123 '';
126124})
···11# The certificate for the ACME service is exported as:
22#
33-# config.test-support.letsencrypt.caCert
33+# config.test-support.acme.caCert
44#
55# This value can be used inside the configuration of other test nodes to inject
66# the snakeoil certificate into security.pki.certificateFiles or into package
77# overlays.
88#
99# Another value that's needed if you don't use a custom resolver (see below for
1010-# notes on that) is to add the letsencrypt node as a nameserver to every node
1010+# notes on that) is to add the acme node as a nameserver to every node
1111# that needs to acquire certificates using ACME, because otherwise the API host
1212-# for letsencrypt.org can't be resolved.
1212+# for acme.test can't be resolved.
1313#
1414# A configuration example of a full node setup using this would be this:
1515#
1616# {
1717-# letsencrypt = import ./common/letsencrypt;
1717+# acme = import ./common/acme/server;
1818#
1919# example = { nodes, ... }: {
2020# networking.nameservers = [
2121-# nodes.letsencrypt.config.networking.primaryIPAddress
2121+# nodes.acme.config.networking.primaryIPAddress
2222# ];
2323# security.pki.certificateFiles = [
2424-# nodes.letsencrypt.config.test-support.letsencrypt.caCert
2424+# nodes.acme.config.test-support.acme.caCert
2525# ];
2626# };
2727# }
···3333# override networking.nameservers like this:
3434#
3535# {
3636-# letsencrypt = { nodes, ... }: {
3737-# imports = [ ./common/letsencrypt ];
3838-# networking.nameservers = [
3636+# acme = { nodes, lib, ... }: {
3737+# imports = [ ./common/acme/server ];
3838+# networking.nameservers = lib.mkForce [
3939# nodes.myresolver.config.networking.primaryIPAddress
4040# ];
4141# };
···5555let
5656 snakeOilCerts = import ./snakeoil-certs.nix;
57575858- wfeDomain = "acme-v02.api.letsencrypt.org";
5858+ wfeDomain = "acme.test";
5959 wfeCertFile = snakeOilCerts.${wfeDomain}.cert;
6060 wfeKeyFile = snakeOilCerts.${wfeDomain}.key;
61616262- siteDomain = "letsencrypt.org";
6262+ siteDomain = "acme.test";
6363 siteCertFile = snakeOilCerts.${siteDomain}.cert;
6464 siteKeyFile = snakeOilCerts.${siteDomain}.key;
6565 pebble = pkgs.pebble;
6666 resolver = let
6767- message = "You need to define a resolver for the letsencrypt test module.";
6767+ message = "You need to define a resolver for the acme test module.";
6868 firstNS = lib.head config.networking.nameservers;
6969 in if config.networking.nameservers == [] then throw message else firstNS;
7070···7676 httpPort = 80;
7777 tlsPort = 443;
7878 ocspResponderURL = "http://0.0.0.0:4002";
7979+ strict = true;
7980 };
80818182 pebbleConfFile = pkgs.writeText "pebble.conf" (builtins.toJSON pebbleConf);
8283 pebbleDataDir = "/root/pebble";
83848485in {
8585- imports = [ ../resolver.nix ];
8686+ imports = [ ../../resolver.nix ];
86878787- options.test-support.letsencrypt.caCert = lib.mkOption {
8888+ options.test-support.acme.caCert = lib.mkOption {
8889 type = lib.types.path;
8990 description = ''
9091 A certificate file to use with the <literal>nodes</literal> attribute to
···9899 resolver.enable = let
99100 isLocalResolver = config.networking.nameservers == [ "127.0.0.1" ];
100101 in lib.mkOverride 900 isLocalResolver;
101101- letsencrypt.caCert = snakeOilCerts.ca.cert;
102102+ acme.caCert = snakeOilCerts.ca.cert;
102103 };
103104104105 # This has priority 140, because modules/testing/test-instrumentation.nix
···126127 '';
127128 serviceConfig = {
128129 # Required to bind on privileged ports.
129129- User = "root";
130130- Group = "root";
130130+ AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
131131 };
132132 };
133133 };
···1818 defining this option needs to be explicitly imported.
19192020 The reason this option exists is for the
2121- <filename>nixos/tests/common/letsencrypt</filename> module, which
2121+ <filename>nixos/tests/common/acme/server</filename> module, which
2222 needs that option to disable the resolver once the user has set its own
2323 resolver.
2424 '';
···11+{ stdenv, buildPythonPackage, fetchFromGitHub, requests }:
22+33+buildPythonPackage rec {
44+ pname = "publicsuffix2";
55+ version = "2.20191221";
66+77+ # Tests are missing in the sdist
88+ # See: https://github.com/nexB/python-publicsuffix2/issues/12
99+ src = fetchFromGitHub {
1010+ owner = "nexB";
1111+ repo = "python-publicsuffix2";
1212+ rev = "release-2.2019-12-21";
1313+ sha256 = "1dkvfvl0izq9hqzilnw8ipkbgjs9xyad9p21i3864hzinbh0wp9r";
1414+ };
1515+1616+ nativeBuildInputs = [ requests ];
1717+1818+ meta = with stdenv.lib; {
1919+ description = ''
2020+ Get a public suffix for a domain name using the Public Suffix
2121+ List. Forked from and using the same API as the publicsuffix package.
2222+ '';
2323+ homepage = "https://pypi.python.org/pypi/publicsuffix2/";
2424+ license = licenses.mpl20;
2525+ };
2626+}