Skip to content

Commit 51da703

Browse files
authored
using storage_copy_function (#584)
* using storage_copy_function
1 parent 0303a6e commit 51da703

4 files changed

Lines changed: 52 additions & 7 deletions

File tree

docs/configuration.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,15 @@ configuration file <https://docs.pycsw.org/en/latest/configuration.html>`_.
156156
:storagetype:
157157
The type of storage to use when storing status and results. Possible values are: ``file``, ``s3``. Defaults to ``file``.
158158

159+
:storage_copy_function:
160+
When using file storage you can choose the copy function. Possible values are:
161+
162+
* ``copy``: using ``shutil.copy2``,
163+
* ``move``: using ``shutil.move``,
164+
* ``link``: using ``os.link`` (hardlink).
165+
166+
Default: ``copy``.
167+
159168
[processing]
160169
------------
161170

pywps/configuration.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ def load_configuration(cfgfiles=None):
8989
# after process has finished.
9090
CONFIG.set('server', 'cleantempdir', 'true')
9191
CONFIG.set('server', 'storagetype', 'file')
92+
# File storage outputs can be copied, moved or linked
93+
# from the workdir to the output folder.
94+
# Allowed functions: "copy", "move", "link" (default "copy")
95+
CONFIG.set('server', 'storage_copy_function', 'copy')
9296

9397
CONFIG.add_section('processing')
9498
CONFIG.set('processing', 'mode', 'default')

pywps/exceptions.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,13 @@ class StorageNotSupported(NoApplicableCode):
115115

116116

117117
class NotEnoughStorage(NoApplicableCode):
118-
"""Storage not supported exception implementation
118+
"""Not enough storage exception implementation
119+
"""
120+
code = 400
121+
122+
123+
class FileStorageError(NoApplicableCode):
124+
"""File storage exception implementation
119125
"""
120126
code = 400
121127

pywps/inout/storage/file.py

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import logging
77
import os
88
from urllib.parse import urljoin
9-
from pywps.exceptions import NotEnoughStorage
9+
from pywps.exceptions import NotEnoughStorage, FileStorageError
1010
from pywps import configuration as config
1111
from pywps.inout.basic import IOHandler
1212

@@ -22,7 +22,8 @@ class FileStorageBuilder(StorageImplementationBuilder):
2222
def build(self):
2323
file_path = config.get_config_value('server', 'outputpath')
2424
base_url = config.get_config_value('server', 'outputurl')
25-
return FileStorage(file_path, base_url)
25+
copy_function = config.get_config_value('server', 'storage_copy_function')
26+
return FileStorage(file_path, base_url, copy_function=copy_function)
2627

2728

2829
def _build_output_name(output):
@@ -59,17 +60,17 @@ class FileStorage(CachedStorage):
5960
True
6061
"""
6162

62-
def __init__(self, output_path, output_url):
63+
def __init__(self, output_path, output_url, copy_function=None):
6364
"""
6465
"""
6566
CachedStorage.__init__(self)
6667
self.target = output_path
6768
self.output_url = output_url
69+
self.copy_function = copy_function
6870

6971
def _do_store(self, output):
7072
import platform
7173
import math
72-
import shutil
7374
import tempfile
7475
import uuid
7576

@@ -103,8 +104,12 @@ def _do_store(self, output):
103104
dir=target)[1]
104105

105106
full_output_name = os.path.join(target, output_name)
106-
LOGGER.info('Storing file output to {}'.format(full_output_name))
107-
shutil.copy2(output.file, full_output_name)
107+
LOGGER.info(f'Storing file output to {full_output_name} ({self.copy_function}).')
108+
try:
109+
self.copy(output.file, full_output_name, self.copy_function)
110+
except Exception:
111+
LOGGER.exception(f"Could not copy {output_name}.")
112+
raise FileStorageError("Could not copy output file.")
108113

109114
just_file_name = os.path.basename(output_name)
110115

@@ -113,6 +118,27 @@ def _do_store(self, output):
113118

114119
return (STORE_TYPE.PATH, output_name, url)
115120

121+
@staticmethod
122+
def copy(src, dst, copy_function=None):
123+
"""Copy file from source to destination using `copy_function`.
124+
125+
Values of `copy_function` (default=`copy`):
126+
* copy: using `shutil.copy2`
127+
* move: using `shutil.move`
128+
* link: using `os.link` (hardlink)
129+
"""
130+
import shutil
131+
if copy_function == 'move':
132+
shutil.move(src, dst)
133+
elif copy_function == 'link':
134+
try:
135+
os.link(src, dst)
136+
except Exception:
137+
LOGGER.warn("Could not create hardlink. Fallback to copy.")
138+
FileStorage.copy(src, dst)
139+
else:
140+
shutil.copy2(src, dst)
141+
116142
def write(self, data, destination, data_format=None):
117143
"""
118144
Write data to self.target

0 commit comments

Comments
 (0)