diff --git a/lib/default.nix b/lib/default.nix index 3efaaf0f8f9e..18d2dfae1e18 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -71,7 +71,7 @@ let zipAttrsWithNames zipAttrsWith zipAttrs recursiveUpdateUntil recursiveUpdate matchAttrs overrideExisting getOutput getBin getLib getDev chooseDevOutputs zipWithNames zip; - inherit (lists) singleton foldr fold foldl foldl' imap0 imap1 + inherit (lists) singleton forEach foldr fold foldl foldl' imap0 imap1 concatMap flatten remove findSingle findFirst any all count optional optionals toList range partition zipListsWith zipLists reverseList listDfs toposort sort naturalSort compareLists take diff --git a/lib/lists.nix b/lib/lists.nix index 30d87ece6641..e4fcf959b60c 100644 --- a/lib/lists.nix +++ b/lib/lists.nix @@ -21,6 +21,19 @@ rec { */ singleton = x: [x]; + /* Apply the function to each element in the list. Same as `map`, but arguments + flipped. + + Type: forEach :: [a] -> (a -> b) -> [b] + + Example: + forEach [ 1 2 ] (x: + toString x + ) + => [ "1" "2" ] + */ + forEach = xs: f: map f xs; + /* “right fold” a binary function `op` between successive elements of `list` with `nul' as the starting value, i.e., `foldr op nul [x_1 x_2 ... x_n] == op x_1 (op x_2 ... (op x_n nul))`. diff --git a/nixos/doc/manual/release-notes/rl-1909.xml b/nixos/doc/manual/release-notes/rl-1909.xml index e0f71aadaba5..ca2f26ec4a82 100644 --- a/nixos/doc/manual/release-notes/rl-1909.xml +++ b/nixos/doc/manual/release-notes/rl-1909.xml @@ -424,6 +424,18 @@ installer after creating /var/lib/nextcloud. + + + There exists now lib.forEach, which is like map, but with + arguments flipped. When mapping function body spans many lines (or has nested + maps), it is often hard to follow which list is modified. + + + Previous solution to this problem was either to use lib.flip map + idiom or extract that anonymous mapping function to a named one. Both can still be used + but lib.forEach is preferred over lib.flip map. + + diff --git a/nixos/lib/build-vms.nix b/nixos/lib/build-vms.nix index b622a4d59e89..1bad63b9194c 100644 --- a/nixos/lib/build-vms.nix +++ b/nixos/lib/build-vms.nix @@ -54,11 +54,11 @@ rec { machinesNumbered = zipLists machines (range 1 254); - nodes_ = flip map machinesNumbered (m: nameValuePair m.fst + nodes_ = forEach machinesNumbered (m: nameValuePair m.fst [ ( { config, nodes, ... }: let interfacesNumbered = zipLists config.virtualisation.vlans (range 1 255); - interfaces = flip map interfacesNumbered ({ fst, snd }: + interfaces = forEach interfacesNumbered ({ fst, snd }: nameValuePair "eth${toString snd}" { ipv4.addresses = [ { address = "192.168.${toString fst}.${toString m.snd}"; prefixLength = 24; @@ -88,7 +88,7 @@ rec { "${config.networking.hostName}\n")); virtualisation.qemu.options = - flip map interfacesNumbered + forEach interfacesNumbered ({ fst, snd }: qemuNICFlags snd fst m.snd); }; } diff --git a/nixos/maintainers/option-usages.nix b/nixos/maintainers/option-usages.nix index a67a0ab960e5..11247666ecda 100644 --- a/nixos/maintainers/option-usages.nix +++ b/nixos/maintainers/option-usages.nix @@ -102,7 +102,7 @@ let # builtins multiply by 4 the memory usage and the time used to compute # each options. tryCollectOptions = moduleResult: - flip map (excludeOptions (collect isOption moduleResult)) (opt: + forEach (excludeOptions (collect isOption moduleResult)) (opt: { name = showOption opt.loc; } // builtins.tryEval (strict opt.value)); in keepNames ( diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index 5c08a25c128a..3ea139fc5ce4 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -276,7 +276,7 @@ with lib; throw "services.redshift.longitude is set to null, you can remove this" else builtins.fromJSON value)) - ] ++ (flip map [ "blackboxExporter" "collectdExporter" "fritzboxExporter" + ] ++ (forEach [ "blackboxExporter" "collectdExporter" "fritzboxExporter" "jsonExporter" "minioExporter" "nginxExporter" "nodeExporter" "snmpExporter" "unifiExporter" "varnishExporter" ] (opt: mkRemovedOptionModule [ "services" "prometheus" "${opt}" ] '' diff --git a/nixos/modules/services/monitoring/ups.nix b/nixos/modules/services/monitoring/ups.nix index bc755612fd9b..429b40227d47 100644 --- a/nixos/modules/services/monitoring/ups.nix +++ b/nixos/modules/services/monitoring/ups.nix @@ -225,7 +225,7 @@ in '' maxstartdelay = ${toString cfg.maxStartDelay} - ${flip concatStringsSep (flip map (attrValues cfg.ups) (ups: ups.summary)) " + ${flip concatStringsSep (forEach (attrValues cfg.ups) (ups: ups.summary)) " "} ''; diff --git a/nixos/modules/services/networking/consul.nix b/nixos/modules/services/networking/consul.nix index 3a92a883fbf8..f080f12eaccd 100644 --- a/nixos/modules/services/networking/consul.nix +++ b/nixos/modules/services/networking/consul.nix @@ -15,7 +15,7 @@ let ++ cfg.extraConfigFiles; devices = attrValues (filterAttrs (_: i: i != null) cfg.interface); - systemdDevices = flip map devices + systemdDevices = forEach devices (i: "sys-subsystem-net-devices-${utils.escapeSystemdPath i}.device"); in { diff --git a/nixos/modules/services/networking/hylafax/systemd.nix b/nixos/modules/services/networking/hylafax/systemd.nix index ef177e4be345..0c6602e7f8ab 100644 --- a/nixos/modules/services/networking/hylafax/systemd.nix +++ b/nixos/modules/services/networking/hylafax/systemd.nix @@ -7,7 +7,7 @@ let inherit (lib) concatStringsSep optionalString; cfg = config.services.hylafax; - mapModems = lib.flip map (lib.attrValues cfg.modems); + mapModems = lib.forEach (lib.attrValues cfg.modems); mkConfigFile = name: conf: # creates hylafax config file, diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix index 0f9d2420903b..91fc7d72bc6d 100644 --- a/nixos/modules/services/networking/ssh/sshd.nix +++ b/nixos/modules/services/networking/ssh/sshd.nix @@ -502,7 +502,7 @@ in assertions = [{ assertion = if cfg.forwardX11 then cfgc.setXAuthLocation else true; message = "cannot enable X11 forwarding without setting xauth location";}] - ++ flip map cfg.listenAddresses ({ addr, ... }: { + ++ forEach cfg.listenAddresses ({ addr, ... }: { assertion = addr != null; message = "addr must be specified in each listenAddresses entry"; }); diff --git a/nixos/modules/services/x11/xautolock.nix b/nixos/modules/services/x11/xautolock.nix index cbe000058dc6..10eef8aefbcd 100644 --- a/nixos/modules/services/x11/xautolock.nix +++ b/nixos/modules/services/x11/xautolock.nix @@ -129,7 +129,7 @@ in assertion = cfg.killer != null -> cfg.killtime >= 10; message = "killtime has to be at least 10 minutes according to `man xautolock`"; } - ] ++ (lib.flip map [ "locker" "notifier" "nowlocker" "killer" ] + ] ++ (lib.forEach [ "locker" "notifier" "nowlocker" "killer" ] (option: { assertion = cfg."${option}" != null -> builtins.substring 0 1 cfg."${option}" == "/"; diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix index 7ffe1c125610..c94a06438315 100644 --- a/nixos/modules/services/x11/xserver.nix +++ b/nixos/modules/services/x11/xserver.nix @@ -78,7 +78,7 @@ let in imap1 mkHead cfg.xrandrHeads; xrandrDeviceSection = let - monitors = flip map xrandrHeads (h: '' + monitors = forEach xrandrHeads (h: '' Option "monitor-${h.config.output}" "${h.name}" ''); # First option is indented through the space in the config but any diff --git a/nixos/modules/system/boot/loader/grub/grub.nix b/nixos/modules/system/boot/loader/grub/grub.nix index 4e4d14985b0d..eca9dad64222 100644 --- a/nixos/modules/system/boot/loader/grub/grub.nix +++ b/nixos/modules/system/boot/loader/grub/grub.nix @@ -684,7 +684,7 @@ in assertion = if args.efiSysMountPoint == null then true else hasPrefix "/" args.efiSysMountPoint; message = "EFI paths must be absolute, not ${args.efiSysMountPoint}"; } - ] ++ flip map args.devices (device: { + ] ++ forEach args.devices (device: { assertion = device == "nodev" || hasPrefix "/" device; message = "GRUB devices must be absolute paths, not ${device} in ${args.path}"; })); diff --git a/nixos/modules/tasks/network-interfaces-systemd.nix b/nixos/modules/tasks/network-interfaces-systemd.nix index 857aaf1e6e30..fbca54978e5b 100644 --- a/nixos/modules/tasks/network-interfaces-systemd.nix +++ b/nixos/modules/tasks/network-interfaces-systemd.nix @@ -74,7 +74,7 @@ in enable = true; networks."99-main" = genericNetwork mkDefault; } - (mkMerge (flip map interfaces (i: { + (mkMerge (forEach interfaces (i: { netdevs = mkIf i.virtual ({ "40-${i.name}" = { netdevConfig = { @@ -90,7 +90,7 @@ in name = mkDefault i.name; DHCP = mkForce (dhcpStr (if i.useDHCP != null then i.useDHCP else cfg.useDHCP && interfaceIps i == [ ])); - address = flip map (interfaceIps i) + address = forEach (interfaceIps i) (ip: "${ip.address}/${toString ip.prefixLength}"); networkConfig.IPv6PrivacyExtensions = "kernel"; } ]; @@ -102,7 +102,7 @@ in Kind = "bridge"; }; }; - networks = listToAttrs (flip map bridge.interfaces (bi: + networks = listToAttrs (forEach bridge.interfaces (bi: nameValuePair "40-${bi}" (mkMerge [ (genericNetwork (mkOverride 999)) { DHCP = mkOverride 0 (dhcpStr false); networkConfig.Bridge = name; @@ -173,7 +173,7 @@ in }; - networks = listToAttrs (flip map bond.interfaces (bi: + networks = listToAttrs (forEach bond.interfaces (bi: nameValuePair "40-${bi}" (mkMerge [ (genericNetwork (mkOverride 999)) { DHCP = mkOverride 0 (dhcpStr false); networkConfig.Bond = name; diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix index c75d7cbc408b..5ac753c92a78 100644 --- a/nixos/modules/tasks/network-interfaces.nix +++ b/nixos/modules/tasks/network-interfaces.nix @@ -926,7 +926,7 @@ in warnings = concatMap (i: i.warnings) interfaces; assertions = - (flip map interfaces (i: { + (forEach interfaces (i: { # With the linux kernel, interface name length is limited by IFNAMSIZ # to 16 bytes, including the trailing null byte. # See include/linux/if.h in the kernel sources @@ -934,12 +934,12 @@ in message = '' The name of networking.interfaces."${i.name}" is too long, it needs to be less than 16 characters. ''; - })) ++ (flip map slaveIfs (i: { + })) ++ (forEach slaveIfs (i: { assertion = i.ipv4.addresses == [ ] && i.ipv6.addresses == [ ]; message = '' The networking.interfaces."${i.name}" must not have any defined ips when it is a slave. ''; - })) ++ (flip map interfaces (i: { + })) ++ (forEach interfaces (i: { assertion = i.preferTempAddress -> cfg.enableIPv6; message = '' Temporary addresses are only needed when IPv6 is enabled. @@ -967,8 +967,8 @@ in "net.ipv6.conf.default.disable_ipv6" = mkDefault (!cfg.enableIPv6); "net.ipv6.conf.all.forwarding" = mkDefault (any (i: i.proxyARP) interfaces); } // listToAttrs (flip concatMap (filter (i: i.proxyARP) interfaces) - (i: flip map [ "4" "6" ] (v: nameValuePair "net.ipv${v}.conf.${i.name}.proxy_arp" true))) - // listToAttrs (flip map (filter (i: i.preferTempAddress) interfaces) + (i: forEach [ "4" "6" ] (v: nameValuePair "net.ipv${v}.conf.${i.name}.proxy_arp" true))) + // listToAttrs (forEach (filter (i: i.preferTempAddress) interfaces) (i: nameValuePair "net.ipv6.conf.${i.name}.use_tempaddr" 2)); # Capabilities won't work unless we have at-least a 4.3 Linux @@ -1050,7 +1050,7 @@ in ${cfg.localCommands} ''; }; - } // (listToAttrs (flip map interfaces (i: + } // (listToAttrs (forEach interfaces (i: let deviceDependency = if (config.boot.isContainer || i.name == "lo") then [] diff --git a/nixos/tests/networking.nix b/nixos/tests/networking.nix index 949d946bdc4c..6ce64dcebea0 100644 --- a/nixos/tests/networking.nix +++ b/nixos/tests/networking.nix @@ -21,7 +21,7 @@ let useNetworkd = networkd; firewall.checkReversePath = true; firewall.allowedUDPPorts = [ 547 ]; - interfaces = mkOverride 0 (listToAttrs (flip map vlanIfs (n: + interfaces = mkOverride 0 (listToAttrs (forEach vlanIfs (n: nameValuePair "eth${toString n}" { ipv4.addresses = [ { address = "192.168.${toString n}.1"; prefixLength = 24; } ]; ipv6.addresses = [ { address = "fd00:1234:5678:${toString n}::1"; prefixLength = 64; } ]; diff --git a/pkgs/applications/networking/irc/weechat/wrapper.nix b/pkgs/applications/networking/irc/weechat/wrapper.nix index c773aecf2894..e6fa95488e10 100644 --- a/pkgs/applications/networking/irc/weechat/wrapper.nix +++ b/pkgs/applications/networking/irc/weechat/wrapper.nix @@ -56,7 +56,7 @@ let init = let init = builtins.replaceStrings [ "\n" ] [ ";" ] (config.init or ""); - mkScript = drv: lib.flip map drv.scripts (script: "/script load ${drv}/share/${script}"); + mkScript = drv: lib.forEach drv.scripts (script: "/script load ${drv}/share/${script}"); scripts = builtins.concatStringsSep ";" (lib.foldl (scripts: drv: scripts ++ mkScript drv) [ ] (config.scripts or [])); diff --git a/pkgs/applications/networking/remote/citrix-receiver/default.nix b/pkgs/applications/networking/remote/citrix-receiver/default.nix index 1f70cb56b54f..bf5f5df934d1 100644 --- a/pkgs/applications/networking/remote/citrix-receiver/default.nix +++ b/pkgs/applications/networking/remote/citrix-receiver/default.nix @@ -58,7 +58,7 @@ let versions = [ "13.8.0" "13.9.0" "13.9.1" ]; in lib.listToAttrs - (lib.flip map versions + (lib.forEach versions (v: lib.nameValuePair v (throw "Unsupported citrix_receiver version: ${v}"))); in deprecatedVersions // supportedVersions; diff --git a/pkgs/applications/networking/remote/citrix-workspace/default.nix b/pkgs/applications/networking/remote/citrix-workspace/default.nix index 745ad7a9c5d7..cf89666a379e 100644 --- a/pkgs/applications/networking/remote/citrix-workspace/default.nix +++ b/pkgs/applications/networking/remote/citrix-workspace/default.nix @@ -62,7 +62,7 @@ let versions = [ ]; in lib.listToAttrs - (lib.flip map versions + (lib.forEach versions (v: lib.nameValuePair v (throw "Unsupported citrix_workspace version: ${v}"))); in deprecatedVersions // supportedVersions; diff --git a/pkgs/tools/inputmethods/ibus-engines/ibus-typing-booster/wrapper.nix b/pkgs/tools/inputmethods/ibus-engines/ibus-typing-booster/wrapper.nix index 1115e4e232fc..56ddf93af45f 100644 --- a/pkgs/tools/inputmethods/ibus-engines/ibus-typing-booster/wrapper.nix +++ b/pkgs/tools/inputmethods/ibus-engines/ibus-typing-booster/wrapper.nix @@ -4,7 +4,7 @@ let - hunspellDirs = with lib; makeSearchPath ":" (flatten (flip map langs (lang: [ + hunspellDirs = with lib; makeSearchPath ":" (flatten (forEach langs (lang: [ "${hunspellDicts.${lang}}/share/hunspell" "${hunspellDicts.${lang}}/share/myspell" "${hunspellDicts.${lang}}/share/myspell/dicts"