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`). The directory is managed by Tach, and your cached results are stored on-disk on each machine where tasks are run.

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: [[email protected]](mailto://[email protected]); [[email protected]](mailto://[email protected])!

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
31 changes: 23 additions & 8 deletions python/tach/cache/setup.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,39 @@
from __future__ import annotations

import uuid
from os import getenv, name as os_name
from pathlib import Path
from re import match, compile

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"

path_is_not_absolute_re = compile(r'^(?![a-zA-Z]:[\\/]|\\\\|/|~[/\\])') if os_name == 'nt' else compile(r'^[^/~]')
if match(path_is_not_absolute_re, 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 +42,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)
6 changes: 4 additions & 2 deletions python/tach/logging/worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
from typing import Any
from urllib import error, parse, request

from tach.cache.setup import get_cache_path

LOGGING_URL = "https://vmilasesnyvpalekembc.supabase.co"
PUBLIC_ANON_CLIENT_KEY = (
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InZtaWxhc2Vzbnl2cGFsZWtlbWJjIiwicm9"
Expand All @@ -29,7 +31,7 @@ def update_latest_version(project_root: Path) -> None:
return
except (error.URLError, KeyError):
return
(project_root / ".tach" / ".latest-version").write_text(latest_version)
(get_cache_path(project_root) / ".latest-version").write_text(latest_version)


def log_request(url: str, data: dict[str, Any]) -> None:
Expand Down Expand Up @@ -140,7 +142,7 @@ def create_managed_subprocess(project_root: Path, timeout: int = 5) -> Path:
Launches the worker as a completely separate process using subprocess.Popen.
Returns the path to the temporary file for message passing.
"""
tach_dir = project_root / ".tach"
tach_dir = get_cache_path(project_root)
tach_dir.mkdir(parents=True, exist_ok=True)

# Cannot use FIFO because it is not supported on Windows
Expand Down
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 @@ -35,7 +35,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 @@ -47,7 +48,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,
}
)
.join("computation-cache"),
)
.build()?,
Expand Down