Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Write CACHEDIR.TAG file #2805

Merged
merged 2 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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`.
14 changes: 14 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 @@ -157,10 +158,23 @@ def run(self):
LOGGER.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):
"""Generate a file indicating that this is not meant to be backed up."""
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:
# https://bford.info/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
32 changes: 32 additions & 0 deletions tests/integration/test_cachedir_tag.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from __future__ import annotations

import shutil
import sys
from subprocess import check_output, run
from typing import TYPE_CHECKING

import pytest

from virtualenv import cli_run

if TYPE_CHECKING:
from pathlib import Path

# gtar => gnu-tar on macOS
TAR = next((target for target in ("gtar", "tar") if shutil.which(target)), None)


def compatible_is_tar_present() -> bool:
return TAR and "--exclude-caches" in check_output(args=[TAR, "--help"], text=True)


@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(tmp_path: Path) -> None:
venv = tmp_path / ".venv"
cli_run(["--activators", "", "--without-pip", str(venv)])

args = [TAR, "--create", "--file", "/dev/null", "--exclude-caches", "--verbose", venv.name]
tar_result = run(args=args, capture_output=True, text=True, cwd=tmp_path)
assert tar_result.stdout == ".venv/\n.venv/CACHEDIR.TAG\n"
assert tar_result.stderr == f"{TAR}: .venv/: contains a cache directory tag CACHEDIR.TAG; contents not dumped\n"
28 changes: 28 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,33 @@ 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", ""])

expected = """
Signature: 8a477f597d28d172789f06886806bc55
# This file is a cache directory tag created by Python virtualenv.
# For information about cache directory tags, see:
# https://bford.info/cachedir/
"""
assert cachedir_tag_file.read_text(encoding="utf-8") == textwrap.dedent(expected).strip()


def test_create_cachedir_tag_exists(tmp_path: Path) -> None:
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: Path) -> None:
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
Loading