Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 23 additions & 47 deletions cterasdk/asynchronous/core/files/browser.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from .. import query
from ....cio.core.commands import Open, OpenMany, Upload, Download, EnsureDirectory, \
DownloadMany, UnShare, CreateDirectory, GetMetadata, GetProperties, ListVersions, RecursiveIterator, \
from ....cio.core.commands import Open, Upload, Download, EnsureDirectory, \
UnShare, CreateDirectory, GetMetadata, GetProperties, ListVersions, RecursiveIterator, \
Delete, Recover, Rename, GetShareMetadata, Link, Copy, Move, ResourceIterator, GetPermalink, GetExternalShareInfo
from ....cio.core.types import InvitationPath
from ....lib.storage import commonfs
Expand All @@ -11,60 +11,39 @@
class FileBrowser(BaseCommand):
"""Async File Browser API."""

async def handle(self, path):
async def handle(self, path, objects):
"""
Get a file handle.

:param str path: Path to a file.
:param list[str],optional objects: Files and folders to include.
:returns: File handle.
:rtype: object
:raises cterasdk.exceptions.io.core.OpenError: Raised on error to obtain file handle.
:raises cterasdk.exceptions.io.core.OpenError: Raised on error to obtain a file handle.
:raises cterasdk.exceptions.io.core.GetMetadataError: If the directory was not found.
:raises cterasdk.exceptions.io.core.NotADirectoryException: If the target path is not a directory.
"""
return await Open(io.handle, self._core, path).a_execute()
async with GetProperties(io.listdir, self._core, path) as properties:
return await Open(io.handle_many if properties.is_dir else io.handle, self._core,
properties.path, properties, objects).a_execute()

async def handle_many(self, directory, *objects):
"""
Get a ZIP archive file handle.

:param str directory: Path to a folder.
:param args objects: List of files and folders to include.
:returns: File handle.
:rtype: object
:raises cterasdk.exceptions.io.core.GetMetadataError: If directory not found.
:raises cterasdk.exceptions.io.core.NotADirectoryException: If target path is not a directory.
"""
async with EnsureDirectory(io.listdir, self._core, directory) as (_, resource):
return await OpenMany(io.handle_many, self._core, resource, directory, *objects).a_execute()

async def download(self, path, destination=None):
async def download(self, path, objects=None, destination=None):
"""
Download a file.

:param str path: Path.
:param str, optional destination: File destination. If directory, original filename preserved. Defaults to default directory.
:returns: Path to local file.
:param list[str],optional objects: List of files and / or directory names to download.
:param str, optional destination: File destination. If a directory is provided, the original filename is preserved.
Defaults to the default download directory.
:returns: Path to the local file.
:rtype: str
:raises cterasdk.exceptions.io.core.OpenError: Raised on error to obtain file handle.
:raises cterasdk.exceptions.io.core.OpenError: Raised on error to obtain a file handle.
:raises cterasdk.exceptions.io.core.GetMetadataError: If the directory was not found.
:raises cterasdk.exceptions.io.core.NotADirectoryException: If the target path is not a directory.
"""
return await Download(io.handle, self._core, path, destination).a_execute()

async def download_many(self, directory, objects, destination=None):
"""
Download selected files and/or directories as a ZIP archive.

.. warning::
Only existing files and directories will be included in the resulting ZIP file.

:param str directory: Path to a folder.
:param list[str] objects: List of files and / or directory names to download.
:param str destination: Optional path to destination file or directory. Defaults to default download directory.
:returns: Path to local file.
:rtype: str
:raises cterasdk.exceptions.io.core.GetMetadataError: If directory not found.
:raises cterasdk.exceptions.io.core.NotADirectoryException: If target path is not a directory.
"""
async with EnsureDirectory(io.listdir, self._core, directory) as (_, resource):
return await DownloadMany(io.handle_many, self._core, resource, directory, objects, destination).a_execute()
async with GetProperties(io.listdir, self._core, path) as properties:
return await Download(io.handle_many if properties.is_dir else io.handle, self._core,
properties.path, properties, objects, destination).a_execute()

async def listdir(self, path=None, include_deleted=False):
"""
Expand Down Expand Up @@ -383,11 +362,8 @@ async def mkdir(self, path):
async def makedirs(self, path):
return await self._file_browser.makedirs(self._invitation.join(path))

async def download(self, path, destination=None):
return await self._file_browser.download(self._invitation.join(path), destination)

async def download_many(self, directory, objects, destination=None):
return await self._file_browser.download_many(self._invitation.join(directory), objects, destination)
async def download(self, path, objects=None, destination=None):
return await self._file_browser.download(self._invitation.join(path), objects, destination)

async def upload(self, destination, handle, name=None, size=None):
return await self._file_browser.upload(self._invitation.join(destination), handle, name, size)
Expand Down
102 changes: 34 additions & 68 deletions cterasdk/cio/core/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,24 +356,42 @@ def obtain_current_accounts(collaborators):
class Open(PortalCommand):
"""Open file"""

def __init__(self, function, receiver, path):
def __init__(self, function, receiver, path, properties, objects):
super().__init__(function, receiver)
self.path = automatic_resolution(path, receiver.context)
self.properties = properties
self.objects = objects or []

def get_parameter(self):
return self.path.relative_encode
if self.properties and self.properties.is_dir:
param = Object()
param.paths = [self.path.join(filename).absolute_encode for filename in self.objects] if self.objects else [self.path.absolute]
param.snapshot = None
param.password = None
param.portalName = None
param.showDeleted = False
uid = (
str(self.properties.volume.id)
if self._receiver.context != Context.Invitations
else f'share/{self._receiver.invite}'
)
return uid, encode_request_parameter(param)
return self.path.relative_encode, # pylint: disable=trailing-comma-tuple

def _before_command(self):
raise_or_suppress_access_error(self._receiver, self.path)
logger.info('Getting handle: %s', self.path)
if self.properties and self.properties.is_dir and self.objects:
logger.info('Getting handle: %s', [self.path.join(o).relative for o in self.objects])
else:
logger.info('Getting handle: %s', self.path)

def _execute(self):
with self.trace_execution():
return self._function(self._receiver, self.get_parameter())
return self._function(self._receiver, *self.get_parameter())

async def _a_execute(self):
with self.trace_execution():
return await self._function(self._receiver, self.get_parameter())
return await self._function(self._receiver, *self.get_parameter())

def _handle_exception(self, e):
path = self.path.relative
Expand All @@ -385,86 +403,34 @@ def _handle_exception(self, e):

class Download(PortalCommand):

def __init__(self, function, receiver, path, destination):
def __init__(self, function, receiver, path, properties=None, objects=None, destination=None):
super().__init__(function, receiver)
self.path = automatic_resolution(path, receiver.context)
self.destination = destination

def get_parameter(self):
return commonfs.determine_directory_and_filename(self.path.reference, destination=self.destination)

def _before_command(self):
logger.info('Downloading: %s', self.path)

def _execute(self):
directory, name = self.get_parameter()
with self.trace_execution():
with Open(self._function, self._receiver, self.path) as handle:
return synfs.write(directory, name, handle)

async def _a_execute(self):
directory, name = self.get_parameter()
with self.trace_execution():
async with Open(self._function, self._receiver, self.path) as handle:
return await asynfs.write(directory, name, handle)


class OpenMany(PortalCommand):

def __init__(self, function, receiver, resource, directory, *objects):
super().__init__(function, receiver)
self.uid = str(resource.cloudFolderInfo.uid) if receiver.context != Context.Invitations else f'share/{receiver.invite}'
self.directory = automatic_resolution(directory, receiver.context)
self.objects = objects

def _before_command(self):
raise_or_suppress_access_error(self._receiver, self.directory)
logger.info('Getting handle: %s', [self.directory.join(o).relative for o in self.objects])

def get_parameter(self):
param = Object()
param.paths = [self.directory.join(filename).absolute_encode for filename in self.objects]
param.snapshot = None
param.password = None
param.portalName = None
param.showDeleted = False
return encode_request_parameter(param)

def _execute(self):
with self.trace_execution():
return self._function(self._receiver, self.uid, self.get_parameter())

async def _a_execute(self):
with self.trace_execution():
return await self._function(self._receiver, self.uid, self.get_parameter())


class DownloadMany(PortalCommand):

def __init__(self, function, receiver, resource, directory, objects, destination):
super().__init__(function, receiver)
self.resource = resource
self.directory = automatic_resolution(directory, receiver.context)
self.properties = properties
self.objects = objects
self.destination = destination

def get_parameter(self):
return commonfs.determine_directory_and_filename(self.directory.reference, self.objects, destination=self.destination, archive=True)
archive = self.properties.is_dir if self.properties else False
return commonfs.determine_directory_and_filename(self.path.reference, self.objects,
self.destination, archive)

def _before_command(self):
for o in self.objects:
logger.info('Downloading: %s', self.directory.join(o).relative)
if self.properties and self.properties.is_dir and self.objects:
logger.info('Downloading: %s', [self.path.join(o).relative for o in self.objects])
else:
logger.info('Downloading: %s', self.path)

def _execute(self):
directory, name = self.get_parameter()
with self.trace_execution():
with OpenMany(self._function, self._receiver, self.resource, self.directory, *self.objects) as handle:
with Open(self._function, self._receiver, self.path, self.properties, self.objects) as handle:
return synfs.write(directory, name, handle)

async def _a_execute(self):
directory, name = self.get_parameter()
with self.trace_execution():
async with OpenMany(self._function, self._receiver, self.resource, self.directory, *self.objects) as handle:
async with Open(self._function, self._receiver, self.path, self.properties, self.objects) as handle:
return await asynfs.write(directory, name, handle)


Expand Down
4 changes: 2 additions & 2 deletions cterasdk/cli/dav.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ async def handle_download(args): # pylint: disable=too-many-branches

async def download(invitation, resource, objects=None, archive=False, destination=None):
if objects is not None or archive:
return await invitation.files.download_many(resource.path.relative, [o.name for o in objects], f'{destination}.zip')
return await invitation.files.download(resource.path.relative, destination.joinpath(resource.path.relative))
return await invitation.files.download(resource.path.relative, [o.name for o in objects], f'{destination}.zip')
return await invitation.files.download(resource.path.relative, destination=destination.joinpath(resource.path.relative))

async with AsyncInvitation.from_uri(args.endpoint) as invitation:
jobs = []
Expand Down
56 changes: 16 additions & 40 deletions cterasdk/core/files/browser.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from .. import query
from ...cio.core.commands import Open, OpenMany, Upload, Download, EnsureDirectory, \
DownloadMany, UnShare, CreateDirectory, GetMetadata, GetProperties, ListVersions, RecursiveIterator, \
from ...cio.core.commands import Open, Upload, Download, EnsureDirectory, \
UnShare, CreateDirectory, GetMetadata, GetProperties, ListVersions, RecursiveIterator, \
Delete, Recover, Rename, GetShareMetadata, Link, Copy, Move, ResourceIterator, GetPermalink, GetExternalShareInfo
from ...cio.core.types import InvitationPath
from ...lib.storage import commonfs
Expand All @@ -11,61 +11,39 @@
class FileBrowser(BaseCommand):
"""CTERA Portal File Browser API."""

def handle(self, path):
def handle(self, path, objects=None):
"""
Get a file handle.

:param str path: Path to a file.
:param list[str],optional objects: Files and folders to include.
:returns: File handle.
:rtype: object
:raises cterasdk.exceptions.io.core.OpenError: Raised on error to obtain a file handle.
"""
return Open(io.handle, self._core, path).execute()

def handle_many(self, directory, *objects):
"""
Get a ZIP archive file handle.

:param str directory: Path to a folder.
:param args objects: Files and folders to include.
:returns: File handle.
:rtype: object
:raises cterasdk.exceptions.io.core.GetMetadataError: If the directory was not found.
:raises cterasdk.exceptions.io.core.NotADirectoryException: If the target path is not a directory.
"""
with EnsureDirectory(io.listdir, self._core, directory) as (_, resource):
return OpenMany(io.handle_many, self._core, resource, directory, *objects).execute()
with GetProperties(io.listdir, self._core, path) as properties:
return Open(io.handle_many if properties.is_dir else io.handle, self._core,
properties.path, properties, objects).execute()

def download(self, path, destination=None):
def download(self, path, objects=None, destination=None):
"""
Download a file.

:param str path: Path.
:param list[str],optional objects: List of files and / or directory names to download.
:param str, optional destination: File destination. If a directory is provided, the original filename is preserved.
Defaults to the default download directory.
:returns: Path to the local file.
:rtype: str
:raises cterasdk.exceptions.io.core.OpenError: Raised on error to obtain a file handle.
"""
return Download(io.handle, self._core, path, destination).execute()

def download_many(self, directory, objects, destination=None):
"""
Download selected files and/or directories as a ZIP archive.

.. warning::
Only existing files and directories will be included in the resulting ZIP file.

:param str directory: Path to a folder.
:param list[str] objects: List of files and / or directory names to download.
:param str destination: Optional path to destination file or directory. Defaults to the default download directory.
:returns: Path to the local file.
:rtype: str
:raises cterasdk.exceptions.io.core.GetMetadataError: If the directory was not found.
:raises cterasdk.exceptions.io.core.NotADirectoryException: If the target path is not a directory.
"""
with EnsureDirectory(io.listdir, self._core, directory) as (_, resource):
return DownloadMany(io.handle_many, self._core, resource, directory, objects, destination).execute()
with GetProperties(io.listdir, self._core, path) as properties:
return Download(io.handle_many if properties.is_dir else io.handle, self._core,
properties.path, properties, objects, destination).execute()

def listdir(self, path=None, include_deleted=False):
"""
Expand Down Expand Up @@ -352,7 +330,8 @@ def device_config(self, device, destination=None):
:raises cterasdk.exceptions.io.core.OpenError: Raised on error obtaining file handle.
"""
destination = destination if destination is not None else f'{commonfs.downloads()}/{device}.xml'
return Download(io.handle, self._core, f'backups/{device}/Device Configuration/db.xml', destination).execute()
return Download(io.handle, self._core,
f'backups/{device}/Device Configuration/db.xml', destination=destination).execute()


class InvitationBrowser:
Expand Down Expand Up @@ -380,11 +359,8 @@ def mkdir(self, path):
def makedirs(self, path):
return self._file_browser.makedirs(self._invitation.join(path))

def download(self, path, destination=None):
return self._file_browser.download(self._invitation.join(path), destination)

def download_many(self, directory, objects, destination=None):
return self._file_browser.download_many(self._invitation.join(directory), objects, destination)
def download(self, path, objects=None, destination=None):
return self._file_browser.download(self._invitation.join(path), objects, destination)

def upload(self, destination, handle, name=None, size=None):
return self._file_browser.upload(self._invitation.join(destination), handle, name, size)
Expand Down
2 changes: 1 addition & 1 deletion cterasdk/lib/storage/commonfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def determine_zip_archive_name(directory, objects):

:rtype: str
"""
if len(objects) > 1:
if not objects or len(objects) > 1:
path = Path(directory)
else:
path = Path(objects[0])
Expand Down
Loading
Loading