complete base file and directory models

This commit is contained in:
L-Nafaryus 2024-08-05 18:29:03 +05:00
parent 9986429bdf
commit aefedfe187
Signed by: L-Nafaryus
GPG Key ID: 553C97999B363D38
4 changed files with 89 additions and 101 deletions

View File

@ -16,6 +16,8 @@ from materia.models.database import (
from materia.models.user import User, UserCredentials, UserInfo from materia.models.user import User, UserCredentials, UserInfo
from materia.models.filesystem import FileSystem
from materia.models.repository import ( from materia.models.repository import (
Repository, Repository,
RepositoryInfo, RepositoryInfo,

View File

@ -47,22 +47,19 @@ class Directory(Base):
await session.flush() await session.flush()
await session.refresh(self, attribute_names=["repository"]) await session.refresh(self, attribute_names=["repository"])
relative_path = await self.relative_path(session) repository_path = await self.repository.path(session, config)
directory_path = await self.path(session, config) directory_path = await self.path(session, config)
try: new_directory = FileSystem(directory_path, repository_path)
directory_path.mkdir() await new_directory.make_directory()
except OSError as e:
raise DirectoryError(
f"Failed to create directory at /{relative_path}:",
*e.args,
)
return self return self
async def remove(self, session: SessionContext, config: Config): async def remove(self, session: SessionContext, config: Config):
session.add(self) session.add(self)
await session.refresh(self, attribute_names=["directories", "files"]) await session.refresh(
self, attribute_names=["repository", "directories", "files"]
)
if self.directories: if self.directories:
for directory in self.directories: for directory in self.directories:
@ -72,15 +69,11 @@ class Directory(Base):
for file in self.files: for file in self.files:
file.remove(session, config) file.remove(session, config)
relative_path = await self.relative_path(session) repository_path = await self.repository.path(session, config)
directory_path = await self.path(session, config) directory_path = await self.path(session, config)
try: current_directory = FileSystem(directory_path, repository_path)
shutil.rmtree(str(directory_path)) await current_directory.remove()
except OSError as e:
raise DirectoryError(
f"Failed to remove directory at /{relative_path}:", *e.args
)
await session.delete(self) await session.delete(self)
await session.flush() await session.flush()
@ -153,38 +146,59 @@ class Directory(Base):
async def copy( async def copy(
self, directory: Optional["Directory"], session: SessionContext, config: Config self, directory: Optional["Directory"], session: SessionContext, config: Config
) -> Self: ) -> Self:
pass session.add(self)
await session.refresh(self, attribute_names=["repository"])
repository_path = await self.repository.path(session, config)
directory_path = await self.path(session, config)
directory_path = (
await directory.path(session, config) if directory else repository_path
)
current_directory = FileSystem(directory_path, repository_path)
new_directory = await current_directory.copy(directory_path)
cloned = self.clone()
cloned.name = new_directory.name()
cloned.parent_id = directory.id if directory else None
session.add(cloned)
await session.flush()
return self
async def move( async def move(
self, directory: Optional["Directory"], session: SessionContext, config: Config self, directory: Optional["Directory"], session: SessionContext, config: Config
) -> Self: ) -> Self:
pass session.add(self)
await session.refresh(self, attribute_names=["repository"])
repository_path = await self.repository.path(session, config)
directory_path = await self.path(session, config)
directory_path = (
await directory.path(session, config) if directory else repository_path
)
current_directory = FileSystem(directory_path, repository_path)
moved_directory = await current_directory.move(directory_path)
self.name = moved_directory.name()
self.parent_id = directory.id if directory else None
self.updated = time()
await session.flush()
return self
async def rename(self, name: str, session: SessionContext, config: Config) -> Self: async def rename(self, name: str, session: SessionContext, config: Config) -> Self:
session.add(self) session.add(self)
await session.refresh(self, attribute_names=["repository"])
repository_path = await self.repository.path(session, config)
directory_path = await self.path(session, config) directory_path = await self.path(session, config)
relative_path = await self.relative_path(session)
new_path = directory_path.with_name(name)
identity = 1
while True: current_directory = FileSystem(directory_path, repository_path)
if new_path == directory_path: renamed_directory = await current_directory.rename(name, force=True)
break
if not new_path.exists():
break
new_path = directory_path.with_name(f"{name}.{str(identity)}") self.name = renamed_directory.name()
identity += 1
try:
await aiofiles.os.rename(directory_path, new_path)
except OSError as e:
raise DirectoryError(
f"Failed to rename directory at /{relative_path}", *e.args
)
self.name = new_path.name
await session.flush() await session.flush()
return self return self
@ -222,3 +236,4 @@ class DirectoryInfo(BaseModel):
from materia.models.repository import Repository from materia.models.repository import Repository
from materia.models.file import File from materia.models.file import File
from materia.models.filesystem import FileSystem

View File

@ -47,18 +47,12 @@ class File(Base):
await session.flush() await session.flush()
await session.refresh(self, attribute_names=["repository"]) await session.refresh(self, attribute_names=["repository"])
relative_path = await self.relative_path(session)
file_path = await self.path(session, config) file_path = await self.path(session, config)
size = None
try: new_file = FileSystem(file_path, await self.repository.path(session, config))
async with aiofiles.open(file_path, mode="wb") as file: await new_file.write_file(data)
await file.write(data)
size = (await aiofiles.os.stat(file_path)).st_size
except OSError as e:
raise FileError(f"Failed to write file at /{relative_path}", *e.args)
self.size = size self.size = await new_file.size()
await session.flush() await session.flush()
return self return self
@ -66,13 +60,10 @@ class File(Base):
async def remove(self, session: SessionContext, config: Config): async def remove(self, session: SessionContext, config: Config):
session.add(self) session.add(self)
relative_path = await self.relative_path(session)
file_path = await self.path(session, config) file_path = await self.path(session, config)
try: new_file = FileSystem(file_path, await self.repository.path(session, config))
await aiofiles.os.remove(file_path) await new_file.remove()
except OSError as e:
raise FileError(f"Failed to remove file at /{relative_path}:", *e.args)
await session.delete(self) await session.delete(self)
await session.flush() await session.flush()
@ -149,15 +140,12 @@ class File(Base):
directory_path = ( directory_path = (
await directory.path(session, config) if directory else repository_path await directory.path(session, config) if directory else repository_path
) )
new_path = File.generate_name(file_path, directory_path, self.name)
try: current_file = FileSystem(file_path, repository_path)
await aioshutil.copy(file_path, new_path) new_file = await current_file.copy(directory_path)
except OSError as e:
raise FileError("Failed to move file:", *e.args)
cloned = self.clone() cloned = self.clone()
cloned.name = new_path.name cloned.name = new_file.name()
cloned.parent_id = directory.id if directory else None cloned.parent_id = directory.id if directory else None
session.add(cloned) session.add(cloned)
await session.flush() await session.flush()
@ -175,51 +163,28 @@ class File(Base):
directory_path = ( directory_path = (
await directory.path(session, config) if directory else repository_path await directory.path(session, config) if directory else repository_path
) )
new_path = File.generate_name(file_path, directory_path, self.name)
try: current_file = FileSystem(file_path, repository_path)
await aioshutil.move(file_path, new_path) moved_file = await current_file.move(directory_path)
except OSError as e:
raise FileError("Failed to move file:", *e.args)
self.name = new_path.name self.name = moved_file.name()
self.parent_id = directory.id if directory else None self.parent_id = directory.id if directory else None
self.updated = time() self.updated = time()
await session.flush() await session.flush()
return self return self
@staticmethod
def generate_name(old_file: Path, target_directory: Path, name: str) -> Path:
new_path = target_directory.joinpath(name)
identity = 1
while True:
if new_path == old_file:
break
if not new_path.exists():
break
new_path = target_directory.joinpath(
f"{name.removesuffix(new_path.suffix)}.{str(identity)}{new_path.suffix}"
)
identity += 1
return new_path
async def rename(self, name: str, session: SessionContext, config: Config) -> Self: async def rename(self, name: str, session: SessionContext, config: Config) -> Self:
session.add(self) session.add(self)
await session.refresh(self, attribute_names=["repository"])
repository_path = await self.repository.path(session, config)
file_path = await self.path(session, config) file_path = await self.path(session, config)
relative_path = await self.relative_path(session)
new_path = File.generate_name(file_path, file_path.parent, name)
try: current_file = FileSystem(file_path, repository_path)
await aiofiles.os.rename(file_path, new_path) renamed_file = await current_file.rename(name, force=True)
except OSError as e:
raise FileError(f"Failed to rename file at /{relative_path}", *e.args)
self.name = new_path.name self.name = renamed_file.name()
self.updated = time() self.updated = time()
await session.flush() await session.flush()
return self return self
@ -263,3 +228,4 @@ class FileInfo(BaseModel):
from materia.models.repository import Repository from materia.models.repository import Repository
from materia.models.directory import Directory from materia.models.directory import Directory
from materia.models.filesystem import FileSystem

View File

@ -44,6 +44,9 @@ class FileSystem:
async def is_directory(self) -> bool: async def is_directory(self) -> bool:
return await async_path.isdir(self.path) return await async_path.isdir(self.path)
def name(self) -> str:
return self.path.name
async def remove(self): async def remove(self):
try: try:
if await self.is_file(): if await self.is_file():
@ -67,18 +70,18 @@ class FileSystem:
return name return name
while await async_path.exists(new_path): while await async_path.exists(new_path):
if self.is_file(): if await self.is_file():
if with_counter := re.match(r"^(.+)(\.\d+)(\.\w+)$", new_path.name): if with_counter := re.match(r"^(.+)\.(\d+)\.(\w+)$", new_path.name):
new_name, _, extension = with_counter.groups() new_name, _, extension = with_counter.groups()
elif with_extension := re.match(r"^(.+)(\.\w+)$", new_path.name): elif with_extension := re.match(r"^(.+)\.(\w+)$", new_path.name):
new_name, extension = with_extension.groups() new_name, extension = with_extension.groups()
new_path = target_directory.joinpath( new_path = target_directory.joinpath(
"{}.{}.{}".format(new_name, count, extension) "{}.{}.{}".format(new_name, count, extension)
) )
if self.is_directory(): if await self.is_directory():
if with_counter := re.match(r"^(.+)(\.\d+)$", new_path.name): if with_counter := re.match(r"^(.+)\.(\d+)$", new_path.name):
new_name, _ = with_counter.groups() new_name, _ = with_counter.groups()
else: else:
new_name = new_path.name new_name = new_path.name
@ -106,12 +109,10 @@ class FileSystem:
"Failed to move content to target destination: already exists" "Failed to move content to target destination: already exists"
) )
await aioshutil.move( new_path = target_directory.joinpath(
self.path, await self.generate_name(target_directory, new_name)
target_directory.joinpath(
await self.generate_name(target_directory, new_name)
),
) )
await aioshutil.move(self.path, new_path)
except Exception as e: except Exception as e:
raise FileSystemError( raise FileSystemError(
@ -119,15 +120,17 @@ class FileSystem:
*e.args, *e.args,
) )
async def rename(self, new_name: str, force: bool = False): return FileSystem(new_path, self.working_directory)
await self.move(self.path.parent, new_name=new_name, force=force)
async def rename(self, new_name: str, force: bool = False) -> Path:
return await self.move(self.path.parent, new_name=new_name, force=force)
async def copy( async def copy(
self, self,
target_directory: Path, target_directory: Path,
new_name: Optional[str] = None, new_name: Optional[str] = None,
force: bool = False, force: bool = False,
): ) -> Self:
new_name = new_name if new_name else self.path.name new_name = new_name if new_name else self.path.name
try: try:
@ -155,6 +158,8 @@ class FileSystem:
*e.args, *e.args,
) )
return FileSystem(new_path, self.working_directory)
async def make_directory(self): async def make_directory(self):
try: try:
if await self.exists(): if await self.exists():