diff --git a/src/dirmonitor.py b/src/dirmonitor.py index 926ad50..3b0cce4 100644 --- a/src/dirmonitor.py +++ b/src/dirmonitor.py @@ -36,6 +36,73 @@ def walk(self, root: str) -> Iterator[tuple[str, os.stat_result]]: yield from self.walk(path) class _DirectorySnapshotDiff(DirectorySnapshotDiff): + def __init__( + self, + ref: DirectorySnapshot, + snapshot: DirectorySnapshot, + *, + ignore_device: bool = False, + ) -> None: + super().__init__(ref, snapshot, ignore_device=ignore_device) + created = snapshot.paths - ref.paths + deleted = ref.paths - snapshot.paths + + if ignore_device: + + def get_inode(directory: DirectorySnapshot, full_path: bytes | str) -> int | tuple[int, int]: + return directory.inode(full_path)[0] + + else: + + def get_inode(directory: DirectorySnapshot, full_path: bytes | str) -> int | tuple[int, int]: + return directory.inode(full_path) + + # check that all unchanged paths have the same inode + for path in ref.paths & snapshot.paths: + if get_inode(ref, path) != get_inode(snapshot, path): + created.add(path) + deleted.add(path) + + # find moved paths + moved: set[tuple[bytes | str, bytes | str]] = set() + for path in set(deleted): + inode = ref.inode(path) + new_path = snapshot.path(inode) + if new_path and ref.mtime(path) == snapshot.mtime(new_path): + # file is not deleted but moved + deleted.remove(path) + moved.add((path, new_path)) + + for path in set(created): + inode = snapshot.inode(path) + old_path = ref.path(inode) + if old_path and ref.mtime(old_path) == snapshot.mtime(path): + created.remove(path) + moved.add((old_path, path)) + + # find modified paths + # first check paths that have not moved + modified: set[bytes | str] = set() + for path in ref.paths & snapshot.paths: + if get_inode(ref, path) == get_inode(snapshot, path) and ( + ref.mtime(path) != snapshot.mtime(path) or ref.size(path) != snapshot.size(path) + ): + modified.add(path) + + for old_path, new_path in moved: + if ref.mtime(old_path) != snapshot.mtime(new_path) or ref.size(old_path) != snapshot.size(new_path): + modified.add(old_path) + + self._dirs_created = [path for path in created if snapshot.isdir(path)] + self._dirs_deleted = [path for path in deleted if ref.isdir(path)] + self._dirs_modified = [path for path in modified if ref.isdir(path)] + self._dirs_moved = [(frm, to) for (frm, to) in moved if ref.isdir(frm)] + + self._files_created = list(created - set(self._dirs_created)) + self._files_deleted = list(deleted - set(self._dirs_deleted)) + self._files_modified = list(modified - set(self._dirs_modified)) + self._files_moved = list(moved - set(self._dirs_moved)) + @property def files_moved(self) -> list[dict[str, bytes | str]]: """重写 files_moved 方法,直接构造moved所需要的字典"""