Add 'rm' command

This commit is contained in:
Nathan McRae 2024-07-08 20:50:55 -07:00
parent bad433b264
commit 326864ecda

View File

@ -48,7 +48,7 @@ class GitRepository (object):
conf = None
def __init__(self, path, force=False):
self.worktree = path
self.worktree = path.replace("\\", "/")
self.gitdir = join_path(path, ".git")
if not (force or os.path.isdir(self.gitdir)):
@ -1197,3 +1197,97 @@ def cmd_status_index_worktree(repo, index):
# its name without its contents.
if not check_ignore(ignore, f):
print(" ", f)
def index_write(repo, index):
with open(GitRepository.repo_file(repo, "index"), "wb") as f:
# Header
# Magic bytes which identify the file type.
f.write(b"DIRC")
f.write(index.version.to_bytes(4, "big"))
f.write(len(index.entries).to_bytes(4, "big"))
# Entries
idx = 0
for e in index.entries:
f.write(e.ctime[0].to_bytes(4, "big"))
f.write(e.ctime[1].to_bytes(4, "big"))
f.write(e.mtime[0].to_bytes(4, "big"))
f.write(e.mtime[1].to_bytes(4, "big"))
f.write(e.dev.to_bytes(4, "big"))
f.write(e.ino.to_bytes(4, "big"))
mode = (e.mode_type << 12) | e.mode_perms
f.write(mode.to_bytes(4, "big"))
f.write(e.uid.to_bytes(4, "big"))
# FIXME: Convert back to int.
f.write(int(e.sha, 16).to_bytes(20, "big"))
flag_assume_valid = 0x1 << 15 if e.flag_assume_valid else 0
name_bytes = e.name.encode("utf8")
bytes_len = len(name_bytes)
if bytes_len >= 0xFFF:
name_length = 0xFFF
else:
name_length = bytes_len
f.write((flag_assume_valid | e.flag_stage | name_length).to_bytes(2, "big"))
f.write(name_bytes)
# Null-terminate the name string
f.write((0).to_bytes(1, "big"))
idx += 62 + len(name_bytes) + 1
# Add padding if necessary
if idx % 8 != 0:
pad = 8 - (idx % 8)
f.write((0).to_bytes(pad, "big"))
idx += pad
argsp = argsubparsers.add_parser("rm", help="Remove files from the working tree and the index.")
argsp.add_argument("path", nargs="+", help="Files to remove")
def cmd_rm(args):
repo = repo_find()
rm(repo, args.path)
def rm(repo, paths, delete=True, skip_missing=False):
index = index_read(repo)
worktree = repo.worktree.replace("\\", "/") + "/"
# Make paths absolute
abspaths = list()
for path in paths:
abspath = os.path.abspath(path).replace("\\", "/")
if abspath.startswith(worktree):
abspaths.append(abspath)
else:
raise Exception(f"Cannot remove paths outside of worktree: {path}")
kept_entries = list()
remove = list()
for e in index.entries:
full_path = join_path(repo.worktree, e.name)
if full_path in abspaths:
remove.append(full_path)
abspaths.remove(full_path)
else:
kept_entries.append(e)
if len(abspaths) > 0 and not skip_missing:
raise Exception(f"Cannot remove paths not in the index: {abspaths}")
if delete:
for path in remove:
os.unlink(path)
index.entries = kept_entries
index_write(repo, index)