Skip to content

Commit

Permalink
feat: Write CACHEDIR.TAG file (#2803)
Browse files Browse the repository at this point in the history
Co-authored-by: Bernát Gábor <[email protected]>
Co-authored-by: Neil Ramsay <[email protected]>
  • Loading branch information
3 people authored Nov 26, 2024
1 parent b3e2b6f commit be19526
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/changelog/2803.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
write CACHEDIR.TAG file on creation - by "user:`neilramsay`
22 changes: 22 additions & 0 deletions src/virtualenv/create/creator.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import logging
import os
import sys
import textwrap
from abc import ABC, abstractmethod
from argparse import ArgumentTypeError
from ast import literal_eval
Expand Down Expand Up @@ -156,10 +157,31 @@ def run(self):
logging.debug("delete %s", self.dest)
safe_delete(self.dest)
self.create()
self.add_cachedir_tag()
self.set_pyenv_cfg()
if not self.no_vcs_ignore:
self.setup_ignore_vcs()

def add_cachedir_tag(self):
"""
Add a Cache Directory Tag file "CACHEDIR.TAG".
The CACHEDIR.TAG file is used by various tools to mark
a directory as cache, so that it can be handled differently.
Some backup tools look for this file to exclude the directory.
See https://bford.info/cachedir/ for more details.
"""
cachedir_tag_file = self.dest / "CACHEDIR.TAG"
if not cachedir_tag_file.exists():
cachedir_tag_text = textwrap.dedent("""
Signature: 8a477f597d28d172789f06886806bc55
# This file is a cache directory tag created by Python virtualenv.
# For information about cache directory tags, see:
# http://www.brynosaurus.com/cachedir/
""").strip()
cachedir_tag_file.write_text(cachedir_tag_text, encoding="utf-8")

def set_pyenv_cfg(self):
self.pyenv_cfg.content = OrderedDict()
self.pyenv_cfg["home"] = os.path.dirname(os.path.abspath(self.interpreter.system_executable))
Expand Down
37 changes: 37 additions & 0 deletions tests/integration/test_cachedir_tag.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from __future__ import annotations

import shutil
import subprocess
import sys

import pytest

from virtualenv import cli_run


@pytest.fixture(scope="session")
def tar_test_env(tmp_path_factory):
base_path = tmp_path_factory.mktemp("tar-cachedir-test")
cli_run(["--activators", "", "--without-pip", str(base_path / ".venv")])
yield base_path
shutil.rmtree(str(base_path))


def compatible_is_tar_present() -> bool:
try:
tar_result = subprocess.run(args=["tar", "--help"], capture_output=True, encoding="utf-8")
return tar_result.stdout.find("--exclude-caches") > -1
except FileNotFoundError:
return False


@pytest.mark.skipif(sys.platform == "win32", reason="Windows does not have tar")
@pytest.mark.skipif(not compatible_is_tar_present(), reason="Compatible tar is not installed")
def test_cachedir_tag_ignored_by_tag(tar_test_env): # noqa: ARG001
tar_result = subprocess.run(
args=["tar", "--create", "--file", "/dev/null", "--exclude-caches", "--verbose", ".venv"],
capture_output=True,
encoding="utf-8",
)
assert tar_result.stdout == ".venv/\n.venv/CACHEDIR.TAG\n"
assert tar_result.stderr == "tar: .venv/: contains a cache directory tag CACHEDIR.TAG; contents not dumped\n"
29 changes: 29 additions & 0 deletions tests/unit/create/test_creator.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import stat
import subprocess
import sys
import textwrap
import zipfile
from collections import OrderedDict
from itertools import product
Expand Down Expand Up @@ -223,6 +224,34 @@ def list_to_str(iterable):
assert git_ignore.splitlines() == [comment, "*"]


def test_create_cachedir_tag(tmp_path):
cachedir_tag_file = tmp_path / "CACHEDIR.TAG"
cli_run([str(tmp_path), "--without-pip", "--activators", ""])
assert (
cachedir_tag_file.read_text(encoding="utf-8")
== textwrap.dedent("""
Signature: 8a477f597d28d172789f06886806bc55
# This file is a cache directory tag created by Python virtualenv.
# For information about cache directory tags, see:
# http://www.brynosaurus.com/cachedir/
""").strip()
)


def test_create_cachedir_tag_exists(tmp_path):
cachedir_tag_file = tmp_path / "CACHEDIR.TAG"
cachedir_tag_file.write_text("magic", encoding="utf-8")
cli_run([str(tmp_path), "--without-pip", "--activators", ""])
assert cachedir_tag_file.read_text(encoding="utf-8") == "magic"


def test_create_cachedir_tag_exists_override(tmp_path):
cachedir_tag_file = tmp_path / "CACHEDIR.TAG"
cachedir_tag_file.write_text("magic", encoding="utf-8")
cli_run([str(tmp_path), "--without-pip", "--activators", ""])
assert cachedir_tag_file.read_text(encoding="utf-8") == "magic"


def test_create_vcs_ignore_exists(tmp_path):
git_ignore = tmp_path / ".gitignore"
git_ignore.write_text("magic", encoding="utf-8")
Expand Down

0 comments on commit be19526

Please sign in to comment.