parent
9cd5d073f2
commit
733bb82292
2 changed files with 51 additions and 0 deletions
|
@ -197,6 +197,12 @@ class Link(Plugin):
|
||||||
success = True
|
success = True
|
||||||
source = os.path.join(self._context.base_directory(canonical_path=canonical_path), source)
|
source = os.path.join(self._context.base_directory(canonical_path=canonical_path), source)
|
||||||
fullpath = os.path.abspath(os.path.expanduser(path))
|
fullpath = os.path.abspath(os.path.expanduser(path))
|
||||||
|
if self._exists(path) and not self._is_link(path) and os.path.realpath(fullpath) == source:
|
||||||
|
# Special case: The path is not a symlink but resolves to the source anyway.
|
||||||
|
# Deleting the path would actually delete the source.
|
||||||
|
# This may happen if a parent directory is a symlink.
|
||||||
|
self._log.warning(f"{path} appears to be the same file as {source}.")
|
||||||
|
return False
|
||||||
if relative:
|
if relative:
|
||||||
source = self._relative_path(source, fullpath)
|
source = self._relative_path(source, fullpath)
|
||||||
if (self._is_link(path) and self._link_destination(path) != source) or (
|
if (self._is_link(path) and self._link_destination(path) != source) or (
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import os
|
import os
|
||||||
|
import pathlib
|
||||||
import sys
|
import sys
|
||||||
from typing import Callable, Optional
|
from typing import Callable, Optional
|
||||||
|
|
||||||
|
@ -962,6 +963,50 @@ def test_link_relink_relative_leaves_file(home: str, dotfiles: Dotfiles, run_dot
|
||||||
assert mtime == new_mtime
|
assert mtime == new_mtime
|
||||||
|
|
||||||
|
|
||||||
|
def test_source_is_not_overwritten_by_symlink_trickery(
|
||||||
|
capsys: pytest.CaptureFixture[str], home: str, dotfiles: Dotfiles, run_dotbot: Callable[..., None]
|
||||||
|
) -> None:
|
||||||
|
dotfiles_path = pathlib.Path(dotfiles.directory)
|
||||||
|
home_path = pathlib.Path(home)
|
||||||
|
|
||||||
|
# Setup:
|
||||||
|
# * A symlink exists from `~/.ssh` to `ssh` in the dotfiles directory.
|
||||||
|
# * Dotbot is configured to force-recreate a symlink between two files
|
||||||
|
# when, in reality, it's actually the same file when resolved.
|
||||||
|
ssh_config = (dotfiles_path / "ssh/config").absolute()
|
||||||
|
os.mkdir(str(ssh_config.parent))
|
||||||
|
ssh_config.write_text("preserve me!")
|
||||||
|
os.symlink(str(ssh_config.parent), str(home_path / ".ssh"))
|
||||||
|
dotfiles.write_config(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"defaults": {
|
||||||
|
"link": {
|
||||||
|
"relink": True,
|
||||||
|
"create": True,
|
||||||
|
"force": True,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"link": {
|
||||||
|
# When symlinks are resolved, these are actually the same file.
|
||||||
|
"~/.ssh/config": "ssh/config",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Execute dotbot.
|
||||||
|
with pytest.raises(SystemExit):
|
||||||
|
run_dotbot()
|
||||||
|
|
||||||
|
stdout, _ = capsys.readouterr()
|
||||||
|
assert "appears to be the same file" in stdout
|
||||||
|
# Verify that the file was not overwritten.
|
||||||
|
assert ssh_config.read_text() == "preserve me!"
|
||||||
|
|
||||||
|
|
||||||
def test_link_defaults_1(home: str, dotfiles: Dotfiles, run_dotbot: Callable[..., None]) -> None:
|
def test_link_defaults_1(home: str, dotfiles: Dotfiles, run_dotbot: Callable[..., None]) -> None:
|
||||||
"""Verify that link doesn't overwrite non-dotfiles links by default."""
|
"""Verify that link doesn't overwrite non-dotfiles links by default."""
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue