diff --git a/setup.py b/setup.py index 19bb2f2..2fe6d8a 100644 --- a/setup.py +++ b/setup.py @@ -3,6 +3,6 @@ setuptools.setup( name="xgit", packages=setuptools.find_packages(), - install_requires=["typer>=0.9.0"], + install_requires=["typer>=0.9.0", "rich", "typing_extensions"], entry_points={"console_scripts": ["xgit = xgit.cli:main"]}, ) diff --git a/xgit/cli.py b/xgit/cli.py index 7363af1..36f5732 100644 --- a/xgit/cli.py +++ b/xgit/cli.py @@ -1,6 +1,6 @@ import typer -from xgit.commands import init, cat_file, ls_files, hash_object +from xgit.commands import init, cat_file, ls_files, show_index, hash_object app = typer.Typer(add_completion=False, rich_markup_mode="markdown") @@ -9,6 +9,7 @@ app.command()(init.init) app.command()(cat_file.cat_file) app.command()(ls_files.ls_files) +app.command(hidden=True)(show_index.show_index) def main(): diff --git a/xgit/commands/show_index.py b/xgit/commands/show_index.py new file mode 100644 index 0000000..84293d0 --- /dev/null +++ b/xgit/commands/show_index.py @@ -0,0 +1,37 @@ +from typing import Optional +from pathlib import Path + +from typer import Option, Argument +from rich.pretty import pprint +from typing_extensions import Annotated + +from xgit.types.index import get_index +from xgit.utils.utils import find_repo + + +def show_index( + files: Annotated[Optional[list[str]], Argument(help="要展示的 entry,默认展示全部")] = None, + verbose: Annotated[bool, Option("-v", "--verbose", help="以详细模式展示 entry")] = False, +): + """ + 以可读的方式输出 index。只打印当前目录和子目录下在的 index 中的 entry,不打印父目录中的其他 entry。 + 这并非 git 本身支持的功能,只是为了方便调试和展示结果。 + """ + index = get_index() + + cwd = Path.cwd().resolve() + repo = find_repo().resolve() + + # 如果指定了 files,则只打印这些文件的 entry + if files: + file_paths = [Path(cwd / f).resolve() for f in files] + index.entries = [e for e in index.entries if repo / e.file_name in file_paths] + + # 只打印当前目录和子目录下在的 index 中的 entry + index.entries = [e for e in index.entries if Path(repo / e.file_name).is_relative_to(cwd)] + + if verbose: + for entry in index.entries: + entry.verbose = True + + pprint(index) diff --git a/xgit/types/index.py b/xgit/types/index.py index 2a46cb0..6c5f630 100644 --- a/xgit/types/index.py +++ b/xgit/types/index.py @@ -1,7 +1,7 @@ import hashlib from typing import Optional -from xgit.utils.utils import find_repo, get_repo_file +from xgit.utils.utils import find_repo, get_repo_file, timestamp_to_str from xgit.types.metadata import Metadata from xgit.utils.constants import GIT_DIR @@ -60,6 +60,12 @@ def to_bytes(self) -> bytes: data |= self.name_length return data.to_bytes(2, "big") + def __rich_repr__(self): + yield "assume_valid", self.assume_valid + yield "extended", self.extended + yield "stage", self.stage + yield "name_length", self.name_length + metadata: Metadata sha: str flags: Flag @@ -171,6 +177,32 @@ def to_bytes(self) -> bytes: return entry + # 以下用于 show-index 输出 + + verbose: bool = False + + def __rich_repr__(self): + if not self.verbose: + yield "file_name", self.file_name + yield "ctime", timestamp_to_str(self.metadata.ctime_s, self.metadata.ctime_ns) + yield "mtime", timestamp_to_str(self.metadata.mtime_s, self.metadata.mtime_ns) + yield "sha", self.sha + else: + yield "ctime_s", self.metadata.ctime_s + yield "ctime_ns", self.metadata.ctime_ns + yield "mtime_s", self.metadata.mtime_s + yield "mtime_ns", self.metadata.mtime_ns + yield "dev", self.metadata.dev + yield "inode", self.metadata.inode + yield "mode", oct(self.metadata.mode) + yield "uid", self.metadata.uid + yield "gid", self.metadata.gid + yield "file_size", self.metadata.file_size + yield "sha", self.sha + yield "flags", self.flags + yield "extended_flags", self.extended_flags + yield "file_name", self.file_name + class Index: version: int @@ -203,6 +235,12 @@ def to_bytes(self) -> bytes: index += hashlib.sha1(index).digest() return index + def __rich_repr__(self): + yield "version", self.version + yield "entry_count", self.entry_count + yield "entries", self.entries + yield "extensions", self.extensions + def get_index() -> Index: """ diff --git a/xgit/utils/utils.py b/xgit/utils/utils.py index f117249..5c6ee48 100644 --- a/xgit/utils/utils.py +++ b/xgit/utils/utils.py @@ -1,4 +1,5 @@ import sys +import datetime from pathlib import Path import typer @@ -39,3 +40,10 @@ def get_object(obj: str): def check_exist(obj: str) -> bool: object_file = get_object(obj) return object_file.exists() + + +def timestamp_to_str(time_s, time_ns): + dt = datetime.datetime.fromtimestamp(time_s) + microseconds = time_ns // 1000 + dt = dt + datetime.timedelta(microseconds=microseconds) + return dt.strftime("%Y-%m-%d %H:%M:%S.%f")