diff --git a/home-manager/services/dolt/default.nix b/home-manager/services/dolt/default.nix index 6d7cb71db..2dcbcd59a 100644 --- a/home-manager/services/dolt/default.nix +++ b/home-manager/services/dolt/default.nix @@ -9,7 +9,9 @@ let inherit (inputs.host) isKyber isGalactica; homeDir = config.home.homeDirectory; repoDir = "${homeDir}/dotfiles"; - beadsDir = "${repoDir}/.beads"; + legacyBeadsDir = "${repoDir}/.beads"; + sharedServerDir = "${homeDir}/.beads/shared-server"; + beadsDir = "${sharedServerDir}/dolt"; doltManifest = "${beadsDir}/beads_global/.dolt/noms/manifest"; mirrorDir = "${homeDir}/.cache/beads-jsonl-mirror"; remoteUrl = "https://github.com/shunkakinoki/beads"; @@ -18,7 +20,7 @@ let # 1.86+ adds the git+https:// remote scheme used by the beads_global GitHub backup. doltMinVersion = "1.86"; startScript = pkgs.replaceVars ./start.sh { - inherit beadsDir; + inherit beadsDir legacyBeadsDir; inherit (pkgs) dolt; }; backupScript = pkgs.replaceVars ./backup-dolt-main.sh { @@ -37,6 +39,7 @@ lib.mkIf enabled { home.sessionVariables = { BEADS_DOLT_SHARED_SERVER = "1"; BEADS_DOLT_SERVER_PORT = "3307"; + BEADS_SHARED_SERVER_DIR = sharedServerDir; DOLT_CLI_USER = "root"; DOLT_CLI_PASSWORD = ""; }; diff --git a/home-manager/services/dolt/start.sh b/home-manager/services/dolt/start.sh index d76595ef3..560962586 100644 --- a/home-manager/services/dolt/start.sh +++ b/home-manager/services/dolt/start.sh @@ -1,15 +1,29 @@ #!/usr/bin/env bash -# @beadsDir@ and @dolt@ are substituted by pkgs.replaceVars. +# @beadsDir@, @legacyBeadsDir@, and @dolt@ are substituted by pkgs.replaceVars. set -euo pipefail mkdir -p "@beadsDir@" -# Legacy migration: a `dolt` directory predates the rename to `df`. -# Only migrate when `df` does not exist yet; once `df` is in place the -# `dolt` directory is treated as its own (possibly external) database. -if [ -d "@beadsDir@/dolt" ] && [ ! -L "@beadsDir@/dolt" ] && [ ! -e "@beadsDir@/df" ]; then - mv -f "@beadsDir@/dolt" "@beadsDir@/df" -fi +# Move databases served by the pre-shared-server configuration into the +# canonical root. Existing destinations win, so activation never overwrites a +# newer clone. A legacy database named `dolt` was the old name for `df`. +for legacy_db in "@legacyBeadsDir@"/*; do + if [ ! -d "$legacy_db/.dolt" ] || [ -L "$legacy_db" ]; then + continue + fi + + db_name="${legacy_db##*/}" + target_name="$db_name" + if [ "$db_name" = "dolt" ] && [ ! -e "@beadsDir@/df" ]; then + target_name="df" + fi + + if [ -e "@beadsDir@/$target_name" ]; then + continue + fi + + mv -f -- "$legacy_db" "@beadsDir@/$target_name" +done # Additional databases (e.g. data shared with another repo) are managed by # the user as real directories under @beadsDir@/. dolt sql-server diff --git a/spec/dolt_start_spec.sh b/spec/dolt_start_spec.sh index c39f83055..4900249fe 100644 --- a/spec/dolt_start_spec.sh +++ b/spec/dolt_start_spec.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# shellcheck disable=SC2329 +# shellcheck disable=SC2016,SC2329 Describe 'home-manager/services/dolt/start.sh' SCRIPT="$PWD/home-manager/services/dolt/start.sh" @@ -27,6 +27,11 @@ When run bash -c "grep '@beadsDir@' '$SCRIPT'" The output should include '@beadsDir@' End +It 'references @legacyBeadsDir@' +When run bash -c "grep '@legacyBeadsDir@' '$SCRIPT'" +The output should include '@legacyBeadsDir@' +End + It 'references @dolt@' When run bash -c "grep '@dolt@' '$SCRIPT'" The output should include '@dolt@' @@ -34,19 +39,60 @@ End End Describe 'dolt migration behavior' -It 'migrates legacy dolt directory to df' -When run bash -c "grep 'mv -f' '$SCRIPT'" -The output should include 'mv -f' +setup_migration() { + TEST_ROOT=$(mktemp -d) + LEGACY_DIR="$TEST_ROOT/legacy" + SHARED_DIR="$TEST_ROOT/shared/dolt" + FAKE_DOLT="$TEST_ROOT/fake-dolt" + RENDERED_SCRIPT="$TEST_ROOT/start.sh" + mkdir -p "$LEGACY_DIR" "$SHARED_DIR" "$FAKE_DOLT/bin" + printf '%s\n' '#!/usr/bin/env bash' 'exit 0' >"$FAKE_DOLT/bin/dolt" + chmod +x "$FAKE_DOLT/bin/dolt" + sed \ + -e "s|@legacyBeadsDir@|$LEGACY_DIR|g" \ + -e "s|@beadsDir@|$SHARED_DIR|g" \ + -e "s|@dolt@|$FAKE_DOLT|g" \ + "$SCRIPT" >"$RENDERED_SCRIPT" +} + +cleanup_migration() { + rm -rf "$TEST_ROOT" +} + +Before 'setup_migration' +After 'cleanup_migration' + +It 'moves a legacy database into the shared-server root' +mkdir -p "$LEGACY_DIR/beads/.dolt" +When run bash "$RENDERED_SCRIPT" +The status should be success +The path "$SHARED_DIR/beads/.dolt" should be directory +The path "$LEGACY_DIR/beads" should not be exist End -It 'gates the migration on df not yet existing' -When run bash -c "grep -- '-e \"@beadsDir@/df\"' '$SCRIPT'" -The output should include '-e "@beadsDir@/df"' +It 'does not overwrite an existing shared-server database' +mkdir -p "$LEGACY_DIR/df/.dolt" "$SHARED_DIR/df/.dolt" +touch "$LEGACY_DIR/df/.dolt/legacy-marker" +When run bash "$RENDERED_SCRIPT" +The status should be success +The path "$LEGACY_DIR/df/.dolt/legacy-marker" should be file +The path "$SHARED_DIR/df/.dolt" should be directory End -It 'does not recreate the legacy dolt -> df symlink' -When run bash -c "grep -c 'ln -sfn df' '$SCRIPT' || true" -The output should equal '0' +It 'maps the old dolt database name to df during legacy-root migration' +mkdir -p "$LEGACY_DIR/dolt/.dolt" +When run bash "$RENDERED_SCRIPT" +The status should be success +The path "$SHARED_DIR/df/.dolt" should be directory +The path "$SHARED_DIR/dolt" should not be exist +End + +It 'does not rename a legitimate dolt database in the shared-server root' +mkdir -p "$SHARED_DIR/dolt/.dolt" +When run bash "$RENDERED_SCRIPT" +The status should be success +The path "$SHARED_DIR/dolt/.dolt" should be directory +The path "$SHARED_DIR/df" should not be exist End End @@ -68,3 +114,22 @@ End End End + +Describe 'home-manager/services/dolt/default.nix' +MODULE="$PWD/home-manager/services/dolt/default.nix" + +It 'uses the canonical Beads shared-server directory' +When run grep -F 'sharedServerDir = "${homeDir}/.beads/shared-server";' "$MODULE" +The output should include 'sharedServerDir = "${homeDir}/.beads/shared-server";' +End + +It 'serves databases from the shared-server dolt directory' +When run grep -F 'beadsDir = "${sharedServerDir}/dolt";' "$MODULE" +The output should include 'beadsDir = "${sharedServerDir}/dolt";' +End + +It 'exports the same shared-server directory to bd' +When run grep -F 'BEADS_SHARED_SERVER_DIR = sharedServerDir;' "$MODULE" +The output should include 'BEADS_SHARED_SERVER_DIR = sharedServerDir;' +End +End