Merge master into staging-next

This commit is contained in:
github-actions[bot] 2024-02-06 00:02:21 +00:00 committed by GitHub
commit 8e7913be95
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
66 changed files with 1425 additions and 433 deletions

View File

@ -1256,7 +1256,7 @@ let
(opt.highestPrio or defaultOverridePriority)
(f opt.value);
doRename = { from, to, visible, warn, use, withPriority ? true }:
doRename = { from, to, visible, warn, use, withPriority ? true, condition ? true }:
{ config, options, ... }:
let
fromOpt = getAttrFromPath from options;
@ -1272,7 +1272,7 @@ let
} // optionalAttrs (toType != null) {
type = toType;
});
config = mkMerge [
config = mkIf condition (mkMerge [
(optionalAttrs (options ? warnings) {
warnings = optional (warn && fromOpt.isDefined)
"The option `${showOption from}' defined in ${showFiles fromOpt.files} has been renamed to `${showOption to}'.";
@ -1280,7 +1280,7 @@ let
(if withPriority
then mkAliasAndWrapDefsWithPriority (setAttrByPath to) fromOpt
else mkAliasAndWrapDefinitions (setAttrByPath to) fromOpt)
];
]);
};
/* Use this function to import a JSON file as NixOS configuration.

View File

@ -465,6 +465,9 @@ checkConfigOutput '^1234$' config.c.d.e ./doRename-basic.nix
checkConfigOutput '^"The option `a\.b. defined in `.*/doRename-warnings\.nix. has been renamed to `c\.d\.e.\."$' \
config.result \
./doRename-warnings.nix
checkConfigOutput "^true$" config.result ./doRename-condition.nix ./doRename-condition-enable.nix
checkConfigOutput "^true$" config.result ./doRename-condition.nix ./doRename-condition-no-enable.nix
checkConfigOutput "^true$" config.result ./doRename-condition.nix ./doRename-condition-migrated.nix
# Anonymous modules get deduplicated by key
checkConfigOutput '^"pear"$' config.once.raw ./merge-module-with-key.nix

View File

@ -0,0 +1,10 @@
{ config, lib, ... }:
{
config = {
services.foo.enable = true;
services.foo.bar = "baz";
result =
assert config.services.foos == { "" = { bar = "baz"; }; };
true;
};
}

View File

@ -0,0 +1,10 @@
{ config, lib, ... }:
{
config = {
services.foos."".bar = "baz";
result =
assert config.services.foos == { "" = { bar = "baz"; }; };
assert config.services.foo.bar == "baz";
true;
};
}

View File

@ -0,0 +1,9 @@
{ config, lib, options, ... }:
{
config = {
result =
assert config.services.foos == { };
assert ! options.services.foo.bar.isDefined;
true;
};
}

View File

@ -0,0 +1,42 @@
/*
Simulate a migration from a single-instance `services.foo` to a multi instance
`services.foos.<name>` module, where `name = ""` serves as the legacy /
compatibility instance.
- No instances must exist, unless one is defined in the multi-instance module,
or if the legacy enable option is set to true.
- The legacy instance options must be renamed to the new instance, if it exists.
The relevant scenarios are tested in separate files:
- ./doRename-condition-enable.nix
- ./doRename-condition-no-enable.nix
*/
{ config, lib, ... }:
let
inherit (lib) mkOption mkEnableOption types doRename;
in
{
options = {
services.foo.enable = mkEnableOption "foo";
services.foos = mkOption {
type = types.attrsOf (types.submodule {
options = {
bar = mkOption { type = types.str; };
};
});
default = { };
};
result = mkOption {};
};
imports = [
(doRename {
from = [ "services" "foo" "bar" ];
to = [ "services" "foos" "" "bar" ];
visible = true;
warn = false;
use = x: x;
withPriority = true;
condition = config.services.foo.enable;
})
];
}

View File

@ -100,9 +100,11 @@ moonscript,https://github.com/leafo/moonscript.git,dev-1,,,,arobyn
nlua,,,,,,teto
nui.nvim,,,,,,mrcjkb
nvim-cmp,https://github.com/hrsh7th/nvim-cmp,,,,,
nvim-nio,,,,,,mrcjkb
penlight,https://github.com/lunarmodules/Penlight.git,,,,,alerque
plenary.nvim,https://github.com/nvim-lua/plenary.nvim.git,,,,5.1,
rapidjson,https://github.com/xpol/lua-rapidjson.git,,,,,
rocks.nvim,,,,,5.1,teto mrcjkb
rest.nvim,,,,,5.1,teto
rustaceanvim,,,,,,mrcjkb
say,https://github.com/Olivine-Labs/say.git,,,,,

1 name src ref server version luaversion maintainers
100 nlua teto
101 nui.nvim mrcjkb
102 nvim-cmp https://github.com/hrsh7th/nvim-cmp
103 nvim-nio mrcjkb
104 penlight https://github.com/lunarmodules/Penlight.git alerque
105 plenary.nvim https://github.com/nvim-lua/plenary.nvim.git 5.1
106 rapidjson https://github.com/xpol/lua-rapidjson.git
107 rocks.nvim 5.1 teto mrcjkb
108 rest.nvim 5.1 teto
109 rustaceanvim mrcjkb
110 say https://github.com/Olivine-Labs/say.git

View File

@ -14,6 +14,15 @@ let
in
{
imports = [
(mkRemovedOptionModule [ "services" "rabbitmq" "cookie" ] ''
This option wrote the Erlang cookie to the store, while it should be kept secret.
Please remove it from your NixOS configuration and deploy a cookie securely instead.
The renamed `unsafeCookie` must ONLY be used in isolated non-production environments such as NixOS VM tests.
'')
];
###### interface
options = {
services.rabbitmq = {
@ -62,13 +71,18 @@ in
'';
};
cookie = mkOption {
unsafeCookie = mkOption {
default = "";
type = types.str;
description = lib.mdDoc ''
Erlang cookie is a string of arbitrary length which must
be the same for several nodes to be allowed to communicate.
Leave empty to generate automatically.
Setting the cookie via this option exposes the cookie to the store, which
is not recommended for security reasons.
Only use this option in an isolated non-production environment such as
NixOS VM tests.
'';
};
@ -209,9 +223,8 @@ in
};
preStart = ''
${optionalString (cfg.cookie != "") ''
echo -n ${cfg.cookie} > ${cfg.dataDir}/.erlang.cookie
chmod 600 ${cfg.dataDir}/.erlang.cookie
${optionalString (cfg.unsafeCookie != "") ''
install -m 600 <(echo -n ${cfg.unsafeCookie}) ${cfg.dataDir}/.erlang.cookie
''}
'';
};

View File

@ -17,15 +17,6 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aho-corasick"
version = "0.7.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
dependencies = [
"memchr",
]
[[package]]
name = "aho-corasick"
version = "1.1.2"
@ -163,6 +154,12 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
[[package]]
name = "block"
version = "0.1.6"
@ -355,6 +352,7 @@ dependencies = [
"printer",
"rayon",
"regex",
"serde",
"serde_json",
"subprocess",
"tokio",
@ -568,6 +566,12 @@ dependencies = [
"serde_json",
]
[[package]]
name = "dunce"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b"
[[package]]
name = "either"
version = "1.9.0"
@ -604,6 +608,16 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "errno"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
dependencies = [
"libc",
"windows-sys 0.52.0",
]
[[package]]
name = "extracted_fzy"
version = "0.1.0"
@ -783,7 +797,7 @@ version = "0.17.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b989d6a7ca95a362cf2cfc5ad688b3a467be1f87e480b8dad07fee8c79b0044"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"libc",
"libgit2-sys",
"log",
@ -796,7 +810,7 @@ version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "759c97c1e17c55525b57192c06a267cda0ac5210b222d6b82189a2338fa1c13d"
dependencies = [
"aho-corasick 1.1.2",
"aho-corasick",
"bstr",
"fnv",
"log",
@ -805,40 +819,38 @@ dependencies = [
[[package]]
name = "grep-matcher"
version = "0.1.6"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3902ca28f26945fe35cad349d776f163981d777fee382ccd6ef451126f51b319"
checksum = "47a3141a10a43acfedc7c98a60a834d7ba00dfe7bec9071cbfc19b55b292ac02"
dependencies = [
"memchr",
]
[[package]]
name = "grep-regex"
version = "0.1.11"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "997598b41d53a37a2e3fc5300d5c11d825368c054420a9c65125b8fe1078463f"
checksum = "f748bb135ca835da5cbc67ca0e6955f968db9c5df74ca4f56b18e1ddbc68230d"
dependencies = [
"aho-corasick 0.7.20",
"bstr",
"grep-matcher",
"log",
"regex",
"regex-syntax 0.6.29",
"thread_local",
"regex-automata 0.4.3",
"regex-syntax 0.8.2",
]
[[package]]
name = "grep-searcher"
version = "0.1.11"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5601c4b9f480f0c9ebb40b1f6cbf447b8a50c5369223937a6c5214368c58779f"
checksum = "ba536ae4f69bec62d8839584dd3153d3028ef31bb229f04e09fb5a9e5a193c54"
dependencies = [
"bstr",
"bytecount",
"encoding_rs",
"encoding_rs_io",
"grep-matcher",
"log",
"memchr",
"memmap2",
]
@ -1203,6 +1215,12 @@ version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]]
name = "linux-raw-sys"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
[[package]]
name = "lock_api"
version = "0.4.11"
@ -1219,6 +1237,19 @@ version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "lsp-types"
version = "0.94.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c66bfd44a06ae10647fe3f8214762e9369fd4248df1350924b4ef9e770a85ea1"
dependencies = [
"bitflags 1.3.2",
"serde",
"serde_json",
"serde_repr",
"url",
]
[[package]]
name = "malloc_buf"
version = "0.0.6"
@ -1230,7 +1261,7 @@ dependencies = [
[[package]]
name = "maple"
version = "0.1.49"
version = "0.1.50"
dependencies = [
"built",
"chrono",
@ -1263,6 +1294,7 @@ dependencies = [
"ignore",
"itertools",
"maple_derive",
"maple_lsp",
"matcher",
"once_cell",
"parking_lot",
@ -1276,6 +1308,7 @@ dependencies = [
"rpc",
"serde",
"serde_json",
"strsim",
"sublime_syntax",
"subprocess",
"thiserror",
@ -1301,6 +1334,23 @@ dependencies = [
"types",
]
[[package]]
name = "maple_lsp"
version = "0.1.0"
dependencies = [
"futures-util",
"lsp-types",
"parking_lot",
"paths",
"rpc",
"serde",
"serde_json",
"thiserror",
"tokio",
"tracing",
"which",
]
[[package]]
name = "matcher"
version = "0.1.0"
@ -1331,9 +1381,9 @@ checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
[[package]]
name = "memmap2"
version = "0.5.10"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327"
checksum = "deaba38d7abf1d4cca21cc89e932e542ba2b9258664d2a9ef0e61512039c9375"
dependencies = [
"libc",
]
@ -1394,7 +1444,7 @@ version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"cfg-if",
"libc",
"memoffset 0.7.1",
@ -1485,7 +1535,7 @@ version = "6.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"libc",
"once_cell",
"onig_sys",
@ -1535,6 +1585,7 @@ name = "paths"
version = "0.1.0"
dependencies = [
"dirs",
"dunce",
"itertools",
"serde",
]
@ -1663,7 +1714,7 @@ version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
dependencies = [
"bitflags",
"bitflags 1.3.2",
]
[[package]]
@ -1672,7 +1723,7 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
dependencies = [
"bitflags",
"bitflags 1.3.2",
]
[[package]]
@ -1692,7 +1743,7 @@ version = "1.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
dependencies = [
"aho-corasick 1.1.2",
"aho-corasick",
"memchr",
"regex-automata 0.4.3",
"regex-syntax 0.8.2",
@ -1713,7 +1764,7 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
dependencies = [
"aho-corasick 1.1.2",
"aho-corasick",
"memchr",
"regex-syntax 0.8.2",
]
@ -1813,6 +1864,19 @@ version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustix"
version = "0.38.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3"
dependencies = [
"bitflags 2.4.1",
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.48.0",
]
[[package]]
name = "rustls"
version = "0.21.8"
@ -1921,6 +1985,17 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_repr"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_spanned"
version = "0.6.4"
@ -2053,7 +2128,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e02b4b303bf8d08bfeb0445cba5068a3d306b6baece1d5582171a9bf49188f91"
dependencies = [
"bincode",
"bitflags",
"bitflags 1.3.2",
"flate2",
"fnv",
"once_cell",
@ -2073,7 +2148,7 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"core-foundation",
"system-configuration-sys",
]
@ -2471,6 +2546,9 @@ name = "tree_sitter"
version = "0.1.0"
dependencies = [
"cc",
"once_cell",
"serde",
"toml 0.5.11",
"tree-sitter",
"tree-sitter-bash",
"tree-sitter-c",
@ -2553,6 +2631,7 @@ dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
"serde",
]
[[package]]
@ -2707,6 +2786,19 @@ version = "0.25.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc"
[[package]]
name = "which"
version = "5.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bf3ea8596f3a0dd5980b46430f2058dfe2c36a27ccfbb1845d6fbfcd9ba6e14"
dependencies = [
"either",
"home",
"once_cell",
"rustix",
"windows-sys 0.48.0",
]
[[package]]
name = "winapi"
version = "0.3.9"
@ -2774,6 +2866,15 @@ dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets 0.52.0",
]
[[package]]
name = "windows-targets"
version = "0.42.2"
@ -2804,6 +2905,21 @@ dependencies = [
"windows_x86_64_msvc 0.48.5",
]
[[package]]
name = "windows-targets"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
dependencies = [
"windows_aarch64_gnullvm 0.52.0",
"windows_aarch64_msvc 0.52.0",
"windows_i686_gnu 0.52.0",
"windows_i686_msvc 0.52.0",
"windows_x86_64_gnu 0.52.0",
"windows_x86_64_gnullvm 0.52.0",
"windows_x86_64_msvc 0.52.0",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
@ -2816,6 +2932,12 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
@ -2828,6 +2950,12 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
@ -2840,6 +2968,12 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
@ -2852,6 +2986,12 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
@ -2864,6 +3004,12 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
@ -2876,6 +3022,12 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
@ -2888,6 +3040,12 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
[[package]]
name = "winnow"
version = "0.5.18"

View File

@ -11,13 +11,13 @@
}:
let
version = "0.49";
version = "0.50";
src = fetchFromGitHub {
owner = "liuchengxu";
repo = "vim-clap";
rev = "v${version}";
hash = "sha256-xir0v3SzfkxNXKR6N7Rso0QFtVQIRfu0TIPGWSEwsHM=";
hash = "sha256-EYAylATdtwDzM92tN4OlzbQ1XqErRwT9mCNpzj63oxk=";
};
meta = with lib; {

View File

@ -61,8 +61,8 @@ rec {
};
kops_1_28 = mkKops rec {
version = "1.28.3";
sha256 = "sha256-pkHTVAssNDjMHpdRxqPCNwG2of8TKIzZN0uqk+hPZSA=";
version = "1.28.4";
sha256 = "sha256-nknsrLdV7tQKLOir5RM3LRhTS+dyiAc1GjbByJzjwCo=";
rev = "v${version}";
};
}

View File

@ -13,11 +13,11 @@
stdenv.mkDerivation rec {
pname = "appflowy";
version = "0.4.3";
version = "0.4.6";
src = fetchzip {
url = "https://github.com/AppFlowy-IO/appflowy/releases/download/${version}/AppFlowy-${version}-linux-x86_64.tar.gz";
hash = "sha256-JrcqVPlFr8zD9ZSBxk9WqN7KCLKq+yCjMfA4QbIfDZE=";
hash = "sha256-496uXlJ/3ID8fnW/LKwk0Waca4gSQBuKIFMJ4EJGcsA=";
stripRoot = false;
};

View File

@ -40,5 +40,7 @@ python3Packages.buildPythonApplication rec {
license = lib.licenses.gpl2Plus;
platforms = lib.platforms.linux;
maintainers = [ lib.maintainers.mathnerd314 ];
# ModuleNotFoundError: No module named 'rabbitvcs'
broken = true; # Added 2024-01-28
};
}

View File

@ -2,10 +2,10 @@
buildDotnetGlobalTool {
pname = "csharpier";
version = "0.27.0";
version = "0.27.2";
executables = "dotnet-csharpier";
nugetSha256 = "sha256-aI8sZoUXAA/bOn7ITMkBFXHeTVRm9O/qX+bWfOKwRDs=";
nugetSha256 = "sha256-P4v4h09FuisIry9B/6batrG0CpLqnrkxnlk1yEd1JbY=";
meta = with lib; {
description = "An opinionated code formatter for C#";

View File

@ -5,19 +5,22 @@
python3.pkgs.buildPythonApplication rec {
pname = "gcp-scanner";
version = "1.3.0";
version = "1.4.0";
pyproject = true;
src = fetchFromGitHub {
owner = "google";
repo = "gcp_scanner";
rev = "refs/tags/v${version}";
hash = "sha256-mMvAoqwptCA73JiUl8HIhFBO198NnUmvCbf8Rk9dWxA=";
hash = "sha256-6bIrSaTqpXQjB64YWAI64DlgQBD2XD+zMvKymMtwpDk=";
};
pythonRelaxDeps = true;
nativeBuildInputs = with python3.pkgs; [
setuptools
setuptools-git-versioning
pythonRelaxDepsHook
];
propagatedBuildInputs = with python3.pkgs; [

View File

@ -6,16 +6,16 @@
let
pname = "lefthook";
version = "1.5.7";
version = "1.6.1";
in
buildGoModule rec {
buildGoModule {
inherit pname version;
src = fetchFromGitHub {
owner = "evilmartians";
repo = "lefthook";
rev = "v${version}";
hash = "sha256-0z4hTx9ClGh20Ncf23SbwuPBdGoFz80FQUx7s77l7y8=";
hash = "sha256-015tIgu9L62uZm4ae1JzU/GAK6fwX8BI9HGYhc+4jQQ=";
};
vendorHash = "sha256-/VLS7+nPERjIU7V2CzqXH69Z3/y+GKZbAFn+KcRKRuA=";

View File

@ -0,0 +1,48 @@
{ lib
, fetchFromGitHub
, python3
}:
python3.pkgs.buildPythonApplication rec {
pname = "nmap-parse";
version = "0-unstable-2022-09-26";
format = "other";
src = fetchFromGitHub {
owner = "jonny1102";
repo = "nmap-parse";
# https://github.com/jonny1102/nmap-parse/issues/12
rev = "ae270ac9ce05bfbe822dbbb29411adf562d40abf";
hash = "sha256-iaE4a5blbDPaKPRnR46+AfegXOEW88i+z/VIVGCepeM=";
};
propagatedBuildInputs = with python3.pkgs; [
beautifulsoup4
cmd2
colorama
ipy
tabulate
];
installPhase = ''
runHook preInstall
install -Dm 755 "nmap-parse.py" "$out/bin/nmap-parse"
install -vd $out/${python3.sitePackages}/
cp -R modules $out/${python3.sitePackages}
runHook postInstall
'';
# Project has no tests
doCheck = false;
meta = with lib; {
description = "Command line nmap XML parser";
homepage = "https://github.com/jonny1102/nmap-parse";
license = licenses.mit;
maintainers = with maintainers; [ fab ];
mainProgram = "nmap-parse";
};
}

View File

@ -0,0 +1,32 @@
{ lib
, buildGoModule
, fetchFromGitHub
}:
buildGoModule rec {
pname = "np";
version = "0.11.0";
src = fetchFromGitHub {
owner = "leesoh";
repo = "np";
rev = "refs/tags/v${version}";
hash = "sha256-4krjQi/zEC4a+CjacgbnQIMKKFVr6H2FSwRVB6pkHf0=";
};
vendorHash = "sha256-rSg4YFLZdtyC/tm/EULyt7r0O9PXI72W8y6/ltDSbj4=";
ldflags = [
"-s"
"-w"
];
meta = with lib; {
description = "A tool to parse, deduplicate, and query multiple port scans";
homepage = "https://github.com/leesoh/np";
changelog = "https://github.com/leesoh/np/releases/tag/v${version}";
license = licenses.agpl3Only;
maintainers = with maintainers; [ fab ];
mainProgram = "np";
};
}

View File

@ -2,7 +2,7 @@
python3Packages.buildPythonApplication rec {
pname = "pyprland";
version = "1.7.1";
version = "1.8.7";
format = "pyproject";
disabled = python3Packages.pythonOlder "3.10";
@ -11,7 +11,7 @@ python3Packages.buildPythonApplication rec {
owner = "hyprland-community";
repo = "pyprland";
rev = "refs/tags/${version}";
hash = "sha256-VS1qWJxTJDRlmb4pfzSqU0geOcPAVYDYy2d/f5KcOpQ=";
hash = "sha256-6ne1wohpknxXpaLg29COM84pXUBKXBVH0jaLfypLtUo=";
};
nativeBuildInputs = with python3Packages; [ poetry-core ];
@ -21,11 +21,29 @@ python3Packages.buildPythonApplication rec {
chmod -x $out/${python3Packages.python.sitePackages}/pyprland/command.py
'';
# NOTE: this is required for the imports check below to work properly
HYPRLAND_INSTANCE_SIGNATURE = "dummy";
pythonImportsCheck = [
"pyprland"
"pyprland.command"
"pyprland.common"
"pyprland.ipc"
"pyprland.plugins"
"pyprland.plugins.experimental"
"pyprland.plugins.expose"
"pyprland.plugins.interface"
"pyprland.plugins.layout_center"
"pyprland.plugins.lost_windows"
"pyprland.plugins.magnify"
"pyprland.plugins.monitors"
"pyprland.plugins.monitors_v0"
"pyprland.plugins.pyprland"
"pyprland.plugins.scratchpads"
"pyprland.plugins.shift_monitors"
"pyprland.plugins.toggle_dpms"
"pyprland.plugins.toggle_special"
"pyprland.plugins.workspaces_follow_focus"
];
meta = with lib; {

View File

@ -3,47 +3,45 @@
, rustPlatform
, fetchFromGitHub
, installShellFiles
, Foundation
, darwin
}:
rustPlatform.buildRustPackage rec {
pname = "rage";
version = "0.9.2";
version = "0.10.0";
src = fetchFromGitHub {
owner = "str4d";
repo = pname;
rev = "v${version}";
hash = "sha256-hFuuwmwe0ti4Y8mSJyNqUIhZjFC6qtv6W5cwtNjPUFQ=";
hash = "sha256-7PfNDFDuvQ9T3BeA15FuY1jAprGLsyglWXcNrZvtPAE=";
};
cargoHash = "sha256-1gtLWU6uiWzUfYy9y3pb2vcnUC3H+Mf9rglmqNd989M=";
cargoHash = "sha256-5aLT0JfeFj0fZP/1sHXulCQtoquHYriapMdPtN+fxko=";
nativeBuildInputs = [
installShellFiles
];
buildInputs = lib.optionals stdenv.isDarwin [
Foundation
darwin.apple_sdk.frameworks.Foundation
];
# cargo test has an x86-only dependency
doCheck = stdenv.hostPlatform.isx86;
postBuild = ''
cargo run --example generate-docs
cargo run --example generate-completions
'';
postInstall = ''
installManPage target/manpages/*
installShellCompletion target/completions/*.{bash,fish,zsh}
installManPage target/*/release/manpages/man1/*
installShellCompletion \
--bash target/*/release/completions/*.bash \
--fish target/*/release/completions/*.fish \
--zsh target/*/release/completions/_*
'';
meta = with lib; {
description = "A simple, secure and modern encryption tool with small explicit keys, no config options, and UNIX-style composability";
homepage = "https://github.com/str4d/rage";
changelog = "https://github.com/str4d/rage/raw/v${version}/rage/CHANGELOG.md";
changelog = "https://github.com/str4d/rage/blob/v${version}/rage/CHANGELOG.md";
license = with licenses; [ asl20 mit ]; # either at your option
maintainers = with maintainers; [ marsam ryantm ];
mainProgram = "rage";

View File

@ -54,6 +54,14 @@ stdenv.mkDerivation rec {
hash = "sha256-LNoPg1KCoP8RWxU/AzHR52f4Dww24I9BGQJedMhFxyQ=";
relative = "libcxx";
})
] ++ lib.optionals (stdenv.isDarwin && lib.versionOlder stdenv.hostPlatform.darwinMinVersion "10.13") [
# https://github.com/llvm/llvm-project/issues/64226
(fetchpatch {
name = "0042-mbstate_t-not-defined.patch";
url = "https://github.com/macports/macports-ports/raw/acd8acb171f1658596ed1cf25da48d5b932e2d19/lang/llvm-17/files/0042-mbstate_t-not-defined.patch";
relative = "libcxx";
hash = "sha256-fVbX99W1gQrSaMFeBkzsJmNWNy0xVSw+oFvDe4AYXL0=";
})
];
postPatch = ''

View File

@ -110,8 +110,5 @@ stdenv.mkDerivation rec {
# the UIUC License (a BSD-like license)":
license = with lib.licenses; [ mit ncsa ];
maintainers = llvm_meta.maintainers ++ [ lib.maintainers.vlstill ];
# Broken until https://github.com/llvm/llvm-project/issues/64226 is resolved
# We should check if the version is not 10.13 but that is currently broken.
broken = stdenv.isDarwin && stdenv.isx86_64;
};
}

View File

@ -13,13 +13,13 @@
stdenv.mkDerivation rec {
pname = "frei0r-plugins";
version = "2.3.1";
version = "2.3.2";
src = fetchFromGitHub {
owner = "dyne";
repo = "frei0r";
rev = "v${version}";
hash = "sha256-5itlZfnloQXV/aCiNgOOZzEeO1d+NLY4qSk8uMVAOmA=";
hash = "sha256-shPCCKcmacSB/mqwLU6BPR1p+/9Myg759MMehj9yijI=";
};
nativeBuildInputs = [ cmake pkg-config ];

View File

@ -8,13 +8,13 @@
}:
stdenv.mkDerivation rec {
version = "3.8.0";
version = "3.9.0";
pname = "libre";
src = fetchFromGitHub {
owner = "baresip";
repo = "re";
rev = "v${version}";
sha256 = "sha256-zKoK5GsgNnmQrEZ5HAse2e1Gy7fPO42DEvVAL5ZTNhc=";
sha256 = "sha256-oFaCeVaUrAN83DT8m4gvXSaKzxq5AJw2RHwOelm8HAU=";
};
buildInputs = [

View File

@ -12,11 +12,11 @@
stdenv.mkDerivation rec {
pname = "tdb";
version = "1.4.9";
version = "1.4.10";
src = fetchurl {
url = "mirror://samba/tdb/${pname}-${version}.tar.gz";
hash = "sha256-CsImBz46LbhkjaevdEy5X1B2alL+6wAdVYsrMht0p2U=";
hash = "sha256-AjOOM8FsIcnilXHO9SPnaytwhjYlT28wxs8ZXUjGLa8=";
};
nativeBuildInputs = [

View File

@ -460,14 +460,14 @@ buildLuarocksPackage {
fidget-nvim = callPackage({ buildLuarocksPackage, fetchurl, fetchzip, lua, luaOlder }:
buildLuarocksPackage {
pname = "fidget.nvim";
version = "1.0.0-1";
version = "1.1.0-1";
knownRockspec = (fetchurl {
url = "mirror://luarocks/fidget.nvim-1.0.0-1.rockspec";
sha256 = "09hhm95gvdxd6n9mz2y012gmvs05mpfr4w0qgwcr8zb4kz11nqlw";
url = "mirror://luarocks/fidget.nvim-1.1.0-1.rockspec";
sha256 = "0pgjbsqp6bs9kwi0qphihwhl47j1lzdgg3xfa6msikrcf8d7j0hf";
}).outPath;
src = fetchzip {
url = "https://github.com/j-hui/fidget.nvim/archive/fa1445fe7230845ea66b2c8bec3398fe5d900307.zip";
sha256 = "0krvmyww42dx4q0gxv0qdyv14zxbbl5g4g8pa5dl5qdlznw9vagq";
url = "https://github.com/j-hui/fidget.nvim/archive/300018af4abd00610a345e382ca1f4b7ba420f77.zip";
sha256 = "0bwjcqkb735wqnzc8rngvpq1b2rxgc7m0arjypvnvzsxw6wd1f61";
};
disabled = (luaOlder "5.1");
@ -2860,6 +2860,29 @@ buildLuarocksPackage {
};
}) {};
nvim-nio = callPackage({ buildLuarocksPackage, fetchurl, fetchzip, lua, luaOlder }:
buildLuarocksPackage {
pname = "nvim-nio";
version = "1.2.0-1";
knownRockspec = (fetchurl {
url = "mirror://luarocks/nvim-nio-1.2.0-1.rockspec";
sha256 = "0a62iv1lyx8ldrdbip6az0ixm8dmpcai3k8j5jsf49cr4zjpcjzk";
}).outPath;
src = fetchzip {
url = "https://github.com/nvim-neotest/nvim-nio/archive/11864149f47e0c7a38c4dadbcea8fc17c968556e.zip";
sha256 = "141py3csgbijpqhscgmsbnkg4lbx7ma7nwpj0akfc7v37c143dq3";
};
disabled = (luaOlder "5.1");
propagatedBuildInputs = [ lua ];
meta = {
homepage = "https://github.com/nvim-neotest/nvim-nio";
description = "A library for asynchronous IO in Neovim";
license.fullName = "MIT";
};
}) {};
penlight = callPackage({ buildLuarocksPackage, fetchgit, lua, luaOlder, luafilesystem }:
buildLuarocksPackage {
pname = "penlight";
@ -2948,6 +2971,29 @@ buildLuarocksPackage {
};
}) {};
rocks-nvim = callPackage({ buildLuarocksPackage, fetchurl, fetchzip, fidget-nvim, fzy, lua, luaOlder, nvim-nio, toml, toml-edit }:
buildLuarocksPackage {
pname = "rocks.nvim";
version = "2.7.3-1";
knownRockspec = (fetchurl {
url = "mirror://luarocks/rocks.nvim-2.7.3-1.rockspec";
sha256 = "1nv6ym32d9vk69c6mg2i4bzn1lq0p1c039g5scf7482rx029zvnh";
}).outPath;
src = fetchzip {
url = "https://github.com/nvim-neorocks/rocks.nvim/archive/v2.7.3.zip";
sha256 = "02s7bqskfpk2xbipryvv7ybxl3gjllmn8wa8by1sqmmb4p56836j";
};
disabled = (luaOlder "5.1");
propagatedBuildInputs = [ fidget-nvim fzy lua nvim-nio toml toml-edit ];
meta = {
homepage = "https://github.com/nvim-neorocks/rocks.nvim";
description = "Neovim plugin management inspired by Cargo.";
license.fullName = "GPL-3.0";
};
}) {};
rest-nvim = callPackage({ buildLuarocksPackage, fetchurl, fetchzip, lua, luaOlder }:
buildLuarocksPackage {
pname = "rest.nvim";

View File

@ -18,7 +18,7 @@
buildPythonPackage rec {
pname = "asf-search";
version = "6.7.3";
version = "7.0.4";
format = "setuptools";
disabled = pythonOlder "3.7";
@ -27,7 +27,7 @@ buildPythonPackage rec {
owner = "asfadmin";
repo = "Discovery-asf_search";
rev = "refs/tags/v${version}";
hash = "sha256-wtsPnppsW44OdvdkkuyPoqADzpecUytXEc6G4q7HEw0=";
hash = "sha256-eq8VKML50TfOnHZFXr+Ht7FUMm+NHJOksKvv3uMcq3g=";
};
propagatedBuildInputs = [

View File

@ -12,14 +12,14 @@
buildPythonPackage rec {
pname = "awscrt";
version = "0.19.19";
version = "0.20.3";
format = "setuptools";
disabled = pythonOlder "3.7";
src = fetchPypi {
inherit pname version;
hash = "sha256-HBURU13uFGpsJqOC7T6tViWaEFs7fX2CNVOuVn0Djf4=";
hash = "sha256-xB5HHDSUKHYGosbCa4/pesx0uJQarp2aEhpHDBmDh1g=";
};
buildInputs = lib.optionals stdenv.isDarwin [

View File

@ -10,16 +10,16 @@
buildPythonPackage rec {
pname = "django-maintenance-mode";
version = "0.19.0";
version = "0.21.1";
pyproject = true;
disabled = pythonOlder "3.7";
disabled = pythonOlder "3.8";
src = fetchFromGitHub {
owner = "fabiocaccamo";
repo = "django-maintenance-mode";
rev = "refs/tags/${version}";
hash = "sha256-NAm3xMcHePTYxysihYj48bk7r9ykEtPcxPjSEju/zMM=";
hash = "sha256-rZo0yru+y5TkdULBQDMGAVb494PSLtbnNX/7cuphKNk=";
};
nativeBuildInputs = [

View File

@ -15,7 +15,7 @@
, httpx
}:
let
version = "1.20.9";
version = "1.22.3";
in
buildPythonPackage rec {
pname = "litellm";
@ -26,7 +26,7 @@ buildPythonPackage rec {
owner = "BerriAI";
repo = "litellm";
rev = "refs/tags/v${version}";
hash = "sha256-Sb5vfaKFUjBWfR/SPHLJLPD/EpoEwW56xKqgbUgM0K4=";
hash = "sha256-80XEbc0DW4CWGIAjbV2bossAKqvmqZqfZoFZi8H4NNc=";
};
postPatch = ''

View File

@ -45,6 +45,5 @@ buildPythonPackage rec {
changelog = "https://github.com/mitmproxy/mitmproxy_rs/blob/${src.rev}/CHANGELOG.md";
license = licenses.mit;
maintainers = with maintainers; [ fab ];
platforms = platforms.all;
};
}

View File

@ -1,58 +0,0 @@
{ lib
, buildPythonPackage
, fetchFromGitHub
, stdenv
, darwin
, pytestCheckHook
, pythonOlder
, rustPlatform
, setuptools-rust
}:
buildPythonPackage rec {
pname = "mitmproxy-wireguard";
version = "0.1.23";
format = "pyproject";
disabled = pythonOlder "3.7";
src = fetchFromGitHub {
owner = "decathorpe";
repo = "mitmproxy_wireguard";
rev = "refs/tags/${version}";
hash = "sha256-z9ucTBLLRXc1lcHA0r1wUleoP8X7yIlHrtdZdLD9qJk=";
};
buildInputs = lib.optionals stdenv.isDarwin [
darwin.libiconv
darwin.apple_sdk.frameworks.Security
];
nativeBuildInputs = [
setuptools-rust
] ++ (with rustPlatform; [
cargoSetupHook
maturinBuildHook
]);
cargoDeps = rustPlatform.fetchCargoTarball {
inherit src;
name = "${pname}-${version}";
hash = "sha256-qgyAaUpyuWVYMxUA4Gg8inlUMlSLo++16+nVvmDMhTQ=";
};
# Module has no tests, only a test client
doCheck = false;
pythonImportsCheck = [
"mitmproxy_wireguard"
];
meta = with lib; {
description = "WireGuard frontend for mitmproxy";
homepage = "https://github.com/decathorpe/mitmproxy_wireguard";
changelog = "https://github.com/decathorpe/mitmproxy_wireguard/releases/tag/${version}";
license = licenses.mit;
maintainers = with maintainers; [ fab ];
};
}

View File

@ -16,7 +16,7 @@
buildPythonPackage rec {
pname = "panel";
version = "1.3.4";
version = "1.3.8";
format = "wheel";
@ -25,7 +25,7 @@ buildPythonPackage rec {
# tries to fetch even more artifacts
src = fetchPypi {
inherit pname version format;
hash = "sha256-FK/ekqXCtTHyzLeFs0tHEeH0VXk0yFcns1lOLa5z0KU=";
hash = "sha256-Sb85MZhqDd8/e0vaPGXGoxHVJ3UkrNtOC/9py6a/V3U=";
};
nativeBuildInputs = [

View File

@ -16,7 +16,7 @@
buildPythonPackage rec {
pname = "param";
version = "2.0.1";
version = "2.0.2";
pyproject = true;
disabled = pythonOlder "3.7";
@ -25,7 +25,7 @@ buildPythonPackage rec {
owner = "holoviz";
repo = pname;
rev = "refs/tags/v${version}";
hash = "sha256-IJchqSXZ87WZUKGDY3ObfdYCRfXM++N//kM7kb1wFow=";
hash = "sha256-kVuab6+l4KOtSvj6aI9zsQJ91tfCDJkHrSTcRL9SViY=";
};
nativeBuildInputs = [

View File

@ -10,7 +10,7 @@
buildPythonPackage rec {
pname = "pathos";
version = "0.3.1";
version = "0.3.2";
format = "setuptools";
disabled = pythonOlder "3.7";
@ -18,8 +18,8 @@ buildPythonPackage rec {
src = fetchFromGitHub {
owner = "uqfoundation";
repo = pname;
rev = "refs/tags/pathos-${version}";
hash = "sha256-uQv1t3TRbvoQv86wNOdc5k0cgKt9kvnw5/DGbbbE46w=";
rev = "refs/tags/${version}";
hash = "sha256-b4HCiAvBGkFMxWh2PHC2kZ9G4PsQqVhKeIxLBKj09jU=";
};
propagatedBuildInputs = [
@ -39,7 +39,7 @@ buildPythonPackage rec {
meta = with lib; {
description = "Parallel graph management and execution in heterogeneous computing";
homepage = "https://pathos.readthedocs.io/";
changelog = "https://github.com/uqfoundation/pathos/releases/tag/pathos-${version}";
changelog = "https://github.com/uqfoundation/pathos/releases/tag/${version}";
license = licenses.bsd3;
maintainers = with maintainers; [ ];
};

View File

@ -27,14 +27,14 @@
buildPythonPackage rec {
pname = "snowflake-connector-python";
version = "3.6.0";
version = "3.7.0";
format = "pyproject";
disabled = pythonOlder "3.7";
src = fetchPypi {
inherit pname version;
hash = "sha256-FWZ6kYeA152nVeamC79pGAUYVJUej1bM31aSKD6ahHk=";
hash = "sha256-sr+uxkBZMHsIyq2tQCFNSI/vtKI/zXVTrHX16nWKkWk=";
};
# snowflake-connector-python requires arrow 10.0.1, which we don't have in

View File

@ -9,13 +9,13 @@
buildDotnetModule rec {
pname = "jackett";
version = "0.21.1658";
version = "0.21.1672";
src = fetchFromGitHub {
owner = pname;
repo = pname;
rev = "v${version}";
hash = "sha512-nhtCvuOoRiQxsuE4UCa2PdYNp0OzYRHPEwTIFGuRKIgrEGuGUECGGBHKDNCnOmMiGyxm495r+sKtHqTfhQSUng==";
hash = "sha512-afXP02lZwCjL0XqLzapVM/N2qlE7rxdbfPrTaulN8N227jOPRgq3g96rnXr42crMv1IhThUbEFxN0E1vcMDm5w==";
};
projectFile = "src/Jackett.Server/Jackett.Server.csproj";

View File

@ -213,6 +213,12 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
[[package]]
name = "indoc"
version = "2.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8"
[[package]]
name = "is-terminal"
version = "0.4.9"
@ -289,10 +295,12 @@ dependencies = [
"anyhow",
"clap",
"colored",
"indoc",
"itertools",
"lazy_static",
"regex",
"rnix",
"rowan",
"serde",
"serde_json",
"temp-env",

View File

@ -14,6 +14,8 @@ anyhow = "1.0"
lazy_static = "1.4.0"
colored = "2.0.4"
itertools = "0.11.0"
rowan = "0.15.11"
[dev-dependencies]
temp-env = "0.3.5"
indoc = "2.0.4"

View File

@ -76,6 +76,7 @@ let
CallPackage = {
call_package_variant = value._callPackageVariant;
is_derivation = pkgs.lib.isDerivation value;
location = builtins.unsafeGetAttrPos name pkgs;
};
};

View File

@ -1,7 +1,10 @@
use crate::nixpkgs_problem::NixpkgsProblem;
use crate::ratchet;
use crate::structure;
use crate::utils;
use crate::validation::ResultIteratorExt as _;
use crate::validation::{self, Validation::Success};
use crate::NixFileStore;
use std::path::Path;
use anyhow::Context;
@ -48,6 +51,15 @@ struct CallPackageInfo {
call_package_variant: CallPackageVariant,
/// Whether the attribute is a derivation (`lib.isDerivation`)
is_derivation: bool,
location: Option<Location>,
}
/// The structure returned by `builtins.unsafeGetAttrPos`
#[derive(Deserialize, Clone, Debug)]
struct Location {
pub file: PathBuf,
pub line: usize,
pub column: usize,
}
#[derive(Deserialize)]
@ -70,6 +82,7 @@ enum CallPackageVariant {
/// See the `eval.nix` file for how this is achieved on the Nix side
pub fn check_values(
nixpkgs_path: &Path,
nix_file_store: &mut NixFileStore,
package_names: Vec<String>,
keep_nix_path: bool,
) -> validation::Result<ratchet::Nixpkgs> {
@ -142,150 +155,223 @@ pub fn check_values(
)
})?;
let check_result = validation::sequence(attributes.into_iter().map(
|(attribute_name, attribute_value)| {
let relative_package_file = structure::relative_file_for_package(&attribute_name);
use ratchet::RatchetState::*;
use Attribute::*;
use AttributeInfo::*;
use ByNameAttribute::*;
use CallPackageVariant::*;
use NonByNameAttribute::*;
let check_result = match attribute_value {
// The attribute succeeds evaluation and is NOT defined in pkgs/by-name
NonByName(EvalSuccess(attribute_info)) => {
let uses_by_name = match attribute_info {
// In these cases the package doesn't qualify for being in pkgs/by-name,
// so the UsesByName ratchet is already as tight as it can be
NonAttributeSet => Success(NonApplicable),
NonCallPackage => Success(NonApplicable),
// This is the case when the `pkgs/by-name`-internal _internalCallByNamePackageFile
// is used for a package outside `pkgs/by-name`
CallPackage(CallPackageInfo {
call_package_variant: Auto,
..
}) => {
// With the current detection mechanism, this also triggers for aliases
// to pkgs/by-name packages, and there's no good method of
// distinguishing alias vs non-alias.
// Using `config.allowAliases = false` at least currently doesn't work
// because there's nothing preventing people from defining aliases that
// are present even with that disabled.
// In the future we could kind of abuse this behavior to have better
// enforcement of conditional aliases, but for now we just need to not
// give an error.
Success(NonApplicable)
}
// Only derivations can be in pkgs/by-name,
// so this attribute doesn't qualify
CallPackage(CallPackageInfo {
is_derivation: false,
..
}) => Success(NonApplicable),
// The case of an attribute that qualifies:
// - Uses callPackage
// - Is a derivation
CallPackage(CallPackageInfo {
is_derivation: true,
call_package_variant: Manual { path, empty_arg },
}) => Success(Loose(ratchet::CouldUseByName {
call_package_path: path,
empty_arg,
})),
};
uses_by_name.map(|x| ratchet::Package {
manual_definition: Tight,
uses_by_name: x,
})
}
NonByName(EvalFailure) => {
// We don't know anything about this attribute really
Success(ratchet::Package {
// We'll assume that we can't remove any manual definitions, which has the
// minimal drawback that if there was a manual definition that could've
// been removed, fixing the package requires removing the definition, no
// big deal, that's a minor edit.
manual_definition: Tight,
// Regarding whether this attribute could `pkgs/by-name`, we don't really
// know, so return NonApplicable, which has the effect that if a
// package evaluation gets broken temporarily, the fix can remove it from
// pkgs/by-name again. For now this isn't our problem, but in the future we
// might have another check to enforce that evaluation must not be broken.
// The alternative of assuming that it's using `pkgs/by-name` already
// has the problem that if a package evaluation gets broken temporarily,
// fixing it requires a move to pkgs/by-name, which could happen more
// often and isn't really justified.
uses_by_name: NonApplicable,
})
}
ByName(Missing) => NixpkgsProblem::UndefinedAttr {
relative_package_file: relative_package_file.clone(),
package_name: attribute_name.clone(),
}
.into(),
ByName(Existing(NonAttributeSet)) => NixpkgsProblem::NonDerivation {
relative_package_file: relative_package_file.clone(),
package_name: attribute_name.clone(),
}
.into(),
ByName(Existing(NonCallPackage)) => NixpkgsProblem::WrongCallPackage {
relative_package_file: relative_package_file.clone(),
package_name: attribute_name.clone(),
}
.into(),
ByName(Existing(CallPackage(CallPackageInfo {
is_derivation,
call_package_variant,
}))) => {
let check_result = if !is_derivation {
NixpkgsProblem::NonDerivation {
relative_package_file: relative_package_file.clone(),
package_name: attribute_name.clone(),
}
.into()
} else {
Success(())
};
check_result.and(match &call_package_variant {
Auto => Success(ratchet::Package {
manual_definition: Tight,
uses_by_name: Tight,
}),
Manual { path, empty_arg } => {
let correct_file = if let Some(call_package_path) = path {
relative_package_file == *call_package_path
} else {
false
};
if correct_file {
Success(ratchet::Package {
// Empty arguments for non-auto-called packages are not allowed anymore.
manual_definition: if *empty_arg { Loose(()) } else { Tight },
uses_by_name: Tight,
})
} else {
NixpkgsProblem::WrongCallPackage {
relative_package_file: relative_package_file.clone(),
package_name: attribute_name.clone(),
}
.into()
}
}
})
}
};
check_result.map(|value| (attribute_name.clone(), value))
},
));
let check_result = validation::sequence(
attributes
.into_iter()
.map(|(attribute_name, attribute_value)| {
let check_result = match attribute_value {
Attribute::NonByName(non_by_name_attribute) => handle_non_by_name_attribute(
nixpkgs_path,
nix_file_store,
non_by_name_attribute,
)?,
Attribute::ByName(by_name_attribute) => {
by_name(&attribute_name, by_name_attribute)
}
};
Ok::<_, anyhow::Error>(check_result.map(|value| (attribute_name.clone(), value)))
})
.collect_vec()?,
);
Ok(check_result.map(|elems| ratchet::Nixpkgs {
package_names: elems.iter().map(|(name, _)| name.to_owned()).collect(),
package_map: elems.into_iter().collect(),
}))
}
/// Handles the evaluation result for an attribute in `pkgs/by-name`,
/// turning it into a validation result.
fn by_name(
attribute_name: &str,
by_name_attribute: ByNameAttribute,
) -> validation::Validation<ratchet::Package> {
use ratchet::RatchetState::*;
use AttributeInfo::*;
use ByNameAttribute::*;
use CallPackageVariant::*;
let relative_package_file = structure::relative_file_for_package(attribute_name);
match by_name_attribute {
Missing => NixpkgsProblem::UndefinedAttr {
relative_package_file: relative_package_file.to_owned(),
package_name: attribute_name.to_owned(),
}
.into(),
Existing(NonAttributeSet) => NixpkgsProblem::NonDerivation {
relative_package_file: relative_package_file.to_owned(),
package_name: attribute_name.to_owned(),
}
.into(),
Existing(NonCallPackage) => NixpkgsProblem::WrongCallPackage {
relative_package_file: relative_package_file.to_owned(),
package_name: attribute_name.to_owned(),
}
.into(),
Existing(CallPackage(CallPackageInfo {
is_derivation,
call_package_variant,
..
})) => {
let check_result = if !is_derivation {
NixpkgsProblem::NonDerivation {
relative_package_file: relative_package_file.to_owned(),
package_name: attribute_name.to_owned(),
}
.into()
} else {
Success(())
};
check_result.and(match &call_package_variant {
Auto => Success(ratchet::Package {
manual_definition: Tight,
uses_by_name: Tight,
}),
// TODO: Use the call_package_argument_info_at instead/additionally and
// simplify the eval.nix code
Manual { path, empty_arg } => {
let correct_file = if let Some(call_package_path) = path {
relative_package_file == *call_package_path
} else {
false
};
if correct_file {
Success(ratchet::Package {
// Empty arguments for non-auto-called packages are not allowed anymore.
manual_definition: if *empty_arg { Loose(()) } else { Tight },
uses_by_name: Tight,
})
} else {
NixpkgsProblem::WrongCallPackage {
relative_package_file: relative_package_file.to_owned(),
package_name: attribute_name.to_owned(),
}
.into()
}
}
})
}
}
}
/// Handles the evaluation result for an attribute _not_ in `pkgs/by-name`,
/// turning it into a validation result.
fn handle_non_by_name_attribute(
nixpkgs_path: &Path,
nix_file_store: &mut NixFileStore,
non_by_name_attribute: NonByNameAttribute,
) -> validation::Result<ratchet::Package> {
use ratchet::RatchetState::*;
use AttributeInfo::*;
use CallPackageVariant::*;
use NonByNameAttribute::*;
Ok(match non_by_name_attribute {
// The attribute succeeds evaluation and is NOT defined in pkgs/by-name
EvalSuccess(attribute_info) => {
let uses_by_name = match attribute_info {
// In these cases the package doesn't qualify for being in pkgs/by-name,
// so the UsesByName ratchet is already as tight as it can be
NonAttributeSet => Success(NonApplicable),
NonCallPackage => Success(NonApplicable),
// This is the case when the `pkgs/by-name`-internal _internalCallByNamePackageFile
// is used for a package outside `pkgs/by-name`
CallPackage(CallPackageInfo {
call_package_variant: Auto,
..
}) => {
// With the current detection mechanism, this also triggers for aliases
// to pkgs/by-name packages, and there's no good method of
// distinguishing alias vs non-alias.
// Using `config.allowAliases = false` at least currently doesn't work
// because there's nothing preventing people from defining aliases that
// are present even with that disabled.
// In the future we could kind of abuse this behavior to have better
// enforcement of conditional aliases, but for now we just need to not
// give an error.
Success(NonApplicable)
}
// Only derivations can be in pkgs/by-name,
// so this attribute doesn't qualify
CallPackage(CallPackageInfo {
is_derivation: false,
..
}) => Success(NonApplicable),
// A location of None indicates something weird, we can't really know where
// this attribute is defined, probably an alias
CallPackage(CallPackageInfo { location: None, .. }) => Success(Tight),
// The case of an attribute that qualifies:
// - Uses callPackage
// - Is a derivation
CallPackage(CallPackageInfo {
is_derivation: true,
call_package_variant: Manual { .. },
location: Some(location),
}) =>
// We'll use the attribute's location to parse the file that defines it
{
match nix_file_store
.get(&location.file)?
.call_package_argument_info_at(
location.line,
location.column,
nixpkgs_path,
)? {
// If the definition is not of the form `<attr> = callPackage <arg1> <arg2>;`,
// it's generally not possible to migrate to `pkgs/by-name`
None => Success(NonApplicable),
Some(call_package_argument_info) => {
if let Some(ref rel_path) = call_package_argument_info.relative_path {
if rel_path.starts_with(utils::BASE_SUBPATH) {
// Package variants of by-name packages are explicitly allowed according to RFC 140
// https://github.com/NixOS/rfcs/blob/master/rfcs/0140-simple-package-paths.md#package-variants:
//
// foo-variant = callPackage ../by-name/fo/foo/package.nix {
// someFlag = true;
// }
//
// While such definitions could be moved to `pkgs/by-name` by using
// `.override { someFlag = true; }` instead, this changes the semantics in
// relation with overlays.
Success(NonApplicable)
} else {
Success(Loose(call_package_argument_info))
}
} else {
Success(Loose(call_package_argument_info))
}
}
}
}
};
uses_by_name.map(|x| ratchet::Package {
manual_definition: Tight,
uses_by_name: x,
})
}
EvalFailure => {
// We don't know anything about this attribute really
Success(ratchet::Package {
// We'll assume that we can't remove any manual definitions, which has the
// minimal drawback that if there was a manual definition that could've
// been removed, fixing the package requires removing the definition, no
// big deal, that's a minor edit.
manual_definition: Tight,
// Regarding whether this attribute could `pkgs/by-name`, we don't really
// know, so return NonApplicable, which has the effect that if a
// package evaluation gets broken temporarily, the fix can remove it from
// pkgs/by-name again. For now this isn't our problem, but in the future we
// might have another check to enforce that evaluation must not be broken.
// The alternative of assuming that it's using `pkgs/by-name` already
// has the problem that if a package evaluation gets broken temporarily,
// fixing it requires a move to pkgs/by-name, which could happen more
// often and isn't really justified.
uses_by_name: NonApplicable,
})
}
})
}

View File

@ -1,4 +1,6 @@
use crate::nix_file::NixFileStore;
mod eval;
mod nix_file;
mod nixpkgs_problem;
mod ratchet;
mod references;
@ -116,6 +118,8 @@ pub fn check_nixpkgs<W: io::Write>(
keep_nix_path: bool,
error_writer: &mut W,
) -> validation::Result<ratchet::Nixpkgs> {
let mut nix_file_store = NixFileStore::default();
Ok({
let nixpkgs_path = nixpkgs_path.canonicalize().with_context(|| {
format!(
@ -132,9 +136,9 @@ pub fn check_nixpkgs<W: io::Write>(
)?;
Success(ratchet::Nixpkgs::default())
} else {
check_structure(&nixpkgs_path)?.result_map(|package_names|
check_structure(&nixpkgs_path, &mut nix_file_store)?.result_map(|package_names|
// Only if we could successfully parse the structure, we do the evaluation checks
eval::check_values(&nixpkgs_path, package_names, keep_nix_path))?
eval::check_values(&nixpkgs_path, &mut nix_file_store, package_names, keep_nix_path))?
}
})
}
@ -169,7 +173,7 @@ mod tests {
// tempfile::tempdir needs to be wrapped in temp_env lock
// because it accesses TMPDIR environment variable.
fn tempdir() -> anyhow::Result<TempDir> {
pub fn tempdir() -> anyhow::Result<TempDir> {
let empty_list: [(&str, Option<&str>); 0] = [];
Ok(temp_env::with_vars(empty_list, tempfile::tempdir)?)
}

View File

@ -0,0 +1,510 @@
//! This is a utility module for interacting with the syntax of Nix files
use crate::utils::LineIndex;
use anyhow::Context;
use rnix::ast;
use rnix::ast::Expr;
use rnix::ast::HasEntry;
use rnix::SyntaxKind;
use rowan::ast::AstNode;
use rowan::TextSize;
use rowan::TokenAtOffset;
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::fs::read_to_string;
use std::path::Path;
use std::path::PathBuf;
/// A structure to store parse results of Nix files in memory,
/// making sure that the same file never has to be parsed twice
#[derive(Default)]
pub struct NixFileStore {
entries: HashMap<PathBuf, NixFile>,
}
impl NixFileStore {
/// Get the store entry for a Nix file if it exists, otherwise parse the file, insert it into
/// the store, and return the value
///
/// Note that this function only gives an anyhow::Result::Err for I/O errors.
/// A parse error is anyhow::Result::Ok(Result::Err(error))
pub fn get(&mut self, path: &Path) -> anyhow::Result<&NixFile> {
match self.entries.entry(path.to_owned()) {
Entry::Occupied(entry) => Ok(entry.into_mut()),
Entry::Vacant(entry) => Ok(entry.insert(NixFile::new(path)?)),
}
}
}
/// A structure for storing a successfully parsed Nix file
pub struct NixFile {
/// The parent directory of the Nix file, for more convenient error handling
pub parent_dir: PathBuf,
/// The path to the file itself, for errors
pub path: PathBuf,
pub syntax_root: rnix::Root,
pub line_index: LineIndex,
}
impl NixFile {
/// Creates a new NixFile, failing for I/O or parse errors
fn new(path: impl AsRef<Path>) -> anyhow::Result<NixFile> {
let Some(parent_dir) = path.as_ref().parent() else {
anyhow::bail!("Could not get parent of path {}", path.as_ref().display())
};
let contents = read_to_string(&path)
.with_context(|| format!("Could not read file {}", path.as_ref().display()))?;
let line_index = LineIndex::new(&contents);
// NOTE: There's now another Nixpkgs CI check to make sure all changed Nix files parse
// correctly, though that uses mainline Nix instead of rnix, so it doesn't give the same
// errors. In the future we should unify these two checks, ideally moving the other CI
// check into this tool as well and checking for both mainline Nix and rnix.
rnix::Root::parse(&contents)
// rnix's ::ok returns Result<_, _> , so no error is thrown away like it would be with
// std::result's ::ok
.ok()
.map(|syntax_root| NixFile {
parent_dir: parent_dir.to_path_buf(),
path: path.as_ref().to_owned(),
syntax_root,
line_index,
})
.with_context(|| format!("Could not parse file {} with rnix", path.as_ref().display()))
}
}
/// Information about callPackage arguments
#[derive(Debug, PartialEq)]
pub struct CallPackageArgumentInfo {
/// The relative path of the first argument, or `None` if it's not a path.
pub relative_path: Option<PathBuf>,
/// Whether the second argument is an empty attribute set
pub empty_arg: bool,
}
impl NixFile {
/// Returns information about callPackage arguments for an attribute at a specific line/column
/// index.
/// If the location is not of the form `<attr> = callPackage <arg1> <arg2>;`, `None` is
/// returned.
/// This function only returns `Err` for problems that can't be caused by the Nix contents,
/// but rather problems in this programs code itself.
///
/// This is meant to be used with the location returned from `builtins.unsafeGetAttrPos`, e.g.:
/// - Create file `default.nix` with contents
/// ```nix
/// self: {
/// foo = self.callPackage ./default.nix { };
/// }
/// ```
/// - Evaluate
/// ```nix
/// builtins.unsafeGetAttrPos "foo" (import ./default.nix { })
/// ```
/// results in `{ file = ./default.nix; line = 2; column = 3; }`
/// - Get the NixFile for `.file` from a `NixFileStore`
/// - Call this function with `.line`, `.column` and `relative_to` as the (absolute) current directory
///
/// You'll get back
/// ```rust
/// Some(CallPackageArgumentInfo { path = Some("default.nix"), empty_arg: true })
/// ```
///
/// Note that this also returns the same for `pythonPackages.callPackage`. It doesn't make an
/// attempt at distinguishing this.
pub fn call_package_argument_info_at(
&self,
line: usize,
column: usize,
relative_to: &Path,
) -> anyhow::Result<Option<CallPackageArgumentInfo>> {
let Some(attrpath_value) = self.attrpath_value_at(line, column)? else {
return Ok(None);
};
self.attrpath_value_call_package_argument_info(attrpath_value, relative_to)
}
// Internal function mainly to make it independently testable
fn attrpath_value_at(
&self,
line: usize,
column: usize,
) -> anyhow::Result<Option<ast::AttrpathValue>> {
let index = self.line_index.fromlinecolumn(line, column);
let token_at_offset = self
.syntax_root
.syntax()
.token_at_offset(TextSize::from(index as u32));
// The token_at_offset function takes indices to mean a location _between_ characters,
// which in this case is some spacing followed by the attribute name:
//
// foo = 10;
// /\
// This is the token offset, we get both the (newline + indentation) on the left side,
// and the attribute name on the right side.
let TokenAtOffset::Between(_space, token) = token_at_offset else {
anyhow::bail!("Line {line} column {column} in {} is not the start of a token, but rather {token_at_offset:?}", self.path.display())
};
// token looks like "foo"
let Some(node) = token.parent() else {
anyhow::bail!(
"Token on line {line} column {column} in {} does not have a parent node: {token:?}",
self.path.display()
)
};
// node looks like "foo"
let Some(attrpath_node) = node.parent() else {
anyhow::bail!(
"Node in {} does not have a parent node: {node:?}",
self.path.display()
)
};
if attrpath_node.kind() != SyntaxKind::NODE_ATTRPATH {
// This can happen for e.g. `inherit foo`, so definitely not a syntactic `callPackage`
return Ok(None);
}
// attrpath_node looks like "foo.bar"
let Some(attrpath_value_node) = attrpath_node.parent() else {
anyhow::bail!(
"Attribute path node in {} does not have a parent node: {attrpath_node:?}",
self.path.display()
)
};
if !ast::AttrpathValue::can_cast(attrpath_value_node.kind()) {
anyhow::bail!(
"Node in {} is not an attribute path value node: {attrpath_value_node:?}",
self.path.display()
)
}
// attrpath_value_node looks like "foo.bar = 10;"
// unwrap is fine because we confirmed that we can cast with the above check.
// We could avoid this `unwrap` for a `clone`, since `cast` consumes the argument,
// but we still need it for the error message when the cast fails.
Ok(Some(ast::AttrpathValue::cast(attrpath_value_node).unwrap()))
}
// Internal function mainly to make attrpath_value_at independently testable
fn attrpath_value_call_package_argument_info(
&self,
attrpath_value: ast::AttrpathValue,
relative_to: &Path,
) -> anyhow::Result<Option<CallPackageArgumentInfo>> {
let Some(attrpath) = attrpath_value.attrpath() else {
anyhow::bail!("attrpath value node doesn't have an attrpath: {attrpath_value:?}")
};
// At this point we know it's something like `foo...bar = ...`
if attrpath.attrs().count() > 1 {
// If the attribute path has multiple entries, the left-most entry is an attribute and
// can't be a `callPackage`.
//
// FIXME: `builtins.unsafeGetAttrPos` will return the same position for all attribute
// paths and we can't really know which one it is. We could have a case like
// `foo.bar = callPackage ... { }` and trying to determine if `bar` is a `callPackage`,
// where this is not correct.
// However, this case typically doesn't occur anyways,
// because top-level packages wouldn't be nested under an attribute set.
return Ok(None);
}
let Some(value) = attrpath_value.value() else {
anyhow::bail!("attrpath value node doesn't have a value: {attrpath_value:?}")
};
// At this point we know it's something like `foo = ...`
let Expr::Apply(apply1) = value else {
// Not even a function call, instead something like `foo = null`
return Ok(None);
};
let Some(function1) = apply1.lambda() else {
anyhow::bail!("apply node doesn't have a lambda: {apply1:?}")
};
let Some(arg1) = apply1.argument() else {
anyhow::bail!("apply node doesn't have an argument: {apply1:?}")
};
// At this point we know it's something like `foo = <fun> <arg>`.
// For a callPackage, `<fun>` would be `callPackage ./file` and `<arg>` would be `{ }`
let empty_arg = if let Expr::AttrSet(attrset) = arg1 {
// We can only statically determine whether the argument is empty if it's an attribute
// set _expression_, even though other kind of expressions could evaluate to an attribute
// set _value_. But this is what we want anyways
attrset.entries().next().is_none()
} else {
false
};
// Because callPackage takes two curried arguments, the first function needs to be a
// function call itself
let Expr::Apply(apply2) = function1 else {
// Not a callPackage, instead something like `foo = import ./foo`
return Ok(None);
};
let Some(function2) = apply2.lambda() else {
anyhow::bail!("apply node doesn't have a lambda: {apply2:?}")
};
let Some(arg2) = apply2.argument() else {
anyhow::bail!("apply node doesn't have an argument: {apply2:?}")
};
// At this point we know it's something like `foo = <fun2> <arg2> <arg1>`.
// For a callPackage, `<fun2>` would be `callPackage`, `<arg2>` would be `./file`
// Check that <arg2> is a path expression
let path = if let Expr::Path(actual_path) = arg2 {
// Try to statically resolve the path and turn it into a nixpkgs-relative path
if let ResolvedPath::Within(p) = self.static_resolve_path(actual_path, relative_to) {
Some(p)
} else {
// We can't statically know an existing path inside Nixpkgs used as <arg2>
None
}
} else {
// <arg2> is not a path, but rather e.g. an inline expression
None
};
// Check that <fun2> is an identifier, or an attribute path with an identifier at the end
let ident = match function2 {
Expr::Ident(ident) => {
// This means it's something like `foo = callPackage <arg2> <arg1>`
ident
}
Expr::Select(select) => {
// This means it's something like `foo = self.callPackage <arg2> <arg1>`.
// We also end up here for e.g. `pythonPackages.callPackage`, but the
// callPackage-mocking method will take care of not triggering for this case.
if select.default_expr().is_some() {
// Very odd case, but this would be `foo = self.callPackage or true ./test.nix {}
// (yes this is valid Nix code)
return Ok(None);
}
let Some(attrpath) = select.attrpath() else {
anyhow::bail!("select node doesn't have an attrpath: {select:?}")
};
let Some(last) = attrpath.attrs().last() else {
// This case shouldn't be possible, it would be `foo = self. ./test.nix {}`,
// which shouldn't parse
anyhow::bail!("select node has an empty attrpath: {select:?}")
};
if let ast::Attr::Ident(ident) = last {
ident
} else {
// Here it's something like `foo = self."callPackage" /test.nix {}`
// which we're not gonna bother with
return Ok(None);
}
}
// Any other expression we're not gonna treat as callPackage
_ => return Ok(None),
};
let Some(token) = ident.ident_token() else {
anyhow::bail!("ident node doesn't have a token: {ident:?}")
};
if token.text() == "callPackage" {
Ok(Some(CallPackageArgumentInfo {
relative_path: path,
empty_arg,
}))
} else {
Ok(None)
}
}
}
/// The result of trying to statically resolve a Nix path expression
pub enum ResolvedPath {
/// Something like `./foo/${bar}/baz`, can't be known statically
Interpolated,
/// Something like `<nixpkgs>`, can't be known statically
SearchPath,
/// Path couldn't be resolved due to an IO error,
/// e.g. if the path doesn't exist or you don't have the right permissions
Unresolvable(std::io::Error),
/// The path is outside the given absolute path
Outside,
/// The path is within the given absolute path.
/// The `PathBuf` is the relative path under the given absolute path.
Within(PathBuf),
}
impl NixFile {
/// Statically resolves a Nix path expression and checks that it's within an absolute path
///
/// E.g. for the path expression `./bar.nix` in `./foo.nix` and an absolute path of the
/// current directory, the function returns `ResolvedPath::Within(./bar.nix)`
pub fn static_resolve_path(&self, node: ast::Path, relative_to: &Path) -> ResolvedPath {
if node.parts().count() != 1 {
// If there's more than 1 interpolated part, it's of the form `./foo/${bar}/baz`.
return ResolvedPath::Interpolated;
}
let text = node.to_string();
if text.starts_with('<') {
// A search path like `<nixpkgs>`. There doesn't appear to be better way to detect
// these in rnix
return ResolvedPath::SearchPath;
}
// Join the file's parent directory and the path expression, then resolve it
// FIXME: Expressions like `../../../../foo/bar/baz/qux` or absolute paths
// may resolve close to the original file, but may have left the relative_to.
// That should be checked more strictly
match self.parent_dir.join(Path::new(&text)).canonicalize() {
Err(resolution_error) => ResolvedPath::Unresolvable(resolution_error),
Ok(resolved) => {
// Check if it's within relative_to
match resolved.strip_prefix(relative_to) {
Err(_prefix_error) => ResolvedPath::Outside,
Ok(suffix) => ResolvedPath::Within(suffix.to_path_buf()),
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tests;
use indoc::indoc;
#[test]
fn detects_attributes() -> anyhow::Result<()> {
let temp_dir = tests::tempdir()?;
let file = temp_dir.path().join("file.nix");
let contents = indoc! {r#"
toInherit: {
foo = 1;
"bar" = 2;
${"baz"} = 3;
"${"qux"}" = 4;
# A
quux
# B
=
# C
5
# D
;
# E
/**/quuux/**/=/**/5/**/;/*E*/
inherit toInherit;
}
"#};
std::fs::write(&file, contents)?;
let nix_file = NixFile::new(&file)?;
// These are builtins.unsafeGetAttrPos locations for the attributes
let cases = [
(2, 3, Some("foo = 1;")),
(3, 3, Some(r#""bar" = 2;"#)),
(4, 3, Some(r#"${"baz"} = 3;"#)),
(5, 3, Some(r#""${"qux"}" = 4;"#)),
(8, 3, Some("quux\n # B\n =\n # C\n 5\n # D\n ;")),
(17, 7, Some("quuux/**/=/**/5/**/;")),
(19, 10, None),
];
for (line, column, expected_result) in cases {
let actual_result = nix_file
.attrpath_value_at(line, column)?
.map(|node| node.to_string());
assert_eq!(actual_result.as_deref(), expected_result);
}
Ok(())
}
#[test]
fn detects_call_package() -> anyhow::Result<()> {
let temp_dir = tests::tempdir()?;
let file = temp_dir.path().join("file.nix");
let contents = indoc! {r#"
self: with self; {
a.sub = null;
b = null;
c = import ./file.nix;
d = import ./file.nix { };
e = pythonPackages.callPackage ./file.nix { };
f = callPackage ./file.nix { };
g = callPackage ({ }: { }) { };
h = callPackage ./file.nix { x = 0; };
i = callPackage ({ }: { }) (let in { });
}
"#};
std::fs::write(&file, contents)?;
let nix_file = NixFile::new(&file)?;
let cases = [
(2, None),
(3, None),
(4, None),
(5, None),
(
6,
Some(CallPackageArgumentInfo {
relative_path: Some(PathBuf::from("file.nix")),
empty_arg: true,
}),
),
(
7,
Some(CallPackageArgumentInfo {
relative_path: Some(PathBuf::from("file.nix")),
empty_arg: true,
}),
),
(
8,
Some(CallPackageArgumentInfo {
relative_path: None,
empty_arg: true,
}),
),
(
9,
Some(CallPackageArgumentInfo {
relative_path: Some(PathBuf::from("file.nix")),
empty_arg: false,
}),
),
(
10,
Some(CallPackageArgumentInfo {
relative_path: None,
empty_arg: false,
}),
),
];
for (line, expected_result) in cases {
let actual_result = nix_file.call_package_argument_info_at(line, 3, temp_dir.path())?;
assert_eq!(actual_result, expected_result);
}
Ok(())
}
}

View File

@ -1,6 +1,5 @@
use crate::structure;
use crate::utils::PACKAGE_NIX_FILENAME;
use rnix::parser::ParseError;
use std::ffi::OsString;
use std::fmt;
use std::io;
@ -58,11 +57,6 @@ pub enum NixpkgsProblem {
subpath: PathBuf,
io_error: io::Error,
},
CouldNotParseNix {
relative_package_dir: PathBuf,
subpath: PathBuf,
error: ParseError,
},
PathInterpolation {
relative_package_dir: PathBuf,
subpath: PathBuf,
@ -184,14 +178,6 @@ impl fmt::Display for NixpkgsProblem {
relative_package_dir.display(),
subpath.display(),
),
NixpkgsProblem::CouldNotParseNix { relative_package_dir, subpath, error } =>
write!(
f,
"{}: File {} could not be parsed by rnix: {}",
relative_package_dir.display(),
subpath.display(),
error,
),
NixpkgsProblem::PathInterpolation { relative_package_dir, subpath, line, text } =>
write!(
f,

View File

@ -2,11 +2,11 @@
//!
//! Each type has a `compare` method that validates the ratchet checks for that item.
use crate::nix_file::CallPackageArgumentInfo;
use crate::nixpkgs_problem::NixpkgsProblem;
use crate::structure;
use crate::validation::{self, Validation, Validation::Success};
use std::collections::HashMap;
use std::path::PathBuf;
/// The ratchet value for the entirety of Nixpkgs.
#[derive(Default)]
@ -148,16 +148,8 @@ impl ToNixpkgsProblem for ManualDefinition {
/// It also checks that once a package uses pkgs/by-name, it can't switch back to all-packages.nix
pub enum UsesByName {}
#[derive(Clone)]
pub struct CouldUseByName {
/// The first callPackage argument, used for better errors
pub call_package_path: Option<PathBuf>,
/// Whether the second callPackage argument is empty, used for better errors
pub empty_arg: bool,
}
impl ToNixpkgsProblem for UsesByName {
type ToContext = CouldUseByName;
type ToContext = CallPackageArgumentInfo;
fn to_nixpkgs_problem(
name: &str,
@ -167,13 +159,13 @@ impl ToNixpkgsProblem for UsesByName {
if let Some(()) = optional_from {
NixpkgsProblem::MovedOutOfByName {
package_name: name.to_owned(),
call_package_path: to.call_package_path.clone(),
call_package_path: to.relative_path.clone(),
empty_arg: to.empty_arg,
}
} else {
NixpkgsProblem::NewPackageNotUsingByName {
package_name: name.to_owned(),
call_package_path: to.call_package_path.clone(),
call_package_path: to.relative_path.clone(),
empty_arg: to.empty_arg,
}
}

View File

@ -1,23 +1,32 @@
use crate::nixpkgs_problem::NixpkgsProblem;
use crate::utils;
use crate::utils::LineIndex;
use crate::validation::{self, ResultIteratorExt, Validation::Success};
use crate::NixFileStore;
use anyhow::Context;
use rnix::{Root, SyntaxKind::NODE_PATH};
use rowan::ast::AstNode;
use std::ffi::OsStr;
use std::fs::read_to_string;
use std::path::Path;
/// Check that every package directory in pkgs/by-name doesn't link to outside that directory.
/// Both symlinks and Nix path expressions are checked.
pub fn check_references(
nix_file_store: &mut NixFileStore,
relative_package_dir: &Path,
absolute_package_dir: &Path,
) -> validation::Result<()> {
// The empty argument here is the subpath under the package directory to check
// An empty one means the package directory itself
check_path(relative_package_dir, absolute_package_dir, Path::new("")).with_context(|| {
// The first subpath to check is the package directory itself, which we can represent as an
// empty path, since the absolute package directory gets prepended to this.
// We don't use `./.` to keep the error messages cleaner
// (there's no canonicalisation going on underneath)
let subpath = Path::new("");
check_path(
nix_file_store,
relative_package_dir,
absolute_package_dir,
subpath,
)
.with_context(|| {
format!(
"While checking the references in package directory {}",
relative_package_dir.display()
@ -26,7 +35,12 @@ pub fn check_references(
}
/// Checks for a specific path to not have references outside
///
/// The subpath is the relative path within the package directory we're currently checking.
/// A relative path so that the error messages don't get absolute paths (which are messy in CI).
/// The absolute package directory gets prepended before doing anything with it though.
fn check_path(
nix_file_store: &mut NixFileStore,
relative_package_dir: &Path,
absolute_package_dir: &Path,
subpath: &Path,
@ -62,21 +76,27 @@ fn check_path(
utils::read_dir_sorted(&path)?
.into_iter()
.map(|entry| {
let entry_subpath = subpath.join(entry.file_name());
check_path(relative_package_dir, absolute_package_dir, &entry_subpath)
.with_context(|| {
format!("Error while recursing into {}", subpath.display())
})
check_path(
nix_file_store,
relative_package_dir,
absolute_package_dir,
&subpath.join(entry.file_name()),
)
})
.collect_vec()?,
.collect_vec()
.with_context(|| format!("Error while recursing into {}", subpath.display()))?,
)
} else if path.is_file() {
// Only check Nix files
if let Some(ext) = path.extension() {
if ext == OsStr::new("nix") {
check_nix_file(relative_package_dir, absolute_package_dir, subpath).with_context(
|| format!("Error while checking Nix file {}", subpath.display()),
)?
check_nix_file(
nix_file_store,
relative_package_dir,
absolute_package_dir,
subpath,
)
.with_context(|| format!("Error while checking Nix file {}", subpath.display()))?
} else {
Success(())
}
@ -92,91 +112,63 @@ fn check_path(
/// Check whether a nix file contains path expression references pointing outside the package
/// directory
fn check_nix_file(
nix_file_store: &mut NixFileStore,
relative_package_dir: &Path,
absolute_package_dir: &Path,
subpath: &Path,
) -> validation::Result<()> {
let path = absolute_package_dir.join(subpath);
let parent_dir = path
.parent()
.with_context(|| format!("Could not get parent of path {}", subpath.display()))?;
let contents = read_to_string(&path)
.with_context(|| format!("Could not read file {}", subpath.display()))?;
let nix_file = nix_file_store.get(&path)?;
let root = Root::parse(&contents);
if let Some(error) = root.errors().first() {
// NOTE: There's now another Nixpkgs CI check to make sure all changed Nix files parse
// correctly, though that uses mainline Nix instead of rnix, so it doesn't give the same
// errors. In the future we should unify these two checks, ideally moving the other CI
// check into this tool as well and checking for both mainline Nix and rnix.
return Ok(NixpkgsProblem::CouldNotParseNix {
relative_package_dir: relative_package_dir.to_path_buf(),
subpath: subpath.to_path_buf(),
error: error.clone(),
}
.into());
}
let line_index = LineIndex::new(&contents);
Ok(validation::sequence_(root.syntax().descendants().map(
|node| {
Ok(validation::sequence_(
nix_file.syntax_root.syntax().descendants().map(|node| {
let text = node.text().to_string();
let line = line_index.line(node.text_range().start().into());
let line = nix_file.line_index.line(node.text_range().start().into());
if node.kind() != NODE_PATH {
// We're only interested in Path expressions
Success(())
} else if node.children().count() != 0 {
// Filters out ./foo/${bar}/baz
// TODO: We can just check ./foo
NixpkgsProblem::PathInterpolation {
// We're only interested in Path expressions
let Some(path) = rnix::ast::Path::cast(node) else {
return Success(());
};
use crate::nix_file::ResolvedPath;
match nix_file.static_resolve_path(path, absolute_package_dir) {
ResolvedPath::Interpolated => NixpkgsProblem::PathInterpolation {
relative_package_dir: relative_package_dir.to_path_buf(),
subpath: subpath.to_path_buf(),
line,
text,
}
.into()
} else if text.starts_with('<') {
// Filters out search paths like <nixpkgs>
NixpkgsProblem::SearchPath {
.into(),
ResolvedPath::SearchPath => NixpkgsProblem::SearchPath {
relative_package_dir: relative_package_dir.to_path_buf(),
subpath: subpath.to_path_buf(),
line,
text,
}
.into()
} else {
// Resolves the reference of the Nix path
// turning `../baz` inside `/foo/bar/default.nix` to `/foo/baz`
match parent_dir.join(Path::new(&text)).canonicalize() {
Ok(target) => {
// Then checking if it's still in the package directory
// No need to handle the case of it being inside the directory, since we scan through the
// entire directory recursively anyways
if let Err(_prefix_error) = target.strip_prefix(absolute_package_dir) {
NixpkgsProblem::OutsidePathReference {
relative_package_dir: relative_package_dir.to_path_buf(),
subpath: subpath.to_path_buf(),
line,
text,
}
.into()
} else {
Success(())
}
}
Err(e) => NixpkgsProblem::UnresolvablePathReference {
relative_package_dir: relative_package_dir.to_path_buf(),
subpath: subpath.to_path_buf(),
line,
text,
io_error: e,
}
.into(),
.into(),
ResolvedPath::Outside => NixpkgsProblem::OutsidePathReference {
relative_package_dir: relative_package_dir.to_path_buf(),
subpath: subpath.to_path_buf(),
line,
text,
}
.into(),
ResolvedPath::Unresolvable(e) => NixpkgsProblem::UnresolvablePathReference {
relative_package_dir: relative_package_dir.to_path_buf(),
subpath: subpath.to_path_buf(),
line,
text,
io_error: e,
}
.into(),
ResolvedPath::Within(..) => {
// No need to handle the case of it being inside the directory, since we scan through the
// entire directory recursively anyways
Success(())
}
}
},
)))
}),
))
}

View File

@ -3,6 +3,7 @@ use crate::references;
use crate::utils;
use crate::utils::{BASE_SUBPATH, PACKAGE_NIX_FILENAME};
use crate::validation::{self, ResultIteratorExt, Validation::Success};
use crate::NixFileStore;
use itertools::concat;
use lazy_static::lazy_static;
use regex::Regex;
@ -34,7 +35,10 @@ pub fn relative_file_for_package(package_name: &str) -> PathBuf {
/// Check the structure of Nixpkgs, returning the attribute names that are defined in
/// `pkgs/by-name`
pub fn check_structure(path: &Path) -> validation::Result<Vec<String>> {
pub fn check_structure(
path: &Path,
nix_file_store: &mut NixFileStore,
) -> validation::Result<Vec<String>> {
let base_dir = path.join(BASE_SUBPATH);
let shard_results = utils::read_dir_sorted(&base_dir)?
@ -88,7 +92,13 @@ pub fn check_structure(path: &Path) -> validation::Result<Vec<String>> {
let package_results = entries
.into_iter()
.map(|package_entry| {
check_package(path, &shard_name, shard_name_valid, package_entry)
check_package(
nix_file_store,
path,
&shard_name,
shard_name_valid,
package_entry,
)
})
.collect_vec()?;
@ -102,6 +112,7 @@ pub fn check_structure(path: &Path) -> validation::Result<Vec<String>> {
}
fn check_package(
nix_file_store: &mut NixFileStore,
path: &Path,
shard_name: &str,
shard_name_valid: bool,
@ -161,6 +172,7 @@ fn check_package(
});
let result = result.and(references::check_references(
nix_file_store,
&relative_package_dir,
&path.join(&relative_package_dir),
)?);

View File

@ -35,12 +35,13 @@ impl LineIndex {
// the vec
for split in s.split_inclusive('\n') {
index += split.len();
newlines.push(index);
newlines.push(index - 1);
}
LineIndex { newlines }
}
/// Returns the line number for a string index
/// Returns the line number for a string index.
/// If the index points to a newline, returns the line number before the newline
pub fn line(&self, index: usize) -> usize {
match self.newlines.binary_search(&index) {
// +1 because lines are 1-indexed
@ -48,4 +49,47 @@ impl LineIndex {
Err(x) => x + 1,
}
}
/// Returns the string index for a line and column.
pub fn fromlinecolumn(&self, line: usize, column: usize) -> usize {
// If it's the 1th line, the column is the index
if line == 1 {
// But columns are 1-indexed
column - 1
} else {
// For the nth line, we add the index of the (n-1)st newline to the column,
// and remove one more from the index since arrays are 0-indexed.
// Then add the 1-indexed column to get not the newline index itself,
// but rather the index of the position on the next line
self.newlines[line - 2] + column
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn line_index() {
let line_index = LineIndex::new("a\nbc\n\ndef\n");
let pairs = [
(0, 1, 1),
(1, 1, 2),
(2, 2, 1),
(3, 2, 2),
(4, 2, 3),
(5, 3, 1),
(6, 4, 1),
(7, 4, 2),
(8, 4, 3),
(9, 4, 4),
];
for (index, line, column) in pairs {
assert_eq!(line_index.line(index), line);
assert_eq!(line_index.fromlinecolumn(line, column), index);
}
}
}

View File

@ -0,0 +1,7 @@
self: super: {
set = self.callPackages ({ callPackage }: {
foo = callPackage ({ someDrv }: someDrv) { };
}) { };
inherit (self.set) foo;
}

View File

@ -0,0 +1 @@
import <test-nixpkgs> { root = ./.; }

View File

@ -0,0 +1,5 @@
self: super: {
foo-variant-unvarianted = self.callPackage ./package.nix { };
foo-variant-new = self.callPackage ./pkgs/by-name/fo/foo/package.nix { };
}

View File

@ -0,0 +1,3 @@
self: super: {
foo-variant-unvarianted = self.callPackage ./pkgs/by-name/fo/foo/package.nix { };
}

View File

@ -0,0 +1 @@
import <test-nixpkgs> { root = ./.; }

View File

@ -0,0 +1 @@
{ someDrv }: someDrv

View File

@ -0,0 +1 @@
import <test-nixpkgs> { root = ./.; }

View File

@ -0,0 +1 @@
{ someDrv }: someDrv

View File

@ -0,0 +1 @@
{ someDrv }: someDrv

View File

@ -55,7 +55,7 @@ with py.pkgs; buildPythonApplication rec {
substituteInPlace pyproject.toml \
--replace 'cryptography>=3.3.2,<40.0.2' 'cryptography>=3.3.2' \
--replace 'flit_core>=3.7.1,<3.8.1' 'flit_core>=3.7.1' \
--replace 'awscrt==0.19.18' 'awscrt>=0.19' \
--replace 'awscrt>=0.19.18,<=0.19.19' 'awscrt>=0.19.18' \
--replace 'docutils>=0.10,<0.20' 'docutils>=0.10' \
--replace 'prompt-toolkit>=3.0.24,<3.0.39' 'prompt-toolkit>=3.0.24'

View File

@ -32,13 +32,13 @@ let
]);
in stdenv.mkDerivation rec {
pname = "gwe";
version = "0.15.6";
version = "0.15.7";
src = fetchFromGitLab {
owner = "leinardi";
repo = pname;
rev = version;
sha256 = "sha256-xlAz67sThXZ5o2kABb+aQI/7N7jmRpWU/5m24u8TkII=";
sha256 = "sha256-0/VQD3WuSMShsPjydOxVEufBZqVOCTFO3UbJpsy+oLE=";
};
prePatch = ''

View File

@ -11,10 +11,10 @@ stdenv.mkDerivation rec {
buildInputs = [ liblockfile ];
env.NIX_CFLAGS_COMPILE = toString [
env.NIX_CFLAGS_COMPILE = lib.optionalString stdenv.cc.isGNU (toString [
# Needed with GCC 12
"-Wno-error=format-overflow"
];
]);
installPhase = ''
runHook preInstall
@ -25,7 +25,6 @@ stdenv.mkDerivation rec {
'';
meta = {
broken = stdenv.isDarwin;
description = "Programs for locking and unlocking files and mailboxes";
homepage = "http://packages.debian.org/sid/lockfile-progs";
license = lib.licenses.gpl2Only;

View File

@ -2,13 +2,13 @@
stdenvNoCC.mkDerivation rec {
pname = "xdg-ninja";
version = "0.2.0.1";
version = "0.2.0.2";
src = fetchFromGitHub {
owner = "b3nj5m1n";
repo = "xdg-ninja";
rev = "v${version}";
sha256 = "sha256-ZyqxMlyCB8gEsZTVrxgLdW/mQ/4xeTHTK+lDKIzYs6I=";
sha256 = "sha256-ASJIFQ/BpZMQGRtw8kPhtMCbXC1eb/X8TWQz+CAnaSM=";
};
nativeBuildInputs = [ makeWrapper ];

View File

@ -5,13 +5,13 @@
stdenv.mkDerivation rec {
pname = "ocserv";
version = "1.2.3";
version = "1.2.4";
src = fetchFromGitLab {
owner = "openconnect";
repo = "ocserv";
rev = version;
sha256 = "sha256-PHAhkHEbt5CsVc5gr/gh+xR7wfRb752bpz301g5ra9s=";
sha256 = "sha256-IYiYC9oAw35YjpptUEnhuZQqoDevku25r7qi6SG8xtk=";
};
nativeBuildInputs = [ autoreconfHook gperf pkg-config ronn ];

View File

@ -7751,10 +7751,6 @@ with pkgs;
inherit (pkgs.darwin.apple_sdk.libs) utmp;
};
rage = callPackage ../tools/security/rage {
inherit (darwin.apple_sdk.frameworks) Foundation;
};
rar2fs = callPackage ../tools/filesystems/rar2fs { };
rocmPackages = rocmPackages_5;

View File

@ -275,6 +275,7 @@ mapAliases ({
mir_eval = mir-eval; # added 2024-01-07
mistune_0_8 = throw "mistune_0_8 was removed because it was outdated and insecure"; # added 2022-08-12
mistune_2_0 = mistune; # added 2022-08-12
mitmproxy-wireguard = throw "mitmproxy-wireguard has been removed because it was replaced by upstream with mitmproxy-rs"; # added 2023-11-06
mkdocs-minify = mkdocs-minify-plugin; # added 2023-11-28
mox = throw "mox was removed because it is unmaintained"; # added 2023-02-21
mrkd = throw "mrkd has been promoted to a top-level attribute"; # added 2023-08-01

View File

@ -7121,8 +7121,6 @@ self: super: with self; {
mitmproxy-rs = callPackage ../development/python-modules/mitmproxy-rs { };
mitmproxy-wireguard = callPackage ../development/python-modules/mitmproxy-wireguard { };
mitogen = callPackage ../development/python-modules/mitogen { };
mixins = callPackage ../development/python-modules/mixins { };