{ lib }: { /* Returns a function that maps [ "someOption" ["fooBar" "someSubOption"] { old = "someOtherOption"; new = ["foo_bar" "some_other_option"]} ] to [ (lib.mkRenamedOptionModule (oldPath ++ ["someOption"]) (newPath ++ ["some_option"]) ) (lib.mkRenamedOptionModule (oldPath ++ ["fooBar" "someSubOption"]) (newPath ++ ["foo_bar" "some_sub_option"]) ) (lib.mkRenamedOptionModule (oldPath ++ ["someOtherOption"]) (newPath ++ ["foo_bar" "some_other_option"]) ) ] The transform parameter is a function that takes a string and returns a string. It is applied to each element of the old option path to generate the new option path. Defaults to lib.hm.strings.toSnakeCase. */ mkSettingsRenamedOptionModules = oldPrefix: newPrefix: { transform ? lib.hm.strings.toSnakeCase, }: map ( spec: let finalSpec = if lib.isAttrs spec then lib.mapAttrs (_: lib.toList) spec else { old = lib.toList spec; new = map transform finalSpec.old; }; in lib.mkRenamedOptionModule (oldPrefix ++ finalSpec.old) (newPrefix ++ finalSpec.new) ); /* Recursively transforms attribute set keys, issuing a warning for each transformation. Example: let # Renames camelCase keys to snake_case. migrateCamelCase = lib.hm.deprecations.remapAttrsRecursive { # A key needs migration if it contains a lowercase letter followed by an uppercase one. pred = key: builtins.match ".*[a-z][A-Z].*" key != null; # The transformation to apply. transform = lib.hm.strings.toSnakeCase; }; in # { my-key = { fooBar = 1; }; } migrateCamelCase "programs.mymodule.settings" { my-key = { fooBar = 1; }; } # => { my-key = { foo_bar = 1; }; } # (with a warning about the fooBar -> foo_bar conversion) */ remapAttrsRecursive = { pred, transform }: let migrate = path: value: if builtins.isAttrs value then lib.mapAttrs' ( name: val: let newName = if pred name then transform name else name; warnOrId = if newName != name then lib.warn "home-manager: The setting '${name}' in '${path}' was automatically renamed to '${newName}'. Please update your configuration." else x: x; in warnOrId { name = newName; value = migrate "${path}.${name}" val; } ) value else if builtins.isList value then lib.imap0 (index: val: migrate "${path}.[${toString index}]" val) value else value; in pathStr: attrs: migrate pathStr attrs; }