LocalStorage mapped to real fs
This commit is contained in:
@@ -37,8 +37,13 @@ async def a_main():
|
||||
print("Config:", config.get_config())
|
||||
print("Hello World")
|
||||
from .storage.local_storage import LocalStorage
|
||||
from .storage.storage import AsyncFileContextManager as FCTX
|
||||
from pathlib import PurePosixPath
|
||||
fs = LocalStorage(r"D:\AuberyZhao\BackupBox\backup_box")
|
||||
cfg = config.get_config()
|
||||
stm: config.StorageItem = { "type": "LocalStorageItem", "path": "" }
|
||||
for stm in cfg["storage"].values():
|
||||
break
|
||||
fs = LocalStorage.from_config(stm)
|
||||
async for rt in fs.sync_storage():
|
||||
print(rt)
|
||||
print(fs.dump_fs_tree())
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
from backup_box.storage.storage import AsyncFileReader, AsyncFileWriter
|
||||
from pathlib import PurePath, PurePosixPath
|
||||
from pathlib import PurePosixPath, PurePath
|
||||
from ..config import StorageItem
|
||||
from .vnode import VFileSystem, VFile, VDir
|
||||
from .vnode import VFileSystem, VFile, VDir, new_storage_dir, new_storage_file
|
||||
from typing import Literal, overload
|
||||
from stat import S_ISDIR
|
||||
from aiofiles import open
|
||||
from aiofiles.os import remove, rmdir, stat, listdir, mkdir
|
||||
|
||||
class LocalStorage(VFileSystem):
|
||||
def __init__(self, base_path: str) -> None:
|
||||
@@ -15,7 +18,7 @@ class LocalStorage(VFileSystem):
|
||||
raise ValueError("config type mismatch!")
|
||||
return LocalStorage(cfg["path"])
|
||||
|
||||
def _vnode_path_to_syspath(self, *path: VFile | VDir):
|
||||
def _vnode_path_to_syspath(self, *path: VFile | VDir) -> PurePath:
|
||||
filtered = []
|
||||
# filter abslute path
|
||||
for n in path:
|
||||
@@ -25,33 +28,53 @@ class LocalStorage(VFileSystem):
|
||||
if name in [".", "..", ""]:
|
||||
continue
|
||||
filtered.append(name)
|
||||
return self._base.joinpath(*filtered)
|
||||
return PurePath(self._base.joinpath(*filtered))
|
||||
|
||||
async def _fill_vnode_with_real_fs(self, vparent: VDir, real_path: PurePath):
|
||||
try:
|
||||
for name in await listdir(real_path):
|
||||
p = real_path.joinpath(name)
|
||||
st = await stat(p)
|
||||
if S_ISDIR(st.st_mode):
|
||||
child_node = new_storage_dir(name)
|
||||
await self._fill_vnode_with_real_fs(child_node, p)
|
||||
else:
|
||||
child_node = new_storage_file(name, int(st.st_mtime), st.st_size)
|
||||
vparent["c"].append(child_node)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
async def sync_storage(self):
|
||||
curr = 0
|
||||
total = 1
|
||||
parents: list[VDir] = []
|
||||
self._root["c"].clear()
|
||||
node = self._root
|
||||
yield curr, total
|
||||
while True:
|
||||
if node["ty"] == "dir":
|
||||
pass
|
||||
if len(parents) <= 0:
|
||||
break
|
||||
await self._fill_vnode_with_real_fs(self._root, self._base)
|
||||
yield 1, 1
|
||||
|
||||
async def _on_remove_node(self, node_path: list[VFile | VDir]) -> None:
|
||||
raise NotImplementedError
|
||||
real_path = self._vnode_path_to_syspath(*node_path)
|
||||
st = await stat(real_path)
|
||||
if S_ISDIR(st.st_mode):
|
||||
await rmdir(real_path)
|
||||
else:
|
||||
await remove(real_path)
|
||||
|
||||
async def _on_create_node(self, node_path: list[VFile | VDir]) -> None:
|
||||
raise NotImplementedError
|
||||
if len(node_path) > 0 and node_path[-1]["ty"] == "dir":
|
||||
real_path = self._vnode_path_to_syspath(*node_path)
|
||||
await mkdir(real_path)
|
||||
|
||||
@overload
|
||||
async def _on_open_node(self, node_path: list[VFile | VDir], mode: Literal['r'] = "r") -> AsyncFileReader: ...
|
||||
async def _on_open_node(self, node_path: list[VFile | VDir], mode: Literal["r"] = "r") -> AsyncFileReader: ...
|
||||
@overload
|
||||
async def _on_open_node(self, node_path: list[VFile | VDir], mode: Literal['w']) -> AsyncFileWriter: ...
|
||||
async def _on_open_node(self, node_path: list[VFile | VDir], mode: Literal['r'] | Literal['w'] = "r") -> AsyncFileWriter | AsyncFileReader:
|
||||
raise NotImplementedError
|
||||
async def _on_open_node(self, node_path: list[VFile | VDir], mode: Literal["w"]) -> AsyncFileWriter: ...
|
||||
async def _on_open_node(self, node_path: list[VFile | VDir], mode: Literal["r"] | Literal["w"] = "r") -> AsyncFileWriter | AsyncFileReader:
|
||||
real_path = self._vnode_path_to_syspath(*node_path)
|
||||
if mode == "r":
|
||||
return await open(real_path, "rb")
|
||||
elif mode == "w":
|
||||
return await open(real_path, "wb")
|
||||
else:
|
||||
raise ValueError()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2,24 +2,34 @@ from ..config import StorageItem
|
||||
from abc import ABC, abstractmethod
|
||||
from pathlib import PurePosixPath
|
||||
from collections.abc import Awaitable, AsyncIterable
|
||||
from typing import overload, Literal, Protocol, SupportsBytes
|
||||
from contextlib import AbstractAsyncContextManager
|
||||
from typing import overload, Literal, Protocol, SupportsBytes, Self, runtime_checkable
|
||||
|
||||
class AsyncFileReader(Protocol):
|
||||
async def read(self, n: int = -1) -> bytes:
|
||||
async def read(self, n: int = -1, /) -> bytes:
|
||||
...
|
||||
|
||||
async def close(self) -> None:
|
||||
...
|
||||
|
||||
class AsyncFileWriter(Protocol):
|
||||
async def write(self, s: SupportsBytes) -> int:
|
||||
async def write(self, s: SupportsBytes, /) -> int:
|
||||
...
|
||||
|
||||
async def close(self) -> None:
|
||||
...
|
||||
|
||||
class AsyncFileLike(AsyncFileReader, AsyncFileWriter):
|
||||
...
|
||||
class AsyncFileContextManager[T](AbstractAsyncContextManager[T]):
|
||||
def __init__(self, fobj: T) -> None:
|
||||
self.__fobj = fobj
|
||||
|
||||
async def __aenter__(self) -> T:
|
||||
return self.__fobj # type: ignore
|
||||
|
||||
async def __aexit__(self, exc_type, exc, tb):
|
||||
if hasattr(self.__fobj, "close"):
|
||||
func = getattr(self.__fobj, "close")
|
||||
await func()
|
||||
|
||||
class Storage(ABC):
|
||||
@classmethod
|
||||
@@ -28,7 +38,7 @@ class Storage(ABC):
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def from_config(cls, cfg: StorageItem) -> 'Storage':
|
||||
def from_config(cls, cfg: StorageItem) -> Self:
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
|
||||
Reference in New Issue
Block a user