mirror of
https://github.com/Aider-AI/aider.git
synced 2025-06-01 18:25:00 +00:00
Added DirectoryRepo as a GitRepo substitute, so /ls, /map etc. can be used on a dir with other version control systems (--no-git).
This commit is contained in:
parent
0c5b51d2ac
commit
69d53c9783
4 changed files with 133 additions and 16 deletions
|
@ -815,7 +815,7 @@ class Coder:
|
||||||
self.shell_commands = []
|
self.shell_commands = []
|
||||||
self.message_cost = 0
|
self.message_cost = 0
|
||||||
|
|
||||||
if self.repo:
|
if isinstance(self.repo, GitRepo):
|
||||||
self.commit_before_message.append(self.repo.get_head_commit_sha())
|
self.commit_before_message.append(self.repo.get_head_commit_sha())
|
||||||
|
|
||||||
def run(self, with_message=None, preproc=True):
|
def run(self, with_message=None, preproc=True):
|
||||||
|
@ -1935,7 +1935,7 @@ class Coder:
|
||||||
return all_files - inchat_files - read_only_files
|
return all_files - inchat_files - read_only_files
|
||||||
|
|
||||||
def check_for_dirty_commit(self, path):
|
def check_for_dirty_commit(self, path):
|
||||||
if not self.repo:
|
if not isinstance(self.repo, GitRepo):
|
||||||
return
|
return
|
||||||
if not self.dirty_commits:
|
if not self.dirty_commits:
|
||||||
return
|
return
|
||||||
|
@ -2135,7 +2135,7 @@ class Coder:
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def auto_commit(self, edited, context=None):
|
def auto_commit(self, edited, context=None):
|
||||||
if not self.repo or not self.auto_commits or self.dry_run:
|
if not isinstance(self.repo, GitRepo) or not self.auto_commits or self.dry_run:
|
||||||
return
|
return
|
||||||
|
|
||||||
if not context:
|
if not context:
|
||||||
|
@ -2175,7 +2175,7 @@ class Coder:
|
||||||
return
|
return
|
||||||
if not self.dirty_commits:
|
if not self.dirty_commits:
|
||||||
return
|
return
|
||||||
if not self.repo:
|
if not isinstance(self.repo, GitRepo):
|
||||||
return
|
return
|
||||||
|
|
||||||
self.repo.commit(fnames=self.need_commit_before_edits)
|
self.repo.commit(fnames=self.need_commit_before_edits)
|
||||||
|
|
|
@ -18,7 +18,7 @@ from aider.editor import pipe_editor
|
||||||
from aider.format_settings import format_settings
|
from aider.format_settings import format_settings
|
||||||
from aider.help import Help, install_help_extra
|
from aider.help import Help, install_help_extra
|
||||||
from aider.llm import litellm
|
from aider.llm import litellm
|
||||||
from aider.repo import ANY_GIT_ERROR
|
from aider.repo import ANY_GIT_ERROR, GitRepo
|
||||||
from aider.run_cmd import run_cmd
|
from aider.run_cmd import run_cmd
|
||||||
from aider.scrape import Scraper, install_playwright
|
from aider.scrape import Scraper, install_playwright
|
||||||
from aider.utils import is_image_file
|
from aider.utils import is_image_file
|
||||||
|
@ -282,7 +282,7 @@ class Commands:
|
||||||
self.io.tool_error(f"Unable to complete commit: {err}")
|
self.io.tool_error(f"Unable to complete commit: {err}")
|
||||||
|
|
||||||
def raw_cmd_commit(self, args=None):
|
def raw_cmd_commit(self, args=None):
|
||||||
if not self.coder.repo:
|
if not isinstance(self.coder.repo, GitRepo):
|
||||||
self.io.tool_error("No git repository found.")
|
self.io.tool_error("No git repository found.")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -296,7 +296,7 @@ class Commands:
|
||||||
def cmd_lint(self, args="", fnames=None):
|
def cmd_lint(self, args="", fnames=None):
|
||||||
"Lint and fix in-chat files or all dirty files if none in chat"
|
"Lint and fix in-chat files or all dirty files if none in chat"
|
||||||
|
|
||||||
if not self.coder.repo:
|
if not isinstance(self.coder.repo, GitRepo):
|
||||||
self.io.tool_error("No git repository found.")
|
self.io.tool_error("No git repository found.")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -483,7 +483,7 @@ class Commands:
|
||||||
self.io.tool_error(f"Unable to complete undo: {err}")
|
self.io.tool_error(f"Unable to complete undo: {err}")
|
||||||
|
|
||||||
def raw_cmd_undo(self, args):
|
def raw_cmd_undo(self, args):
|
||||||
if not self.coder.repo:
|
if not isinstance(self.coder.repo, GitRepo):
|
||||||
self.io.tool_error("No git repository found.")
|
self.io.tool_error("No git repository found.")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -585,7 +585,7 @@ class Commands:
|
||||||
self.io.tool_error(f"Unable to complete diff: {err}")
|
self.io.tool_error(f"Unable to complete diff: {err}")
|
||||||
|
|
||||||
def raw_cmd_diff(self, args=""):
|
def raw_cmd_diff(self, args=""):
|
||||||
if not self.coder.repo:
|
if not isinstance(self.coder.repo, GitRepo):
|
||||||
self.io.tool_error("No git repository found.")
|
self.io.tool_error("No git repository found.")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ from aider.io import InputOutput
|
||||||
from aider.llm import litellm # noqa: F401; properly init litellm on launch
|
from aider.llm import litellm # noqa: F401; properly init litellm on launch
|
||||||
from aider.models import ModelSettings
|
from aider.models import ModelSettings
|
||||||
from aider.repo import ANY_GIT_ERROR, GitRepo
|
from aider.repo import ANY_GIT_ERROR, GitRepo
|
||||||
|
from aider.repo_directory import DirectoryRepo
|
||||||
from aider.report import report_uncaught_exceptions
|
from aider.report import report_uncaught_exceptions
|
||||||
from aider.versioncheck import check_version, install_from_main_branch, install_upgrade
|
from aider.versioncheck import check_version, install_from_main_branch, install_upgrade
|
||||||
from aider.watch import FileWatcher
|
from aider.watch import FileWatcher
|
||||||
|
@ -686,13 +687,8 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||||
git_dname = None
|
git_dname = None
|
||||||
if len(all_files) == 1:
|
if len(all_files) == 1:
|
||||||
if Path(all_files[0]).is_dir():
|
if Path(all_files[0]).is_dir():
|
||||||
if args.git:
|
git_dname = str(Path(all_files[0]).resolve())
|
||||||
git_dname = str(Path(all_files[0]).resolve())
|
fnames = []
|
||||||
fnames = []
|
|
||||||
else:
|
|
||||||
io.tool_error(f"{all_files[0]} is a directory, but --no-git selected.")
|
|
||||||
analytics.event("exit", reason="Directory with --no-git")
|
|
||||||
return 1
|
|
||||||
|
|
||||||
# We can't know the git repo for sure until after parsing the args.
|
# We can't know the git repo for sure until after parsing the args.
|
||||||
# If we guessed wrong, reparse because that changes things like
|
# If we guessed wrong, reparse because that changes things like
|
||||||
|
@ -861,6 +857,12 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||||
else:
|
else:
|
||||||
analytics.event("no-repo")
|
analytics.event("no-repo")
|
||||||
|
|
||||||
|
if not repo:
|
||||||
|
repo = DirectoryRepo(
|
||||||
|
git_dname,
|
||||||
|
args.aiderignore,
|
||||||
|
)
|
||||||
|
|
||||||
commands = Commands(
|
commands = Commands(
|
||||||
io,
|
io,
|
||||||
None,
|
None,
|
||||||
|
|
115
aider/repo_directory.py
Normal file
115
aider/repo_directory.py
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
import pathspec
|
||||||
|
from pathlib import Path, PurePosixPath
|
||||||
|
from aider import utils
|
||||||
|
|
||||||
|
class DirectoryRepo:
|
||||||
|
"""
|
||||||
|
A substitute for GitRepo; lets Aider run mostly full-featured without a git repo
|
||||||
|
(for instance, with another version-control tool like fossil).
|
||||||
|
"""
|
||||||
|
aider_ignore_file = None
|
||||||
|
aider_ignore_spec = None
|
||||||
|
aider_ignore_ts = 0
|
||||||
|
aider_ignore_last_check = 0
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
git_dname,
|
||||||
|
aider_ignore_file=None,
|
||||||
|
):
|
||||||
|
self.normalized_path_cache = {}
|
||||||
|
self.ignore_file_cache = {}
|
||||||
|
self.root = utils.safe_abs_path(Path(git_dname or ".").resolve())
|
||||||
|
if aider_ignore_file:
|
||||||
|
self.aider_ignore_file = Path(aider_ignore_file)
|
||||||
|
|
||||||
|
def commit(self, fnames=None, context=None, message=None, aider_edits=False):
|
||||||
|
return
|
||||||
|
|
||||||
|
def get_rel_repo_dir(self):
|
||||||
|
return "non-git directory"
|
||||||
|
|
||||||
|
def get_tracked_files(self):
|
||||||
|
files = []
|
||||||
|
for dirpath, _, filenames in os.walk(self.root):
|
||||||
|
for filename in filenames:
|
||||||
|
file_path = self.normalize_path(os.path.join(dirpath, filename))
|
||||||
|
if self.ignored_file(file_path):
|
||||||
|
continue
|
||||||
|
files.append(file_path)
|
||||||
|
return files
|
||||||
|
|
||||||
|
def normalize_path(self, path):
|
||||||
|
orig_path = path
|
||||||
|
res = self.normalized_path_cache.get(orig_path)
|
||||||
|
if res:
|
||||||
|
return res
|
||||||
|
|
||||||
|
path = str(Path(PurePosixPath((Path(self.root) / path).relative_to(self.root))))
|
||||||
|
self.normalized_path_cache[orig_path] = path
|
||||||
|
return path
|
||||||
|
|
||||||
|
def refresh_aider_ignore(self):
|
||||||
|
if not self.aider_ignore_file:
|
||||||
|
return
|
||||||
|
|
||||||
|
current_time = time.time()
|
||||||
|
if current_time - self.aider_ignore_last_check < 1:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.aider_ignore_last_check = current_time
|
||||||
|
|
||||||
|
if not self.aider_ignore_file.is_file():
|
||||||
|
return
|
||||||
|
|
||||||
|
mtime = self.aider_ignore_file.stat().st_mtime
|
||||||
|
if mtime != self.aider_ignore_ts:
|
||||||
|
self.aider_ignore_ts = mtime
|
||||||
|
self.ignore_file_cache = {}
|
||||||
|
lines = self.aider_ignore_file.read_text().splitlines()
|
||||||
|
self.aider_ignore_spec = pathspec.PathSpec.from_lines(
|
||||||
|
pathspec.patterns.GitWildMatchPattern,
|
||||||
|
lines,
|
||||||
|
)
|
||||||
|
|
||||||
|
def git_ignored_file(self, path):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def ignored_file(self, fname):
|
||||||
|
self.refresh_aider_ignore()
|
||||||
|
|
||||||
|
if fname in self.ignore_file_cache:
|
||||||
|
return self.ignore_file_cache[fname]
|
||||||
|
|
||||||
|
is_ignored = self.ignored_file_raw(fname)
|
||||||
|
self.ignore_file_cache[fname] = is_ignored
|
||||||
|
return is_ignored
|
||||||
|
|
||||||
|
def ignored_file_raw(self, fname):
|
||||||
|
try:
|
||||||
|
fname = self.normalize_path(fname)
|
||||||
|
except ValueError:
|
||||||
|
return True
|
||||||
|
|
||||||
|
if '.aider' in str(fname):
|
||||||
|
return True
|
||||||
|
|
||||||
|
if not self.aider_ignore_file or not self.aider_ignore_file.is_file():
|
||||||
|
return False
|
||||||
|
|
||||||
|
return self.aider_ignore_spec.match_file(fname)
|
||||||
|
|
||||||
|
def path_in_repo(self, path):
|
||||||
|
if not path:
|
||||||
|
return
|
||||||
|
|
||||||
|
tracked_files = set(self.get_tracked_files())
|
||||||
|
return self.normalize_path(path) in tracked_files
|
||||||
|
|
||||||
|
def get_dirty_files(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def is_dirty(self, path=None):
|
||||||
|
return False
|
Loading…
Add table
Add a link
Reference in a new issue