Skip to content

Commit 5b7aa4f

Browse files
committed
fix(nixos): overwrite stock config on first MySetup adoption
1 parent 0e4cf59 commit 5b7aa4f

7 files changed

Lines changed: 99 additions & 8 deletions

File tree

Linux/NixOS/lib/flake-home-module.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
useGlobalPkgs = true;
1313
useUserPackages = true;
1414
backupFileExtension = "backup";
15+
overwriteBackup = true;
1516
users.${config.mysetup.user.username} = import ../home/home.nix;
1617
extraSpecialArgs = {
1718
inherit

Linux/README.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ nix run 'github:TakuyaYagam1/MySetup/develop'
6363

6464
Fresh install through `/mnt` is not supported in v1. Run this on an already
6565
booted NixOS system with an existing `/etc/nixos/hardware-configuration.nix`.
66+
On first adoption from a stock NixOS/KDE install, MySetup replaces the active
67+
`/etc/nixos/configuration.nix` with a clean host-local override file. The old
68+
tree is kept in the `/etc/nixos.bak.<timestamp>.<pid>.<n>` backup made before
69+
writing `/etc/nixos`. VPN/proxy tools such as Amnezia are only a network
70+
workaround before running MySetup; they are not required in the bootstrap
71+
`configuration.nix`.
6672

6773
Nix may ask whether to allow the flake app to use additional substituters. That
6874
is expected for this config; the installer and checks use these binary caches:
@@ -269,10 +275,11 @@ The installer applies changes defensively:
269275
1. Creates a temporary staging wrapper flake for `/etc/nixos`.
270276
2. Writes generated `host-vars.nix`, `configuration.nix`, and `home.nix`
271277
templates when they do not already exist.
272-
3. Preserves host-local `hardware-configuration.nix`, `flake.lock`,
273-
`hashed-password.nix`, `configuration.nix`, `home.nix`, `private/`, and
274-
`secrets/`. Existing thin wrapper flakes are preserved; legacy full mirror
275-
flakes are replaced with the generated thin wrapper.
278+
3. Preserves host-local `hardware-configuration.nix`, `hashed-password.nix`,
279+
`private/`, and `secrets/`. Existing MySetup thin wrapper flakes also keep
280+
`flake.lock`, `configuration.nix`, and `home.nix`; stock NixOS or legacy
281+
non-thin configs are replaced with the generated thin wrapper and clean
282+
override templates.
276283
4. Copies or generates `hashed-password.nix` for the staging build.
277284
5. Runs `nix flake update mysetup --flake <staging>` for the staging wrapper
278285
when using the default thin layout, so the installed host receives the latest
@@ -529,6 +536,11 @@ run `mysetup doctor` and check the relevant log.
529536
multiple Wayland shells, Qt/QML, desktop apps, optional CTF stacks. Make
530537
sure the listed binary caches are accepted (see Install / Reconfigure) -
531538
without them everything compiles from source.
539+
- **First `switch` fails after writing `/etc/nixos` with dbus/systemd activation
540+
errors.** Reboot into the new generation boundary, then run
541+
`sudo nixos-rebuild switch --flake /etc/nixos#NixOS`. The dry-build already
542+
passed; this usually means the live system could not restart part of the
543+
desktop/session stack cleanly.
532544
- **`sudo nixos-rebuild switch` works locally but `mysetup apply` fails.**
533545
The installer wraps switch with stricter checks (dry-build, password
534546
hash, dots mirror). Run `nix run "path:$PWD?dir=Linux/NixOS#mysetup" --

Linux/installer/internal/apply/generate.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ func FlakeNix(s config.State) (string, error) {
2626
}
2727

2828
func ConfigurationNix() string {
29-
return `# Host-local NixOS overrides. This file is preserved by MySetup.
30-
{ pkgs, ... }:
29+
return `{ pkgs, ... }:
3130
3231
{
3332
imports = [

Linux/installer/internal/apply/generate_test.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ func TestThinTemplatesExposeSystemAndHomeOverrides(t *testing.T) {
129129
if !strings.Contains(ConfigurationNix(), "environment.systemPackages") {
130130
t.Fatalf("configuration.nix template must expose system packages\n%s", ConfigurationNix())
131131
}
132+
if strings.Contains(ConfigurationNix(), "Edit this configuration file") ||
133+
strings.Contains(ConfigurationNix(), "services.desktopManager.plasma6") {
134+
t.Fatalf("configuration.nix template must stay a clean MySetup override\n%s", ConfigurationNix())
135+
}
132136
if !strings.Contains(ConfigurationNix(), "./private") {
133137
t.Fatalf("configuration.nix template must import private defaults\n%s", ConfigurationNix())
134138
}
@@ -594,6 +598,50 @@ func TestPrepareThinHostLocalPreservesOverridesLockAndSecrets(t *testing.T) {
594598
}
595599
}
596600

601+
func TestPrepareThinHostLocalOverwritesFreshNixOSOverrides(t *testing.T) {
602+
staging := t.TempDir()
603+
dest := t.TempDir()
604+
for path, content := range map[string]string{
605+
filepath.Join(staging, "configuration.nix"): ConfigurationNix(),
606+
filepath.Join(staging, "home.nix"): HomeNix(),
607+
filepath.Join(dest, "hardware-configuration.nix"): "hardware\n",
608+
filepath.Join(dest, "configuration.nix"): `# Edit this configuration file to define what should be installed on
609+
{ pkgs, ... }:
610+
611+
{
612+
imports = [ ./hardware-configuration.nix ];
613+
boot.loader.systemd-boot.enable = true;
614+
services.desktopManager.plasma6.enable = true;
615+
}
616+
`,
617+
filepath.Join(dest, "home.nix"): "{ pkgs, ... }: { home.packages = [ pkgs.kate ]; }\n",
618+
} {
619+
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
620+
t.Fatal(err)
621+
}
622+
if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
623+
t.Fatal(err)
624+
}
625+
}
626+
627+
if err := prepareStagingHostLocal(context.Background(), run.Runner{Stdout: io.Discard, Stderr: io.Discard}, staging, dest, config.Secrets{}, LayoutThin); err != nil {
628+
t.Fatal(err)
629+
}
630+
631+
for path, want := range map[string]string{
632+
filepath.Join(staging, "configuration.nix"): ConfigurationNix(),
633+
filepath.Join(staging, "home.nix"): HomeNix(),
634+
} {
635+
data, err := os.ReadFile(path)
636+
if err != nil {
637+
t.Fatal(err)
638+
}
639+
if string(data) != want {
640+
t.Fatalf("fresh NixOS adoption must keep generated %s, got:\n%s", filepath.Base(path), data)
641+
}
642+
}
643+
}
644+
597645
func TestPrepareThinHostLocalPreservesPrivateDefault(t *testing.T) {
598646
staging := t.TempDir()
599647
dest := t.TempDir()
@@ -649,9 +697,13 @@ func TestPrepareThinHostLocalReplacesLegacyFullFlake(t *testing.T) {
649697
dest := t.TempDir()
650698
for path, content := range map[string]string{
651699
filepath.Join(staging, "flake.nix"): "generated thin wrapper\n",
700+
filepath.Join(staging, "configuration.nix"): ConfigurationNix(),
701+
filepath.Join(staging, "home.nix"): HomeNix(),
652702
filepath.Join(dest, "flake.nix"): "{ description = \"NixOS + Caelestia\"; }\n",
653703
filepath.Join(dest, "flake.lock"): "legacy full lock\n",
654704
filepath.Join(dest, "hardware-configuration.nix"): "hardware\n",
705+
filepath.Join(dest, "configuration.nix"): "{ pkgs, ... }: { services.desktopManager.plasma6.enable = true; }\n",
706+
filepath.Join(dest, "home.nix"): "{ pkgs, ... }: { home.packages = [ pkgs.kate ]; }\n",
655707
filepath.Join(dest, "hosts", "NixOS", "host-vars.nix"): "{ }\n",
656708
} {
657709
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
@@ -676,6 +728,18 @@ func TestPrepareThinHostLocalReplacesLegacyFullFlake(t *testing.T) {
676728
if _, err := os.Stat(filepath.Join(staging, "flake.lock")); !os.IsNotExist(err) {
677729
t.Fatalf("legacy full flake.lock should not be copied into thin staging, stat err: %v", err)
678730
}
731+
for path, want := range map[string]string{
732+
filepath.Join(staging, "configuration.nix"): ConfigurationNix(),
733+
filepath.Join(staging, "home.nix"): HomeNix(),
734+
} {
735+
data, err := os.ReadFile(path)
736+
if err != nil {
737+
t.Fatal(err)
738+
}
739+
if string(data) != want {
740+
t.Fatalf("legacy non-thin overrides should not overwrite generated %s, got:\n%s", filepath.Base(path), data)
741+
}
742+
}
679743
}
680744

681745
func TestPrepareThinHostLocalStagesLegacySecretsWhenRootMissing(t *testing.T) {

Linux/installer/internal/apply/secrets.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ func copyExistingThinHostLocal(ctx context.Context, runner run.CommandRunner, st
4747
return err
4848
}
4949

50-
preservedFiles := []string{"configuration.nix", "home.nix"}
50+
preservedFiles := []string{}
5151
if thinFlake {
52-
preservedFiles = append([]string{"flake.lock"}, preservedFiles...)
52+
preservedFiles = []string{"flake.lock", "configuration.nix", "home.nix"}
5353
}
5454
if err := copyExistingThinHostLocalFiles(dest, staging, preservedFiles); err != nil {
5555
return err

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,20 @@ instead of Nix's cached GitHub source:
5656
nix run --refresh 'github:TakuyaYagam1/MySetup'
5757
```
5858

59+
Fresh NixOS/KDE bootstrap note: on the first adoption, MySetup replaces the
60+
active `/etc/nixos/configuration.nix` with a clean host-local override file and
61+
backs up the previous `/etc/nixos` to `/etc/nixos.bak.<timestamp>...`. Your
62+
hardware config, password hash, `private/`, and `secrets/` stay preserved. If
63+
the first live `switch` fails because dbus/systemd could not fully reactivate,
64+
reboot and run:
65+
66+
```bash
67+
sudo nixos-rebuild switch --flake /etc/nixos#NixOS
68+
```
69+
70+
VPN/proxy tools such as Amnezia are only a network workaround before running
71+
MySetup; they are not required in the bootstrap `configuration.nix`.
72+
5973
Or with a local clone (useful when iterating on the config):
6074

6175
```bash

flake.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@
243243
useGlobalPkgs = lib.mkDefault true;
244244
useUserPackages = lib.mkDefault true;
245245
backupFileExtension = lib.mkDefault "backup";
246+
overwriteBackup = lib.mkDefault true;
246247
users.${config.mysetup.user.username} = shellHomeModule;
247248
extraSpecialArgs = {
248249
inherit inputs mysetupLib;

0 commit comments

Comments
 (0)