Merge master into staging-next
This commit is contained in:
commit
26c481b435
230 changed files with 7830 additions and 5773 deletions
|
@ -54,12 +54,29 @@ end_of_line = unset
|
|||
[*.lock]
|
||||
indent_size = unset
|
||||
|
||||
[deps.nix]
|
||||
insert_final_newline = unset
|
||||
|
||||
[gemset.nix]
|
||||
insert_final_newline = unset
|
||||
|
||||
[node-packages.nix]
|
||||
insert_final_newline = unset
|
||||
|
||||
[nixos/modules/services/networking/ircd-hybrid/*.{conf,in}]
|
||||
trim_trailing_whitespace = unset
|
||||
|
||||
[nixos/tests/systemd-networkd-vrf.nix]
|
||||
trim_trailing_whitespace = unset
|
||||
|
||||
[pkgs/applications/editors/emacs-modes/recipes-archive-melpa.json]
|
||||
indent_size = unset
|
||||
|
||||
[pkgs/build-support/dotnetenv/Wrapper/**.*]
|
||||
end_of_line = unset
|
||||
insert_final_newline = unset
|
||||
trim_trailing_whitespace = unset
|
||||
|
||||
[pkgs/development/lisp-modules/quicklisp-to-nix.nix]
|
||||
indent_size = unset
|
||||
|
||||
|
|
6
.github/CODEOWNERS
vendored
6
.github/CODEOWNERS
vendored
|
@ -10,6 +10,12 @@
|
|||
# This file
|
||||
/.github/CODEOWNERS @edolstra
|
||||
|
||||
# GitHub actions
|
||||
/.github/workflows @Mic92 @zowoq
|
||||
|
||||
# EditorConfig
|
||||
/.editorconfig @Mic92 @zowoq
|
||||
|
||||
# Libraries
|
||||
/lib @edolstra @nbp @infinisil
|
||||
/lib/systems @nbp @ericson2314 @matthewbauer
|
||||
|
|
21
.github/workflows/editorconfig.yml
vendored
21
.github/workflows/editorconfig.yml
vendored
|
@ -1,4 +1,4 @@
|
|||
name: actions
|
||||
name: "Checking EditorConfig"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
@ -6,17 +6,24 @@ on:
|
|||
- master
|
||||
|
||||
jobs:
|
||||
editorconfig:
|
||||
tests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: technote-space/get-diff-action@v2.0.2
|
||||
- name: editorconfig check
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: technote-space/get-diff-action@v2.0.3
|
||||
- name: fetch editorconfig-checker
|
||||
env:
|
||||
VERSION: "2.0.4"
|
||||
VERSION: "2.1.0"
|
||||
OS: "linux"
|
||||
ARCH: "amd64"
|
||||
ECC_URL: "https://github.com/editorconfig-checker/editorconfig-checker/releases/download"
|
||||
run: |
|
||||
curl -sSf -O -L -C - https://github.com/editorconfig-checker/editorconfig-checker/releases/download/$VERSION/ec-$OS-$ARCH.tar.gz && \
|
||||
curl -sSf -O -L -C - $ECC_URL/$VERSION/ec-$OS-$ARCH.tar.gz && \
|
||||
tar xzf ec-$OS-$ARCH.tar.gz && \
|
||||
./bin/ec-$OS-$ARCH -disable-indentation ${{ env.GIT_DIFF }}
|
||||
mv ./bin/ec-$OS-$ARCH ./bin/editorconfig-checker
|
||||
- name: Checking EditorConfig
|
||||
run: |
|
||||
./bin/editorconfig-checker -disable-indentation \
|
||||
${{ env.GIT_DIFF }}
|
||||
|
|
9
.github/workflows/wait-ofborg.yml
vendored
9
.github/workflows/wait-ofborg.yml
vendored
|
@ -7,9 +7,12 @@ jobs:
|
|||
steps:
|
||||
- name: Wait for ofborg CI
|
||||
run: |
|
||||
# wait for ~30min...
|
||||
# eval sometimes takes a bit longer on staging.
|
||||
if [[ "$BASE_BRANCH" == "refs/heads/staging" ]]; then
|
||||
COUNTDOWN=$((COUNTDOWN*2))
|
||||
fi
|
||||
# ..in future a better fix would be to make ofborg mark CI as pending right away.
|
||||
for i in $(seq 360); do
|
||||
for i in $(seq "$COUNTDOWN"); do
|
||||
res=$(curl --silent \
|
||||
-H "Accept: application/vnd.github.antiope-preview+json" \
|
||||
-H "Authorization: token ${GITHUB_TOKEN}" \
|
||||
|
@ -26,6 +29,8 @@ jobs:
|
|||
# ofborg is not checking forks.
|
||||
if: github.repository_owner == 'NixOS'
|
||||
env:
|
||||
BASE_BRANCH: ${{ github.base_ref }}
|
||||
COUNTDOWN: 360 # wait for ~30min...
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
COMMIT: ${{ github.event.pull_request.head.sha }}
|
||||
OFBORG_APP_ID: 20500
|
||||
|
|
|
@ -40,6 +40,8 @@ pet = buildGoModule rec {
|
|||
|
||||
subPackages = [ "." ]; <co xml:id='ex-buildGoModule-2' />
|
||||
|
||||
runVend = true; <co xml:id='ex-buildGoModule-3' />
|
||||
|
||||
meta = with lib; {
|
||||
description = "Simple command-line snippet manager, written in Go";
|
||||
homepage = "https://github.com/knqyf263/pet";
|
||||
|
@ -66,7 +68,7 @@ pet = buildGoModule rec {
|
|||
</callout>
|
||||
<callout arearefs='ex-buildGoModule-3'>
|
||||
<para>
|
||||
<varname>runVend</varname> runs the vend command to generate the vendor directory. This is useful if your code depends on c code and go mod tidy does not include the needed sources to build.
|
||||
<varname>runVend</varname> runs the vend command to generate the vendor directory. This is useful if your code depends on c code and go mod tidy does not include the needed sources to build.
|
||||
</para>
|
||||
</callout>
|
||||
</calloutlist>
|
||||
|
|
|
@ -48,8 +48,10 @@ rec {
|
|||
else if isAttrs v then err "attrsets" v
|
||||
# functions can’t be printed of course
|
||||
else if isFunction v then err "functions" v
|
||||
# let’s not talk about floats. There is no sensible `toString` for them.
|
||||
else if isFloat v then err "floats" v
|
||||
# Floats currently can't be converted to precise strings,
|
||||
# condition warning on nix version once this isn't a problem anymore
|
||||
# See https://github.com/NixOS/nix/pull/3480
|
||||
else if isFloat v then libStr.floatToString v
|
||||
else err "this value is" (toString v);
|
||||
|
||||
|
||||
|
|
|
@ -110,6 +110,11 @@ lib.mapAttrs (n: v: v // { shortName = n; }) {
|
|||
fullName = ''BSD 4-clause "Original" or "Old" License'';
|
||||
};
|
||||
|
||||
bsdProtection = spdx {
|
||||
spdxId = "BSD-Protection";
|
||||
fullName = "BSD Protection License";
|
||||
};
|
||||
|
||||
bsl11 = {
|
||||
fullName = "Business Source License 1.1";
|
||||
url = "https://mariadb.com/bsl11";
|
||||
|
|
|
@ -612,6 +612,22 @@ rec {
|
|||
*/
|
||||
fixedWidthNumber = width: n: fixedWidthString width "0" (toString n);
|
||||
|
||||
/* Convert a float to a string, but emit a warning when precision is lost
|
||||
during the conversion
|
||||
|
||||
Example:
|
||||
floatToString 0.000001
|
||||
=> "0.000001"
|
||||
floatToString 0.0000001
|
||||
=> trace: warning: Imprecise conversion from float to string 0.000000
|
||||
"0.000000"
|
||||
*/
|
||||
floatToString = float: let
|
||||
result = toString float;
|
||||
precise = float == builtins.fromJSON result;
|
||||
in if precise then result
|
||||
else lib.warn "Imprecise conversion from float to string ${result}" result;
|
||||
|
||||
/* Check whether a value can be coerced to a string */
|
||||
isCoercibleToString = x:
|
||||
builtins.elem (builtins.typeOf x) [ "path" "string" "null" "int" "float" "bool" ] ||
|
||||
|
|
|
@ -1760,6 +1760,16 @@
|
|||
githubId = 490965;
|
||||
name = "Craig Swank";
|
||||
};
|
||||
cust0dian = {
|
||||
email = "serg@effectful.software";
|
||||
github = "cust0dian";
|
||||
githubId = 389387;
|
||||
name = "Serg Nesterov";
|
||||
keys = [{
|
||||
longkeyid = "rsa4096/0x1512F6EB84AECC8C";
|
||||
fingerprint = "6E7D BA30 DB5D BA60 693C 3BE3 1512 F6EB 84AE CC8C";
|
||||
}];
|
||||
};
|
||||
cwoac = {
|
||||
email = "oliver@codersoffortune.net";
|
||||
github = "cwoac";
|
||||
|
@ -5193,6 +5203,12 @@
|
|||
githubId = 13689192;
|
||||
name = "Nguyễn Gia Phong";
|
||||
};
|
||||
mcwitt = {
|
||||
email = "mcwitt@gmail.com";
|
||||
github = "mcwitt";
|
||||
githubId = 319411;
|
||||
name = "Matt Wittmann";
|
||||
};
|
||||
mdaiter = {
|
||||
email = "mdaiter8121@gmail.com";
|
||||
github = "mdaiter";
|
||||
|
|
179
nixos/doc/manual/development/settings-options.xml
Normal file
179
nixos/doc/manual/development/settings-options.xml
Normal file
|
@ -0,0 +1,179 @@
|
|||
<section xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
version="5.0"
|
||||
xml:id="sec-settings-options">
|
||||
<title>Options for Program Settings</title>
|
||||
|
||||
<para>
|
||||
Many programs have configuration files where program-specific settings can be declared. File formats can be separated into two categories:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Nix-representable ones: These can trivially be mapped to a subset of Nix syntax. E.g. JSON is an example, since its values like <literal>{"foo":{"bar":10}}</literal> can be mapped directly to Nix: <literal>{ foo = { bar = 10; }; }</literal>. Other examples are INI, YAML and TOML. The following section explains the convention for these settings.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Non-nix-representable ones: These can't be trivially mapped to a subset of Nix syntax. Most generic programming languages are in this group, e.g. bash, since the statement <literal>if true; then echo hi; fi</literal> doesn't have a trivial representation in Nix.
|
||||
</para>
|
||||
<para>
|
||||
Currently there are no fixed conventions for these, but it is common to have a <literal>configFile</literal> option for setting the configuration file path directly. The default value of <literal>configFile</literal> can be an auto-generated file, with convenient options for controlling the contents. For example an option of type <literal>attrsOf str</literal> can be used for representing environment variables which generates a section like <literal>export FOO="foo"</literal>. Often it can also be useful to also include an <literal>extraConfig</literal> option of type <literal>lines</literal> to allow arbitrary text after the autogenerated part of the file.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<section xml:id="sec-settings-nix-representable">
|
||||
<title>Nix-representable Formats (JSON, YAML, TOML, INI, ...)</title>
|
||||
<para>
|
||||
By convention, formats like this are handled with a generic <literal>settings</literal> option, representing the full program configuration as a Nix value. The type of this option should represent the format. The most common formats have a predefined type and string generator already declared under <literal>pkgs.formats</literal>:
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>pkgs.formats.json</varname> { }
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A function taking an empty attribute set (for future extensibility) and returning a set with JSON-specific attributes <varname>type</varname> and <varname>generate</varname> as specified <link linkend='pkgs-formats-result'>below</link>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>pkgs.formats.yaml</varname> { }
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A function taking an empty attribute set (for future extensibility) and returning a set with YAML-specific attributes <varname>type</varname> and <varname>generate</varname> as specified <link linkend='pkgs-formats-result'>below</link>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>pkgs.formats.ini</varname> { <replaceable>listsAsDuplicateKeys</replaceable> ? false, ... }
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A function taking an attribute set with values
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>listsAsDuplicateKeys</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A boolean for controlling whether list values can be used to represent duplicate INI keys
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
It returns a set with INI-specific attributes <varname>type</varname> and <varname>generate</varname> as specified <link linkend='pkgs-formats-result'>below</link>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>pkgs.formats.toml</varname> { }
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A function taking an empty attribute set (for future extensibility) and returning a set with TOML-specific attributes <varname>type</varname> and <varname>generate</varname> as specified <link linkend='pkgs-formats-result'>below</link>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
</para>
|
||||
<para xml:id="pkgs-formats-result">
|
||||
These functions all return an attribute set with these values:
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>type</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A module system type representing a value of the format
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>generate</varname> <replaceable>filename</replaceable> <replaceable>jsonValue</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A function that can render a value of the format to a file. Returns a file path.
|
||||
<note>
|
||||
<para>
|
||||
This function puts the value contents in the Nix store. So this should be avoided for secrets.
|
||||
</para>
|
||||
</note>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</para>
|
||||
<example xml:id="ex-settings-nix-representable">
|
||||
<title>Module with conventional <literal>settings</literal> option</title>
|
||||
<para>
|
||||
The following shows a module for an example program that uses a JSON configuration file. It demonstrates how above values can be used, along with some other related best practices. See the comments for explanations.
|
||||
</para>
|
||||
<programlisting>
|
||||
{ options, config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.services.foo;
|
||||
# Define the settings format used for this program
|
||||
settingsFormat = pkgs.formats.json {};
|
||||
in {
|
||||
|
||||
options.services.foo = {
|
||||
enable = lib.mkEnableOption "foo service";
|
||||
|
||||
settings = lib.mkOption {
|
||||
# Setting this type allows for correct merging behavior
|
||||
type = settingsFormat.type;
|
||||
default = {};
|
||||
description = ''
|
||||
Configuration for foo, see
|
||||
<link xlink:href="https://example.com/docs/foo"/>
|
||||
for supported values.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
# We can assign some default settings here to make the service work by just
|
||||
# enabling it. We use `mkDefault` for values that can be changed without
|
||||
# problems
|
||||
services.foo.settings = {
|
||||
# Fails at runtime without any value set
|
||||
log_level = lib.mkDefault "WARN";
|
||||
|
||||
# We assume systemd's `StateDirectory` is used, so we require this value,
|
||||
# therefore no mkDefault
|
||||
data_path = "/var/lib/foo";
|
||||
|
||||
# Since we use this to create a user we need to know the default value at
|
||||
# eval time
|
||||
user = lib.mkDefault "foo";
|
||||
};
|
||||
|
||||
environment.etc."foo.json".source =
|
||||
# The formats generator function takes a filename and the Nix value
|
||||
# representing the format value and produces a filepath with that value
|
||||
# rendered in the format
|
||||
settingsFormat.generate "foo-config.json" cfg.settings;
|
||||
|
||||
# We know that the `user` attribute exists because we set a default value
|
||||
# for it above, allowing us to use it without worries here
|
||||
users.users.${cfg.settings.user} = {}
|
||||
|
||||
# ...
|
||||
};
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
</section>
|
||||
|
||||
</section>
|
|
@ -183,4 +183,5 @@ in {
|
|||
<xi:include href="meta-attributes.xml" />
|
||||
<xi:include href="importing-modules.xml" />
|
||||
<xi:include href="replace-modules.xml" />
|
||||
<xi:include href="settings-options.xml" />
|
||||
</chapter>
|
||||
|
|
|
@ -216,12 +216,12 @@ start_all()
|
|||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<methodname>send_keys</methodname>
|
||||
<methodname>send_key</methodname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Simulate pressing keys on the virtual keyboard, e.g.,
|
||||
<literal>send_keys("ctrl-alt-delete")</literal>.
|
||||
<literal>send_key("ctrl-alt-delete")</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -232,7 +232,7 @@ start_all()
|
|||
<listitem>
|
||||
<para>
|
||||
Simulate typing a sequence of characters on the virtual keyboard, e.g.,
|
||||
<literal>send_keys("foobar\n")</literal> will type the string
|
||||
<literal>send_chars("foobar\n")</literal> will type the string
|
||||
<literal>foobar</literal> followed by the Enter key.
|
||||
</para>
|
||||
</listitem>
|
||||
|
|
|
@ -544,21 +544,42 @@ systemd.services.nginx.serviceConfig.ReadWritePaths = [ "/var/www" ];
|
|||
to be used for every display-manager in NixOS.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The <literal>bitcoind</literal> module has changed to multi-instance, using submodules.
|
||||
Therefore, it is now mandatory to name each instance, e.g.:
|
||||
Therefore, it is now mandatory to name each instance.
|
||||
To use this new multi-instance config with an existing bitcoind data directory and user,
|
||||
you have to adjust the original config, e.g.:
|
||||
<programlisting>
|
||||
services.bitcoind = {
|
||||
enable = true;
|
||||
};
|
||||
services.bitcoind = {
|
||||
enable = true;
|
||||
extraConfig = "...";
|
||||
...
|
||||
};
|
||||
</programlisting>
|
||||
requires a name now:
|
||||
To something similar:
|
||||
<programlisting>
|
||||
services.bitcoind."example-mainnet" = {
|
||||
enable = true;
|
||||
};
|
||||
services.bitcoind.mainnet = {
|
||||
enable = true;
|
||||
dataDir = "/var/lib/bitcoind";
|
||||
user = "bitcoin";
|
||||
extraConfig = "...";
|
||||
...
|
||||
};
|
||||
</programlisting>
|
||||
The key settings are:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>dataDir</literal> - to continue using the same data directory.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>user</literal> - to continue using the same user so that bitcoind maintains access to its files.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
|
|
|
@ -36,7 +36,7 @@ let
|
|||
// lib.optionalAttrs (opt ? example) { example = substFunction opt.example; }
|
||||
// lib.optionalAttrs (opt ? default) { default = substFunction opt.default; }
|
||||
// lib.optionalAttrs (opt ? type) { type = substFunction opt.type; }
|
||||
// lib.optionalAttrs (opt ? relatedPackages && opt.relatedPackages != []) { relatedPackages = genRelatedPackages opt.relatedPackages; }
|
||||
// lib.optionalAttrs (opt ? relatedPackages && opt.relatedPackages != []) { relatedPackages = genRelatedPackages opt.relatedPackages opt.name; }
|
||||
);
|
||||
|
||||
# Generate DocBook documentation for a list of packages. This is
|
||||
|
@ -48,7 +48,7 @@ let
|
|||
# - a list: that will be interpreted as an attribute path from `pkgs`,
|
||||
# - an attrset: that can specify `name`, `path`, `package`, `comment`
|
||||
# (either of `name`, `path` is required, the rest are optional).
|
||||
genRelatedPackages = packages:
|
||||
genRelatedPackages = packages: optName:
|
||||
let
|
||||
unpack = p: if lib.isString p then { name = p; }
|
||||
else if lib.isList p then { path = p; }
|
||||
|
@ -58,7 +58,7 @@ let
|
|||
title = args.title or null;
|
||||
name = args.name or (lib.concatStringsSep "." args.path);
|
||||
path = args.path or [ args.name ];
|
||||
package = args.package or (lib.attrByPath path (throw "Invalid package attribute path `${toString path}'") pkgs);
|
||||
package = args.package or (lib.attrByPath path (throw "Invalid package attribute path `${toString path}' found while evaluating `relatedPackages' of option `${optName}'") pkgs);
|
||||
in "<listitem>"
|
||||
+ "<para><literal>${lib.optionalString (title != null) "${title} aka "}pkgs.${name} (${package.meta.name})</literal>"
|
||||
+ lib.optionalString (!package.meta.available) " <emphasis>[UNAVAILABLE]</emphasis>"
|
||||
|
|
|
@ -8,17 +8,17 @@ use Time::HiRes qw(clock_gettime CLOCK_MONOTONIC);
|
|||
|
||||
sub new {
|
||||
my ($class) = @_;
|
||||
|
||||
|
||||
my $logFile = defined $ENV{LOGFILE} ? "$ENV{LOGFILE}" : "/dev/null";
|
||||
my $log = new XML::Writer(OUTPUT => new IO::File(">$logFile"));
|
||||
|
||||
|
||||
my $self = {
|
||||
log => $log,
|
||||
logQueue => Thread::Queue->new()
|
||||
};
|
||||
|
||||
|
||||
$self->{log}->startTag("logfile");
|
||||
|
||||
|
||||
bless $self, $class;
|
||||
return $self;
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
azure
|
||||
azure
|
||||
|
|
|
@ -20,7 +20,7 @@ $ ./upload-image.sh ./examples/basic/image.nix
|
|||
+ nix-build ./examples/basic/image.nix --out-link azure
|
||||
/nix/store/qdpzknpskzw30vba92mb24xzll1dqsmd-azure-image
|
||||
...
|
||||
95.5 %, 0 Done, 0 Failed, 1 Pending, 0 Skipped, 1 Total, 2-sec Throughput (Mb/s): 932.9565
|
||||
95.5 %, 0 Done, 0 Failed, 1 Pending, 0 Skipped, 1 Total, 2-sec Throughput (Mb/s): 932.9565
|
||||
...
|
||||
/subscriptions/aff271ee-e9be-4441-b9bb-42f5af4cbaeb/resourceGroups/nixos-images/providers/Microsoft.Compute/images/azure-image-todo-makethisbetter
|
||||
```
|
||||
|
|
|
@ -37,8 +37,8 @@ if ! az disk show -g "${group}" -n "${img_name}" &>/dev/null; then
|
|||
)"
|
||||
|
||||
azcopy copy "${img_file}" "${sasurl}" \
|
||||
--blob-type PageBlob
|
||||
|
||||
--blob-type PageBlob
|
||||
|
||||
az disk revoke-access \
|
||||
--resource-group "${group}" \
|
||||
--name "${img_name}"
|
||||
|
|
|
@ -646,6 +646,8 @@
|
|||
./services/networking/iperf3.nix
|
||||
./services/networking/ircd-hybrid/default.nix
|
||||
./services/networking/iwd.nix
|
||||
./services/networking/jicofo.nix
|
||||
./services/networking/jitsi-videobridge.nix
|
||||
./services/networking/keepalived/default.nix
|
||||
./services/networking/keybase.nix
|
||||
./services/networking/kippo.nix
|
||||
|
@ -852,6 +854,7 @@
|
|||
./services/web-apps/icingaweb2/module-monitoring.nix
|
||||
./services/web-apps/ihatemoney
|
||||
./services/web-apps/jirafeau.nix
|
||||
./services/web-apps/jitsi-meet.nix
|
||||
./services/web-apps/limesurvey.nix
|
||||
./services/web-apps/mattermost.nix
|
||||
./services/web-apps/mediawiki.nix
|
||||
|
|
|
@ -31,27 +31,42 @@ let
|
|||
let
|
||||
os = val:
|
||||
optionalString (val != null) "${val}";
|
||||
os' = prefixx: val:
|
||||
optionalString (val != null) (prefixx + "${val}");
|
||||
os' = prefix: val:
|
||||
optionalString (val != null) (prefix + "${val}");
|
||||
flatten = key: value:
|
||||
"&${key}=${value}";
|
||||
in
|
||||
"-s ${opt.type}://" + os opt.location + "?" + os' "name=" name
|
||||
+ concatStrings (mapAttrsToList flatten opt.query);
|
||||
"--stream.stream=\"${opt.type}://" + os opt.location + "?" + os' "name=" name
|
||||
+ concatStrings (mapAttrsToList flatten opt.query) + "\"";
|
||||
|
||||
optionalNull = val: ret:
|
||||
optional (val != null) ret;
|
||||
|
||||
optionString = concatStringsSep " " (mapAttrsToList streamToOption cfg.streams
|
||||
++ ["-p ${toString cfg.port}"]
|
||||
++ ["--controlPort ${toString cfg.controlPort}"]
|
||||
++ optionalNull cfg.sampleFormat "--sampleFormat ${cfg.sampleFormat}"
|
||||
++ optionalNull cfg.codec "-c ${cfg.codec}"
|
||||
++ optionalNull cfg.streamBuffer "--streamBuffer ${cfg.streamBuffer}"
|
||||
++ optionalNull cfg.buffer "-b ${cfg.buffer}"
|
||||
++ optional cfg.sendToMuted "--sendToMuted");
|
||||
# global options
|
||||
++ [ "--stream.bind_to_address ${cfg.listenAddress}" ]
|
||||
++ [ "--stream.port ${toString cfg.port}" ]
|
||||
++ optionalNull cfg.sampleFormat "--stream.sampleformat ${cfg.sampleFormat}"
|
||||
++ optionalNull cfg.codec "--stream.codec ${cfg.codec}"
|
||||
++ optionalNull cfg.streamBuffer "--stream.stream_buffer ${cfg.streamBuffer}"
|
||||
++ optionalNull cfg.buffer "--stream.buffer ${cfg.buffer}"
|
||||
++ optional cfg.sendToMuted "--stream.send_to_muted"
|
||||
# tcp json rpc
|
||||
++ [ "--tcp.enabled ${toString cfg.tcp.enable}" ]
|
||||
++ optionals cfg.tcp.enable [
|
||||
"--tcp.address ${cfg.tcp.listenAddress}"
|
||||
"--tcp.port ${toString cfg.tcp.port}" ]
|
||||
# http json rpc
|
||||
++ [ "--http.enabled ${toString cfg.http.enable}" ]
|
||||
++ optionals cfg.http.enable [
|
||||
"--http.address ${cfg.http.listenAddress}"
|
||||
"--http.port ${toString cfg.http.port}"
|
||||
] ++ optional (cfg.http.docRoot != null) "--http.doc_root \"${toString cfg.http.docRoot}\"");
|
||||
|
||||
in {
|
||||
imports = [
|
||||
(mkRenamedOptionModule [ "services" "snapserver" "controlPort"] [ "services" "snapserver" "tcp" "port" ])
|
||||
];
|
||||
|
||||
###### interface
|
||||
|
||||
|
@ -67,6 +82,15 @@ in {
|
|||
'';
|
||||
};
|
||||
|
||||
listenAddress = mkOption {
|
||||
type = types.str;
|
||||
default = "::";
|
||||
example = "0.0.0.0";
|
||||
description = ''
|
||||
The address where snapclients can connect.
|
||||
'';
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
default = 1704;
|
||||
|
@ -75,14 +99,6 @@ in {
|
|||
'';
|
||||
};
|
||||
|
||||
controlPort = mkOption {
|
||||
type = types.port;
|
||||
default = 1705;
|
||||
description = ''
|
||||
The port for control connections (JSON-RPC).
|
||||
'';
|
||||
};
|
||||
|
||||
openFirewall = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
|
@ -94,6 +110,90 @@ in {
|
|||
inherit sampleFormat;
|
||||
inherit codec;
|
||||
|
||||
streamBuffer = mkOption {
|
||||
type = with types; nullOr int;
|
||||
default = null;
|
||||
description = ''
|
||||
Stream read (input) buffer in ms.
|
||||
'';
|
||||
example = 20;
|
||||
};
|
||||
|
||||
buffer = mkOption {
|
||||
type = with types; nullOr int;
|
||||
default = null;
|
||||
description = ''
|
||||
Network buffer in ms.
|
||||
'';
|
||||
example = 1000;
|
||||
};
|
||||
|
||||
sendToMuted = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Send audio to muted clients.
|
||||
'';
|
||||
};
|
||||
|
||||
tcp.enable = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether to enable the JSON-RPC via TCP.
|
||||
'';
|
||||
};
|
||||
|
||||
tcp.listenAddress = mkOption {
|
||||
type = types.str;
|
||||
default = "::";
|
||||
example = "0.0.0.0";
|
||||
description = ''
|
||||
The address where the TCP JSON-RPC listens on.
|
||||
'';
|
||||
};
|
||||
|
||||
tcp.port = mkOption {
|
||||
type = types.port;
|
||||
default = 1705;
|
||||
description = ''
|
||||
The port where the TCP JSON-RPC listens on.
|
||||
'';
|
||||
};
|
||||
|
||||
http.enable = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether to enable the JSON-RPC via HTTP.
|
||||
'';
|
||||
};
|
||||
|
||||
http.listenAddress = mkOption {
|
||||
type = types.str;
|
||||
default = "::";
|
||||
example = "0.0.0.0";
|
||||
description = ''
|
||||
The address where the HTTP JSON-RPC listens on.
|
||||
'';
|
||||
};
|
||||
|
||||
http.port = mkOption {
|
||||
type = types.port;
|
||||
default = 1780;
|
||||
description = ''
|
||||
The port where the HTTP JSON-RPC listens on.
|
||||
'';
|
||||
};
|
||||
|
||||
http.docRoot = mkOption {
|
||||
type = with types; nullOr path;
|
||||
default = null;
|
||||
description = ''
|
||||
Path to serve from the HTTP servers root.
|
||||
'';
|
||||
};
|
||||
|
||||
streams = mkOption {
|
||||
type = with types; attrsOf (submodule {
|
||||
options = {
|
||||
|
@ -147,34 +247,7 @@ in {
|
|||
};
|
||||
'';
|
||||
};
|
||||
|
||||
streamBuffer = mkOption {
|
||||
type = with types; nullOr int;
|
||||
default = null;
|
||||
description = ''
|
||||
Stream read (input) buffer in ms.
|
||||
'';
|
||||
example = 20;
|
||||
};
|
||||
|
||||
buffer = mkOption {
|
||||
type = with types; nullOr int;
|
||||
default = null;
|
||||
description = ''
|
||||
Network buffer in ms.
|
||||
'';
|
||||
example = 1000;
|
||||
};
|
||||
|
||||
sendToMuted = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Send audio to muted clients.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -206,7 +279,10 @@ in {
|
|||
};
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = optionals cfg.openFirewall [ cfg.port cfg.controlPort ];
|
||||
networking.firewall.allowedTCPPorts =
|
||||
optionals cfg.openFirewall [ cfg.port ]
|
||||
++ optional cfg.tcp.enable cfg.tcp.port
|
||||
++ optional cfg.http.enable cfg.http.port;
|
||||
};
|
||||
|
||||
meta = {
|
||||
|
|
|
@ -18,7 +18,7 @@ in {
|
|||
};
|
||||
|
||||
host = mkOption {
|
||||
description = "Remote host where snapshots should be sent.";
|
||||
description = "Remote host where snapshots should be sent. <literal>lz4</literal> is expected to be installed on this host.";
|
||||
example = "example.com";
|
||||
type = types.str;
|
||||
};
|
||||
|
|
152
nixos/modules/services/networking/jicofo.nix
Normal file
152
nixos/modules/services/networking/jicofo.nix
Normal file
|
@ -0,0 +1,152 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.jicofo;
|
||||
in
|
||||
{
|
||||
options.services.jicofo = with types; {
|
||||
enable = mkEnableOption "Jitsi Conference Focus - component of Jitsi Meet";
|
||||
|
||||
xmppHost = mkOption {
|
||||
type = str;
|
||||
example = "localhost";
|
||||
description = ''
|
||||
Hostname of the XMPP server to connect to.
|
||||
'';
|
||||
};
|
||||
|
||||
xmppDomain = mkOption {
|
||||
type = nullOr str;
|
||||
example = "meet.example.org";
|
||||
description = ''
|
||||
Domain name of the XMMP server to which to connect as a component.
|
||||
|
||||
If null, <option>xmppHost</option> is used.
|
||||
'';
|
||||
};
|
||||
|
||||
componentPasswordFile = mkOption {
|
||||
type = str;
|
||||
example = "/run/keys/jicofo-component";
|
||||
description = ''
|
||||
Path to file containing component secret.
|
||||
'';
|
||||
};
|
||||
|
||||
userName = mkOption {
|
||||
type = str;
|
||||
default = "focus";
|
||||
description = ''
|
||||
User part of the JID for XMPP user connection.
|
||||
'';
|
||||
};
|
||||
|
||||
userDomain = mkOption {
|
||||
type = str;
|
||||
example = "auth.meet.example.org";
|
||||
description = ''
|
||||
Domain part of the JID for XMPP user connection.
|
||||
'';
|
||||
};
|
||||
|
||||
userPasswordFile = mkOption {
|
||||
type = str;
|
||||
example = "/run/keys/jicofo-user";
|
||||
description = ''
|
||||
Path to file containing password for XMPP user connection.
|
||||
'';
|
||||
};
|
||||
|
||||
bridgeMuc = mkOption {
|
||||
type = str;
|
||||
example = "jvbbrewery@internal.meet.example.org";
|
||||
description = ''
|
||||
JID of the internal MUC used to communicate with Videobridges.
|
||||
'';
|
||||
};
|
||||
|
||||
config = mkOption {
|
||||
type = attrsOf str;
|
||||
default = { };
|
||||
example = literalExample ''
|
||||
{
|
||||
"org.jitsi.jicofo.auth.URL" = "XMPP:jitsi-meet.example.com";
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Contents of the <filename>sip-communicator.properties</filename> configuration file for jicofo.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services.jicofo.config = mapAttrs (_: v: mkDefault v) {
|
||||
"org.jitsi.jicofo.BRIDGE_MUC" = cfg.bridgeMuc;
|
||||
};
|
||||
|
||||
users.groups.jitsi-meet = {};
|
||||
|
||||
systemd.services.jicofo = let
|
||||
jicofoProps = {
|
||||
"-Dnet.java.sip.communicator.SC_HOME_DIR_LOCATION" = "/etc/jitsi";
|
||||
"-Dnet.java.sip.communicator.SC_HOME_DIR_NAME" = "jicofo";
|
||||
"-Djava.util.logging.config.file" = "/etc/jitsi/jicofo/logging.properties";
|
||||
};
|
||||
in
|
||||
{
|
||||
description = "JItsi COnference FOcus";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
|
||||
restartTriggers = [
|
||||
config.environment.etc."jitsi/jicofo/sip-communicator.properties".source
|
||||
];
|
||||
environment.JAVA_SYS_PROPS = concatStringsSep " " (mapAttrsToList (k: v: "${k}=${toString v}") jicofoProps);
|
||||
|
||||
script = ''
|
||||
${pkgs.jicofo}/bin/jicofo \
|
||||
--host=${cfg.xmppHost} \
|
||||
--domain=${if cfg.xmppDomain == null then cfg.xmppHost else cfg.xmppDomain} \
|
||||
--secret=$(cat ${cfg.componentPasswordFile}) \
|
||||
--user_name=${cfg.userName} \
|
||||
--user_domain=${cfg.userDomain} \
|
||||
--user_password=$(cat ${cfg.userPasswordFile})
|
||||
'';
|
||||
|
||||
serviceConfig = {
|
||||
Type = "exec";
|
||||
|
||||
DynamicUser = true;
|
||||
User = "jicofo";
|
||||
Group = "jitsi-meet";
|
||||
|
||||
CapabilityBoundingSet = "";
|
||||
NoNewPrivileges = true;
|
||||
ProtectSystem = "strict";
|
||||
ProtectHome = true;
|
||||
PrivateTmp = true;
|
||||
PrivateDevices = true;
|
||||
ProtectHostname = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectControlGroups = true;
|
||||
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ];
|
||||
RestrictNamespaces = true;
|
||||
LockPersonality = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
};
|
||||
};
|
||||
|
||||
environment.etc."jitsi/jicofo/sip-communicator.properties".source =
|
||||
pkgs.writeText "sip-communicator.properties" (
|
||||
generators.toKeyValue {} cfg.config
|
||||
);
|
||||
environment.etc."jitsi/jicofo/logging.properties".source =
|
||||
mkDefault "${pkgs.jicofo}/etc/jitsi/jicofo/logging.properties-journal";
|
||||
};
|
||||
|
||||
meta.maintainers = with lib.maintainers; [ ];
|
||||
}
|
276
nixos/modules/services/networking/jitsi-videobridge.nix
Normal file
276
nixos/modules/services/networking/jitsi-videobridge.nix
Normal file
|
@ -0,0 +1,276 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.jitsi-videobridge;
|
||||
attrsToArgs = a: concatStringsSep " " (mapAttrsToList (k: v: "${k}=${toString v}") a);
|
||||
|
||||
# HOCON is a JSON superset that videobridge2 uses for configuration.
|
||||
# It can substitute environment variables which we use for passwords here.
|
||||
# https://github.com/lightbend/config/blob/master/README.md
|
||||
#
|
||||
# Substitution for environment variable FOO is represented as attribute set
|
||||
# { __hocon_envvar = "FOO"; }
|
||||
toHOCON = x: if isAttrs x && x ? __hocon_envvar then ("\${" + x.__hocon_envvar + "}")
|
||||
else if isAttrs x then "{${ concatStringsSep "," (mapAttrsToList (k: v: ''"${k}":${toHOCON v}'') x) }}"
|
||||
else if isList x then "[${ concatMapStringsSep "," toHOCON x }]"
|
||||
else builtins.toJSON x;
|
||||
|
||||
# We're passing passwords in environment variables that have names generated
|
||||
# from an attribute name, which may not be a valid bash identifier.
|
||||
toVarName = s: "XMPP_PASSWORD_" + stringAsChars (c: if builtins.match "[A-Za-z0-9]" c != null then c else "_") s;
|
||||
|
||||
defaultJvbConfig = {
|
||||
videobridge = {
|
||||
ice = {
|
||||
tcp = {
|
||||
enabled = true;
|
||||
port = 4443;
|
||||
};
|
||||
udp.port = 10000;
|
||||
};
|
||||
stats = {
|
||||
enabled = true;
|
||||
transports = [ { type = "muc"; } ];
|
||||
};
|
||||
apis.xmpp-client.configs = flip mapAttrs cfg.xmppConfigs (name: xmppConfig: {
|
||||
hostname = xmppConfig.hostName;
|
||||
domain = xmppConfig.domain;
|
||||
username = xmppConfig.userName;
|
||||
password = { __hocon_envvar = toVarName name; };
|
||||
muc_jids = xmppConfig.mucJids;
|
||||
muc_nickname = xmppConfig.mucNickname;
|
||||
disable_certificate_verification = xmppConfig.disableCertificateVerification;
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
# Allow overriding leaves of the default config despite types.attrs not doing any merging.
|
||||
jvbConfig = recursiveUpdate defaultJvbConfig cfg.config;
|
||||
in
|
||||
{
|
||||
options.services.jitsi-videobridge = with types; {
|
||||
enable = mkEnableOption "Jitsi Videobridge, a WebRTC compatible video router";
|
||||
|
||||
config = mkOption {
|
||||
type = attrs;
|
||||
default = { };
|
||||
example = literalExample ''
|
||||
{
|
||||
videobridge = {
|
||||
ice.udp.port = 5000;
|
||||
websockets = {
|
||||
enabled = true;
|
||||
server-id = "jvb1";
|
||||
};
|
||||
};
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Videobridge configuration.
|
||||
|
||||
See <link xlink:href="https://github.com/jitsi/jitsi-videobridge/blob/master/src/main/resources/reference.conf" />
|
||||
for default configuration with comments.
|
||||
'';
|
||||
};
|
||||
|
||||
xmppConfigs = mkOption {
|
||||
description = ''
|
||||
XMPP servers to connect to.
|
||||
|
||||
See <link xlink:href="https://github.com/jitsi/jitsi-videobridge/blob/master/doc/muc.md" /> for more information.
|
||||
'';
|
||||
default = { };
|
||||
example = literalExample ''
|
||||
{
|
||||
"localhost" = {
|
||||
hostName = "localhost";
|
||||
userName = "jvb";
|
||||
domain = "auth.xmpp.example.org";
|
||||
passwordFile = "/var/lib/jitsi-meet/videobridge-secret";
|
||||
mucJids = "jvbbrewery@internal.xmpp.example.org";
|
||||
};
|
||||
}
|
||||
'';
|
||||
type = attrsOf (submodule ({ name, ... }: {
|
||||
options = {
|
||||
hostName = mkOption {
|
||||
type = str;
|
||||
example = "xmpp.example.org";
|
||||
description = ''
|
||||
Hostname of the XMPP server to connect to. Name of the attribute set is used by default.
|
||||
'';
|
||||
};
|
||||
domain = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
example = "auth.xmpp.example.org";
|
||||
description = ''
|
||||
Domain part of JID of the XMPP user, if it is different from hostName.
|
||||
'';
|
||||
};
|
||||
userName = mkOption {
|
||||
type = str;
|
||||
default = "jvb";
|
||||
description = ''
|
||||
User part of the JID.
|
||||
'';
|
||||
};
|
||||
passwordFile = mkOption {
|
||||
type = str;
|
||||
example = "/run/keys/jitsi-videobridge-xmpp1";
|
||||
description = ''
|
||||
File containing the password for the user.
|
||||
'';
|
||||
};
|
||||
mucJids = mkOption {
|
||||
type = str;
|
||||
example = "jvbbrewery@internal.xmpp.example.org";
|
||||
description = ''
|
||||
JID of the MUC to join. JiCoFo needs to be configured to join the same MUC.
|
||||
'';
|
||||
};
|
||||
mucNickname = mkOption {
|
||||
# Upstream DEBs use UUID, let's use hostname instead.
|
||||
type = str;
|
||||
description = ''
|
||||
Videobridges use the same XMPP account and need to be distinguished by the
|
||||
nickname (aka resource part of the JID). By default, system hostname is used.
|
||||
'';
|
||||
};
|
||||
disableCertificateVerification = mkOption {
|
||||
type = bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to skip validation of the server's certificate.
|
||||
'';
|
||||
};
|
||||
};
|
||||
config = {
|
||||
hostName = mkDefault name;
|
||||
mucNickname = mkDefault (builtins.replaceStrings [ "." ] [ "-" ] (
|
||||
config.networking.hostName + optionalString (config.networking.domain != null) ".${config.networking.domain}"
|
||||
));
|
||||
};
|
||||
}));
|
||||
};
|
||||
|
||||
nat = {
|
||||
localAddress = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
example = "192.168.1.42";
|
||||
description = ''
|
||||
Local address when running behind NAT.
|
||||
'';
|
||||
};
|
||||
|
||||
publicAddress = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
example = "1.2.3.4";
|
||||
description = ''
|
||||
Public address when running behind NAT.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
extraProperties = mkOption {
|
||||
type = attrsOf str;
|
||||
default = { };
|
||||
description = ''
|
||||
Additional Java properties passed to jitsi-videobridge.
|
||||
'';
|
||||
};
|
||||
|
||||
openFirewall = mkOption {
|
||||
type = bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to open ports in the firewall for the videobridge.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
users.groups.jitsi-meet = {};
|
||||
|
||||
services.jitsi-videobridge.extraProperties = optionalAttrs (cfg.nat.localAddress != null) {
|
||||
"org.ice4j.ice.harvest.NAT_HARVESTER_LOCAL_ADDRESS" = cfg.nat.localAddress;
|
||||
"org.ice4j.ice.harvest.NAT_HARVESTER_PUBLIC_ADDRESS" = cfg.nat.publicAddress;
|
||||
};
|
||||
|
||||
systemd.services.jitsi-videobridge2 = let
|
||||
jvbProps = {
|
||||
"-Dnet.java.sip.communicator.SC_HOME_DIR_LOCATION" = "/etc/jitsi";
|
||||
"-Dnet.java.sip.communicator.SC_HOME_DIR_NAME" = "videobridge";
|
||||
"-Djava.util.logging.config.file" = "/etc/jitsi/videobridge/logging.properties";
|
||||
"-Dconfig.file" = pkgs.writeText "jvb.conf" (toHOCON jvbConfig);
|
||||
} // (mapAttrs' (k: v: nameValuePair "-D${k}" v) cfg.extraProperties);
|
||||
in
|
||||
{
|
||||
aliases = [ "jitsi-videobridge.service" ];
|
||||
description = "Jitsi Videobridge";
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
environment.JAVA_SYS_PROPS = attrsToArgs jvbProps;
|
||||
|
||||
script = (concatStrings (mapAttrsToList (name: xmppConfig:
|
||||
"export ${toVarName name}=$(cat ${xmppConfig.passwordFile})\n"
|
||||
) cfg.xmppConfigs))
|
||||
+ ''
|
||||
${pkgs.jitsi-videobridge}/bin/jitsi-videobridge --apis=none
|
||||
'';
|
||||
|
||||
serviceConfig = {
|
||||
Type = "exec";
|
||||
|
||||
DynamicUser = true;
|
||||
User = "jitsi-videobridge";
|
||||
Group = "jitsi-meet";
|
||||
|
||||
CapabilityBoundingSet = "";
|
||||
NoNewPrivileges = true;
|
||||
ProtectSystem = "strict";
|
||||
ProtectHome = true;
|
||||
PrivateTmp = true;
|
||||
PrivateDevices = true;
|
||||
ProtectHostname = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectControlGroups = true;
|
||||
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ];
|
||||
RestrictNamespaces = true;
|
||||
LockPersonality = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
|
||||
TasksMax = 65000;
|
||||
LimitNPROC = 65000;
|
||||
LimitNOFILE = 65000;
|
||||
};
|
||||
};
|
||||
|
||||
environment.etc."jitsi/videobridge/logging.properties".source =
|
||||
mkDefault "${pkgs.jitsi-videobridge}/etc/jitsi/videobridge/logging.properties-journal";
|
||||
|
||||
# (from videobridge2 .deb)
|
||||
# this sets the max, so that we can bump the JVB UDP single port buffer size.
|
||||
boot.kernel.sysctl."net.core.rmem_max" = mkDefault 10485760;
|
||||
boot.kernel.sysctl."net.core.netdev_max_backlog" = mkDefault 100000;
|
||||
|
||||
networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall
|
||||
[ jvbConfig.videobridge.ice.tcp.port ];
|
||||
networking.firewall.allowedUDPPorts = mkIf cfg.openFirewall
|
||||
[ jvbConfig.videobridge.ice.udp.port ];
|
||||
|
||||
assertions = [{
|
||||
message = "publicAddress must be set if and only if localAddress is set";
|
||||
assertion = (cfg.nat.publicAddress == null) == (cfg.nat.localAddress == null);
|
||||
}];
|
||||
};
|
||||
|
||||
meta.maintainers = with lib.maintainers; [ ];
|
||||
}
|
|
@ -48,6 +48,14 @@ in
|
|||
'';
|
||||
};
|
||||
|
||||
rsaPrivateKeyFile = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.path;
|
||||
description = ''
|
||||
Path of the private RSA keyfile.
|
||||
'';
|
||||
};
|
||||
|
||||
debugLevel = mkOption {
|
||||
default = 0;
|
||||
type = types.addCheck types.int (l: l >= 0 && l <= 5);
|
||||
|
@ -139,6 +147,7 @@ in
|
|||
Name = ${if data.name == null then "$HOST" else data.name}
|
||||
DeviceType = ${data.interfaceType}
|
||||
${optionalString (data.ed25519PrivateKeyFile != null) "Ed25519PrivateKeyFile = ${data.ed25519PrivateKeyFile}"}
|
||||
${optionalString (data.rsaPrivateKeyFile != null) "PrivateKeyFile = ${data.rsaPrivateKeyFile}"}
|
||||
${optionalString (data.listenAddress != null) "ListenAddress = ${data.listenAddress}"}
|
||||
${optionalString (data.bindToAddress != null) "BindToAddress = ${data.bindToAddress}"}
|
||||
Interface = tinc.${network}
|
||||
|
@ -170,12 +179,15 @@ in
|
|||
# Determine how we should generate our keys
|
||||
if type tinc >/dev/null 2>&1; then
|
||||
# Tinc 1.1+ uses the tinc helper application for key generation
|
||||
${if data.ed25519PrivateKeyFile != null then " # Keyfile managed by nix" else ''
|
||||
${if data.ed25519PrivateKeyFile != null then " # ed25519 Keyfile managed by nix" else ''
|
||||
# Prefer ED25519 keys (only in 1.1+)
|
||||
[ -f "/etc/tinc/${network}/ed25519_key.priv" ] || tinc -n ${network} generate-ed25519-keys
|
||||
''}
|
||||
# Otherwise use RSA keys
|
||||
${if data.rsaPrivateKeyFile != null then " # RSA Keyfile managed by nix" else ''
|
||||
[ -f "/etc/tinc/${network}/rsa_key.priv" ] || tinc -n ${network} generate-rsa-keys 4096
|
||||
''}
|
||||
# In case there isn't anything to do
|
||||
true
|
||||
else
|
||||
# Tinc 1.0 uses the tincd application
|
||||
[ -f "/etc/tinc/${network}/rsa_key.priv" ] || tincd -n ${network} -K 4096
|
||||
|
|
|
@ -321,7 +321,7 @@ in
|
|||
enable = true;
|
||||
virtualHosts = mapAttrs (hostName: cfg: mkMerge [ cfg.nginx {
|
||||
root = mkForce "${pkg hostName cfg}/share/dokuwiki";
|
||||
extraConfig = "fastcgi_param HTTPS on;";
|
||||
extraConfig = lib.optionalString (cfg.nginx.addSSL || cfg.nginx.forceSSL || cfg.nginx.onlySSL || cfg.nginx.enableACME) "fastcgi_param HTTPS on;";
|
||||
|
||||
locations."~ /(conf/|bin/|inc/|install.php)" = {
|
||||
extraConfig = "deny all;";
|
||||
|
@ -359,7 +359,7 @@ in
|
|||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_param REDIRECT_STATUS 200;
|
||||
fastcgi_pass unix:${config.services.phpfpm.pools."dokuwiki-${hostName}".socket};
|
||||
fastcgi_param HTTPS on;
|
||||
${lib.optionalString (cfg.nginx.addSSL || cfg.nginx.forceSSL || cfg.nginx.onlySSL || cfg.nginx.enableACME) "fastcgi_param HTTPS on;"}
|
||||
'';
|
||||
};
|
||||
}]) eachSite;
|
||||
|
|
333
nixos/modules/services/web-apps/jitsi-meet.nix
Normal file
333
nixos/modules/services/web-apps/jitsi-meet.nix
Normal file
|
@ -0,0 +1,333 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.jitsi-meet;
|
||||
|
||||
# The configuration files are JS of format "var <<string>> = <<JSON>>;". In order to
|
||||
# override only some settings, we need to extract the JSON, use jq to merge it with
|
||||
# the config provided by user, and then reconstruct the file.
|
||||
overrideJs =
|
||||
source: varName: userCfg: appendExtra:
|
||||
let
|
||||
extractor = pkgs.writeText "extractor.js" ''
|
||||
var fs = require("fs");
|
||||
eval(fs.readFileSync(process.argv[2], 'utf8'));
|
||||
process.stdout.write(JSON.stringify(eval(process.argv[3])));
|
||||
'';
|
||||
userJson = pkgs.writeText "user.json" (builtins.toJSON userCfg);
|
||||
in (pkgs.runCommand "${varName}.js" { } ''
|
||||
${pkgs.nodejs}/bin/node ${extractor} ${source} ${varName} > default.json
|
||||
(
|
||||
echo "var ${varName} = "
|
||||
${pkgs.jq}/bin/jq -s '.[0] * .[1]' default.json ${userJson}
|
||||
echo ";"
|
||||
echo ${escapeShellArg appendExtra}
|
||||
) > $out
|
||||
'');
|
||||
|
||||
# Essential config - it's probably not good to have these as option default because
|
||||
# types.attrs doesn't do merging. Let's merge explicitly, can still be overriden if
|
||||
# user desires.
|
||||
defaultCfg = {
|
||||
hosts = {
|
||||
domain = cfg.hostName;
|
||||
muc = "conference.${cfg.hostName}";
|
||||
focus = "focus.${cfg.hostName}";
|
||||
};
|
||||
bosh = "//${cfg.hostName}/http-bind";
|
||||
};
|
||||
in
|
||||
{
|
||||
options.services.jitsi-meet = with types; {
|
||||
enable = mkEnableOption "Jitsi Meet - Secure, Simple and Scalable Video Conferences";
|
||||
|
||||
hostName = mkOption {
|
||||
type = str;
|
||||
example = "meet.example.org";
|
||||
description = ''
|
||||
Hostname of the Jitsi Meet instance.
|
||||
'';
|
||||
};
|
||||
|
||||
config = mkOption {
|
||||
type = attrs;
|
||||
default = { };
|
||||
example = literalExample ''
|
||||
{
|
||||
enableWelcomePage = false;
|
||||
defaultLang = "fi";
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Client-side web application settings that override the defaults in <filename>config.js</filename>.
|
||||
|
||||
See <link xlink:href="https://github.com/jitsi/jitsi-meet/blob/master/config.js" /> for default
|
||||
configuration with comments.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Text to append to <filename>config.js</filename> web application config file.
|
||||
|
||||
Can be used to insert JavaScript logic to determine user's region in cascading bridges setup.
|
||||
'';
|
||||
};
|
||||
|
||||
interfaceConfig = mkOption {
|
||||
type = attrs;
|
||||
default = { };
|
||||
example = literalExample ''
|
||||
{
|
||||
SHOW_JITSI_WATERMARK = false;
|
||||
SHOW_WATERMARK_FOR_GUESTS = false;
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Client-side web-app interface settings that override the defaults in <filename>interface_config.js</filename>.
|
||||
|
||||
See <link xlink:href="https://github.com/jitsi/jitsi-meet/blob/master/interface_config.js" /> for
|
||||
default configuration with comments.
|
||||
'';
|
||||
};
|
||||
|
||||
videobridge = {
|
||||
enable = mkOption {
|
||||
type = bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether to enable Jitsi Videobridge instance and configure it to connect to Prosody.
|
||||
|
||||
Additional configuration is possible with <option>services.jitsi-videobridge</option>.
|
||||
'';
|
||||
};
|
||||
|
||||
passwordFile = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
example = "/run/keys/videobridge";
|
||||
description = ''
|
||||
File containing password to the Prosody account for videobridge.
|
||||
|
||||
If <literal>null</literal>, a file with password will be generated automatically. Setting
|
||||
this option is useful if you plan to connect additional videobridges to the XMPP server.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
jicofo.enable = mkOption {
|
||||
type = bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether to enable JiCoFo instance and configure it to connect to Prosody.
|
||||
|
||||
Additional configuration is possible with <option>services.jicofo</option>.
|
||||
'';
|
||||
};
|
||||
|
||||
nginx.enable = mkOption {
|
||||
type = bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether to enable nginx virtual host that will serve the javascript application and act as
|
||||
a proxy for the XMPP server. Further nginx configuration can be done by adapting
|
||||
<option>services.nginx.virtualHosts.<hostName></option>.
|
||||
When this is enabled, ACME will be used to retrieve a TLS certificate by default. To disable
|
||||
this, set the <option>services.nginx.virtualHosts.<hostName>.enableACME</option> to
|
||||
<literal>false</literal> and if appropriate do the same for
|
||||
<option>services.nginx.virtualHosts.<hostName>.forceSSL</option>.
|
||||
'';
|
||||
};
|
||||
|
||||
prosody.enable = mkOption {
|
||||
type = bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether to configure Prosody to relay XMPP messages between Jitsi Meet components. Turn this
|
||||
off if you want to configure it manually.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services.prosody = mkIf cfg.prosody.enable {
|
||||
enable = mkDefault true;
|
||||
xmppComplianceSuite = mkDefault false;
|
||||
modules = {
|
||||
admin_adhoc = mkDefault false;
|
||||
bosh = mkDefault true;
|
||||
ping = mkDefault true;
|
||||
roster = mkDefault true;
|
||||
saslauth = mkDefault true;
|
||||
tls = mkDefault true;
|
||||
};
|
||||
muc = [
|
||||
{
|
||||
domain = "conference.${cfg.hostName}";
|
||||
name = "Jitsi Meet MUC";
|
||||
roomLocking = false;
|
||||
roomDefaultPublicJids = true;
|
||||
extraConfig = ''
|
||||
storage = "memory"
|
||||
'';
|
||||
}
|
||||
{
|
||||
domain = "internal.${cfg.hostName}";
|
||||
name = "Jitsi Meet Videobridge MUC";
|
||||
extraConfig = ''
|
||||
storage = "memory"
|
||||
admins = { "focus@auth.${cfg.hostName}", "jvb@auth.${cfg.hostName}" }
|
||||
'';
|
||||
#-- muc_room_cache_size = 1000
|
||||
}
|
||||
];
|
||||
extraModules = [ "pubsub" ];
|
||||
extraConfig = mkAfter ''
|
||||
Component "focus.${cfg.hostName}"
|
||||
component_secret = os.getenv("JICOFO_COMPONENT_SECRET")
|
||||
'';
|
||||
virtualHosts.${cfg.hostName} = {
|
||||
enabled = true;
|
||||
domain = cfg.hostName;
|
||||
extraConfig = ''
|
||||
authentication = "anonymous"
|
||||
c2s_require_encryption = false
|
||||
admins = { "focus@auth.${cfg.hostName}" }
|
||||
'';
|
||||
ssl = {
|
||||
cert = "/var/lib/jitsi-meet/jitsi-meet.crt";
|
||||
key = "/var/lib/jitsi-meet/jitsi-meet.key";
|
||||
};
|
||||
};
|
||||
virtualHosts."auth.${cfg.hostName}" = {
|
||||
enabled = true;
|
||||
domain = "auth.${cfg.hostName}";
|
||||
extraConfig = ''
|
||||
authentication = "internal_plain"
|
||||
'';
|
||||
ssl = {
|
||||
cert = "/var/lib/jitsi-meet/jitsi-meet.crt";
|
||||
key = "/var/lib/jitsi-meet/jitsi-meet.key";
|
||||
};
|
||||
};
|
||||
};
|
||||
systemd.services.prosody.serviceConfig = mkIf cfg.prosody.enable {
|
||||
EnvironmentFile = [ "/var/lib/jitsi-meet/secrets-env" ];
|
||||
SupplementaryGroups = [ "jitsi-meet" ];
|
||||
};
|
||||
|
||||
users.groups.jitsi-meet = {};
|
||||
systemd.tmpfiles.rules = [
|
||||
"d '/var/lib/jitsi-meet' 0750 root jitsi-meet - -"
|
||||
];
|
||||
|
||||
systemd.services.jitsi-meet-init-secrets = {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
before = [ "jicofo.service" "jitsi-videobridge2.service" ] ++ (optional cfg.prosody.enable "prosody.service");
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
};
|
||||
|
||||
script = let
|
||||
secrets = [ "jicofo-component-secret" "jicofo-user-secret" ] ++ (optional (cfg.videobridge.passwordFile == null) "videobridge-secret");
|
||||
videobridgeSecret = if cfg.videobridge.passwordFile != null then cfg.videobridge.passwordFile else "/var/lib/jitsi-meet/videobridge-secret";
|
||||
in
|
||||
''
|
||||
cd /var/lib/jitsi-meet
|
||||
${concatMapStringsSep "\n" (s: ''
|
||||
if [ ! -f ${s} ]; then
|
||||
tr -dc a-zA-Z0-9 </dev/urandom | head -c 64 > ${s}
|
||||
chown root:jitsi-meet ${s}
|
||||
chmod 640 ${s}
|
||||
fi
|
||||
'') secrets}
|
||||
|
||||
# for easy access in prosody
|
||||
echo "JICOFO_COMPONENT_SECRET=$(cat jicofo-component-secret)" > secrets-env
|
||||
chown root:jitsi-meet secrets-env
|
||||
chmod 640 secrets-env
|
||||
''
|
||||
+ optionalString cfg.prosody.enable ''
|
||||
${config.services.prosody.package}/bin/prosodyctl register focus auth.${cfg.hostName} "$(cat /var/lib/jitsi-meet/jicofo-user-secret)"
|
||||
${config.services.prosody.package}/bin/prosodyctl register jvb auth.${cfg.hostName} "$(cat ${videobridgeSecret})"
|
||||
|
||||
# generate self-signed certificates
|
||||
if [ ! -f /var/lib/jitsi-meet.crt ]; then
|
||||
${getBin pkgs.openssl}/bin/openssl req \
|
||||
-x509 \
|
||||
-newkey rsa:4096 \
|
||||
-keyout /var/lib/jitsi-meet/jitsi-meet.key \
|
||||
-out /var/lib/jitsi-meet/jitsi-meet.crt \
|
||||
-days 36500 \
|
||||
-nodes \
|
||||
-subj '/CN=${cfg.hostName}/CN=auth.${cfg.hostName}'
|
||||
chmod 640 /var/lib/jitsi-meet/jitsi-meet.{crt,key}
|
||||
chown root:jitsi-meet /var/lib/jitsi-meet/jitsi-meet.{crt,key}
|
||||
fi
|
||||
'';
|
||||
};
|
||||
|
||||
services.nginx = mkIf cfg.nginx.enable {
|
||||
enable = mkDefault true;
|
||||
virtualHosts.${cfg.hostName} = {
|
||||
enableACME = mkDefault true;
|
||||
forceSSL = mkDefault true;
|
||||
root = pkgs.jitsi-meet;
|
||||
extraConfig = ''
|
||||
ssi on;
|
||||
'';
|
||||
locations."@root_path".extraConfig = ''
|
||||
rewrite ^/(.*)$ / break;
|
||||
'';
|
||||
locations."~ ^/([^/\\?&:'\"]+)$".tryFiles = "$uri @root_path";
|
||||
locations."=/http-bind" = {
|
||||
proxyPass = "http://localhost:5280/http-bind";
|
||||
extraConfig = ''
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Host $host;
|
||||
'';
|
||||
};
|
||||
locations."=/external_api.js" = mkDefault {
|
||||
alias = "${pkgs.jitsi-meet}/libs/external_api.min.js";
|
||||
};
|
||||
locations."=/config.js" = mkDefault {
|
||||
alias = overrideJs "${pkgs.jitsi-meet}/config.js" "config" (recursiveUpdate defaultCfg cfg.config) cfg.extraConfig;
|
||||
};
|
||||
locations."=/interface_config.js" = mkDefault {
|
||||
alias = overrideJs "${pkgs.jitsi-meet}/interface_config.js" "interfaceConfig" cfg.interfaceConfig "";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services.jitsi-videobridge = mkIf cfg.videobridge.enable {
|
||||
enable = true;
|
||||
xmppConfigs."localhost" = {
|
||||
userName = "jvb";
|
||||
domain = "auth.${cfg.hostName}";
|
||||
passwordFile = "/var/lib/jitsi-meet/videobridge-secret";
|
||||
mucJids = "jvbbrewery@internal.${cfg.hostName}";
|
||||
disableCertificateVerification = true;
|
||||
};
|
||||
};
|
||||
|
||||
services.jicofo = mkIf cfg.jicofo.enable {
|
||||
enable = true;
|
||||
xmppHost = "localhost";
|
||||
xmppDomain = cfg.hostName;
|
||||
userDomain = "auth.${cfg.hostName}";
|
||||
userName = "focus";
|
||||
userPasswordFile = "/var/lib/jitsi-meet/jicofo-user-secret";
|
||||
componentPasswordFile = "/var/lib/jitsi-meet/jicofo-component-secret";
|
||||
bridgeMuc = "jvbbrewery@internal.${cfg.hostName}";
|
||||
config = {
|
||||
"org.jitsi.jicofo.ALWAYS_TRUST_MODE_ENABLED" = "true";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
meta.maintainers = with lib.maintainers; [ ];
|
||||
}
|
|
@ -139,7 +139,7 @@ in
|
|||
boot.initrd.postMountCommands = mkIf cfg.flushBeforeStage2 ''
|
||||
for iface in $ifaces; do
|
||||
ip address flush "$iface"
|
||||
ip link down "$iface"
|
||||
ip link set "$iface" down
|
||||
done
|
||||
'';
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ let
|
|||
bootloaderId = if args.efiBootloaderId == null then "NixOS${efiSysMountPoint'}" else args.efiBootloaderId;
|
||||
timeout = if config.boot.loader.timeout == null then -1 else config.boot.loader.timeout;
|
||||
users = if cfg.users == {} || cfg.version != 1 then cfg.users else throw "GRUB version 1 does not support user accounts.";
|
||||
theme = f cfg.theme;
|
||||
inherit efiSysMountPoint;
|
||||
inherit (args) devices;
|
||||
inherit (efi) canTouchEfiVariables;
|
||||
|
@ -426,6 +427,19 @@ in
|
|||
'';
|
||||
};
|
||||
|
||||
theme = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
example = literalExample "pkgs.nixos-grub2-theme";
|
||||
default = null;
|
||||
description = ''
|
||||
Grub theme to be used.
|
||||
|
||||
<note><para>
|
||||
This options has no effect for GRUB 1.
|
||||
</para></note>
|
||||
'';
|
||||
};
|
||||
|
||||
splashMode = mkOption {
|
||||
type = types.enum [ "normal" "stretch" ];
|
||||
default = "stretch";
|
||||
|
@ -697,7 +711,7 @@ in
|
|||
in pkgs.writeScript "install-grub.sh" (''
|
||||
#!${pkgs.runtimeShell}
|
||||
set -e
|
||||
export PERL5LIB=${with pkgs.perlPackages; makePerlPath [ FileSlurp XMLLibXML XMLSAX XMLSAXBase ListCompare JSON ]}
|
||||
export PERL5LIB=${with pkgs.perlPackages; makePerlPath [ FileSlurp FileCopyRecursive XMLLibXML XMLSAX XMLSAXBase ListCompare JSON ]}
|
||||
${optionalString cfg.enableCryptodisk "export GRUB_ENABLE_CRYPTODISK=y"}
|
||||
'' + flip concatMapStrings cfg.mirroredBoots (args: ''
|
||||
${pkgs.perl}/bin/perl ${install-grub-pl} ${grubConfig args} $@
|
||||
|
|
|
@ -6,9 +6,11 @@ use File::Basename;
|
|||
use File::Path;
|
||||
use File::stat;
|
||||
use File::Copy;
|
||||
use File::Copy::Recursive qw(rcopy pathrm);
|
||||
use File::Slurp;
|
||||
use File::Temp;
|
||||
use JSON;
|
||||
use File::Find;
|
||||
require List::Compare;
|
||||
use POSIX;
|
||||
use Cwd;
|
||||
|
@ -82,6 +84,7 @@ my $gfxpayloadBios = get("gfxpayloadBios");
|
|||
my $bootloaderId = get("bootloaderId");
|
||||
my $forceInstall = get("forceInstall");
|
||||
my $font = get("font");
|
||||
my $theme = get("theme");
|
||||
$ENV{'PATH'} = get("path");
|
||||
|
||||
die "unsupported GRUB version\n" if $grubVersion != 1 && $grubVersion != 2;
|
||||
|
@ -370,6 +373,28 @@ else {
|
|||
fi
|
||||
";
|
||||
}
|
||||
|
||||
rmtree("$bootPath/theme") or die "cannot clean up theme folder in $bootPath\n" if -e "$bootPath/theme";
|
||||
|
||||
if ($theme) {
|
||||
# Copy theme
|
||||
rcopy($theme, "$bootPath/theme") or die "cannot copy $theme to $bootPath\n";
|
||||
$conf .= "
|
||||
# Sets theme.
|
||||
set theme=" . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/theme/theme.txt
|
||||
export theme
|
||||
# Load theme fonts, if any
|
||||
";
|
||||
|
||||
find( { wanted => sub {
|
||||
if ($_ =~ /\.pf2$/i) {
|
||||
$font = File::Spec->abs2rel($File::Find::name, $theme);
|
||||
$conf .= "
|
||||
loadfont " . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/theme/$font
|
||||
";
|
||||
}
|
||||
}, no_chdir => 1 }, $theme );
|
||||
}
|
||||
}
|
||||
|
||||
$conf .= "$extraConfig\n";
|
||||
|
|
|
@ -58,6 +58,35 @@ in {
|
|||
Run <literal>VBoxManage modifyvm --help</literal> to see more options.
|
||||
'';
|
||||
};
|
||||
extraDisk = mkOption {
|
||||
description = ''
|
||||
Optional extra disk/hdd configuration.
|
||||
The disk will be an 'ext4' partition on a separate VMDK file.
|
||||
'';
|
||||
default = null;
|
||||
example = {
|
||||
label = "storage";
|
||||
mountPoint = "/home/demo/storage";
|
||||
size = 100 * 1024;
|
||||
};
|
||||
type = types.nullOr (types.submodule {
|
||||
options = {
|
||||
size = mkOption {
|
||||
type = types.int;
|
||||
description = "Size in MiB";
|
||||
};
|
||||
label = mkOption {
|
||||
type = types.str;
|
||||
default = "vm-extra-storage";
|
||||
description = "Label for the disk partition";
|
||||
};
|
||||
mountPoint = mkOption {
|
||||
type = types.str;
|
||||
description = "Path where to mount this disk.";
|
||||
};
|
||||
};
|
||||
});
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -96,6 +125,20 @@ in {
|
|||
echo "creating VirtualBox pass-through disk wrapper (no copying involved)..."
|
||||
VBoxManage internalcommands createrawvmdk -filename disk.vmdk -rawdisk $diskImage
|
||||
|
||||
${optionalString (cfg.extraDisk != null) ''
|
||||
echo "creating extra disk: data-disk.raw"
|
||||
dataDiskImage=data-disk.raw
|
||||
truncate -s ${toString cfg.extraDisk.size}M $dataDiskImage
|
||||
|
||||
parted --script $dataDiskImage -- \
|
||||
mklabel msdos \
|
||||
mkpart primary ext4 1MiB -1
|
||||
eval $(partx $dataDiskImage -o START,SECTORS --nr 1 --pairs)
|
||||
mkfs.ext4 -F -L ${cfg.extraDisk.label} $dataDiskImage -E offset=$(sectorsToBytes $START) $(sectorsToKilobytes $SECTORS)K
|
||||
echo "creating extra disk: data-disk.vmdk"
|
||||
VBoxManage internalcommands createrawvmdk -filename data-disk.vmdk -rawdisk $dataDiskImage
|
||||
''}
|
||||
|
||||
echo "creating VirtualBox VM..."
|
||||
vmName="${cfg.vmName}";
|
||||
VBoxManage createvm --name "$vmName" --register \
|
||||
|
@ -106,6 +149,10 @@ in {
|
|||
VBoxManage storagectl "$vmName" --name SATA --add sata --portcount 4 --bootable on --hostiocache on
|
||||
VBoxManage storageattach "$vmName" --storagectl SATA --port 0 --device 0 --type hdd \
|
||||
--medium disk.vmdk
|
||||
${optionalString (cfg.extraDisk != null) ''
|
||||
VBoxManage storageattach "$vmName" --storagectl SATA --port 1 --device 0 --type hdd \
|
||||
--medium data-disk.vmdk
|
||||
''}
|
||||
|
||||
echo "exporting VirtualBox VM..."
|
||||
mkdir -p $out
|
||||
|
@ -119,11 +166,19 @@ in {
|
|||
'';
|
||||
};
|
||||
|
||||
fileSystems."/" = {
|
||||
device = "/dev/disk/by-label/nixos";
|
||||
autoResize = true;
|
||||
fsType = "ext4";
|
||||
};
|
||||
fileSystems = {
|
||||
"/" = {
|
||||
device = "/dev/disk/by-label/nixos";
|
||||
autoResize = true;
|
||||
fsType = "ext4";
|
||||
};
|
||||
} // (lib.optionalAttrs (cfg.extraDisk != null) {
|
||||
${cfg.extraDisk.mountPoint} = {
|
||||
device = "/dev/disk/by-label/" + cfg.extraDisk.label;
|
||||
autoResize = true;
|
||||
fsType = "ext4";
|
||||
};
|
||||
});
|
||||
|
||||
boot.growPartition = true;
|
||||
boot.loader.grub.device = "/dev/sda";
|
||||
|
|
|
@ -162,6 +162,7 @@ in
|
|||
jellyfin = handleTest ./jellyfin.nix {};
|
||||
jenkins = handleTest ./jenkins.nix {};
|
||||
jirafeau = handleTest ./jirafeau.nix {};
|
||||
jitsi-meet = handleTest ./jitsi-meet.nix {};
|
||||
k3s = handleTest ./k3s.nix {};
|
||||
kafka = handleTest ./kafka.nix {};
|
||||
keepalived = handleTest ./keepalived.nix {};
|
||||
|
@ -310,6 +311,7 @@ in
|
|||
simple = handleTest ./simple.nix {};
|
||||
slurm = handleTest ./slurm.nix {};
|
||||
smokeping = handleTest ./smokeping.nix {};
|
||||
snapcast = handleTest ./snapcast.nix {};
|
||||
snapper = handleTest ./snapper.nix {};
|
||||
sogo = handleTest ./sogo.nix {};
|
||||
solr = handleTest ./solr.nix {};
|
||||
|
@ -369,6 +371,7 @@ in
|
|||
yabar = handleTest ./yabar.nix {};
|
||||
yggdrasil = handleTest ./yggdrasil.nix {};
|
||||
zfs = handleTest ./zfs.nix {};
|
||||
zigbee2mqtt = handleTest ./zigbee2mqtt.nix {};
|
||||
zoneminder = handleTest ./zoneminder.nix {};
|
||||
zookeeper = handleTest ./zookeeper.nix {};
|
||||
zsh-history = handleTest ./zsh-history.nix {};
|
||||
|
|
|
@ -13,7 +13,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
|
|||
machine.succeed("modprobe bcachefs")
|
||||
machine.succeed("bcachefs version")
|
||||
machine.succeed("ls /dev")
|
||||
|
||||
|
||||
machine.succeed(
|
||||
"mkdir /tmp/mnt",
|
||||
"udevadm settle",
|
||||
|
|
|
@ -43,7 +43,7 @@ in {
|
|||
nodes = {
|
||||
client = { ... }: {
|
||||
services.borgbackup.jobs = {
|
||||
|
||||
|
||||
local = {
|
||||
paths = dataDir;
|
||||
repo = localRepo;
|
||||
|
|
|
@ -5,7 +5,7 @@ let
|
|||
hostPort = 10080;
|
||||
containerIp = "192.168.0.100";
|
||||
containerPort = 80;
|
||||
in
|
||||
in
|
||||
|
||||
import ./make-test-python.nix ({ pkgs, ...} : {
|
||||
name = "containers-portforward";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import ./make-test-python.nix (
|
||||
{
|
||||
nodes = {
|
||||
router = {config, pkgs, ...}: {
|
||||
router = {config, pkgs, ...}: {
|
||||
config = {
|
||||
# This machine simulates a router with IPv6 forwarding and a static IPv6 address.
|
||||
boot.kernel.sysctl = {
|
||||
|
|
|
@ -16,10 +16,10 @@ import ./make-test.nix ({ pkgs, ...} : {
|
|||
services.openssh.extraConfig = "PermitEmptyPasswords yes";
|
||||
users.extraUsers.root.password = "";
|
||||
};
|
||||
};
|
||||
};
|
||||
testScript = ''
|
||||
startAll;
|
||||
|
||||
|
||||
$docker->waitForUnit("sockets.target");
|
||||
$docker->succeed("docker run nix nix-store --version");
|
||||
$docker->succeed("docker run bash bash --version");
|
||||
|
|
55
nixos/tests/jitsi-meet.nix
Normal file
55
nixos/tests/jitsi-meet.nix
Normal file
|
@ -0,0 +1,55 @@
|
|||
import ./make-test-python.nix ({ pkgs, ... }: {
|
||||
name = "jitsi-meet";
|
||||
meta = with pkgs.stdenv.lib.maintainers; {
|
||||
maintainers = [ mmilata ];
|
||||
};
|
||||
|
||||
nodes = {
|
||||
client = { nodes, pkgs, ... }: {
|
||||
};
|
||||
server = { config, pkgs, ... }: {
|
||||
services.jitsi-meet = {
|
||||
enable = true;
|
||||
hostName = "server";
|
||||
};
|
||||
services.jitsi-videobridge.openFirewall = true;
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
||||
|
||||
services.nginx.virtualHosts.server = {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
};
|
||||
|
||||
security.acme.email = "me@example.org";
|
||||
security.acme.acceptTerms = true;
|
||||
security.acme.server = "https://example.com"; # self-signed only
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
server.wait_for_unit("jitsi-videobridge2.service")
|
||||
server.wait_for_unit("jicofo.service")
|
||||
server.wait_for_unit("nginx.service")
|
||||
server.wait_for_unit("prosody.service")
|
||||
|
||||
server.wait_until_succeeds(
|
||||
"journalctl -b -u jitsi-videobridge2 -o cat | grep -q 'Performed a successful health check'"
|
||||
)
|
||||
server.wait_until_succeeds(
|
||||
"journalctl -b -u jicofo -o cat | grep -q 'connected .JID: focus@auth.server'"
|
||||
)
|
||||
server.wait_until_succeeds(
|
||||
"journalctl -b -u prosody -o cat | grep -q 'Authenticated as focus@auth.server'"
|
||||
)
|
||||
server.wait_until_succeeds(
|
||||
"journalctl -b -u prosody -o cat | grep -q 'focus.server:component: External component successfully authenticated'"
|
||||
)
|
||||
server.wait_until_succeeds(
|
||||
"journalctl -b -u prosody -o cat | grep -q 'Authenticated as jvb@auth.server'"
|
||||
)
|
||||
|
||||
client.wait_for_unit("network.target")
|
||||
assert "<title>Jitsi Meet</title>" in client.succeed("curl -sSfkL http://server/")
|
||||
'';
|
||||
})
|
|
@ -7,7 +7,7 @@ import ./make-test-python.nix ({ pkgs, ... }:
|
|||
};
|
||||
|
||||
nodes =
|
||||
{
|
||||
{
|
||||
client = { };
|
||||
|
||||
server =
|
||||
|
|
|
@ -45,7 +45,7 @@ import ./make-test-python.nix ({ pkgs, ... }:
|
|||
node.start()
|
||||
''
|
||||
+ runMongoDBTest pkgs.mongodb-3_4
|
||||
+ runMongoDBTest pkgs.mongodb-3_6
|
||||
+ runMongoDBTest pkgs.mongodb-3_6
|
||||
+ runMongoDBTest pkgs.mongodb-4_0
|
||||
+ runMongoDBTest pkgs.mongodb-4_2
|
||||
+ ''
|
||||
|
|
|
@ -3,7 +3,7 @@ import ../make-test-python.nix ({ pkgs, lib, ... }:
|
|||
with lib;
|
||||
|
||||
let
|
||||
krb5 =
|
||||
krb5 =
|
||||
{ enable = true;
|
||||
domain_realm."nfs.test" = "NFS.TEST";
|
||||
libdefaults.default_realm = "NFS.TEST";
|
||||
|
@ -31,7 +31,7 @@ in
|
|||
|
||||
{
|
||||
name = "nfsv4-with-kerberos";
|
||||
|
||||
|
||||
nodes = {
|
||||
client = { lib, ... }:
|
||||
{ inherit krb5 users;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
let
|
||||
let
|
||||
certs = import ./common/acme/server/snakeoil-certs.nix;
|
||||
in
|
||||
import ./make-test-python.nix {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
let
|
||||
let
|
||||
certs = import ./common/acme/server/snakeoil-certs.nix;
|
||||
in
|
||||
import ./make-test-python.nix {
|
||||
|
|
58
nixos/tests/snapcast.nix
Normal file
58
nixos/tests/snapcast.nix
Normal file
|
@ -0,0 +1,58 @@
|
|||
import ./make-test-python.nix ({ pkgs, ...} :
|
||||
|
||||
let
|
||||
port = 10004;
|
||||
tcpPort = 10005;
|
||||
httpPort = 10080;
|
||||
in {
|
||||
name = "snapcast";
|
||||
meta = with pkgs.stdenv.lib.maintainers; {
|
||||
maintainers = [ hexa ];
|
||||
};
|
||||
|
||||
nodes = {
|
||||
server = {
|
||||
services.snapserver = {
|
||||
enable = true;
|
||||
port = port;
|
||||
tcp.port = tcpPort;
|
||||
http.port = httpPort;
|
||||
streams = {
|
||||
mpd = {
|
||||
type = "pipe";
|
||||
location = "/run/snapserver/mpd";
|
||||
};
|
||||
bluetooth = {
|
||||
type = "pipe";
|
||||
location = "/run/snapserver/bluetooth";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
import json
|
||||
|
||||
get_rpc_version = {"id": "1", "jsonrpc": "2.0", "method": "Server.GetRPCVersion"}
|
||||
|
||||
start_all()
|
||||
|
||||
server.wait_for_unit("snapserver.service")
|
||||
server.wait_until_succeeds("ss -ntl | grep -q ${toString port}")
|
||||
server.wait_until_succeeds("ss -ntl | grep -q ${toString tcpPort}")
|
||||
server.wait_until_succeeds("ss -ntl | grep -q ${toString httpPort}")
|
||||
|
||||
with subtest("check that pipes are created"):
|
||||
server.succeed("test -p /run/snapserver/mpd")
|
||||
server.succeed("test -p /run/snapserver/bluetooth")
|
||||
|
||||
with subtest("test tcp json-rpc"):
|
||||
server.succeed(f"echo '{json.dumps(get_rpc_version)}' | nc -w 1 localhost ${toString tcpPort}")
|
||||
|
||||
with subtest("test http json-rpc"):
|
||||
server.succeed(
|
||||
"curl --fail http://localhost:${toString httpPort}/jsonrpc -d '{json.dumps(get_rpc_version)}'"
|
||||
)
|
||||
'';
|
||||
})
|
|
@ -24,9 +24,8 @@ in {
|
|||
testScript = ''
|
||||
machine.wait_for_unit("syncthing-init.service")
|
||||
config = machine.succeed("cat /var/lib/syncthing/.config/syncthing/config.xml")
|
||||
|
||||
|
||||
assert "testFolder" in config
|
||||
assert "${testId}" in config
|
||||
'';
|
||||
})
|
||||
|
||||
|
|
|
@ -159,6 +159,8 @@ in {
|
|||
node2.wait_for_unit("network.target")
|
||||
node3.wait_for_unit("network.target")
|
||||
|
||||
# NOTE: please keep in mind that the trailing whitespaces in the following strings
|
||||
# are intentional as the output is compared against the raw `iproute2`-output.
|
||||
client_ipv4_table = """
|
||||
192.168.1.2 dev vrf1 proto static metric 100
|
||||
192.168.2.3 dev vrf2 proto static metric 100
|
||||
|
@ -194,18 +196,16 @@ in {
|
|||
client.succeed("ping -c5 192.168.1.2")
|
||||
client.succeed("ping -c5 192.168.2.3")
|
||||
|
||||
# Test whether SSH through a VRF IP is possible.
|
||||
# (Note: this seems to be an issue on Linux 5.x, so I decided to add this to
|
||||
# ensure that we catch this when updating the default kernel).
|
||||
# with subtest("tcp traffic through vrf works"):
|
||||
# node1.wait_for_open_port(22)
|
||||
# client.succeed(
|
||||
# "cat ${snakeOilPrivateKey} > privkey.snakeoil"
|
||||
# )
|
||||
# client.succeed("chmod 600 privkey.snakeoil")
|
||||
# client.succeed(
|
||||
# "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil root@192.168.1.2 true"
|
||||
# )
|
||||
# Test whether TCP through a VRF IP is possible.
|
||||
with subtest("tcp traffic through vrf works"):
|
||||
node1.wait_for_open_port(22)
|
||||
client.succeed(
|
||||
"cat ${snakeOilPrivateKey} > privkey.snakeoil"
|
||||
)
|
||||
client.succeed("chmod 600 privkey.snakeoil")
|
||||
client.succeed(
|
||||
"ulimit -l 2048; ip vrf exec vrf1 ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil root@192.168.1.2 true"
|
||||
)
|
||||
|
||||
# Only configured routes through the VRF from the main routing table should
|
||||
# work. Additional IPs are only reachable when binding to the vrf interface.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import ./make-test.nix ({ pkgs, ... }: let
|
||||
import ./make-test-python.nix ({ pkgs, ... }: let
|
||||
snakeOil = pkgs.runCommand "snakeoil-certs" {
|
||||
outputs = [ "out" "cacert" "cert" "key" "crl" ];
|
||||
buildInputs = [ pkgs.gnutls.bin ];
|
||||
|
@ -105,187 +105,178 @@ in {
|
|||
newServerSystem = nodes.newServer.config.system.build.toplevel;
|
||||
switchToNewServer = "${newServerSystem}/bin/switch-to-configuration test";
|
||||
in ''
|
||||
sub su ($$) {
|
||||
my ($user, $cmd) = @_;
|
||||
my $esc = $cmd =~ s/'/'\\${"'"}'/gr;
|
||||
return "su - $user -c '$esc'";
|
||||
}
|
||||
from shlex import quote
|
||||
|
||||
sub setupClientsFor ($$;$) {
|
||||
my ($org, $user, $extraInit) = @_;
|
||||
|
||||
for my $client ($client1, $client2) {
|
||||
$client->nest("initialize client for user $user", sub {
|
||||
$client->succeed(
|
||||
(su $user, "rm -rf /home/$user/.task"),
|
||||
(su $user, "task rc.confirmation=no config confirmation no")
|
||||
);
|
||||
def su(user, cmd):
|
||||
return f"su - {user} -c {quote(cmd)}"
|
||||
|
||||
my $exportinfo = $server->succeed(
|
||||
"nixos-taskserver user export $org $user"
|
||||
);
|
||||
|
||||
$exportinfo =~ s/'/'\\'''/g;
|
||||
def no_extra_init(client, org, user):
|
||||
pass
|
||||
|
||||
$client->nest("importing taskwarrior configuration", sub {
|
||||
my $cmd = su $user, "eval '$exportinfo' >&2";
|
||||
my ($status, $out) = $client->execute_($cmd);
|
||||
if ($status != 0) {
|
||||
$client->log("output: $out");
|
||||
die "command `$cmd' did not succeed (exit code $status)\n";
|
||||
}
|
||||
});
|
||||
|
||||
eval { &$extraInit($client, $org, $user) };
|
||||
def setup_clients_for(org, user, extra_init=no_extra_init):
|
||||
for client in [client1, client2]:
|
||||
with client.nested(f"initialize client for user {user}"):
|
||||
client.succeed(
|
||||
su(user, f"rm -rf /home/{user}/.task"),
|
||||
su(user, "task rc.confirmation=no config confirmation no"),
|
||||
)
|
||||
|
||||
$client->succeed(su $user,
|
||||
"task config taskd.server server:${portStr} >&2"
|
||||
);
|
||||
exportinfo = server.succeed(f"nixos-taskserver user export {org} {user}")
|
||||
|
||||
$client->succeed(su $user, "task sync init >&2");
|
||||
});
|
||||
}
|
||||
}
|
||||
with client.nested("importing taskwarrior configuration"):
|
||||
client.succeed(su(user, f"eval {quote(exportinfo)} >&2"))
|
||||
|
||||
sub restartServer {
|
||||
$server->succeed("systemctl restart taskserver.service");
|
||||
$server->waitForOpenPort(${portStr});
|
||||
}
|
||||
extra_init(client, org, user)
|
||||
|
||||
sub readdImperativeUser {
|
||||
$server->nest("(re-)add imperative user bar", sub {
|
||||
$server->execute("nixos-taskserver org remove imperativeOrg");
|
||||
$server->succeed(
|
||||
"nixos-taskserver org add imperativeOrg",
|
||||
"nixos-taskserver user add imperativeOrg bar"
|
||||
);
|
||||
setupClientsFor "imperativeOrg", "bar";
|
||||
});
|
||||
}
|
||||
client.succeed(su(user, "task config taskd.server server:${portStr} >&2"))
|
||||
|
||||
sub testSync ($) {
|
||||
my $user = $_[0];
|
||||
subtest "sync for user $user", sub {
|
||||
$client1->succeed(su $user, "task add foo >&2");
|
||||
$client1->succeed(su $user, "task sync >&2");
|
||||
$client2->fail(su $user, "task list >&2");
|
||||
$client2->succeed(su $user, "task sync >&2");
|
||||
$client2->succeed(su $user, "task list >&2");
|
||||
};
|
||||
}
|
||||
client.succeed(su(user, "task sync init >&2"))
|
||||
|
||||
|
||||
def restart_server():
|
||||
server.systemctl("restart taskserver.service")
|
||||
server.wait_for_open_port(${portStr})
|
||||
|
||||
|
||||
def re_add_imperative_user():
|
||||
with server.nested("(re-)add imperative user bar"):
|
||||
server.execute("nixos-taskserver org remove imperativeOrg")
|
||||
server.succeed(
|
||||
"nixos-taskserver org add imperativeOrg",
|
||||
"nixos-taskserver user add imperativeOrg bar",
|
||||
)
|
||||
setup_clients_for("imperativeOrg", "bar")
|
||||
|
||||
|
||||
def test_sync(user):
|
||||
with subtest(f"sync for user {user}"):
|
||||
client1.succeed(su(user, "task add foo >&2"))
|
||||
client1.succeed(su(user, "task sync >&2"))
|
||||
client2.fail(su(user, "task list >&2"))
|
||||
client2.succeed(su(user, "task sync >&2"))
|
||||
client2.succeed(su(user, "task list >&2"))
|
||||
|
||||
|
||||
def check_client_cert(user):
|
||||
# debug level 3 is a workaround for gnutls issue https://gitlab.com/gnutls/gnutls/-/issues/1040
|
||||
cmd = (
|
||||
f"gnutls-cli -d 3"
|
||||
f" --x509cafile=/home/{user}/.task/keys/ca.cert"
|
||||
f" --x509keyfile=/home/{user}/.task/keys/private.key"
|
||||
f" --x509certfile=/home/{user}/.task/keys/public.cert"
|
||||
f" --port=${portStr} server < /dev/null"
|
||||
)
|
||||
return su(user, cmd)
|
||||
|
||||
sub checkClientCert ($) {
|
||||
my $user = $_[0];
|
||||
# debug level 3 is a workaround for gnutls issue https://gitlab.com/gnutls/gnutls/-/issues/1040
|
||||
my $cmd = "gnutls-cli -d 3".
|
||||
" --x509cafile=/home/$user/.task/keys/ca.cert".
|
||||
" --x509keyfile=/home/$user/.task/keys/private.key".
|
||||
" --x509certfile=/home/$user/.task/keys/public.cert".
|
||||
" --port=${portStr} server < /dev/null";
|
||||
return su $user, $cmd;
|
||||
}
|
||||
|
||||
# Explicitly start the VMs so that we don't accidentally start newServer
|
||||
$server->start;
|
||||
$client1->start;
|
||||
$client2->start;
|
||||
server.start()
|
||||
client1.start()
|
||||
client2.start()
|
||||
|
||||
$server->waitForUnit("taskserver.service");
|
||||
server.wait_for_unit("taskserver.service")
|
||||
|
||||
$server->succeed(
|
||||
"nixos-taskserver user list testOrganisation | grep -qxF alice",
|
||||
"nixos-taskserver user list testOrganisation | grep -qxF foo",
|
||||
"nixos-taskserver user list anotherOrganisation | grep -qxF bob"
|
||||
);
|
||||
server.succeed(
|
||||
"nixos-taskserver user list testOrganisation | grep -qxF alice",
|
||||
"nixos-taskserver user list testOrganisation | grep -qxF foo",
|
||||
"nixos-taskserver user list anotherOrganisation | grep -qxF bob",
|
||||
)
|
||||
|
||||
$server->waitForOpenPort(${portStr});
|
||||
server.wait_for_open_port(${portStr})
|
||||
|
||||
$client1->waitForUnit("multi-user.target");
|
||||
$client2->waitForUnit("multi-user.target");
|
||||
client1.wait_for_unit("multi-user.target")
|
||||
client2.wait_for_unit("multi-user.target")
|
||||
|
||||
setupClientsFor "testOrganisation", "alice";
|
||||
setupClientsFor "testOrganisation", "foo";
|
||||
setupClientsFor "anotherOrganisation", "bob";
|
||||
setup_clients_for("testOrganisation", "alice")
|
||||
setup_clients_for("testOrganisation", "foo")
|
||||
setup_clients_for("anotherOrganisation", "bob")
|
||||
|
||||
testSync $_ for ("alice", "bob", "foo");
|
||||
for user in ["alice", "bob", "foo"]:
|
||||
test_sync(user)
|
||||
|
||||
$server->fail("nixos-taskserver user add imperativeOrg bar");
|
||||
readdImperativeUser;
|
||||
server.fail("nixos-taskserver user add imperativeOrg bar")
|
||||
re_add_imperative_user()
|
||||
|
||||
testSync "bar";
|
||||
test_sync("bar")
|
||||
|
||||
subtest "checking certificate revocation of user bar", sub {
|
||||
$client1->succeed(checkClientCert "bar");
|
||||
with subtest("checking certificate revocation of user bar"):
|
||||
client1.succeed(check_client_cert("bar"))
|
||||
|
||||
$server->succeed("nixos-taskserver user remove imperativeOrg bar");
|
||||
restartServer;
|
||||
server.succeed("nixos-taskserver user remove imperativeOrg bar")
|
||||
restart_server()
|
||||
|
||||
$client1->fail(checkClientCert "bar");
|
||||
client1.fail(check_client_cert("bar"))
|
||||
|
||||
$client1->succeed(su "bar", "task add destroy everything >&2");
|
||||
$client1->fail(su "bar", "task sync >&2");
|
||||
};
|
||||
client1.succeed(su("bar", "task add destroy everything >&2"))
|
||||
client1.fail(su("bar", "task sync >&2"))
|
||||
|
||||
readdImperativeUser;
|
||||
re_add_imperative_user()
|
||||
|
||||
subtest "checking certificate revocation of org imperativeOrg", sub {
|
||||
$client1->succeed(checkClientCert "bar");
|
||||
with subtest("checking certificate revocation of org imperativeOrg"):
|
||||
client1.succeed(check_client_cert("bar"))
|
||||
|
||||
$server->succeed("nixos-taskserver org remove imperativeOrg");
|
||||
restartServer;
|
||||
server.succeed("nixos-taskserver org remove imperativeOrg")
|
||||
restart_server()
|
||||
|
||||
$client1->fail(checkClientCert "bar");
|
||||
client1.fail(check_client_cert("bar"))
|
||||
|
||||
$client1->succeed(su "bar", "task add destroy even more >&2");
|
||||
$client1->fail(su "bar", "task sync >&2");
|
||||
};
|
||||
client1.succeed(su("bar", "task add destroy even more >&2"))
|
||||
client1.fail(su("bar", "task sync >&2"))
|
||||
|
||||
readdImperativeUser;
|
||||
re_add_imperative_user()
|
||||
|
||||
subtest "check whether declarative config overrides user bar", sub {
|
||||
restartServer;
|
||||
testSync "bar";
|
||||
};
|
||||
with subtest("check whether declarative config overrides user bar"):
|
||||
restart_server()
|
||||
test_sync("bar")
|
||||
|
||||
subtest "check manual configuration", sub {
|
||||
# Remove the keys from automatic CA creation, to make sure the new
|
||||
# generation doesn't use keys from before.
|
||||
$server->succeed('rm -rf ${cfg.dataDir}/keys/* >&2');
|
||||
|
||||
$server->succeed('${switchToNewServer} >&2');
|
||||
$server->waitForUnit("taskserver.service");
|
||||
$server->waitForOpenPort(${portStr});
|
||||
def init_manual_config(client, org, user):
|
||||
cfgpath = f"/home/{user}/.task"
|
||||
|
||||
$server->succeed(
|
||||
"nixos-taskserver org add manualOrg",
|
||||
"nixos-taskserver user add manualOrg alice"
|
||||
);
|
||||
client.copy_from_host(
|
||||
"${snakeOil.cacert}",
|
||||
f"{cfgpath}/ca.cert",
|
||||
)
|
||||
for file in ["alice.key", "alice.cert"]:
|
||||
client.copy_from_host(
|
||||
f"${snakeOil}/{file}",
|
||||
f"{cfgpath}/{file}",
|
||||
)
|
||||
|
||||
setupClientsFor "manualOrg", "alice", sub {
|
||||
my ($client, $org, $user) = @_;
|
||||
my $cfgpath = "/home/$user/.task";
|
||||
for file in [f"{user}.key", f"{user}.cert"]:
|
||||
client.copy_from_host(
|
||||
f"${snakeOil}/{file}",
|
||||
f"{cfgpath}/{file}",
|
||||
)
|
||||
|
||||
$client->copyFileFromHost("${snakeOil.cacert}", "$cfgpath/ca.cert");
|
||||
for my $file ('alice.key', 'alice.cert') {
|
||||
$client->copyFileFromHost("${snakeOil}/$file", "$cfgpath/$file");
|
||||
}
|
||||
client.succeed(
|
||||
su("alice", f"task config taskd.ca {cfgpath}/ca.cert"),
|
||||
su("alice", f"task config taskd.key {cfgpath}/{user}.key"),
|
||||
su(user, f"task config taskd.certificate {cfgpath}/{user}.cert"),
|
||||
)
|
||||
|
||||
for my $file ("$user.key", "$user.cert") {
|
||||
$client->copyFileFromHost(
|
||||
"${snakeOil}/$file", "$cfgpath/$file"
|
||||
);
|
||||
}
|
||||
$client->copyFileFromHost(
|
||||
"${snakeOil.cacert}", "$cfgpath/ca.cert"
|
||||
);
|
||||
$client->succeed(
|
||||
(su "alice", "task config taskd.ca $cfgpath/ca.cert"),
|
||||
(su "alice", "task config taskd.key $cfgpath/$user.key"),
|
||||
(su $user, "task config taskd.certificate $cfgpath/$user.cert")
|
||||
);
|
||||
};
|
||||
|
||||
testSync "alice";
|
||||
};
|
||||
with subtest("check manual configuration"):
|
||||
# Remove the keys from automatic CA creation, to make sure the new
|
||||
# generation doesn't use keys from before.
|
||||
server.succeed("rm -rf ${cfg.dataDir}/keys/* >&2")
|
||||
|
||||
server.succeed(
|
||||
"${switchToNewServer} >&2"
|
||||
)
|
||||
server.wait_for_unit("taskserver.service")
|
||||
server.wait_for_open_port(${portStr})
|
||||
|
||||
server.succeed(
|
||||
"nixos-taskserver org add manualOrg",
|
||||
"nixos-taskserver user add manualOrg alice",
|
||||
)
|
||||
|
||||
setup_clients_for("manualOrg", "alice", init_manual_config)
|
||||
|
||||
test_sync("alice")
|
||||
'';
|
||||
})
|
||||
|
|
|
@ -44,7 +44,7 @@ import ./make-test-python.nix ({ ... }: {
|
|||
configured.succeed(
|
||||
"curl --fail -o /dev/null 127.0.0.1:3000 --user somelogin:somesecret"
|
||||
)
|
||||
|
||||
|
||||
with subtest("restart preserves changes"):
|
||||
# given running wiki
|
||||
default.wait_for_unit("tiddlywiki.service")
|
||||
|
|
|
@ -34,4 +34,4 @@ import ./make-test-python.nix ({ pkgs, ... }: {
|
|||
"curl -L http://localhost:9090/metrics | grep 'promhttp_metric_handler_requests_total{code=\"500\"} 0'"
|
||||
)
|
||||
'';
|
||||
})
|
||||
})
|
||||
|
|
|
@ -55,13 +55,13 @@
|
|||
}:
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "ardour";
|
||||
version = "6.0";
|
||||
version = "6.2";
|
||||
|
||||
# don't fetch releases from the GitHub mirror, they are broken
|
||||
src = fetchgit {
|
||||
url = "git://git.ardour.org/ardour/ardour.git";
|
||||
rev = version;
|
||||
sha256 = "162jd96zahl05fdmjwvpdfjxbhd6ifbav6xqa0vv6rsdl4zk395q";
|
||||
sha256 = "17jxbqavricy01x4ymq6d302djsqfnv84m7dm4fd8cpka0dqjp1y";
|
||||
};
|
||||
|
||||
patches = [
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "BJumblr";
|
||||
version = "0.2";
|
||||
version = "1.4.0";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "sjaehn";
|
||||
repo = pname;
|
||||
rev = "v${version}";
|
||||
sha256 = "14z8113zkwykbhm1a8h2xs972dgifvlfij92b08jckyc7cbz84ys";
|
||||
rev = version;
|
||||
sha256 = "03x1gvri9yk000fvvc8zvvywf38cc41vkyhhp9xby71b23n5wbn0";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [ pkgconfig ];
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "cava";
|
||||
version = "0.7.1";
|
||||
version = "0.7.2";
|
||||
|
||||
buildInputs = [
|
||||
alsaLib
|
||||
|
@ -16,7 +16,7 @@ stdenv.mkDerivation rec {
|
|||
owner = "karlstav";
|
||||
repo = "cava";
|
||||
rev = version;
|
||||
sha256 = "0p2g3xxl2n425bghs1qnff30jaj9cba94j2gbhgxmwaxhz26vbk7";
|
||||
sha256 = "1chc08spjf5i17n8y48aqzdxsj8vvf0r2l62ldw2pqgw60dacvs1";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [ autoreconfHook ];
|
||||
|
|
|
@ -12,13 +12,13 @@
|
|||
|
||||
mkDerivation rec {
|
||||
pname = "projectm";
|
||||
version = "3.1.3";
|
||||
version = "3.1.7";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "projectM-visualizer";
|
||||
repo = "projectM";
|
||||
rev = "v${version}";
|
||||
sha256 = "1mjnahr694phksmvc069y89rv85s4l2z9fixkc3l1f5qj2vgn4sy";
|
||||
sha256 = "1wm5fym6c1yb972pmil7j9axinqqwrj68cwd2sc7ky8c5z2fsdna";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "realTimeConfigQuickScan";
|
||||
version = "unstable-2020-08-03";
|
||||
version = "unstable-2020-07-23";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "raboof";
|
||||
repo = pname;
|
||||
rev = "4b482db17f8d8567ba0abf33459ceb5f756f088c";
|
||||
sha256 = "00l69gzwla9gjv5kpklgxlwnl48wnh8h6w0k8i69qr2cxigg4rhj";
|
||||
rev = "4697ba093d43d512b74a73b89531cb8c5adaa274";
|
||||
sha256 = "16kanzp5i353x972zjkwgi3m8z90wc58613mlfzb0n01djdnm6k5";
|
||||
};
|
||||
|
||||
buildInputs = [ perlPackages.perl makeWrapper ];
|
||||
|
@ -16,28 +16,35 @@ stdenv.mkDerivation rec {
|
|||
dontBuild = true;
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
mkdir -p $out/bin
|
||||
mkdir -p $out/share/doc
|
||||
mkdir -p $out/share/$pname
|
||||
mkdir -p $out/share/doc/$pname
|
||||
# Install Script Files:
|
||||
# *.pm files
|
||||
for i in *.pm; do
|
||||
install -Dm 755 "$i" "$out/share/$i"
|
||||
install -Dm 755 "$i" "$out/share/$pname/$i"
|
||||
done
|
||||
# Install doc files:
|
||||
install -D COPYING "$out/share/doc/COPYING"
|
||||
install -D README.md "$out/share/doc/README.md"
|
||||
install -D COPYING "$out/share/doc/$pname/COPYING"
|
||||
install -D README.md "$out/share/doc/$pname/README.md"
|
||||
# Install Executable scripts:
|
||||
install -Dm 755 realTimeConfigQuickScan.pl "$out/bin/realTimeConfigQuickScan"
|
||||
install -Dm 755 QuickScan.pl "$out/bin/QuickScan"
|
||||
wrapProgram $out/bin/realTimeConfigQuickScan \
|
||||
--set PERL5LIB "$out/share"
|
||||
wrapProgram $out/bin/QuickScan \
|
||||
--set PERL5LIB "$out/share:${with perlPackages; makePerlPath [ Tk ]}"
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
postFixup = ''
|
||||
wrapProgram $out/bin/realTimeConfigQuickScan \
|
||||
--set PERL5LIB "$out/share/$pname"
|
||||
wrapProgram $out/bin/QuickScan \
|
||||
--set PERL5LIB "$out/share/$pname:${with perlPackages; makePerlPath [ Tk ]}"
|
||||
'';
|
||||
|
||||
meta = with stdenv.lib; {
|
||||
description = "Linux configuration checker for systems to be used for real-time audio";
|
||||
homepage = "https://github.com/raboof/realtimeconfigquickscan";
|
||||
license = licenses.gpl2;
|
||||
license = licenses.gpl2Plus;
|
||||
maintainers = with maintainers; [ magnetophon ];
|
||||
platforms = platforms.linux ;
|
||||
};
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{ stdenv, lib, fetchFromGitHub, cmake, pkgconfig
|
||||
, alsaLib, asio, avahi, boost170, flac, libogg, libvorbis, soxr }:
|
||||
, alsaLib, asio, avahi, boost170, flac, libogg, libvorbis, soxr
|
||||
, nixosTests }:
|
||||
|
||||
let
|
||||
|
||||
|
@ -57,6 +58,8 @@ stdenv.mkDerivation rec {
|
|||
cp -r ../doc/* ../*.md $out/share/doc/snapcast
|
||||
'';
|
||||
|
||||
passthru.tests.snapcast = nixosTests.snapcast;
|
||||
|
||||
meta = with lib; {
|
||||
description = "Synchronous multi-room audio player";
|
||||
homepage = "https://github.com/badaix/snapcast";
|
||||
|
|
|
@ -35,23 +35,30 @@ let
|
|||
gtk3 # Fix error: GLib-GIO-ERROR **: Settings schema 'org.gtk.Settings.FileChooser' is not installed
|
||||
];
|
||||
|
||||
dontBuild = true;
|
||||
dontConfigure = true;
|
||||
|
||||
unpackPhase = ''
|
||||
ar p $src data.tar.xz | tar xJ ./usr/
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
mkdir -p $out
|
||||
mv usr/bin usr/share $out
|
||||
rm -rf $out/share/lintian
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
preFixup = ''
|
||||
gappsWrapperArgs+=(
|
||||
--prefix "PATH" : "${gvfs}/bin" \
|
||||
--prefix "PATH" : "${gvfs}/bin"
|
||||
)
|
||||
'';
|
||||
|
||||
buildCommand = ''
|
||||
mkdir -p $out/usr/
|
||||
ar p $src data.tar.xz | tar -C $out -xJ ./usr
|
||||
sed -i -e "s|Exec=.*$|Exec=$out/bin/${pname}|" $out/usr/share/applications/${pname}.desktop
|
||||
mv $out/usr/* $out/
|
||||
rm -r $out/share/lintian
|
||||
rm -r $out/usr/
|
||||
sed -i "s/${pname})/.${pname}-wrapped)/" $out/bin/${pname}
|
||||
|
||||
fixupPhase
|
||||
|
||||
postFixup = ''
|
||||
share=$out/share/${pname}
|
||||
|
||||
patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" \
|
||||
|
@ -70,6 +77,8 @@ let
|
|||
ln -s ${pkgs.git}/bin/git $dugite/git/libexec/git-core/git
|
||||
|
||||
find $share -name "*.node" -exec patchelf --set-rpath "${atomEnv.libPath}:$share" {} \;
|
||||
|
||||
sed -i -e "s|Exec=.*$|Exec=$out/bin/${pname}|" $out/share/applications/${pname}.desktop
|
||||
'';
|
||||
|
||||
meta = with stdenv.lib; {
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "lite";
|
||||
version = "1.06";
|
||||
version = "1.11";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "rxi";
|
||||
repo = pname;
|
||||
rev = "v${version}";
|
||||
sha256 = "1lw4a6xv8pdlgwnhh870caij4iyzxdyjw4qmm4fswja9mbqkj32f";
|
||||
sha256 = "0wxqfb4ly8g7w5qph76xys95b55ackkags8jgd1nasmiyi8gcd5a";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [ makeWrapper pkg-config ];
|
||||
|
|
|
@ -116,11 +116,14 @@ let
|
|||
in
|
||||
symlinkJoin {
|
||||
name = "neovim-${stdenv.lib.getVersion neovim}";
|
||||
# Remove the symlinks created by symlinkJoin which we need to perform
|
||||
# extra actions upon
|
||||
postBuild = ''
|
||||
# Remove the symlinks created by symlinkJoin which we need to perform
|
||||
# extra actions upon
|
||||
rm $out/share/applications/nvim.desktop $out/bin/nvim
|
||||
rm $out/bin/nvim
|
||||
makeWrapper ${lib.escapeShellArgs initialMakeWrapperArgs} ${extraMakeWrapperArgs}
|
||||
''
|
||||
+ lib.optionalString stdenv.isLinux ''
|
||||
rm $out/share/applications/nvim.desktop
|
||||
substitute ${neovim}/share/applications/nvim.desktop $out/share/applications/nvim.desktop \
|
||||
--replace 'TryExec=nvim' "TryExec=$out/bin/nvim" \
|
||||
--replace 'Name=Neovim' 'Name=WrappedNeovim'
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "quilter";
|
||||
version = "2.2.4";
|
||||
version = "2.5.0";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "lainsce";
|
||||
repo = pname;
|
||||
rev = version;
|
||||
sha256 = "0xmnfqqdn7p84aksb8yzs14ikgy5driylr6m4p5ffsb6i9aa0i9h";
|
||||
sha256 = "0622mh46z3fi6zvipmgj8k4d4gj1c2781l10frk7wqq1sysjrxps";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [
|
||||
|
|
|
@ -13,8 +13,8 @@ let
|
|||
else throw "ImageMagick is not supported on this platform.";
|
||||
|
||||
cfg = {
|
||||
version = "7.0.10-19";
|
||||
sha256 = "12ilfdbxllkaa3bs9z86d2nkklqz5c0l57kqj91l2ixjlvra64w0";
|
||||
version = "7.0.10-25";
|
||||
sha256 = "15y07kgy4mx3qyxsbd9g6s2yaa2mxnfvfzas35jw0vz6qjjyaw5c";
|
||||
patches = [];
|
||||
};
|
||||
in
|
||||
|
|
|
@ -11,11 +11,11 @@
|
|||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "drawio";
|
||||
version = "13.5.1";
|
||||
version = "13.5.7";
|
||||
|
||||
src = fetchurl {
|
||||
url = "https://github.com/jgraph/drawio-desktop/releases/download/v${version}/draw.io-x86_64-${version}.rpm";
|
||||
sha256 = "00ggm867c5005qfm35qf8a94d87ln91irb1ir6012am2k5bn8c8p";
|
||||
sha256 = "1b2sb44zsa6g5nnsa7drn4fn61jfz3a3g3bisai85fyjff746ipc";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [
|
||||
|
|
72
pkgs/applications/graphics/lazpaint/default.nix
Normal file
72
pkgs/applications/graphics/lazpaint/default.nix
Normal file
|
@ -0,0 +1,72 @@
|
|||
{ stdenv, fetchFromGitHub, lazarus, fpc, pango, cairo, glib
|
||||
, atk, gtk2, libX11, gdk-pixbuf, busybox, python3, makeWrapper }:
|
||||
|
||||
with stdenv;
|
||||
|
||||
let
|
||||
bgrabitmap = fetchFromGitHub {
|
||||
owner = "bgrabitmap";
|
||||
repo = "bgrabitmap";
|
||||
rev = "v11.1";
|
||||
sha256 = "0bcmiiwly4a7w8p3m5iskzvk8rz87qhc0gcijrdvwg87cafd88gz";
|
||||
};
|
||||
bgracontrols = fetchFromGitHub {
|
||||
owner = "bgrabitmap";
|
||||
repo = "bgracontrols";
|
||||
rev = "v6.7.2";
|
||||
sha256 = "0cwxzv0rl6crkf6f67mvga5cn5pyhr6ksm8cqhpxjiqi937dnyxx";
|
||||
};
|
||||
in stdenv.mkDerivation rec {
|
||||
pname = "lazpaint";
|
||||
version = "7.1.3";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "bgrabitmap";
|
||||
repo = "lazpaint";
|
||||
rev = "v${version}";
|
||||
sha256 = "1sfb5hmhzscz3nv4cmc192jimkg70l4z3q3yxkivhw1hwwsv9cbg";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [ lazarus fpc makeWrapper ];
|
||||
|
||||
buildInputs = [ pango cairo glib atk gtk2 libX11 gdk-pixbuf ];
|
||||
|
||||
NIX_LDFLAGS = "--as-needed -rpath ${lib.makeLibraryPath buildInputs}";
|
||||
|
||||
buildPhase = ''
|
||||
cp -r --no-preserve=mode ${bgrabitmap} bgrabitmap
|
||||
cp -r --no-preserve=mode ${bgracontrols} bgracontrols
|
||||
|
||||
lazbuild --lazarusdir=${lazarus}/share/lazarus \
|
||||
--build-mode=Release \
|
||||
bgrabitmap/bgrabitmap/bgrabitmappack.lpk \
|
||||
bgracontrols/bgracontrols.lpk \
|
||||
lazpaintcontrols/lazpaintcontrols.lpk \
|
||||
lazpaint/lazpaint.lpi
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
# Reuse existing install script
|
||||
cd lazpaint/release/debian
|
||||
substituteInPlace makedeb.sh --replace "rm -rf" "ls"
|
||||
patchShebangs ./makedeb.sh
|
||||
PATH=$PATH:${busybox}/bin ./makedeb.sh
|
||||
cp -r staging/usr $out
|
||||
|
||||
# Python is needed for scripts
|
||||
makeWrapper $out/share/lazpaint/lazpaint $out/bin/lazpaint \
|
||||
--prefix PATH : ${stdenv.lib.makeBinPath [ python3 ]}
|
||||
|
||||
substituteInPlace $out/share/applications/lazpaint.desktop \
|
||||
--replace /usr/share/pixmaps/lazpaint.png $out/share/pixmaps/lazpaint.png \
|
||||
--replace /usr/share/lazpaint/lazpaint $out/bin/lazpaint
|
||||
'';
|
||||
|
||||
meta = with stdenv.lib; {
|
||||
description = "Image editor like PaintBrush or Paint.Net";
|
||||
homepage = "https://sourceforge.net/projects/lazpaint/";
|
||||
license = licenses.gpl3;
|
||||
platforms = platforms.linux;
|
||||
maintainers = with maintainers; [ gnidorah ];
|
||||
};
|
||||
}
|
|
@ -18,13 +18,13 @@
|
|||
|
||||
mkDerivation rec {
|
||||
pname = "nomacs";
|
||||
version = "3.15.1616";
|
||||
version = "3.16.224";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "nomacs";
|
||||
repo = "nomacs";
|
||||
rev = version;
|
||||
sha256 = "0g1saqf31zncqdiwk7aaf951j3g33bg0vcjcr5mvg600jxiinw8j";
|
||||
sha256 = "05d4hqg0gl3g9s2xf1hr7mc7g4cqarcap4nzxxa51fsphw2b8x16";
|
||||
};
|
||||
|
||||
enableParallelBuilding = true;
|
||||
|
|
|
@ -74,7 +74,7 @@ let
|
|||
akregator = callPackage ./akregator.nix {};
|
||||
ark = callPackage ./ark {};
|
||||
baloo-widgets = callPackage ./baloo-widgets.nix {};
|
||||
bovo = callPackage ./bovo.nix {};
|
||||
bovo = callPackage ./bovo.nix {};
|
||||
bomber = callPackage ./bomber.nix {};
|
||||
calendarsupport = callPackage ./calendarsupport.nix {};
|
||||
dolphin = callPackage ./dolphin.nix {};
|
||||
|
@ -113,6 +113,7 @@ let
|
|||
kdialog = callPackage ./kdialog.nix {};
|
||||
keditbookmarks = callPackage ./keditbookmarks.nix {};
|
||||
kfind = callPackage ./kfind.nix {};
|
||||
kfloppy = callPackage ./kfloppy.nix {};
|
||||
kgeography = callPackage ./kgeography.nix {};
|
||||
kget = callPackage ./kget.nix {};
|
||||
kgpg = callPackage ./kgpg.nix {};
|
||||
|
|
20
pkgs/applications/kde/kfloppy.nix
Normal file
20
pkgs/applications/kde/kfloppy.nix
Normal file
|
@ -0,0 +1,20 @@
|
|||
{ mkDerivation, lib, extra-cmake-modules, kdoctools, kcompletion, kxmlgui }:
|
||||
|
||||
mkDerivation {
|
||||
name = "kfloppy";
|
||||
meta = with lib; {
|
||||
homepage = "https://kde.org/applications/en/utilities/org.kde.kfloppy";
|
||||
description = "KFloppy is a utility to format 3.5\" and 5.25\" floppy disks";
|
||||
maintainers = with maintainers; [ freezeboy ];
|
||||
license = licenses.gpl2Plus;
|
||||
platforms = platforms.linux;
|
||||
};
|
||||
nativeBuildInputs = [
|
||||
extra-cmake-modules
|
||||
];
|
||||
buildInputs = [
|
||||
kdoctools
|
||||
kcompletion
|
||||
kxmlgui
|
||||
];
|
||||
}
|
|
@ -1,24 +1,30 @@
|
|||
{ clipnotify, makeWrapper, xsel, dmenu, utillinux, gawk, stdenv, fetchFromGitHub, lib }:
|
||||
{ clipnotify, makeWrapper, xsel, dmenu, utillinux, gawk, stdenv, fetchFromGitHub, fetchpatch, lib }:
|
||||
let
|
||||
runtimePath = lib.makeBinPath [ clipnotify xsel dmenu utillinux gawk ];
|
||||
in
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "clipmenu";
|
||||
version = "6.0.1";
|
||||
version = "6.1.0";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "cdown";
|
||||
repo = "clipmenu";
|
||||
rev = version;
|
||||
sha256 = "0053j4i14lz5m2bzc5sch5id5ilr1bl196mp8fp0q8x74w3vavs9";
|
||||
sha256 = "0ddj5xcwrdb2qvrndvhv8j6swcqc8dvv5i00pqk35rfk5mrl4hwv";
|
||||
};
|
||||
|
||||
|
||||
patches = [
|
||||
(fetchpatch {
|
||||
url = "https://github.com/cdown/clipmenu/commit/443b58583ef216e2405e4a38d401f7c36386d21e.patch";
|
||||
sha256 = "12m4rpw7jbr31c919llbsmn8dcf7yh9aijln4iym6h2lylzqzzdz";
|
||||
})
|
||||
];
|
||||
|
||||
makeFlags = [ "PREFIX=$(out)" ];
|
||||
buildInputs = [ makeWrapper ];
|
||||
nativeBuildInputs = [ xsel clipnotify ];
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/bin
|
||||
cp clipdel clipmenu clipmenud $out/bin
|
||||
|
||||
for bin in $out/bin/*; do
|
||||
wrapProgram "$bin" --prefix PATH : "${runtimePath}"
|
||||
done
|
||||
|
|
|
@ -2,20 +2,19 @@
|
|||
|
||||
let
|
||||
pname = "joplin-desktop";
|
||||
version = "1.0.216";
|
||||
desktopItem = makeDesktopItem {
|
||||
name = "Joplin";
|
||||
exec = "joplin-desktop";
|
||||
type = "Application";
|
||||
desktopName = "Joplin";
|
||||
};
|
||||
in appimageTools.wrapType2 rec {
|
||||
version = "1.0.233";
|
||||
name = "${pname}-${version}";
|
||||
|
||||
src = fetchurl {
|
||||
url = "https://github.com/laurent22/joplin/releases/download/v${version}/Joplin-${version}.AppImage";
|
||||
sha256 = "17rb7h98h9i2p5kw5gznx5swpz6yxqdxwc9x5cgbkc31vk10iszn";
|
||||
sha256 = "1fmk56b9b70ly1r471mhppr8fz1wm2gpxji1v760ynha8fqy7qg1";
|
||||
};
|
||||
|
||||
appimageContents = appimageTools.extractType2 {
|
||||
inherit name src;
|
||||
};
|
||||
in appimageTools.wrapType2 rec {
|
||||
inherit name src;
|
||||
|
||||
profile = ''
|
||||
export LC_ALL=C.UTF-8
|
||||
|
@ -25,9 +24,12 @@ in appimageTools.wrapType2 rec {
|
|||
multiPkgs = null; # no 32bit needed
|
||||
extraPkgs = appimageTools.defaultFhsEnvArgs.multiPkgs;
|
||||
extraInstallCommands = ''
|
||||
mkdir -p $out/share/applications
|
||||
ln -s ${desktopItem}/share/applications/* $out/share/applications
|
||||
mv $out/bin/{${name},${pname}}
|
||||
install -m 444 -D ${appimageContents}/joplin.desktop $out/share/applications/joplin.desktop
|
||||
install -m 444 -D ${appimageContents}/joplin.png \
|
||||
$out/share/pixmaps/joplin.png
|
||||
substituteInPlace $out/share/applications/joplin.desktop \
|
||||
--replace 'Exec=AppRun' 'Exec=${pname}'
|
||||
'';
|
||||
|
||||
|
||||
|
|
|
@ -2,16 +2,16 @@
|
|||
|
||||
rustPlatform.buildRustPackage rec {
|
||||
pname = "kondo";
|
||||
version = "0.3";
|
||||
version = "0.4";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "tbillington";
|
||||
repo = pname;
|
||||
rev = "v${version}";
|
||||
sha256 = "1rrg0xfm3vn5jh861r4ismrga673g7v6qnzl2v1haflgjhvdazwd";
|
||||
sha256 = "0kl2zn6ir3w75ny25ksgxl93vlyb13gzx2795zyimqqnsrdpbbrf";
|
||||
};
|
||||
|
||||
cargoSha256 = "1y7g8gw9hsm997d6i99c3dj2gb8y8cgws5001n85f9bpnlvvmf9y";
|
||||
cargoSha256 = "1ax81a2828z3yla1psg5xi8ild65m6zcsvx48ncz902mpzqlj92b";
|
||||
|
||||
meta = with stdenv.lib; {
|
||||
description = "Save disk space by cleaning unneeded files from software projects";
|
||||
|
|
29
pkgs/applications/misc/navi/default.nix
Normal file
29
pkgs/applications/misc/navi/default.nix
Normal file
|
@ -0,0 +1,29 @@
|
|||
{ rustPlatform, fetchFromGitHub, lib, fzf, makeWrapper }:
|
||||
|
||||
rustPlatform.buildRustPackage rec {
|
||||
pname = "navi";
|
||||
version = "2.7.1";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "denisidoro";
|
||||
repo = "navi";
|
||||
rev = "v${version}";
|
||||
sha256 = "12p9l41k7isaapr0xbsm7brkjrv7i8826y029i12psz92nsynk29";
|
||||
};
|
||||
|
||||
cargoSha256 = "11dc3gc7fyikbbgacmljhysr2sl7lmq6w3bsfcf2cqny39r25yp0";
|
||||
|
||||
nativeBuildInputs = [ makeWrapper ];
|
||||
|
||||
postInstall = ''
|
||||
wrapProgram $out/bin/navi --prefix PATH : ${lib.makeBinPath [ fzf ]}
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
description = "An interactive cheatsheet tool for the command-line and application launchers";
|
||||
homepage = "https://github.com/denisidoro/navi";
|
||||
license = licenses.asl20;
|
||||
platforms = platforms.unix;
|
||||
maintainers = with maintainers; [ cust0dian ];
|
||||
};
|
||||
}
|
|
@ -2,16 +2,16 @@
|
|||
|
||||
buildGoModule rec {
|
||||
pname = "amfora";
|
||||
version = "1.3.0";
|
||||
version = "1.4.0";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "makeworld-the-better-one";
|
||||
repo = "amfora";
|
||||
rev = "v${version}";
|
||||
sha256 = "0bnjwsyi6l9p27rajwh0nq53zi4km7qpgyb08q17j0vd87gpdhka";
|
||||
sha256 = "1z4r1yqy5nkfa7yqcsqpqfdcghw8idryzb3s6d6ibca47r0qlcvw";
|
||||
};
|
||||
|
||||
vendorSha256 = "1rj2m3rg8ixclj5jr0nmp266vwj1mg5ampxn04i3wgaayy49dbdi";
|
||||
vendorSha256 = "0xj2s14dq10fwqqxjn4d8x6zljd5d15gjbja2gb75rfv09s4fdgv";
|
||||
|
||||
meta = with lib; {
|
||||
description = "A fancy terminal browser for the Gemini protocol";
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{ newScope, config, stdenv, llvmPackages_9, llvmPackages_10
|
||||
, makeWrapper, ed, gnugrep
|
||||
, makeWrapper, ed, gnugrep, coreutils
|
||||
, glib, gtk3, gnome3, gsettings-desktop-schemas, gn, fetchgit
|
||||
, libva ? null
|
||||
, pipewire_0_2
|
||||
|
@ -196,7 +196,7 @@ in stdenv.mkDerivation {
|
|||
'' + ''
|
||||
|
||||
# libredirect causes chromium to deadlock on startup
|
||||
export LD_PRELOAD="\$(echo -n "\$LD_PRELOAD" | tr ':' '\n' | ${gnugrep}/bin/grep -v /lib/libredirect\\\\.so$ | tr '\n' ':')"
|
||||
export LD_PRELOAD="\$(echo -n "\$LD_PRELOAD" | ${coreutils}/bin/tr ':' '\n' | ${gnugrep}/bin/grep -v /lib/libredirect\\\\.so$ | ${coreutils}/bin/tr '\n' ':')"
|
||||
|
||||
export XDG_DATA_DIRS=$XDG_ICON_DIRS:$GSETTINGS_SCHEMAS_PATH\''${XDG_DATA_DIRS:+:}\$XDG_DATA_DIRS
|
||||
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
# Generated by debian-patches.sh from debian-patches.txt
|
||||
let
|
||||
prefix = "https://sources.debian.org/data/main/e/elinks/0.13.2-1/debian/patches";
|
||||
in
|
||||
[
|
||||
{
|
||||
url = "${prefix}/03_459467_ui.leds.enable_0.diff";
|
||||
sha256 = "0l35lglmnvyzz3xyy18nksra14gsp7yc67rskbzmr61szg8b9jqr";
|
||||
}
|
||||
{
|
||||
url = "${prefix}/04_436817_nostrip.diff";
|
||||
sha256 = "0ixvxaba1ww375gpdh7r67srp3xsfb5vyz2sfv1pgj6mczwg8v24";
|
||||
}
|
||||
{
|
||||
url = "${prefix}/07_617713_cache_control.diff";
|
||||
sha256 = "0drn4r33ywvmihr0drsp2jwz7mlf5z5fv8ra7fpkdavx45xqaf15";
|
||||
}
|
||||
{
|
||||
url = "${prefix}/10-reproducible-build.diff";
|
||||
sha256 = "024yp3xsh0hw29l1wikfmk9j3mqval6pdr4xi7rzffrlaknh58h5";
|
||||
}
|
||||
{
|
||||
url = "${prefix}/14_debug_disable_Werror.diff";
|
||||
sha256 = "0s620r88ikfljflb5nd133cww2wc0i85ag8lzpvrsmg0q00hfmax";
|
||||
}
|
||||
{
|
||||
url = "${prefix}/16_POST_BUFFER_SIZE.diff";
|
||||
sha256 = "17vkvy0d0rabmgk8iqwgdsrgjn6dbb9cf6760qbz82zlb37s09nh";
|
||||
}
|
||||
{
|
||||
url = "${prefix}/11-reproducible-build.diff";
|
||||
sha256 = "1z17g9z68lh12fs6fkralfghh8bs1bs5mlq83d15l4bn3za3s0sl";
|
||||
}
|
||||
]
|
|
@ -0,0 +1,8 @@
|
|||
elinks/0.13.2-1
|
||||
03_459467_ui.leds.enable_0.diff
|
||||
04_436817_nostrip.diff
|
||||
07_617713_cache_control.diff
|
||||
10-reproducible-build.diff
|
||||
14_debug_disable_Werror.diff
|
||||
16_POST_BUFFER_SIZE.diff
|
||||
11-reproducible-build.diff
|
|
@ -1,4 +1,4 @@
|
|||
{ stdenv, fetchurl, fetchpatch, ncurses, xlibsWrapper, bzip2, zlib, openssl
|
||||
{ stdenv, fetchurl, fetchpatch, ncurses, xlibsWrapper, bzip2, zlib, brotli, openssl, autoconf, automake, gettext, pkgconfig, libev
|
||||
, gpm
|
||||
, # Incompatible licenses, LGPLv3 - GPLv2
|
||||
enableGuile ? false, guile ? null
|
||||
|
@ -11,18 +11,15 @@ assert enableGuile -> guile != null;
|
|||
assert enablePython -> python != null;
|
||||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "elinks";
|
||||
version = "0.12pre6";
|
||||
pname = "elinks-0.13.2";
|
||||
version = "0.13.2";
|
||||
|
||||
src = fetchurl {
|
||||
url = "http://elinks.or.cz/download/${pname}-${version}.tar.bz2";
|
||||
sha256 = "1nnakbi01g7yd3zqwprchh5yp45br8086b0kbbpmnclabcvlcdiq";
|
||||
url = "https://deb.debian.org/debian/pool/main/e/elinks/elinks_${version}.orig.tar.gz";
|
||||
sha256 = "0xkpqnqy0x8sizx4snca0pw3q98gkhnw5a05yf144j1x1y2nb14c";
|
||||
};
|
||||
|
||||
patches = [
|
||||
./gc-init.patch
|
||||
./openssl-1.1.patch
|
||||
];
|
||||
patches = map fetchurl (import ./debian-patches.nix);
|
||||
|
||||
postPatch = (stdenv.lib.optional stdenv.isDarwin) ''
|
||||
patch -p0 < ${fetchpatch {
|
||||
|
@ -31,12 +28,15 @@ stdenv.mkDerivation rec {
|
|||
}}
|
||||
'';
|
||||
|
||||
buildInputs = [ ncurses xlibsWrapper bzip2 zlib openssl spidermonkey ]
|
||||
buildInputs = [ ncurses xlibsWrapper bzip2 zlib brotli openssl libev ]
|
||||
++ stdenv.lib.optional stdenv.isLinux gpm
|
||||
++ stdenv.lib.optional enableGuile guile
|
||||
++ stdenv.lib.optional enablePython python
|
||||
++ stdenv.lib.optional enablePerl perl
|
||||
++ stdenv.lib.optional enableSpidermonkey spidermonkey
|
||||
;
|
||||
|
||||
nativeBuildInputs = [ autoconf automake gettext pkgconfig ];
|
||||
|
||||
configureFlags = [
|
||||
"--enable-finger"
|
||||
|
@ -45,18 +45,24 @@ stdenv.mkDerivation rec {
|
|||
"--enable-cgi"
|
||||
"--enable-bittorrent"
|
||||
"--enable-nntp"
|
||||
"--with-openssl=${openssl.dev}"
|
||||
"--with-bzip2=${bzip2.dev}"
|
||||
"--enable-256-colors"
|
||||
"--with-libev"
|
||||
] ++ stdenv.lib.optional enableGuile "--with-guile"
|
||||
++ stdenv.lib.optional enablePython "--with-python"
|
||||
++ stdenv.lib.optional enablePerl "--with-perl"
|
||||
++ stdenv.lib.optional enableSpidermonkey "--with-spidermonkey=${spidermonkey}"
|
||||
;
|
||||
|
||||
preConfigure = ''
|
||||
patchShebangs ./autogen.sh
|
||||
./autogen.sh
|
||||
'';
|
||||
|
||||
meta = with stdenv.lib; {
|
||||
description = "Full-featured text-mode web browser";
|
||||
homepage = "http://elinks.or.cz";
|
||||
description = "Full-featured text-mode web browser (package based on the fork felinks)";
|
||||
homepage = "https://github.com/rkd77/felinks";
|
||||
license = licenses.gpl2;
|
||||
platforms = with platforms; linux ++ darwin;
|
||||
maintainers = with maintainers; [ iblech ];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
Fix libgc initialization in the presence of Guile 2.0.
|
||||
|
||||
--- elinks-0.12pre5/src/main/main.c 2009-07-07 14:23:17.000000000 +0200
|
||||
+++ elinks-0.12pre5/src/main/main.c 2011-04-28 23:20:15.000000000 +0200
|
||||
@@ -339,6 +339,11 @@ int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
#ifdef CONFIG_GC
|
||||
+ /* Guile 2.x uses libgc too and it initializes it this way, so we
|
||||
+ * must make sure to initialize it the same way, or it will just
|
||||
+ * segfault. */
|
||||
+ GC_all_interior_pointers = 0;
|
||||
+
|
||||
GC_INIT();
|
||||
GC_set_warn_proc(gc_warning);
|
||||
#endif
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
diff --git a/src/network/ssl/socket.c b/src/network/ssl/socket.c
|
||||
index 45b4b4a8..0385a431 100644
|
||||
--- a/src/network/ssl/socket.c
|
||||
+++ b/src/network/ssl/socket.c
|
||||
@@ -67,7 +67,9 @@ static void
|
||||
ssl_set_no_tls(struct socket *socket)
|
||||
{
|
||||
#ifdef CONFIG_OPENSSL
|
||||
- ((ssl_t *) socket->ssl)->options |= SSL_OP_NO_TLSv1;
|
||||
+#ifdef SSL_OP_NO_TLSv1
|
||||
+ SSL_set_options((ssl_t *)socket->ssl, SSL_OP_NO_TLSv1);
|
||||
+#endif
|
||||
#elif defined(CONFIG_GNUTLS)
|
||||
{
|
||||
/* GnuTLS does not support SSLv2 because it is "insecure".
|
||||
@@ -145,9 +147,11 @@ ssl_connect(struct socket *socket)
|
||||
}
|
||||
|
||||
if (client_cert) {
|
||||
- SSL_CTX *ctx = ((SSL *) socket->ssl)->ctx;
|
||||
+ SSL_CTX *ctx = SSL_get_SSL_CTX((SSL *) socket->ssl);
|
||||
|
||||
- SSL_CTX_use_certificate_chain_file(ctx, client_cert);
|
||||
+ SSL_CTX_use_certificate_chain_file(
|
||||
+ (SSL *) socket->ssl,
|
||||
+ client_cert);
|
||||
SSL_CTX_use_PrivateKey_file(ctx, client_cert,
|
||||
SSL_FILETYPE_PEM);
|
||||
}
|
||||
diff --git a/src/network/ssl/ssl.c b/src/network/ssl/ssl.c
|
||||
index c008121d..c06a80a7 100644
|
||||
--- a/src/network/ssl/ssl.c
|
||||
+++ b/src/network/ssl/ssl.c
|
||||
@@ -50,11 +50,16 @@ init_openssl(struct module *module)
|
||||
* cannot initialize the PRNG and so every attempt to use SSL fails.
|
||||
* It's actually an OpenSSL FAQ, and according to them, it's up to the
|
||||
* application coders to seed the RNG. -- William Yodlowsky */
|
||||
- if (RAND_egd(RAND_file_name(f_randfile, sizeof(f_randfile))) < 0) {
|
||||
+ RAND_file_name(f_randfile, sizeof(f_randfile));
|
||||
+#ifdef HAVE_RAND_EGD
|
||||
+ if (RAND_egd(f_randfile) < 0) {
|
||||
/* Not an EGD, so read and write to it */
|
||||
+#endif
|
||||
if (RAND_load_file(f_randfile, -1))
|
||||
RAND_write_file(f_randfile);
|
||||
+#ifdef HAVE_RAND_EGD
|
||||
}
|
||||
+#endif
|
||||
|
||||
SSLeay_add_ssl_algorithms();
|
||||
context = SSL_CTX_new(SSLv23_client_method());
|
File diff suppressed because it is too large
Load diff
|
@ -7,10 +7,10 @@ in
|
|||
rec {
|
||||
firefox = common rec {
|
||||
pname = "firefox";
|
||||
ffversion = "78.0.1";
|
||||
ffversion = "79.0";
|
||||
src = fetchurl {
|
||||
url = "mirror://mozilla/firefox/releases/${ffversion}/source/firefox-${ffversion}.source.tar.xz";
|
||||
sha512 = "mdO6masIpiZBvYi6kpYUTSnsOda04CUs2CL1LNf1Yad+rfY4ga4aFuLtfKqfgV5IcIIl86XeiC+0grd4irbCYg==";
|
||||
sha512 = "0zgf7wdcz992a4dy1rj0ax0k65an7h9p9iihka3jy4jd7w4g2d0x4mxz5iqn2y26hmgnkvjb921zh28biikahgygqja3z2pcx26ic0r";
|
||||
};
|
||||
|
||||
patches = [
|
||||
|
@ -33,12 +33,40 @@ rec {
|
|||
};
|
||||
};
|
||||
|
||||
firefox-esr-68 = (common rec {
|
||||
firefox-esr-78 = common rec {
|
||||
pname = "firefox-esr";
|
||||
ffversion = "68.10.0esr";
|
||||
ffversion = "78.1.0esr";
|
||||
src = fetchurl {
|
||||
url = "mirror://mozilla/firefox/releases/${ffversion}/source/firefox-${ffversion}.source.tar.xz";
|
||||
sha512 = "xcGDNWA2SFHnz46lFlm8T7YCOblgElzbIP4x90LXV//a748xT4ANyRIU7o41gDPcKvlxwIu7pHTvYVixAYgWUw==";
|
||||
sha512 = "223v796vjsvgs3yw442c8qbsbh43l1aniial05rl70hx44rh9sg108ripj8q83p5l9m0sp67x6ixd2xvifizv6461a1zra1rvbb1caa";
|
||||
};
|
||||
|
||||
patches = [
|
||||
./no-buildconfig-ffx76.patch
|
||||
];
|
||||
|
||||
meta = {
|
||||
description = "A web browser built from Firefox Extended Support Release source tree";
|
||||
homepage = "http://www.mozilla.com/en-US/firefox/";
|
||||
maintainers = with lib.maintainers; [ eelco andir ];
|
||||
platforms = lib.platforms.unix;
|
||||
badPlatforms = lib.platforms.darwin;
|
||||
broken = stdenv.buildPlatform.is32bit; # since Firefox 60, build on 32-bit platforms fails with "out of memory".
|
||||
# not in `badPlatforms` because cross-compilation on 64-bit machine might work.
|
||||
license = lib.licenses.mpl20;
|
||||
};
|
||||
updateScript = callPackage ./update.nix {
|
||||
attrPath = "firefox-esr-78-unwrapped";
|
||||
versionKey = "ffversion";
|
||||
};
|
||||
};
|
||||
|
||||
firefox-esr-68 = (common rec {
|
||||
pname = "firefox-esr";
|
||||
ffversion = "68.11.0esr";
|
||||
src = fetchurl {
|
||||
url = "mirror://mozilla/firefox/releases/${ffversion}/source/firefox-${ffversion}.source.tar.xz";
|
||||
sha512 = "0zg41jnbnpsa07xaizwfsmfav0cgxdqnh8i4yanxy49a45gigk895zqrx2if7pfsmdnj9zpwj9prj8cpnpsfhv6p62f3g2596aa9kvx";
|
||||
};
|
||||
|
||||
patches = [
|
||||
|
|
|
@ -2,16 +2,16 @@
|
|||
|
||||
buildGoModule rec {
|
||||
pname = "helmfile";
|
||||
version = "0.119.1";
|
||||
version = "0.125.1";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "roboll";
|
||||
repo = "helmfile";
|
||||
rev = "v${version}";
|
||||
sha256 = "1j9b0xw59w5ailwa7dqgbsdigviw8ng5r4jbsk9b80izcig805zz";
|
||||
sha256 = "0ym9q1rww3r54czkrckdd1ahlym6n61l2563nmj48hkn5d4qxqbm";
|
||||
};
|
||||
|
||||
vendorSha256 = "11bw10s5wifzw2cy1100hyjv4xv7an7b05lcw6sphwyy56gsp2fy";
|
||||
vendorSha256 = "04mga3jc2c01daygjcn245mv30lc2ibax0mpb1wjk3s8lkl4cxcz";
|
||||
|
||||
nativeBuildInputs = [ makeWrapper ];
|
||||
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
{ lib, buildGoModule, fetchFromGitHub, go-bindata }:
|
||||
{ lib, buildGoModule, fetchFromGitHub, go-bindata, installShellFiles }:
|
||||
|
||||
buildGoModule rec {
|
||||
pname = "istioctl";
|
||||
version = "1.6.5";
|
||||
version = "1.6.6";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "istio";
|
||||
repo = "istio";
|
||||
rev = version;
|
||||
sha256 = "0xga0vjr2nfbxwbawly8vg9vnpavxbmc1agg2a3cp1ncmzfrgpcx";
|
||||
sha256 = "0njchcb58lxk0cixk2rz4qj7b0zpp6zf3i5dda43j4hfsb37mifj";
|
||||
};
|
||||
vendorSha256 = "15l9z2a8p46jvmkl0vvm6s196mlics0qgmpm3yq3bn6cqnybdsij";
|
||||
vendorSha256 = "0cc0lmjsxrn3f78k95wklf3yn5k7h8slwnwmssy1i1h0bkcg1bai";
|
||||
|
||||
nativeBuildInputs = [ go-bindata ];
|
||||
nativeBuildInputs = [ go-bindata installShellFiles ];
|
||||
|
||||
# Bundle charts
|
||||
preBuild = ''
|
||||
|
@ -28,10 +28,17 @@ buildGoModule rec {
|
|||
"istio.io/pkg/version.buildTag=${version}"
|
||||
"istio.io/pkg/version.buildHub=docker.io/istio"
|
||||
];
|
||||
in ["-ldflags=${lib.concatMapStringsSep " " (attr: "-X ${attr}") attrs}"];
|
||||
in ["-ldflags=-s -w ${lib.concatMapStringsSep " " (attr: "-X ${attr}") attrs}"];
|
||||
|
||||
subPackages = [ "istioctl/cmd/istioctl" ];
|
||||
|
||||
postInstall = ''
|
||||
$out/bin/istioctl collateral --man --bash --zsh
|
||||
installManPage *.1
|
||||
installShellCompletion istioctl.bash
|
||||
installShellCompletion --zsh _istioctl
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
description = "Istio configuration command line utility for service operators to debug and diagnose their Istio mesh";
|
||||
homepage = "https://istio.io/latest/docs/reference/commands/istioctl";
|
||||
|
|
|
@ -1,24 +1,35 @@
|
|||
{ buildGoModule, fetchFromGitHub, lib }:
|
||||
{ buildGoModule, fetchFromGitHub, lib, installShellFiles }:
|
||||
|
||||
buildGoModule rec {
|
||||
pname = "jx";
|
||||
version = "2.1.90";
|
||||
version = "2.1.121";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "jenkins-x";
|
||||
repo = "jx";
|
||||
rev = "v${version}";
|
||||
sha256 = "1m2gq1hh8fjgxwx2sipq56q5mlz0m3npnbsw103n2kq4xv1qf3f6";
|
||||
sha256 = "0bjpnh962w5wz4gj5my9g52dawxj8zccvpkxlxy1n7c3dkzjxx5j";
|
||||
};
|
||||
|
||||
vendorSha256 = "0kj6x7323fx1qhrlg789a21mh1fvhil7ng2fhmbmlwq0fcrngdnj";
|
||||
vendorSha256 = "0l9djgvnrgdnw7nsf05yq7qpzzzm3gasgh9a7dyc16pp2kxvza6k";
|
||||
|
||||
subPackages = [ "cmd/jx" ];
|
||||
|
||||
nativeBuildInputs = [ installShellFiles ];
|
||||
|
||||
buildFlagsArray = ''
|
||||
-ldflags=
|
||||
-s -w
|
||||
-X github.com/jenkins-x/jx/pkg/version.Version=${version}
|
||||
-X github.com/jenkins-x/jx/pkg/version.Revision=${version}
|
||||
-X github.com/jenkins-x/jx/pkg/version.Revision=${src.rev}
|
||||
-X github.com/jenkins-x/jx/pkg/version.GitTreeState=clean
|
||||
'';
|
||||
|
||||
postInstall = ''
|
||||
for shell in bash zsh; do
|
||||
$out/bin/jx completion $shell > jx.$shell
|
||||
installShellCompletion jx.$shell
|
||||
done
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
|
|
|
@ -2,16 +2,16 @@
|
|||
|
||||
buildGoModule rec {
|
||||
pname = "kpt";
|
||||
version = "0.31.0";
|
||||
version = "0.32.0";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "GoogleContainerTools";
|
||||
repo = pname;
|
||||
rev = "v${version}";
|
||||
sha256 = "1l5mpml6pf37b76wdq6il00k5q6rvw9ds7807m103k27p7pcqgdx";
|
||||
sha256 = "1pgv15zgv30dpv148bn6x0anv9q6x78y6ldmzarb9fbjpk6j0wxl";
|
||||
};
|
||||
|
||||
vendorSha256 = "1yb6dwbnimqfamdg57vq68q853fq04qfnh3sfbjg82sd8pz8069g";
|
||||
vendorSha256 = "0l8xdnv2m6byd5dwvs3zgcj1lsci7ax4xvx178a8a78sgkqalvmq";
|
||||
|
||||
postInstall = ''
|
||||
rm $out/bin/{mdtogo,formula}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
buildGoPackage rec {
|
||||
pname = "kube-router";
|
||||
version = "1.0.0";
|
||||
version = "1.0.1";
|
||||
|
||||
goPackagePath = "github.com/cloudnativelabs/kube-router";
|
||||
|
||||
|
@ -10,7 +10,7 @@ buildGoPackage rec {
|
|||
owner = "cloudnativelabs";
|
||||
repo = pname;
|
||||
rev = "v${version}";
|
||||
sha256 = "0b6rsiq3pwp7wknmblgd8kszh9bd7nhvlsnyyamqnhlfjl97929x";
|
||||
sha256 = "00bypaccv8q9xdcz6vlvl1qxqxqssl21bs4nkd1a6q8b4jpl339z";
|
||||
};
|
||||
|
||||
buildFlagsArray = ''
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{ stdenv, fetchFromGitHub, buildGoModule }:
|
||||
|
||||
buildGoModule {
|
||||
pname = "linkerd-unstablle";
|
||||
pname = "linkerd-unstable";
|
||||
version = "2020-05-01";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
|
|
|
@ -4,13 +4,14 @@ with pythonPackages;
|
|||
|
||||
buildPythonApplication rec {
|
||||
pname = "rss2email";
|
||||
version = "3.11";
|
||||
version = "3.12.1";
|
||||
|
||||
propagatedBuildInputs = [ feedparser beautifulsoup4 html2text ];
|
||||
propagatedBuildInputs = [ feedparser html2text ];
|
||||
checkInputs = [ beautifulsoup4 ];
|
||||
|
||||
src = fetchurl {
|
||||
url = "mirror://pypi/r/rss2email/${pname}-${version}.tar.gz";
|
||||
sha256 = "1vk5slp2mhmc1qj30igqkyq3z5h2bl1ayhafqrjapa6cg6rbvhrn";
|
||||
sha256 = "0zqpibh31rl6xlfw9y66d9hfhwrnzy5cjzbksczyw3lh4dfzsql0";
|
||||
};
|
||||
|
||||
outputs = [ "out" "man" "doc" ];
|
||||
|
@ -39,7 +40,7 @@ buildPythonApplication rec {
|
|||
description = "A tool that converts RSS/Atom newsfeeds to email.";
|
||||
homepage = "https://pypi.python.org/pypi/rss2email";
|
||||
license = licenses.gpl2;
|
||||
maintainers = with maintainers; [ jb55 Profpatsch ];
|
||||
maintainers = with maintainers; [ jb55 Profpatsch ekleog ];
|
||||
};
|
||||
passthru.tests = {
|
||||
smoke-test = nixosTests.rss2email;
|
||||
|
|
|
@ -13,11 +13,11 @@ let
|
|||
in
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "openbazaar-client";
|
||||
version = "2.4.6";
|
||||
version = "2.4.7";
|
||||
|
||||
src = fetchurl {
|
||||
url = "https://github.com/OpenBazaar/openbazaar-desktop/releases/download/v${version}/openbazaar2client_${version}_amd64.deb";
|
||||
sha256 = "1p190az8llqh3089aygwash10wqqqfnjl2wvksn6bvx5wm5dpg1p";
|
||||
sha256 = "04wwljaiqm8rsdrzngqrzrjzfrjsrfsaa60c904zhbhmsqc7y4f1";
|
||||
};
|
||||
|
||||
dontBuild = true;
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "ettercap";
|
||||
version = "0.8.3";
|
||||
version = "0.8.3.1";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "Ettercap";
|
||||
repo = "ettercap";
|
||||
rev = "v${version}";
|
||||
sha256 = "0m40bmbrv9a8qlg54z3b5f8r541gl9vah5hm0bbqcgyyljpg39bz";
|
||||
sha256 = "1sdf1ssa81ib6k0mc5m2jzbjl4jd1yv6ahv5dwx2x9w4b2pyqg1c";
|
||||
};
|
||||
|
||||
strictDeps = true;
|
||||
|
|
|
@ -21,13 +21,13 @@
|
|||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "elementary-planner";
|
||||
version = "2.4.5";
|
||||
version = "2.4.6";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "alainm23";
|
||||
repo = "planner";
|
||||
rev = version;
|
||||
sha256 = "0jj901b2v4vfgv0i7d02xhhylfh6rcanaybk52i7ci92ff2gzgcb";
|
||||
sha256 = "0z0997yq809wbsk3w21xv4fcrgqcb958qdlksf4rhzhfnwbiii6y";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [
|
||||
|
|
|
@ -5,13 +5,13 @@
|
|||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "limesuite";
|
||||
version = "20.01.0";
|
||||
version = "20.07.1";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "myriadrf";
|
||||
repo = "LimeSuite";
|
||||
rev = "v${version}";
|
||||
sha256 = "01z4idcby2lm34bbnpbp400ski7p61jjiir6sy6dalnvsl52m7vx";
|
||||
sha256 = "14mxqc350j3rk1202n0ax1rfx49sy40965zj90d4pnakbgz5xr7g";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [ cmake ];
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{ stdenv, fetchFromGitHub, cmake, soapysdr, avahi }:
|
||||
|
||||
let
|
||||
version = "0.5.1";
|
||||
version = "0.5.2";
|
||||
|
||||
in stdenv.mkDerivation {
|
||||
pname = "soapyremote";
|
||||
|
@ -11,7 +11,7 @@ in stdenv.mkDerivation {
|
|||
owner = "pothosware";
|
||||
repo = "SoapyRemote";
|
||||
rev = "soapy-remote-${version}";
|
||||
sha256 = "1qlpjg8mh564q26mni8g6bb8w9nj7hgcq86278fszxpwpnk3jsvk";
|
||||
sha256 = "124sy9v08fm51ds1yzrxspychn34y0rl6y48mzariianazvzmfax";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [ cmake ];
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "picard-tools";
|
||||
version = "2.23.1";
|
||||
version = "2.23.3";
|
||||
|
||||
src = fetchurl {
|
||||
url = "https://github.com/broadinstitute/picard/releases/download/${version}/picard.jar";
|
||||
sha256 = "1g4539x2081jgrbn207nsimpq9q5izd4z6cx7s8lr8p8ab8spbmk";
|
||||
sha256 = "08wgi0hijfbchr2srmndxq3h2fijvyvr8b6zv680fpcjixm5bbhf";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [ makeWrapper ];
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
# - The exact version can be specified through the `version` argument to
|
||||
# the derivation; it defaults to the latest stable version.
|
||||
|
||||
{ stdenv, fetchFromGitHub, writeText, pkgconfig
|
||||
{ stdenv, fetchFromGitHub, writeText, pkgconfig, gnumake42
|
||||
, ocamlPackages, ncurses
|
||||
, buildIde ? !(stdenv.isDarwin && stdenv.lib.versionAtLeast version "8.10")
|
||||
, glib, gnome3, wrapGAppsHook
|
||||
|
@ -107,7 +107,9 @@ self = stdenv.mkDerivation {
|
|||
inherit sha256;
|
||||
};
|
||||
|
||||
nativeBuildInputs = [ pkgconfig ];
|
||||
nativeBuildInputs = [ pkgconfig ]
|
||||
++ stdenv.lib.optional (!versionAtLeast "8.6") gnumake42
|
||||
;
|
||||
buildInputs = [ ncurses ocamlPackages.ocaml ocamlPackages.findlib ]
|
||||
++ stdenv.lib.optional (!versionAtLeast "8.10") ocamlPackages.camlp5
|
||||
++ [ ocamlPackages.num ]
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "lean";
|
||||
version = "3.16.5";
|
||||
version = "3.18.4";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "leanprover-community";
|
||||
repo = "lean";
|
||||
rev = "v${version}";
|
||||
sha256 = "0s1ay6qgpkxhygfbfrl1cw2pd8bpgw2dw71rzhza20ndqwk8nqs5";
|
||||
sha256 = "1pmc2wi1pa346w89ayrrjv9xk6v6myg2zmx1wj4pd9qxv7ivrbsn";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [ cmake ];
|
||||
|
|
|
@ -9,16 +9,16 @@
|
|||
|
||||
rustPlatform.buildRustPackage rec {
|
||||
pname = "delta";
|
||||
version = "0.3.0";
|
||||
version = "0.4.0";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "dandavison";
|
||||
repo = pname;
|
||||
rev = version;
|
||||
sha256 = "0y3gkan5v0d6637yf5p5a9dklyv5zngw7a8pyqzj4ixys72ixg20";
|
||||
sha256 = "1i4ddz2fivn5h35059b68z3lfw48psak79aab6pk7d8iamz4njb9";
|
||||
};
|
||||
|
||||
cargoSha256 = "15sh2lsc16nf9w7sp3avy77f4vyj0rdsm6m1bn60y8gmv2r16v6i";
|
||||
cargoSha256 = "1na6wqjm69diwhkyxlzk0jm3qwkdrah3w6i8p7dhzrsx434lhmya";
|
||||
|
||||
nativeBuildInputs = [ installShellFiles ];
|
||||
|
||||
|
|
|
@ -16,13 +16,13 @@
|
|||
|
||||
buildGoModule rec {
|
||||
pname = "podman";
|
||||
version = "2.0.3";
|
||||
version = "2.0.4";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "containers";
|
||||
repo = "podman";
|
||||
rev = "v${version}";
|
||||
sha256 = "1jqdv3kij2q97qn4niqxxgfva9ajr4wjgx40qk5yhs01d3g0qgmd";
|
||||
sha256 = "0rnli16nh5m3a8jjkkm1k4f896yk1k1rg48rjiajqhfrr98qwr0f";
|
||||
};
|
||||
|
||||
vendorSha256 = null;
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "bspwm";
|
||||
version = "0.9.9";
|
||||
version = "0.9.10";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "baskerville";
|
||||
repo = "bspwm";
|
||||
rev = version;
|
||||
sha256 = "1i7crmljk1vra1r6alxvj6lqqailjjcv0llyg7a0gm23rbv4a42g";
|
||||
sha256 = "0qlv7b4c2mmjfd65y100d11x8iqyg5f6lfiws3cgmpjidhdygnxc";
|
||||
};
|
||||
|
||||
buildInputs = [ libxcb libXinerama xcbutil xcbutilkeysyms xcbutilwm ];
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "i3";
|
||||
version = "4.18.1";
|
||||
version = "4.18.2";
|
||||
|
||||
src = fetchurl {
|
||||
url = "https://i3wm.org/downloads/${pname}-${version}.tar.bz2";
|
||||
sha256 = "0z709cianlzw0x0qwq4361347354xd9ckj1v7vjvhb1zh3x91gws";
|
||||
sha256 = "030jym6b8b07yf4y6pb806hg8k77zsprv569gy0r72rh5zb1g1mj";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [ which pkgconfig makeWrapper installShellFiles ];
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "papirus-icon-theme";
|
||||
version = "20200702";
|
||||
version = "20200801";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "PapirusDevelopmentTeam";
|
||||
repo = pname;
|
||||
rev = version;
|
||||
sha256 = "0p1grfgnmqawayk15qxnl09jai96avx9731qladmcbm2lik4qdpl";
|
||||
sha256 = "0w9ks8izxv7mkh82fnclfcdf6mif991dsbbnxsqmcbvljrmjval2";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
{ callPackage, pkgs }:
|
||||
{
|
||||
#### CORE EFL
|
||||
efl = callPackage ./efl.nix {
|
||||
openjpeg = pkgs.openjpeg_1;
|
||||
};
|
||||
efl = callPackage ./efl.nix { };
|
||||
|
||||
#### WINDOW MANAGER
|
||||
enlightenment = callPackage ./enlightenment.nix { };
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
|
||||
mkDerivation rec {
|
||||
pname = "kwin-tiling";
|
||||
version = "2.2";
|
||||
version = "2.4";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "kwin-scripts";
|
||||
repo = "kwin-tiling";
|
||||
rev = "v${version}";
|
||||
sha256 = "1sx64xv7g9yh3j26zxxrbndv79xam9jq0vs00fczgfv2n0m7j7bl";
|
||||
sha256 = "095slpvipy0zcmbn0l7mdnl9g74jaafkr2gqi09b0by5fkvnbh37";
|
||||
};
|
||||
|
||||
# This is technically not needed, but we might as well clean up
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
mkXfceDerivation {
|
||||
category = "xfce";
|
||||
pname = "xfwm4";
|
||||
version = "4.14.2";
|
||||
version = "4.14.4";
|
||||
|
||||
sha256 = "1zzc4q1j55hjljksmlyghk58bx7kxyq3scihsr9zgyqc24ww1ks3";
|
||||
sha256 = "0nk3qw1accvxrzy00qs06nnlpxjv6p1srkvjn2ad4xrw9ix9ywkb";
|
||||
|
||||
nativeBuildInputs = [ exo librsvg ];
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue