From a87afb5508055083f55b1f0a59b713d67a1f7527 Mon Sep 17 00:00:00 2001 From: Andrei Markin Date: Mon, 20 Jul 2026 17:14:39 +0400 Subject: [PATCH] feat(executors): Add cache commands to typer cli Manages garf cache: * clean and prune cached reports * get report size --- libs/core/garf/core/cache.py | 34 ++++++++++++++ libs/core/garf/core/version.py | 2 +- .../garf/executors/entrypoints/typer_cli.py | 45 +++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) diff --git a/libs/core/garf/core/cache.py b/libs/core/garf/core/cache.py index 69da6f96..4e0b69a1 100644 --- a/libs/core/garf/core/cache.py +++ b/libs/core/garf/core/cache.py @@ -22,6 +22,7 @@ import logging import os import pathlib +import shutil from typing import Final from garf.core import exceptions, query_editor, report @@ -142,3 +143,36 @@ def size(self) -> int: if not os.path.islink(file_path): total_size += os.path.getsize(file_path) return total_size + + def clean(self) -> None: + """Removes all cached files.""" + for item in self.location.iterdir(): + if item.is_dir(): + shutil.rmtree(item) + else: + item.unlink() + + def prune(self, ttl: int = 30) -> int: + """Removes all files older that a lookback in days. + + Args: + ttl: Max cache entry size in days. + + Returns: + Number of bytes pruned. + """ + prune_date = datetime.datetime.now( + datetime.timezone.utc + ) - datetime.timedelta(days=ttl) + pruned_file_size = 0 + for file_path in self.location.rglob('*.json'): + if ( + file_path.is_file() + and datetime.datetime.fromtimestamp( + file_path.stat().st_mtime, datetime.timezone.utc + ) + < prune_date + ): + pruned_file_size += os.path.getsize(file_path) + file_path.unlink() + return pruned_file_size diff --git a/libs/core/garf/core/version.py b/libs/core/garf/core/version.py index 5f2f1a2d..d52cae38 100644 --- a/libs/core/garf/core/version.py +++ b/libs/core/garf/core/version.py @@ -11,4 +11,4 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -__version__ = '1.2.5' +__version__ = '1.2.6' diff --git a/libs/executors/garf/executors/entrypoints/typer_cli.py b/libs/executors/garf/executors/entrypoints/typer_cli.py index 1a59b47a..f0fd08c4 100644 --- a/libs/executors/garf/executors/entrypoints/typer_cli.py +++ b/libs/executors/garf/executors/entrypoints/typer_cli.py @@ -23,6 +23,7 @@ import garf.executors import requests import typer +from garf.core import cache from garf.executors import exceptions, setup from garf.executors.config import Config from garf.executors.entrypoints import utils @@ -56,10 +57,54 @@ help='Garf\n\nCall APIs with SQL in your terminal', rich_markup_mode='rich' ) workflow_app = typer.Typer(help='Execute workflow') +cache_app = typer.Typer(help='Manage garf cache') typer_app.add_typer( workflow_app, name='workflow', ) +typer_app.add_typer( + cache_app, + name='cache', +) + + +@cache_app.command( + context_settings={'allow_extra_args': True, 'ignore_unknown_options': True}, +) +@tracer.start_as_current_span('garf.cli.cache.size') +def size(): + """Shows size of garf cache.""" + size = cache.GarfCache().size + if (size_mbs := size / (1024 * 1024)) < 1024: + typer.echo(f'Garf cache size {size_mbs:.2f} MB') + else: + size_gbs = size_mbs / 1025 + typer.echo(f'Garf cache size {size_gbs:.2f} GB') + raise typer.Exit() + + +@cache_app.command( + context_settings={'allow_extra_args': True, 'ignore_unknown_options': True}, +) +@tracer.start_as_current_span('garf.cli.cache.clean') +def clean(): + """Clears all entries from the cache.""" + garf_cache = cache.GarfCache() + typer.echo(f'Cleaned {garf_cache.size}') + garf_cache.clean() + raise typer.Exit() + + +@cache_app.command( + context_settings={'allow_extra_args': True, 'ignore_unknown_options': True}, +) +@tracer.start_as_current_span('garf.cli.cache.clean') +def prune(time_days: int): + """Removed old entries from the cache.""" + pruned_size = cache.GarfCache().prune(time_days) + typer.echo(f'Pruned {pruned_size}') + raise typer.Exit() + EnableCache = Annotated[ bool,