mirror of
https://github.com/Aider-AI/aider.git
synced 2025-05-31 09:44:59 +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.message_cost = 0
|
||||
|
||||
if self.repo:
|
||||
if isinstance(self.repo, GitRepo):
|
||||
self.commit_before_message.append(self.repo.get_head_commit_sha())
|
||||
|
||||
def run(self, with_message=None, preproc=True):
|
||||
|
@ -1935,7 +1935,7 @@ class Coder:
|
|||
return all_files - inchat_files - read_only_files
|
||||
|
||||
def check_for_dirty_commit(self, path):
|
||||
if not self.repo:
|
||||
if not isinstance(self.repo, GitRepo):
|
||||
return
|
||||
if not self.dirty_commits:
|
||||
return
|
||||
|
@ -2135,7 +2135,7 @@ class Coder:
|
|||
return context
|
||||
|
||||
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
|
||||
|
||||
if not context:
|
||||
|
@ -2175,7 +2175,7 @@ class Coder:
|
|||
return
|
||||
if not self.dirty_commits:
|
||||
return
|
||||
if not self.repo:
|
||||
if not isinstance(self.repo, GitRepo):
|
||||
return
|
||||
|
||||
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.help import Help, install_help_extra
|
||||
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.scrape import Scraper, install_playwright
|
||||
from aider.utils import is_image_file
|
||||
|
@ -282,7 +282,7 @@ class Commands:
|
|||
self.io.tool_error(f"Unable to complete commit: {err}")
|
||||
|
||||
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.")
|
||||
return
|
||||
|
||||
|
@ -296,7 +296,7 @@ class Commands:
|
|||
def cmd_lint(self, args="", fnames=None):
|
||||
"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.")
|
||||
return
|
||||
|
||||
|
@ -483,7 +483,7 @@ class Commands:
|
|||
self.io.tool_error(f"Unable to complete undo: {err}")
|
||||
|
||||
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.")
|
||||
return
|
||||
|
||||
|
@ -585,7 +585,7 @@ class Commands:
|
|||
self.io.tool_error(f"Unable to complete diff: {err}")
|
||||
|
||||
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.")
|
||||
return
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ from aider.io import InputOutput
|
|||
from aider.llm import litellm # noqa: F401; properly init litellm on launch
|
||||
from aider.models import ModelSettings
|
||||
from aider.repo import ANY_GIT_ERROR, GitRepo
|
||||
from aider.repo_directory import DirectoryRepo
|
||||
from aider.report import report_uncaught_exceptions
|
||||
from aider.versioncheck import check_version, install_from_main_branch, install_upgrade
|
||||
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
|
||||
if len(all_files) == 1:
|
||||
if Path(all_files[0]).is_dir():
|
||||
if args.git:
|
||||
git_dname = str(Path(all_files[0]).resolve())
|
||||
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
|
||||
git_dname = str(Path(all_files[0]).resolve())
|
||||
fnames = []
|
||||
|
||||
# We can't know the git repo for sure until after parsing the args.
|
||||
# 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:
|
||||
analytics.event("no-repo")
|
||||
|
||||
if not repo:
|
||||
repo = DirectoryRepo(
|
||||
git_dname,
|
||||
args.aiderignore,
|
||||
)
|
||||
|
||||
commands = Commands(
|
||||
io,
|
||||
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