diff --git a/libwyag.py b/libwyag.py index 438f6ac..33b5b79 100644 --- a/libwyag.py +++ b/libwyag.py @@ -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)