nixos/etc: support direct symlinks with etc overlay

ivan770 1b288bca 2baa58d3

+22 -19
+17 -18
nixos/modules/system/etc/build-composefs-dump.py
··· 175 175 paths[glob_target] = composefs_path 176 176 add_leading_directories(glob_target, attrs, paths) 177 177 else: # Without globbing 178 - if mode == "symlink": 178 + if mode == "symlink" or mode == "direct-symlink": 179 179 composefs_path = ComposefsPath( 180 180 attrs, 181 181 # A high approximation of the size of a symlink ··· 184 184 mode="0777", 185 185 payload=source, 186 186 ) 187 + elif os.path.isdir(source): 188 + composefs_path = ComposefsPath( 189 + attrs, 190 + size=4096, 191 + filetype=FileType.directory, 192 + mode=mode, 193 + payload=source, 194 + ) 187 195 else: 188 - if os.path.isdir(source): 189 - composefs_path = ComposefsPath( 190 - attrs, 191 - size=4096, 192 - filetype=FileType.directory, 193 - mode=mode, 194 - payload=source, 195 - ) 196 - else: 197 - composefs_path = ComposefsPath( 198 - attrs, 199 - size=os.stat(source).st_size, 200 - filetype=FileType.file, 201 - mode=mode, 202 - # payload needs to be relative path in this case 203 - payload=target.lstrip("/"), 204 - ) 196 + composefs_path = ComposefsPath( 197 + attrs, 198 + size=os.stat(source).st_size, 199 + filetype=FileType.file, 200 + mode=mode, 201 + # payload needs to be relative path in this case 202 + payload=target.lstrip("/"), 203 + ) 205 204 paths[target] = composefs_path 206 205 add_leading_directories(target, attrs, paths) 207 206
+1 -1
nixos/modules/system/etc/etc.nix
··· 62 62 ]) etc'} 63 63 ''; 64 64 65 - etcHardlinks = filter (f: f.mode != "symlink") etc'; 65 + etcHardlinks = filter (f: f.mode != "symlink" && f.mode != "direct-symlink") etc'; 66 66 67 67 build-composefs-dump = pkgs.runCommand "build-composefs-dump.py" 68 68 {
+4
nixos/tests/activation/etc-overlay-immutable.nix
··· 13 13 users.mutableUsers = false; 14 14 boot.initrd.systemd.enable = true; 15 15 boot.kernelPackages = pkgs.linuxPackages_latest; 16 + time.timeZone = "Utc"; 16 17 17 18 specialisation.new-generation.configuration = { 18 19 environment.etc."newgen".text = "newgen"; ··· 22 23 testScript = '' 23 24 with subtest("/etc is mounted as an overlay"): 24 25 machine.succeed("findmnt --kernel --type overlay /etc") 26 + 27 + with subtest("direct symlinks point to the target without indirection"): 28 + assert machine.succeed("readlink -n /etc/localtime") == "/etc/zoneinfo/Utc" 25 29 26 30 with subtest("switching to the same generation"): 27 31 machine.succeed("/run/current-system/bin/switch-to-configuration test")