util/fscache: add cachedir-tag support

The cachedir-tag specification defines how to mark directories as
cache-directories. This allows tools like `tar` to ignore those
directories if desired (e.g., see `tar --ignore-caches`). This is very
useful to avoid huge cache-directories in backups and remote
synchronizations.

The spec simply defines a file called `CACHEDIR.TAG` with the first 43
bytes to be: "Signature: 8a477f597d28d172789f06886806bc55" (which
happens to be the MD5-checksum of ".IsCacheDirectory". Further content
is to be ignored. Any such files marks the directory in question as a
cache-directory.

The cachedir-tag has been successfully deployed in tools like `cargo`
and `VLC`, and is currently discussed to be implemented in Firefox. More
information is available here: https://bford.info/cachedir/

Signed-off-by: David Rheinsberg <david.rheinsberg@gmail.com>
This commit is contained in:
David Rheinsberg 2022-12-20 14:07:59 +01:00
parent a3e49df619
commit 18c69d2620
2 changed files with 23 additions and 1 deletions

View file

@ -204,6 +204,7 @@ class FsCache(contextlib.AbstractContextManager, os.PathLike):
_filename_cache_info = "cache.info"
_filename_cache_lock = "cache.lock"
_filename_cache_size = "cache.size"
_filename_cache_tag = "CACHEDIR.TAG"
_filename_object_info = "object.info"
_filename_object_lock = "object.lock"
_version_current = 1
@ -615,6 +616,11 @@ class FsCache(contextlib.AbstractContextManager, os.PathLike):
# Create the file-scaffolding of the cache. We fill in the default
# information and ignore racing operations.
with self._atomic_file(self._filename_cache_tag, self._dirname_objects, ignore_exist=True) as f:
f.write(
"Signature: 8a477f597d28d172789f06886806bc55\n"
"# This is a cache directory tag created by osbuild (see https://bford.info/cachedir/)\n"
)
with self._atomic_file(self._filename_cache_info, self._dirname_objects, ignore_exist=True) as f:
json.dump({"version": self._version_current}, f)
with self._atomic_file(self._filename_cache_lock, self._dirname_objects, ignore_exist=True) as f:

View file

@ -190,10 +190,12 @@ def test_scaffolding(tmpdir):
with cache:
pass
assert len(list(os.scandir(tmpdir))) == 5
assert len(list(os.scandir(tmpdir))) == 6
assert len(list(os.scandir(os.path.join(tmpdir, cache._dirname_objects)))) == 0
assert len(list(os.scandir(os.path.join(tmpdir, cache._dirname_stage)))) == 0
with open(os.path.join(tmpdir, cache._filename_cache_tag), "r", encoding="utf8") as f:
assert len(f.read()) > 0
with open(os.path.join(tmpdir, cache._filename_cache_info), "r", encoding="utf8") as f:
assert json.load(f) == {"version": 1}
with open(os.path.join(tmpdir, cache._filename_cache_lock), "r", encoding="utf8") as f:
@ -202,6 +204,20 @@ def test_scaffolding(tmpdir):
assert f.read() == "0"
def test_cachedir_tag(tmpdir):
#
# Verify compatibility to the cachedir-tag specification.
#
cache = fscache.FsCache("osbuild-test-appid", tmpdir)
with cache:
pass
with open(os.path.join(tmpdir, "CACHEDIR.TAG"), "r", encoding="utf8") as f:
assert f.read(43) == "Signature: 8a477f597d28d172789f06886806bc55"
def test_cache_info(tmpdir):
#
# Verify that the cache reads and augments cache information. Also verify