From 046e6ed9d46b173b5c9a8ef515b77a13a1728dcf Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Fri, 19 May 2023 10:32:02 -0700 Subject: [PATCH] aider: Added in-memory cache to `get_tags` function using a tuple (filename, root_dname) as the cache key. # Context: USER: add an in memory cache to get_tags that only updates if the st_mtime of the filename changes ASSISTANT: To implement an in-memory cache for the `get_tags` function, we will need to modify the `aider/ctags.py` file. We will use a dictionary to store the cache and check the file's modification time to decide whether to update the cache or not. Here are the steps to implement the cache: 1. Create a global variable `TAGS_CACHE` to store the cache. 2. In the `get_tags` function, check if the filename is in the cache and if the modification time has not changed. 3. If the conditions in step 2 are met, return the cached value. 4. If the conditions in step 2 are not met, update the cache with the new tags and return them. Here are the changes to the `aider/ctags.py` file: ```python aider/ctags.py <<<<<<< ORIGINAL import os import json import sys import subprocess # from aider.dump import dump ======= import os import json import sys import subprocess # Global cache for tags TAGS_CACHE = {} # from aider.dump import dump >>>>>>> UPDATED ``` ```python aider/ctags.py <<<<<<< ORIGINAL def get_tags(filename, root_dname): cmd = ["ctags", "--fields=+S", "--output-format=json", filename] output = subprocess.check_output(cmd).decode("utf-8") output = output.splitlines() ======= def get_tags(filename, root_dname): # Check if the file is in the cache and if the modification time has not changed file_mtime = os.path.getmtime(filename) if filename in TAGS_CACHE and TAGS_CACHE[filename]["mtime"] == file_mtime: return TAGS_CACHE[filename]["tags"] cmd = ["ctags", "--fields=+S", "--output-format=json", filename] output = subprocess.check_output(cmd).decode("utf-8") output = output.splitlines() >>>>>>> UPDATED ``` ```python aider/ctags.py <<<<<<< ORIGINAL for line in output: tag = json.loads(line) path = tag.get("path") scope = tag.get("scope") kind = tag.get("kind") name = tag.get("name") signature = tag.get("signature") last = name if signature: last += " " + signature res = split_path(path, root_dname) if scope: res.append(scope) res += [kind, last] yield res ======= tags = [] for line in output: tag = json.loads(line) path = tag.get("path") scope = tag.get("scope") kind = tag.get("kind") name = tag.get("name") signature = tag.get("signature") last = name if signature: last += " " + signature res = split_path(path, root_dname) if scope: res.append(scope) res += [kind, last] tags.append(res) # ^C KeyboardInterrupt USER: sorry, please do that again. but set key=(filename, root_dname) and use that as the cache key ASSISTANT: No problem. I will modify the cache implementation to use a tuple (filename, root_dname) as the cache key. Here are the updated changes to the `aider/ctags.py` file: ```python aider/ctags.py <<<<<<< ORIGINAL import os import json import sys import subprocess # from aider.dump import dump ======= import os import json import sys import subprocess # Global cache for tags TAGS_CACHE = {} # from aider.dump import dump >>>>>>> UPDATED ``` ```python aider/ctags.py <<<<<<< ORIGINAL def get_tags(filename, root_dname): cmd = ["ctags", "--fields=+S", "--output-format=json", filename] output = subprocess.check_output(cmd).decode("utf-8") output = output.splitlines() ======= def get_tags(filename, root_dname): # Check if the file is in the cache and if the modification time has not changed file_mtime = os.path.getmtime(filename) cache_key = (filename, root_dname) if cache_key in TAGS_CACHE and TAGS_CACHE[cache_key]["mtime"] == file_mtime: return TAGS_CACHE[cache_key]["tags"] cmd = ["ctags", "--fields=+S", "--output-format=json", filename] output = subprocess.check_output(cmd).decode("utf-8") output = output.splitlines() >>>>>>> UPDATED ``` ```python aider/ctags.py <<<<<<< ORIGINAL for line in output: tag = json.loads(line) path = tag.get("path") scope = tag.get("scope") kind = tag.get("kind") name = tag.get("name") signature = tag.get("signature") last = name if signature: last += " " + signature res = split_path(path, root_dname) if scope: res.append(scope) res += [kind, last] yield res ======= tags = [] for line in output: tag = json.loads(line) path = tag.get("path") scope = tag.get("scope") kind = tag.get("kind") name = tag.get("name") signature = tag.get("signature") last = name if signature: last += " " + signature res = split_path(path, root_dname) if scope: res.append(scope) res += [kind, last] tags.append(res) # Update the cache TAGS_CACHE[cache_key] = {"mtime": file_mtime, "tags": tags} return tags >>>>>>> UPDATED ``` --- aider/ctags.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/aider/ctags.py b/aider/ctags.py index 722f3b57d..216f9caa6 100644 --- a/aider/ctags.py +++ b/aider/ctags.py @@ -3,6 +3,9 @@ import json import sys import subprocess +# Global cache for tags +TAGS_CACHE = {} + # from aider.dump import dump @@ -50,6 +53,12 @@ def split_path(path, root_dname): def get_tags(filename, root_dname): + # Check if the file is in the cache and if the modification time has not changed + file_mtime = os.path.getmtime(filename) + cache_key = (filename, root_dname) + if cache_key in TAGS_CACHE and TAGS_CACHE[cache_key]["mtime"] == file_mtime: + return TAGS_CACHE[cache_key]["tags"] + cmd = ["ctags", "--fields=+S", "--output-format=json", filename] output = subprocess.check_output(cmd).decode("utf-8") output = output.splitlines() @@ -57,6 +66,7 @@ def get_tags(filename, root_dname): if not output: yield split_path(filename, root_dname) + tags = [] for line in output: tag = json.loads(line) path = tag.get("path") @@ -73,8 +83,12 @@ def get_tags(filename, root_dname): if scope: res.append(scope) res += [kind, last] + tags.append(res) - yield res + # Update the cache + TAGS_CACHE[cache_key] = {"mtime": file_mtime, "tags": tags} + + return tags if __name__ == "__main__":