mirror of
https://github.com/copier-org/copier.git
synced 2025-05-05 15:32:54 +00:00
464 lines
13 KiB
Python
464 lines
13 KiB
Python
import os
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
from plumbum import local
|
|
|
|
from copier import run_copy, run_update
|
|
from copier.errors import DirtyLocalWarning
|
|
|
|
from .helpers import build_file_tree, git
|
|
|
|
|
|
def test_copy_symlink(tmp_path_factory: pytest.TempPathFactory) -> None:
|
|
src, dst = map(tmp_path_factory.mktemp, ("src", "dst"))
|
|
# Prepare repo bundle
|
|
repo = src / "repo"
|
|
repo.mkdir()
|
|
build_file_tree(
|
|
{
|
|
repo / "copier.yaml": """\
|
|
_preserve_symlinks: true
|
|
""",
|
|
repo / "target.txt": "Symlink target",
|
|
repo / "symlink.txt": Path("target.txt"),
|
|
}
|
|
)
|
|
|
|
with local.cwd(src):
|
|
git("init")
|
|
git("add", ".")
|
|
git("commit", "-m", "hello world")
|
|
|
|
run_copy(
|
|
str(repo),
|
|
dst,
|
|
defaults=True,
|
|
overwrite=True,
|
|
vcs_ref="HEAD",
|
|
)
|
|
|
|
assert (dst / "target.txt").exists()
|
|
assert (dst / "symlink.txt").exists()
|
|
assert (dst / "symlink.txt").is_symlink()
|
|
assert (dst / "symlink.txt").readlink() == Path("target.txt")
|
|
|
|
|
|
def test_copy_symlink_templated_name(tmp_path_factory: pytest.TempPathFactory) -> None:
|
|
src, dst = map(tmp_path_factory.mktemp, ("src", "dst"))
|
|
# Prepare repo bundle
|
|
repo = src / "repo"
|
|
repo.mkdir()
|
|
build_file_tree(
|
|
{
|
|
repo / "copier.yaml": """\
|
|
_preserve_symlinks: true
|
|
symlink_name: symlink
|
|
""",
|
|
repo / "target.txt": "Symlink target",
|
|
repo / "{{ symlink_name }}.txt": Path("target.txt"),
|
|
}
|
|
)
|
|
|
|
with local.cwd(src):
|
|
git("init")
|
|
git("add", ".")
|
|
git("commit", "-m", "hello world")
|
|
|
|
run_copy(
|
|
str(repo),
|
|
dst,
|
|
defaults=True,
|
|
overwrite=True,
|
|
vcs_ref="HEAD",
|
|
)
|
|
|
|
assert (dst / "target.txt").exists()
|
|
assert (dst / "symlink.txt").exists()
|
|
assert (dst / "symlink.txt").is_symlink()
|
|
assert (dst / "symlink.txt").readlink() == Path("target.txt")
|
|
|
|
|
|
def test_copy_symlink_templated_target(
|
|
tmp_path_factory: pytest.TempPathFactory,
|
|
) -> None:
|
|
src, dst = map(tmp_path_factory.mktemp, ("src", "dst"))
|
|
# Prepare repo bundle
|
|
repo = src / "repo"
|
|
repo.mkdir()
|
|
build_file_tree(
|
|
{
|
|
repo / "copier.yaml": """\
|
|
_preserve_symlinks: true
|
|
target_name: target
|
|
""",
|
|
repo / "{{ target_name }}.txt": "Symlink target",
|
|
repo / "symlink1.txt.jinja": Path("{{ target_name }}.txt"),
|
|
repo / "symlink2.txt": Path("{{ target_name }}.txt"),
|
|
}
|
|
)
|
|
|
|
with local.cwd(src):
|
|
git("init")
|
|
git("add", ".")
|
|
git("commit", "-m", "hello world")
|
|
|
|
run_copy(
|
|
str(repo),
|
|
dst,
|
|
defaults=True,
|
|
overwrite=True,
|
|
vcs_ref="HEAD",
|
|
)
|
|
|
|
assert (dst / "target.txt").exists()
|
|
assert (dst / "symlink1.txt").exists()
|
|
assert (dst / "symlink1.txt").is_symlink()
|
|
assert (dst / "symlink1.txt").readlink() == Path("target.txt")
|
|
|
|
assert not (dst / "symlink2.txt").exists()
|
|
assert (dst / "symlink2.txt").is_symlink()
|
|
assert (dst / "symlink2.txt").readlink() == Path("{{ target_name }}.txt")
|
|
|
|
|
|
def test_copy_symlink_missing_target(tmp_path_factory: pytest.TempPathFactory) -> None:
|
|
src, dst = map(tmp_path_factory.mktemp, ("src", "dst"))
|
|
# Prepare repo bundle
|
|
repo = src / "repo"
|
|
repo.mkdir()
|
|
build_file_tree(
|
|
{
|
|
repo / "copier.yaml": """\
|
|
_preserve_symlinks: true
|
|
""",
|
|
repo / "symlink.txt": Path("target.txt"),
|
|
}
|
|
)
|
|
|
|
with local.cwd(src):
|
|
git("init")
|
|
git("add", ".")
|
|
git("commit", "-m", "hello world")
|
|
|
|
run_copy(
|
|
str(repo),
|
|
dst,
|
|
defaults=True,
|
|
overwrite=True,
|
|
vcs_ref="HEAD",
|
|
)
|
|
|
|
assert (dst / "symlink.txt").is_symlink()
|
|
assert (dst / "symlink.txt").readlink() == Path("target.txt")
|
|
assert not (
|
|
dst / "symlink.txt"
|
|
).exists() # exists follows symlinks, It returns False as the target doesn't exist
|
|
|
|
|
|
def test_option_preserve_symlinks_false(
|
|
tmp_path_factory: pytest.TempPathFactory,
|
|
) -> None:
|
|
src, dst = map(tmp_path_factory.mktemp, ("src", "dst"))
|
|
# Prepare repo bundle
|
|
repo = src / "repo"
|
|
repo.mkdir()
|
|
build_file_tree(
|
|
{
|
|
repo / "copier.yaml": """\
|
|
_preserve_symlinks: false
|
|
""",
|
|
repo / "target.txt": "Symlink target",
|
|
repo / "symlink.txt": Path("target.txt"),
|
|
}
|
|
)
|
|
|
|
with local.cwd(src):
|
|
git("init")
|
|
git("add", ".")
|
|
git("commit", "-m", "hello world")
|
|
|
|
run_copy(
|
|
str(repo),
|
|
dst,
|
|
defaults=True,
|
|
overwrite=True,
|
|
vcs_ref="HEAD",
|
|
)
|
|
|
|
assert (dst / "target.txt").exists()
|
|
assert (dst / "symlink.txt").exists()
|
|
assert not (dst / "symlink.txt").is_symlink()
|
|
|
|
|
|
def test_option_preserve_symlinks_default(
|
|
tmp_path_factory: pytest.TempPathFactory,
|
|
) -> None:
|
|
src, dst = map(tmp_path_factory.mktemp, ("src", "dst"))
|
|
# Prepare repo bundle
|
|
repo = src / "repo"
|
|
repo.mkdir()
|
|
build_file_tree(
|
|
{
|
|
repo / "copier.yaml": """\
|
|
""",
|
|
repo / "target.txt": "Symlink target",
|
|
repo / "symlink.txt": Path("target.txt"),
|
|
}
|
|
)
|
|
|
|
with local.cwd(src):
|
|
git("init")
|
|
git("add", ".")
|
|
git("commit", "-m", "hello world")
|
|
|
|
run_copy(
|
|
str(repo),
|
|
dst,
|
|
defaults=True,
|
|
overwrite=True,
|
|
vcs_ref="HEAD",
|
|
)
|
|
|
|
assert (dst / "target.txt").exists()
|
|
assert (dst / "symlink.txt").exists()
|
|
assert not (dst / "symlink.txt").is_symlink()
|
|
|
|
|
|
def test_update_symlink(tmp_path_factory: pytest.TempPathFactory) -> None:
|
|
src, dst = map(tmp_path_factory.mktemp, ("src", "dst"))
|
|
|
|
build_file_tree(
|
|
{
|
|
src / ".copier-answers.yml.jinja": """\
|
|
# Changes here will be overwritten by Copier
|
|
{{ _copier_answers|to_nice_yaml }}
|
|
""",
|
|
src / "copier.yml": """\
|
|
_preserve_symlinks: true
|
|
""",
|
|
src / "aaaa.txt": """
|
|
Lorem ipsum
|
|
""",
|
|
src / "bbbb.txt": """
|
|
dolor sit amet
|
|
""",
|
|
src / "symlink.txt": Path("./aaaa.txt"),
|
|
}
|
|
)
|
|
|
|
with local.cwd(src):
|
|
git("init")
|
|
git("add", "-A")
|
|
git("commit", "-m", "first commit on src")
|
|
|
|
run_copy(str(src), dst, defaults=True, overwrite=True)
|
|
|
|
with local.cwd(src):
|
|
# test updating a symlink
|
|
Path("symlink.txt").unlink()
|
|
os.symlink("bbbb.txt", "symlink.txt")
|
|
|
|
# dst must be vcs-tracked to use run_update
|
|
with local.cwd(dst):
|
|
git("init")
|
|
git("add", "-A")
|
|
git("commit", "-m", "first commit on dst")
|
|
|
|
# make sure changes have not yet propagated
|
|
p1 = src / "symlink.txt"
|
|
p2 = dst / "symlink.txt"
|
|
assert p1.read_text() != p2.read_text()
|
|
|
|
with pytest.warns(DirtyLocalWarning):
|
|
run_update(dst, defaults=True, overwrite=True)
|
|
|
|
# make sure changes propagate after update
|
|
p1 = src / "symlink.txt"
|
|
p2 = dst / "symlink.txt"
|
|
assert p1.read_text() == p2.read_text()
|
|
|
|
assert (dst / "symlink.txt").readlink() == Path("bbbb.txt")
|
|
|
|
|
|
def test_update_file_to_symlink(tmp_path_factory: pytest.TempPathFactory) -> None:
|
|
src, dst = map(tmp_path_factory.mktemp, ("src", "dst"))
|
|
|
|
build_file_tree(
|
|
{
|
|
src / ".copier-answers.yml.jinja": """\
|
|
# Changes here will be overwritten by Copier
|
|
{{ _copier_answers|to_nice_yaml }}
|
|
""",
|
|
src / "copier.yml": """\
|
|
_preserve_symlinks: true
|
|
""",
|
|
src / "aaaa.txt": """
|
|
Lorem ipsum
|
|
""",
|
|
src / "bbbb.txt": """
|
|
dolor sit amet
|
|
""",
|
|
src / "cccc.txt": Path("./aaaa.txt"),
|
|
}
|
|
)
|
|
|
|
with local.cwd(src):
|
|
git("init")
|
|
git("add", "-A")
|
|
git("commit", "-m", "first commit on src")
|
|
|
|
run_copy(str(src), dst, defaults=True, overwrite=True)
|
|
|
|
with local.cwd(src):
|
|
# test updating a symlink
|
|
Path("bbbb.txt").unlink()
|
|
os.symlink("aaaa.txt", "bbbb.txt")
|
|
Path("cccc.txt").unlink()
|
|
with Path("cccc.txt").open("w+") as f:
|
|
f.write("Lorem ipsum")
|
|
|
|
# dst must be vcs-tracked to use run_update
|
|
with local.cwd(dst):
|
|
git("init")
|
|
git("add", "-A")
|
|
git("commit", "-m", "first commit on dst")
|
|
|
|
# make sure changes have not yet propagated
|
|
assert not (dst / "bbbb.txt").is_symlink()
|
|
assert (dst / "cccc.txt").is_symlink()
|
|
|
|
with pytest.warns(DirtyLocalWarning):
|
|
run_update(dst, defaults=True, overwrite=True)
|
|
|
|
# make sure changes propagate after update
|
|
assert (dst / "bbbb.txt").is_symlink()
|
|
assert (dst / "bbbb.txt").readlink() == Path("aaaa.txt")
|
|
assert not (dst / "cccc.txt").is_symlink()
|
|
assert (dst / "cccc.txt").read_text() == "Lorem ipsum"
|
|
|
|
|
|
def test_exclude_symlink(tmp_path_factory: pytest.TempPathFactory) -> None:
|
|
src, dst = map(tmp_path_factory.mktemp, ("src", "dst"))
|
|
# Prepare repo bundle
|
|
repo = src / "repo"
|
|
repo.mkdir()
|
|
build_file_tree(
|
|
{
|
|
repo / "copier.yaml": """\
|
|
_preserve_symlinks: true
|
|
""",
|
|
repo / "target.txt": "Symlink target",
|
|
repo / "symlink.txt": Path("target.txt"),
|
|
}
|
|
)
|
|
|
|
with local.cwd(src):
|
|
git("init")
|
|
git("add", ".")
|
|
git("commit", "-m", "hello world")
|
|
|
|
run_copy(
|
|
str(repo),
|
|
dst,
|
|
defaults=True,
|
|
overwrite=True,
|
|
exclude=["symlink.txt"],
|
|
vcs_ref="HEAD",
|
|
)
|
|
assert not (dst / "symlink.txt").exists()
|
|
assert not (dst / "symlink.txt").is_symlink()
|
|
|
|
|
|
def test_pretend_symlink(tmp_path_factory: pytest.TempPathFactory) -> None:
|
|
src, dst = map(tmp_path_factory.mktemp, ("src", "dst"))
|
|
# Prepare repo bundle
|
|
repo = src / "repo"
|
|
repo.mkdir()
|
|
build_file_tree(
|
|
{
|
|
repo / "copier.yaml": """\
|
|
_preserve_symlinks: true
|
|
""",
|
|
repo / "target.txt": "Symlink target",
|
|
repo / "symlink.txt": Path("target.txt"),
|
|
}
|
|
)
|
|
|
|
with local.cwd(src):
|
|
git("init")
|
|
git("add", ".")
|
|
git("commit", "-m", "hello world")
|
|
|
|
run_copy(
|
|
str(repo),
|
|
dst,
|
|
defaults=True,
|
|
overwrite=True,
|
|
pretend=True,
|
|
vcs_ref="HEAD",
|
|
)
|
|
assert not (dst / "symlink.txt").exists()
|
|
assert not (dst / "symlink.txt").is_symlink()
|
|
|
|
|
|
def test_copy_symlink_none_path(tmp_path_factory: pytest.TempPathFactory) -> None:
|
|
src, dst = map(tmp_path_factory.mktemp, ("src", "dst"))
|
|
# Prepare repo bundle
|
|
repo = src / "repo"
|
|
repo.mkdir()
|
|
build_file_tree(
|
|
{
|
|
repo / "copier.yaml": """\
|
|
_preserve_symlinks: true
|
|
render: false
|
|
""",
|
|
repo / "target.txt": "Symlink target",
|
|
repo / "{% if render %}symlink.txt{% endif %}": Path("target.txt"),
|
|
}
|
|
)
|
|
|
|
with local.cwd(src):
|
|
git("init")
|
|
git("add", ".")
|
|
git("commit", "-m", "hello world")
|
|
|
|
run_copy(
|
|
str(repo),
|
|
dst,
|
|
defaults=True,
|
|
overwrite=True,
|
|
vcs_ref="HEAD",
|
|
)
|
|
|
|
assert (dst / "target.txt").exists()
|
|
assert not (dst / "symlink.txt").exists()
|
|
assert not (dst / "symlink.txt").is_symlink()
|
|
|
|
|
|
def test_recursive_symlink(tmp_path_factory: pytest.TempPathFactory) -> None:
|
|
src, dst = map(tmp_path_factory.mktemp, ("src", "dst"))
|
|
build_file_tree(
|
|
{
|
|
src / "copier.yaml": "_preserve_symlinks: true",
|
|
src / "one" / "two" / "three" / "root": Path("../../../"),
|
|
}
|
|
)
|
|
run_copy(str(src), dst, defaults=True, overwrite=True)
|
|
assert (dst / "one" / "two" / "three" / "root").is_symlink()
|
|
assert (dst / "one" / "two" / "three" / "root").readlink() == Path("../../../")
|
|
|
|
|
|
def test_symlinked_dir_expanded(tmp_path_factory: pytest.TempPathFactory) -> None:
|
|
src, dst = map(tmp_path_factory.mktemp, ("src", "dst"))
|
|
build_file_tree(
|
|
{
|
|
src / "a_dir" / "a_file.txt": "some content",
|
|
src / "a_symlinked_dir": Path("a_dir"),
|
|
src / "a_nested" / "symlink": Path("../a_dir"),
|
|
}
|
|
)
|
|
run_copy(str(src), dst, defaults=True, overwrite=True)
|
|
assert (dst / "a_dir" / "a_file.txt").read_text() == "some content"
|
|
assert (dst / "a_symlinked_dir" / "a_file.txt").read_text() == "some content"
|
|
assert (dst / "a_nested" / "symlink" / "a_file.txt").read_text() == "some content"
|