Skip to content
Open
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
2 changes: 1 addition & 1 deletion docs/usage/caching.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ When all of these match a previous cache entry, the cached results are printed d

## Cache storage

The computation cache exists within the `.tach` directory in your project root. The directory is managed by Tach, and your cached results are stored on-disk on each machine where tasks are run.
The computation cache exists within the directory defined by the `TACH_CACHE_DIR` environment variable (default is `.tach` in your project root). The directory is managed by Tach, and your cached results are stored on-disk on each machine where tasks are run.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thinking about this some more, would it be better to specify the cache dir in the config file and/or as a CLI argument? just wondering since i don't think tach has anything else configured via environment variables.

do you mind sharing a bit more info about your use case?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if I can recall the exact use case because it has been a while since I've worked on the project that uses tach. I guess it had something to do that I wanted to do with docker.

Copy link
Copy Markdown
Collaborator

@DetachHead DetachHead Dec 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in that case i think i'll just leave this PR open for now and wait to see if anybody else has a use case for it


We are currently working on a _remote cache_ backend, which will allow multiple developers and CI environments to share a centralized cache to maximize the hit rate. If you are interested in this functionality, reach out through a [GitHub issue](https://github.com/gauge-sh/tach/issues) or via email: [evan@gauge.sh](mailto://evan@gauge.sh); [caelean@gauge.sh](mailto://caelean@gauge.sh)!

Expand Down
8 changes: 4 additions & 4 deletions python/tach/cache/access.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,23 @@
import uuid
from typing import TYPE_CHECKING

from tach.cache.setup import resolve_dot_tach
from tach.cache.setup import get_cache_path, resolve_cache_path

if TYPE_CHECKING:
from pathlib import Path


def get_uid(project_root: Path) -> uuid.UUID | None:
info_path = project_root / ".tach" / "tach.info"
info_path = get_cache_path(project_root) / "tach.info"
if not info_path.exists():
resolve_dot_tach(project_root)
resolve_cache_path(project_root)
contents = info_path.read_text().strip()
uid = uuid.UUID(contents)
return uid


def get_latest_version(project_root: Path) -> str | None:
latest_version_path = project_root / ".tach" / ".latest-version"
latest_version_path = get_cache_path(project_root) / ".latest-version"
if not latest_version_path.exists():
return
version = latest_version_path.read_text().strip()
Expand Down
30 changes: 22 additions & 8 deletions python/tach/cache/setup.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,38 @@
from __future__ import annotations

import pathlib
import uuid
from os import getenv
from pathlib import Path

from tach import __version__


def resolve_dot_tach(project_root: Path) -> Path | None:
def get_cache_path(project_root: Path) -> Path:
env_value = getenv("TACH_CACHE_DIR")

if env_value is None:
return project_root / ".tach"

if not pathlib.Path.is_absolute(pathlib.PurePath(env_value)):
return project_root / env_value

return Path(env_value)


def resolve_cache_path(project_root: Path) -> Path | None:
def _create(path: Path, is_file: bool = False, file_content: str = "") -> None:
if not path.exists():
if is_file:
path.write_text(file_content.strip())
else:
path.mkdir()

# Create .tach
tach_path = project_root / ".tach"
_create(tach_path)
# Create cache dir
cache_dir = get_cache_path(project_root)
_create(cache_dir)
# Create info
info_path = tach_path / "tach.info"
info_path = cache_dir / "tach.info"
_create(info_path, is_file=True, file_content=str(uuid.uuid4()))
# Create .gitignore
gitignore_content = """
Expand All @@ -27,9 +41,9 @@ def _create(path: Path, is_file: bool = False, file_content: str = "") -> None:
# gitignore all content, including this .gitignore
*
"""
gitignore_path = tach_path / ".gitignore"
gitignore_path = cache_dir / ".gitignore"
_create(gitignore_path, is_file=True, file_content=gitignore_content)
# Create version
version_path = tach_path / ".latest-version"
version_path = cache_dir / ".latest-version"
_create(version_path, is_file=True, file_content=__version__)
return Path(tach_path)
return Path(cache_dir)
29 changes: 15 additions & 14 deletions python/tests/test_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,29 @@
from unittest.mock import patch

from tach.cache.access import get_latest_version, get_uid
from tach.cache.setup import resolve_dot_tach
from tach.cache.setup import get_cache_path, resolve_cache_path


def test_resolve_dot_tach(tmp_path):
def test_resolve_cache_path(tmp_path):
project_path = tmp_path / "project"
project_path.mkdir(parents=True, exist_ok=True)
version = "1.0.0"

with patch("tach.cache.setup.__version__", version):
result = resolve_dot_tach(project_path)
result = resolve_cache_path(project_path)

tach_path = project_path / ".tach"
assert tach_path.exists()
assert (tach_path / "tach.info").exists()
assert (tach_path / "tach.info").read_text().strip() != ""
assert (tach_path / ".gitignore").exists()
assert (tach_path / ".latest-version").exists()
assert (tach_path / ".latest-version").read_text().strip() == version
assert result == tach_path
cache_path = get_cache_path(project_path)
assert cache_path.exists()
assert (cache_path / "tach.info").exists()
assert (cache_path / "tach.info").read_text().strip() != ""
assert (cache_path / ".gitignore").exists()
assert (cache_path / ".latest-version").exists()
assert (cache_path / ".latest-version").read_text().strip() == version
assert result == cache_path


@patch("tach.cache.access.resolve_dot_tach")
def test_get_uid(mock_resolve_dot_tach, tmp_path):
@patch("tach.cache.access.resolve_cache_path")
def test_get_uid(mock_resolve_cache_path, tmp_path):
project_path = tmp_path / "project"
tach_info_path = project_path / ".tach" / "tach.info"
tach_info_path.parent.mkdir(parents=True, exist_ok=True)
Expand All @@ -39,7 +39,8 @@ def test_get_uid(mock_resolve_dot_tach, tmp_path):

def test_get_latest_version(tmp_path):
project_path = tmp_path / "project"
latest_version_path = project_path / ".tach" / ".latest-version"
cache_path = get_cache_path(project_path)
latest_version_path = cache_path / ".latest-version"
latest_version_path.parent.mkdir(parents=True, exist_ok=True)
version = "1.0.0"
latest_version_path.write_text(version)
Expand Down
10 changes: 8 additions & 2 deletions src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ impl FromIterator<u8> for CacheKey {
}
}

static CACHE_DIR: &str = ".tach";
static ENV_KEY_CACHE_DIR: &str = "TACH_CACHE_DIR";
static DEFAULT_CACHE_DIR: &str = ".tach";

pub type ComputationCacheValue = (Vec<(u8, String)>, u8);

Expand All @@ -48,7 +49,12 @@ fn build_computation_cache<P: AsRef<Path>>(
.set_disk_directory(
project_root
.as_ref()
.join(CACHE_DIR)
.join(
match env::var(ENV_KEY_CACHE_DIR) {
Ok(env_value) => env_value,
Err() => DEFAULT_CACHE_DIR,
}
)
Comment on lines +52 to +57
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: you can use unwrap_or_else here

Suggested change
.join(
match env::var(ENV_KEY_CACHE_DIR) {
Ok(env_value) => env_value,
Err() => DEFAULT_CACHE_DIR,
}
)
.join(
env::var(ENV_KEY_CACHE_DIR)
.unwrap_or_else(|_| DEFAULT_CACHE_DIR),
)

.join("computation-cache"),
)
.build()?,
Expand Down
Loading