async def copy(self, dest_provider, src_path, dest_path, rename=None, conflict='replace', handle_naming=True): args = (dest_provider, src_path, dest_path) kwargs = {'rename': rename, 'conflict': conflict, 'handle_naming': handle_naming} if handle_naming: dest_path = await dest_provider.handle_naming( src_path, dest_path, rename=rename, conflict=conflict, ) args = (dest_provider, src_path, dest_path) kwargs = {} # files and folders shouldn't overwrite themselves if ( self.shares_storage_root(dest_provider) and src_path.materialized_path == dest_path.materialized_path ): raise exceptions.OverwriteSelfError(src_path) if self.can_intra_copy(dest_provider, src_path): return (await self.intra_copy(*args)) if src_path.is_dir: return (await self._folder_file_op(self.copy, *args, **kwargs)) download_stream = await self.download(src_path) if getattr(download_stream, 'name', None): dest_path.rename(download_stream.name) return (await dest_provider.upload(download_stream, dest_path))
async def move(self, dest_provider: 'BaseProvider', src_path: wb_path.WaterButlerPath, dest_path: wb_path.WaterButlerPath, rename: str=None, conflict: str='replace', handle_naming: bool=True) -> typing.Tuple[wb_metadata.BaseMetadata, bool]: """Moves a file or folder from the current provider to the specified one Performs a copy and then a delete. Calls :func:`BaseProvider.intra_move` if possible. :param dest_provider: ( :class:`.BaseProvider` ) The provider to move to :param src_path: ( :class:`.WaterButlerPath` ) Path to where the resource can be found :param dest_path: ( :class:`.WaterButlerPath` ) Path to where the resource will be moved :param rename: ( :class:`str` ) The desired name of the resulting path, may be incremented :param conflict: ( :class:`str` ) What to do in the event of a name conflict, ``replace`` or ``keep`` :param handle_naming: ( :class:`bool` ) If a naming conflict is detected, should it be automatically handled? """ args = (dest_provider, src_path, dest_path) kwargs = {'rename': rename, 'conflict': conflict} self.provider_metrics.add('move', { 'got_handle_naming': handle_naming, 'conflict': conflict, 'got_rename': rename is not None, }) if handle_naming: dest_path = await dest_provider.handle_naming( src_path, dest_path, rename=rename, conflict=conflict, ) args = (dest_provider, src_path, dest_path) kwargs = {} # files and folders shouldn't overwrite themselves if ( self.shares_storage_root(dest_provider) and src_path.materialized_path == dest_path.materialized_path ): raise exceptions.OverwriteSelfError(src_path) self.provider_metrics.add('move.can_intra_move', False) if self.can_intra_move(dest_provider, src_path): self.provider_metrics.add('move.can_intra_move', True) return await self.intra_move(*args) if src_path.is_dir: meta_data, created = await self._folder_file_op(self.move, *args, **kwargs) # type: ignore else: meta_data, created = await self.copy(*args, handle_naming=False, **kwargs) # type: ignore await self.delete(src_path) return meta_data, created
async def copy(self, dest_provider: 'BaseProvider', src_path: wb_path.WaterButlerPath, dest_path: wb_path.WaterButlerPath, rename: str=None, conflict: str='replace', handle_naming: bool=True) \ -> typing.Tuple[wb_metadata.BaseMetadata, bool]: args = (dest_provider, src_path, dest_path) kwargs = {'rename': rename, 'conflict': conflict, 'handle_naming': handle_naming} self.provider_metrics.add('copy', { 'got_handle_naming': handle_naming, 'conflict': conflict, 'got_rename': rename is not None, }) if handle_naming: dest_path = await dest_provider.handle_naming( src_path, dest_path, rename=rename, conflict=conflict, ) args = (dest_provider, src_path, dest_path) kwargs = {} # files and folders shouldn't overwrite themselves if ( self.shares_storage_root(dest_provider) and src_path.materialized_path == dest_path.materialized_path ): raise exceptions.OverwriteSelfError(src_path) self.provider_metrics.add('copy.can_intra_copy', False) if self.can_intra_copy(dest_provider, src_path): self.provider_metrics.add('copy.can_intra_copy', True) return await self.intra_copy(*args) if src_path.is_dir: return await self._folder_file_op(self.copy, *args, **kwargs) # type: ignore download_stream = await self.download(src_path) if getattr(download_stream, 'name', None): dest_path.rename(download_stream.name) return await dest_provider.upload(download_stream, dest_path)
async def move(self, dest_provider, src_path, dest_path, rename=None, conflict='replace', handle_naming=True): """Moves a file or folder from the current provider to the specified one Performs a copy and then a delete. Calls :func:`BaseProvider.intra_move` if possible. :param BaseProvider dest_provider: The provider to move to :param dict source_options: A dict to be sent to either :func:`BaseProvider.intra_move` or :func:`BaseProvider.copy` and :func:`BaseProvider.delete` :param dict dest_options: A dict to be sent to either :func:`BaseProvider.intra_move` or :func:`BaseProvider.copy` """ args = (dest_provider, src_path, dest_path) kwargs = {'rename': rename, 'conflict': conflict} if handle_naming: dest_path = await dest_provider.handle_naming( src_path, dest_path, rename=rename, conflict=conflict, ) args = (dest_provider, src_path, dest_path) kwargs = {} # files and folders shouldn't overwrite themselves if ( self.shares_storage_root(dest_provider) and src_path.materialized_path == dest_path.materialized_path ): raise exceptions.OverwriteSelfError(src_path) if self.can_intra_move(dest_provider, src_path): return (await self.intra_move(*args)) if src_path.is_dir: metadata, created = await self._folder_file_op(self.move, *args, **kwargs) else: metadata, created = await self.copy(*args, handle_naming=False, **kwargs) await self.delete(src_path) return metadata, created
async def copy( self, dest_provider: provider.BaseProvider, src_path: WaterButlerPath, dest_path: WaterButlerPath, rename: str = None, conflict: str = 'replace', handle_naming: bool = True) -> typing.Tuple[BaseMetadata, bool]: """Override parent's copy to support cross-region osfstorage copies. Delegates to :meth:`.BaseProvider.copy` when destination is not osfstorage. If both providers are in the same region (i.e. `.can_intra_copy` is true), call `.intra_copy`. Otherwise, grab a download stream from the source region, send it to the destination region, *then* execute an `.intra_copy` to make new file metadata entries in the OSF. This is needed because a same-region osfstorage copy will duplicate *all* the versions of the file, but `.BaseProvider.copy` will only copy the most recent version. """ # when moving to non-osfstorage, default move is fine if dest_provider.NAME != 'osfstorage': return await super().copy(dest_provider, src_path, dest_path, rename=rename, conflict=conflict, handle_naming=handle_naming) args = (dest_provider, src_path, dest_path) kwargs = {'rename': rename, 'conflict': conflict} self.provider_metrics.add( 'copy', { 'got_handle_naming': handle_naming, 'conflict': conflict, 'got_rename': rename is not None, }) if handle_naming: dest_path = await dest_provider.handle_naming( src_path, dest_path, rename=rename, conflict=conflict, ) args = (dest_provider, src_path, dest_path) kwargs = {} # files and folders shouldn't overwrite themselves if (self.shares_storage_root(dest_provider) and src_path.materialized_path == dest_path.materialized_path): raise exceptions.OverwriteSelfError(src_path) self.provider_metrics.add('copy.can_intra_copy', False) if self.can_intra_copy(dest_provider, src_path): self.provider_metrics.add('copy.can_intra_copy', True) return await self.intra_copy(*args) if src_path.is_dir: meta_data, created = await self._folder_file_op( self.copy, *args, **kwargs) # type: ignore else: download_stream = await self.download(src_path) if getattr(download_stream, 'name', None): dest_path.rename(download_stream.name) await dest_provider._send_to_storage_provider( download_stream, # type: ignore dest_path, **kwargs) meta_data, created = await self.intra_copy(dest_provider, src_path, dest_path) return meta_data, created
async def move( self, dest_provider: provider.BaseProvider, src_path: WaterButlerPath, dest_path: WaterButlerPath, rename: str = None, conflict: str = 'replace', handle_naming: bool = True) -> typing.Tuple[BaseMetadata, bool]: """Override parent's move to support cross-region osfstorage moves while preserving guids and versions. Delegates to :meth:`.BaseProvider.move` when destination is not osfstorage. If both providers are in the same region (i.e. `.can_intra_move` is true), then calls that. Otherwise, will grab a download stream from the source region, send it to the destination region, *then* execute an `.intra_move` to update the file metada in-place. """ # when moving to non-osfstorage, default move is fine if dest_provider.NAME != 'osfstorage': return await super().move(dest_provider, src_path, dest_path, rename=rename, conflict=conflict, handle_naming=handle_naming) args = (dest_provider, src_path, dest_path) kwargs = {'rename': rename, 'conflict': conflict} self.provider_metrics.add( 'move', { 'got_handle_naming': handle_naming, 'conflict': conflict, 'got_rename': rename is not None, }) if handle_naming: dest_path = await dest_provider.handle_naming( src_path, dest_path, rename=rename, conflict=conflict, ) args = (dest_provider, src_path, dest_path) kwargs = {} # files and folders shouldn't overwrite themselves if (self.shares_storage_root(dest_provider) and src_path.materialized_path == dest_path.materialized_path): raise exceptions.OverwriteSelfError(src_path) self.provider_metrics.add('move.can_intra_move', False) if self.can_intra_move(dest_provider, src_path): self.provider_metrics.add('move.can_intra_move', True) return await self.intra_move(*args) if src_path.is_dir: meta_data, created = await self._folder_file_op( self.move, *args, **kwargs) # type: ignore await self.delete(src_path) else: download_stream = await self.download(src_path) if getattr(download_stream, 'name', None): dest_path.rename(download_stream.name) await dest_provider._send_to_storage_provider( download_stream, # type: ignore dest_path, **kwargs) meta_data, created = await self.intra_move(dest_provider, src_path, dest_path) return meta_data, created