add file size and modify time
This commit is contained in:
@@ -46,6 +46,9 @@ async def a_main():
|
|||||||
fs = LocalStorage.from_config(stm)
|
fs = LocalStorage.from_config(stm)
|
||||||
async for rt in fs.sync_storage():
|
async for rt in fs.sync_storage():
|
||||||
print(rt)
|
print(rt)
|
||||||
|
async with FCTX(fs.open(PurePosixPath("app.txt"), "w")) as fp:
|
||||||
|
await fp.write(b"Hello Wyvern!")
|
||||||
|
await fs.set_last_modify_time(PurePosixPath("app.txt"), 0)
|
||||||
print(fs.dump_fs_tree())
|
print(fs.dump_fs_tree())
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|||||||
@@ -1,16 +1,22 @@
|
|||||||
from backup_box.storage.storage import AsyncFileReader, AsyncFileWriter
|
from backup_box.storage.storage import AsyncFileReader, AsyncFileWriter
|
||||||
from pathlib import PurePosixPath, PurePath
|
from pathlib import PurePath
|
||||||
from ..config import StorageItem
|
from ..config import StorageItem
|
||||||
from .vnode import VFileSystem, VFile, VDir, new_storage_dir, new_storage_file
|
from .vnode import VFileSystem, VFile, VDir, new_storage_dir, new_storage_file
|
||||||
from typing import Literal, overload
|
from typing import Literal, overload
|
||||||
from stat import S_ISDIR
|
from stat import S_ISDIR
|
||||||
from aiofiles import open
|
from aiofiles import open
|
||||||
from aiofiles.os import remove, rmdir, stat, listdir, mkdir
|
from aiofiles.os import remove, rmdir, stat, listdir, mkdir
|
||||||
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
|
from asyncio import get_event_loop
|
||||||
|
from os import utime as utime_sync
|
||||||
|
from functools import partial
|
||||||
|
from time import time
|
||||||
|
|
||||||
class LocalStorage(VFileSystem):
|
class LocalStorage(VFileSystem):
|
||||||
def __init__(self, base_path: str) -> None:
|
def __init__(self, base_path: str) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._base = PurePath(base_path)
|
self._base = PurePath(base_path)
|
||||||
|
self._exec = ThreadPoolExecutor(1)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_config(cls, cfg: StorageItem) -> "LocalStorage":
|
def from_config(cls, cfg: StorageItem) -> "LocalStorage":
|
||||||
@@ -60,13 +66,22 @@ class LocalStorage(VFileSystem):
|
|||||||
async def _on_create_node(self, node_path: list[VFile | VDir]) -> None:
|
async def _on_create_node(self, node_path: list[VFile | VDir]) -> None:
|
||||||
if len(node_path) > 0 and node_path[-1]["ty"] == "dir":
|
if len(node_path) > 0 and node_path[-1]["ty"] == "dir":
|
||||||
real_path = self._vnode_path_to_syspath(*node_path)
|
real_path = self._vnode_path_to_syspath(*node_path)
|
||||||
|
print(real_path)
|
||||||
await mkdir(real_path)
|
await mkdir(real_path)
|
||||||
|
|
||||||
|
async def _on_set_last_modify_time(self, node_path: list[VFile | VDir]) -> None:
|
||||||
|
if len(node_path) <= 0 or node_path[-1]["ty"] != "file":
|
||||||
|
raise IsADirectoryError()
|
||||||
|
real_path = self._vnode_path_to_syspath(*node_path)
|
||||||
|
await get_event_loop().run_in_executor(self._exec, utime_sync, real_path, (int(time()), node_path[-1]["mt"]))
|
||||||
|
|
||||||
@overload
|
@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
|
@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["w"]) -> AsyncFileWriter: ...
|
||||||
async def _on_open_node(self, node_path: list[VFile | VDir], mode: Literal["r"] | Literal["w"] = "r") -> AsyncFileWriter | AsyncFileReader:
|
async def _on_open_node(self, node_path: list[VFile | VDir], mode: Literal["r"] | Literal["w"] = "r") -> AsyncFileWriter | AsyncFileReader:
|
||||||
|
if len(node_path) <= 0:
|
||||||
|
raise IsADirectoryError()
|
||||||
real_path = self._vnode_path_to_syspath(*node_path)
|
real_path = self._vnode_path_to_syspath(*node_path)
|
||||||
if mode == "r":
|
if mode == "r":
|
||||||
return await open(real_path, "rb")
|
return await open(real_path, "rb")
|
||||||
@@ -74,8 +89,3 @@ class LocalStorage(VFileSystem):
|
|||||||
return await open(real_path, "wb")
|
return await open(real_path, "wb")
|
||||||
else:
|
else:
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -20,15 +20,17 @@ class AsyncFileWriter(Protocol):
|
|||||||
...
|
...
|
||||||
|
|
||||||
class AsyncFileContextManager[T](AbstractAsyncContextManager[T]):
|
class AsyncFileContextManager[T](AbstractAsyncContextManager[T]):
|
||||||
def __init__(self, fobj: T) -> None:
|
def __init__(self, fobj: Awaitable[T]) -> None:
|
||||||
self.__fobj = fobj
|
self.__fobj = fobj
|
||||||
|
self.__obj: T | None = None
|
||||||
|
|
||||||
async def __aenter__(self) -> T:
|
async def __aenter__(self) -> T:
|
||||||
return self.__fobj # type: ignore
|
self.__obj = await self.__fobj
|
||||||
|
return self.__obj # type: ignore
|
||||||
|
|
||||||
async def __aexit__(self, exc_type, exc, tb):
|
async def __aexit__(self, exc_type, exc, tb):
|
||||||
if hasattr(self.__fobj, "close"):
|
if hasattr(self.__obj, "close"):
|
||||||
func = getattr(self.__fobj, "close")
|
func = getattr(self.__obj, "close")
|
||||||
await func()
|
await func()
|
||||||
|
|
||||||
class Storage(ABC):
|
class Storage(ABC):
|
||||||
@@ -91,3 +93,18 @@ class Storage(ABC):
|
|||||||
def makedirs(self, path: PurePosixPath, exists_ok=False) -> Awaitable[None]:
|
def makedirs(self, path: PurePosixPath, exists_ok=False) -> Awaitable[None]:
|
||||||
""" create dir """
|
""" create dir """
|
||||||
...
|
...
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_file_size(self, path: PurePosixPath) -> Awaitable[int]:
|
||||||
|
""" get file size, can raise error for dir """
|
||||||
|
...
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_last_modify_time(self, path: PurePosixPath) -> Awaitable[int]:
|
||||||
|
""" get last modify time in seconds since unix time, can raise error for dir """
|
||||||
|
...
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def set_last_modify_time(self, path: PurePosixPath, timestamp: int) -> Awaitable[None]:
|
||||||
|
""" get last modify time in seconds since unix time, can raise error for dir """
|
||||||
|
...
|
||||||
@@ -7,7 +7,7 @@ from abc import abstractmethod
|
|||||||
class VFile(TypedDict):
|
class VFile(TypedDict):
|
||||||
ty: Literal["file"] # type
|
ty: Literal["file"] # type
|
||||||
n: str # virtual file name
|
n: str # virtual file name
|
||||||
mt: int # modify time
|
mt: int # modify time seconds
|
||||||
sz: int # size
|
sz: int # size
|
||||||
|
|
||||||
class VDir(TypedDict):
|
class VDir(TypedDict):
|
||||||
@@ -102,6 +102,13 @@ class VFileSystem(Storage):
|
|||||||
path = PurePosixPath( *(n["n"] for n in node_path) )
|
path = PurePosixPath( *(n["n"] for n in node_path) )
|
||||||
print("create:", path)
|
print("create:", path)
|
||||||
...
|
...
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def _on_set_last_modify_time(self, node_path: list[VFSItem]) -> None:
|
||||||
|
""" create a file or dir, parent dir is always created first. """
|
||||||
|
path = PurePosixPath( *(n["n"] for n in node_path) )
|
||||||
|
print("create:", path)
|
||||||
|
...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
@@ -240,6 +247,8 @@ class VFileSystem(Storage):
|
|||||||
build.append(node)
|
build.append(node)
|
||||||
await self._on_create_node(build)
|
await self._on_create_node(build)
|
||||||
# create dir
|
# create dir
|
||||||
|
if parent == self._root:
|
||||||
|
return
|
||||||
for n in parent["c"]:
|
for n in parent["c"]:
|
||||||
if n["n"] == path.name:
|
if n["n"] == path.name:
|
||||||
if not exists_ok:
|
if not exists_ok:
|
||||||
@@ -253,3 +262,25 @@ class VFileSystem(Storage):
|
|||||||
build.append(node)
|
build.append(node)
|
||||||
await self._on_create_node(build)
|
await self._on_create_node(build)
|
||||||
|
|
||||||
|
async def get_file_size(self, path: PurePosixPath) -> int:
|
||||||
|
node = find_vnode(self._root, path)[-1]
|
||||||
|
if node["ty"] == "file":
|
||||||
|
return node["sz"]
|
||||||
|
raise IsADirectoryError(path)
|
||||||
|
|
||||||
|
async def get_last_modify_time(self, path: PurePosixPath) -> int:
|
||||||
|
node = find_vnode(self._root, path)[-1]
|
||||||
|
if node["ty"] == "file":
|
||||||
|
return node["mt"]
|
||||||
|
else:
|
||||||
|
raise IsADirectoryError(path)
|
||||||
|
|
||||||
|
async def set_last_modify_time(self, path: PurePosixPath, timestamp: int):
|
||||||
|
""" get last modify time in seconds since unix time """
|
||||||
|
nodes = find_vnode(self._root, path)
|
||||||
|
node = nodes[-1]
|
||||||
|
if node["ty"] == "file":
|
||||||
|
node["mt"] = timestamp
|
||||||
|
await self._on_set_last_modify_time(nodes)
|
||||||
|
else:
|
||||||
|
raise IsADirectoryError(path)
|
||||||
|
|||||||
Reference in New Issue
Block a user