Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / commands / pithos.py @ cf115aed

History | View | Annotate | Download (78.3 kB)

1 e3f01d64 Stavros Sachtouris
# Copyright 2011-2013 GRNET S.A. All rights reserved.
2 7493ccb6 Stavros Sachtouris
#
3 7493ccb6 Stavros Sachtouris
# Redistribution and use in source and binary forms, with or
4 7493ccb6 Stavros Sachtouris
# without modification, are permitted provided that the following
5 7493ccb6 Stavros Sachtouris
# conditions are met:
6 7493ccb6 Stavros Sachtouris
#
7 7493ccb6 Stavros Sachtouris
#   1. Redistributions of source code must retain the above
8 7493ccb6 Stavros Sachtouris
#      copyright notice, this list of conditions and the following
9 7493ccb6 Stavros Sachtouris
#      disclaimer.
10 7493ccb6 Stavros Sachtouris
#
11 7493ccb6 Stavros Sachtouris
#   2. Redistributions in binary form must reproduce the above
12 7493ccb6 Stavros Sachtouris
#      copyright notice, this list of conditions and the following
13 7493ccb6 Stavros Sachtouris
#      disclaimer in the documentation and/or other materials
14 7493ccb6 Stavros Sachtouris
#      provided with the distribution.
15 7493ccb6 Stavros Sachtouris
#
16 7493ccb6 Stavros Sachtouris
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 7493ccb6 Stavros Sachtouris
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 7493ccb6 Stavros Sachtouris
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 7493ccb6 Stavros Sachtouris
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 7493ccb6 Stavros Sachtouris
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 7493ccb6 Stavros Sachtouris
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 7493ccb6 Stavros Sachtouris
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 7493ccb6 Stavros Sachtouris
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 7493ccb6 Stavros Sachtouris
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 7493ccb6 Stavros Sachtouris
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 7493ccb6 Stavros Sachtouris
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 7493ccb6 Stavros Sachtouris
# POSSIBILITY OF SUCH DAMAGE.
28 7493ccb6 Stavros Sachtouris
#
29 7493ccb6 Stavros Sachtouris
# The views and conclusions contained in the software and
30 7493ccb6 Stavros Sachtouris
# documentation are those of the authors and should not be
31 7493ccb6 Stavros Sachtouris
# interpreted as representing official policies, either expressed
32 7493ccb6 Stavros Sachtouris
# or implied, of GRNET S.A.command
33 7493ccb6 Stavros Sachtouris
34 1395c40e Stavros Sachtouris
from sys import stdout
35 1395c40e Stavros Sachtouris
from time import localtime, strftime
36 b666ef82 Stavros Sachtouris
from os import path, makedirs, walk
37 1395c40e Stavros Sachtouris
38 234954d1 Stavros Sachtouris
from kamaki.cli import command
39 d486baec Stavros Sachtouris
from kamaki.cli.command_tree import CommandTree
40 8cec3671 Stavros Sachtouris
from kamaki.cli.errors import raiseCLIError, CLISyntaxError, CLIBaseUrlError
41 7147e1ca Stavros Sachtouris
from kamaki.cli.utils import (
42 0f383dcc Stavros Sachtouris
    format_size, to_bytes, print_dict, print_items, page_hold, bold, ask_user,
43 0f383dcc Stavros Sachtouris
    get_path_size, print_json, guess_mime_type)
44 e3d4d442 Stavros Sachtouris
from kamaki.cli.argument import FlagArgument, ValueArgument, IntArgument
45 04d01cd4 Stavros Sachtouris
from kamaki.cli.argument import KeyValueArgument, DateArgument
46 fd1f1d96 Stavros Sachtouris
from kamaki.cli.argument import ProgressBarArgument
47 545c6c29 Stavros Sachtouris
from kamaki.cli.commands import _command_init, errors
48 b4f69041 Stavros Sachtouris
from kamaki.cli.commands import addLogSettings, DontRaiseKeyError
49 6d190dd1 Stavros Sachtouris
from kamaki.cli.commands import (
50 6d190dd1 Stavros Sachtouris
    _optional_output_cmd, _optional_json, _name_filter)
51 7493ccb6 Stavros Sachtouris
from kamaki.clients.pithos import PithosClient, ClientError
52 1f5debf7 Stavros Sachtouris
from kamaki.clients.astakos import AstakosClient
53 1395c40e Stavros Sachtouris
54 a29d2f88 Stavros Sachtouris
pithos_cmds = CommandTree('file', 'Pithos+/Storage API commands')
55 d486baec Stavros Sachtouris
_commands = [pithos_cmds]
56 234954d1 Stavros Sachtouris
57 7493ccb6 Stavros Sachtouris
58 234954d1 Stavros Sachtouris
# Argument functionality
59 234954d1 Stavros Sachtouris
60 efdee310 Stavros Sachtouris
class DelimiterArgument(ValueArgument):
61 befed235 Stavros Sachtouris
    """
62 befed235 Stavros Sachtouris
    :value type: string
63 befed235 Stavros Sachtouris
    :value returns: given string or /
64 03d661d8 Stavros Sachtouris
    """
65 03d661d8 Stavros Sachtouris
66 efdee310 Stavros Sachtouris
    def __init__(self, caller_obj, help='', parsed_name=None, default=None):
67 efdee310 Stavros Sachtouris
        super(DelimiterArgument, self).__init__(help, parsed_name, default)
68 efdee310 Stavros Sachtouris
        self.caller_obj = caller_obj
69 efdee310 Stavros Sachtouris
70 234954d1 Stavros Sachtouris
    @property
71 efdee310 Stavros Sachtouris
    def value(self):
72 2fe2672e Stavros Sachtouris
        if self.caller_obj['recursive']:
73 efdee310 Stavros Sachtouris
            return '/'
74 efdee310 Stavros Sachtouris
        return getattr(self, '_value', self.default)
75 234954d1 Stavros Sachtouris
76 234954d1 Stavros Sachtouris
    @value.setter
77 efdee310 Stavros Sachtouris
    def value(self, newvalue):
78 efdee310 Stavros Sachtouris
        self._value = newvalue
79 efdee310 Stavros Sachtouris
80 234954d1 Stavros Sachtouris
81 befed235 Stavros Sachtouris
class SharingArgument(ValueArgument):
82 befed235 Stavros Sachtouris
    """Set sharing (read and/or write) groups
83 439826ec Stavros Sachtouris
    .
84 befed235 Stavros Sachtouris
    :value type: "read=term1,term2,... write=term1,term2,..."
85 439826ec Stavros Sachtouris
    .
86 befed235 Stavros Sachtouris
    :value returns: {'read':['term1', 'term2', ...],
87 439826ec Stavros Sachtouris
    .   'write':['term1', 'term2', ...]}
88 befed235 Stavros Sachtouris
    """
89 234954d1 Stavros Sachtouris
90 234954d1 Stavros Sachtouris
    @property
91 e3d4d442 Stavros Sachtouris
    def value(self):
92 e3d4d442 Stavros Sachtouris
        return getattr(self, '_value', self.default)
93 234954d1 Stavros Sachtouris
94 e3d4d442 Stavros Sachtouris
    @value.setter
95 e3d4d442 Stavros Sachtouris
    def value(self, newvalue):
96 e3d4d442 Stavros Sachtouris
        perms = {}
97 e3d4d442 Stavros Sachtouris
        try:
98 e3d4d442 Stavros Sachtouris
            permlist = newvalue.split(' ')
99 e3d4d442 Stavros Sachtouris
        except AttributeError:
100 e3d4d442 Stavros Sachtouris
            return
101 e3d4d442 Stavros Sachtouris
        for p in permlist:
102 e3d4d442 Stavros Sachtouris
            try:
103 234954d1 Stavros Sachtouris
                (key, val) = p.split('=')
104 83ba5545 Stavros Sachtouris
            except ValueError as err:
105 24ff0a35 Stavros Sachtouris
                raiseCLIError(
106 24ff0a35 Stavros Sachtouris
                    err,
107 24ff0a35 Stavros Sachtouris
                    'Error in --sharing',
108 234954d1 Stavros Sachtouris
                    details='Incorrect format',
109 234954d1 Stavros Sachtouris
                    importance=1)
110 e3d4d442 Stavros Sachtouris
            if key.lower() not in ('read', 'write'):
111 de73876b Stavros Sachtouris
                msg = 'Error in --sharing'
112 de73876b Stavros Sachtouris
                raiseCLIError(err, msg, importance=1, details=[
113 de73876b Stavros Sachtouris
                    'Invalid permission key %s' % key])
114 e3d4d442 Stavros Sachtouris
            val_list = val.split(',')
115 234954d1 Stavros Sachtouris
            if not key in perms:
116 234954d1 Stavros Sachtouris
                perms[key] = []
117 e3d4d442 Stavros Sachtouris
            for item in val_list:
118 e3d4d442 Stavros Sachtouris
                if item not in perms[key]:
119 e3d4d442 Stavros Sachtouris
                    perms[key].append(item)
120 e3d4d442 Stavros Sachtouris
        self._value = perms
121 e3d4d442 Stavros Sachtouris
122 234954d1 Stavros Sachtouris
123 e3d4d442 Stavros Sachtouris
class RangeArgument(ValueArgument):
124 befed235 Stavros Sachtouris
    """
125 439826ec Stavros Sachtouris
    :value type: string of the form <start>-<end> where <start> and <end> are
126 439826ec Stavros Sachtouris
        integers
127 befed235 Stavros Sachtouris
    :value returns: the input string, after type checking <start> and <end>
128 befed235 Stavros Sachtouris
    """
129 befed235 Stavros Sachtouris
130 234954d1 Stavros Sachtouris
    @property
131 e3d4d442 Stavros Sachtouris
    def value(self):
132 e3d4d442 Stavros Sachtouris
        return getattr(self, '_value', self.default)
133 234954d1 Stavros Sachtouris
134 e3d4d442 Stavros Sachtouris
    @value.setter
135 776b275c Stavros Sachtouris
    def value(self, newvalues):
136 776b275c Stavros Sachtouris
        if not newvalues:
137 e3d4d442 Stavros Sachtouris
            self._value = self.default
138 e3d4d442 Stavros Sachtouris
            return
139 776b275c Stavros Sachtouris
        self._value = ''
140 776b275c Stavros Sachtouris
        for newvalue in newvalues.split(','):
141 776b275c Stavros Sachtouris
            self._value = ('%s,' % self._value) if self._value else ''
142 776b275c Stavros Sachtouris
            start, sep, end = newvalue.partition('-')
143 776b275c Stavros Sachtouris
            if sep:
144 776b275c Stavros Sachtouris
                if start:
145 776b275c Stavros Sachtouris
                    start, end = (int(start), int(end))
146 776b275c Stavros Sachtouris
                    assert start <= end, 'Invalid range value %s' % newvalue
147 776b275c Stavros Sachtouris
                    self._value += '%s-%s' % (int(start), int(end))
148 776b275c Stavros Sachtouris
                else:
149 776b275c Stavros Sachtouris
                    self._value += '-%s' % int(end)
150 7806f19d Stavros Sachtouris
            else:
151 776b275c Stavros Sachtouris
                self._value += '%s' % int(start)
152 234954d1 Stavros Sachtouris
153 201baa17 Stavros Sachtouris
154 234954d1 Stavros Sachtouris
# Command specs
155 234954d1 Stavros Sachtouris
156 e3d4d442 Stavros Sachtouris
157 5eae854d Stavros Sachtouris
class _pithos_init(_command_init):
158 befed235 Stavros Sachtouris
    """Initialize a pithos+ kamaki client"""
159 befed235 Stavros Sachtouris
160 ece4ae4b Stavros Sachtouris
    @staticmethod
161 ece4ae4b Stavros Sachtouris
    def _is_dir(remote_dict):
162 ece4ae4b Stavros Sachtouris
        return 'application/directory' == remote_dict.get(
163 8cec3671 Stavros Sachtouris
            'content_type', remote_dict.get('content-type', ''))
164 ece4ae4b Stavros Sachtouris
165 b4f69041 Stavros Sachtouris
    @DontRaiseKeyError
166 b4f69041 Stavros Sachtouris
    def _custom_container(self):
167 144b3551 Stavros Sachtouris
        return self.config.get_cloud(self.cloud, 'pithos_container')
168 b4f69041 Stavros Sachtouris
169 b4f69041 Stavros Sachtouris
    @DontRaiseKeyError
170 b4f69041 Stavros Sachtouris
    def _custom_uuid(self):
171 144b3551 Stavros Sachtouris
        return self.config.get_cloud(self.cloud, 'pithos_uuid')
172 b4f69041 Stavros Sachtouris
173 b4f69041 Stavros Sachtouris
    def _set_account(self):
174 b4f69041 Stavros Sachtouris
        self.account = self._custom_uuid()
175 b4f69041 Stavros Sachtouris
        if self.account:
176 b4f69041 Stavros Sachtouris
            return
177 b4f69041 Stavros Sachtouris
        if getattr(self, 'auth_base', False):
178 b4f69041 Stavros Sachtouris
            self.account = self.auth_base.user_term('id', self.token)
179 b4f69041 Stavros Sachtouris
        else:
180 b4f69041 Stavros Sachtouris
            astakos_url = self._custom_url('astakos')
181 b4f69041 Stavros Sachtouris
            astakos_token = self._custom_token('astakos') or self.token
182 b4f69041 Stavros Sachtouris
            if not astakos_url:
183 b4f69041 Stavros Sachtouris
                raise CLIBaseUrlError(service='astakos')
184 b4f69041 Stavros Sachtouris
            astakos = AstakosClient(astakos_url, astakos_token)
185 b4f69041 Stavros Sachtouris
            self.account = astakos.user_term('id')
186 b4f69041 Stavros Sachtouris
187 1395c40e Stavros Sachtouris
    @errors.generic.all
188 b4f69041 Stavros Sachtouris
    @addLogSettings
189 1395c40e Stavros Sachtouris
    def _run(self):
190 b4f69041 Stavros Sachtouris
        self.base_url = None
191 b4f69041 Stavros Sachtouris
        if getattr(self, 'cloud', None):
192 b4f69041 Stavros Sachtouris
            self.base_url = self._custom_url('pithos')
193 b4f69041 Stavros Sachtouris
        else:
194 b4f69041 Stavros Sachtouris
            self.cloud = 'default'
195 b4f69041 Stavros Sachtouris
        self.token = self._custom_token('pithos')
196 b4f69041 Stavros Sachtouris
        self.container = self._custom_container()
197 8cec3671 Stavros Sachtouris
198 8cec3671 Stavros Sachtouris
        if getattr(self, 'auth_base', False):
199 b4f69041 Stavros Sachtouris
            self.token = self.token or self.auth_base.token
200 b4f69041 Stavros Sachtouris
            if not self.base_url:
201 b4f69041 Stavros Sachtouris
                pithos_endpoints = self.auth_base.get_service_endpoints(
202 b4f69041 Stavros Sachtouris
                    self._custom_type('pithos') or 'object-store',
203 b4f69041 Stavros Sachtouris
                    self._custom_version('pithos') or '')
204 b4f69041 Stavros Sachtouris
                self.base_url = pithos_endpoints['publicURL']
205 b4f69041 Stavros Sachtouris
        elif not self.base_url:
206 8cec3671 Stavros Sachtouris
            raise CLIBaseUrlError(service='pithos')
207 8cec3671 Stavros Sachtouris
208 1f5debf7 Stavros Sachtouris
        self._set_account()
209 de73876b Stavros Sachtouris
        self.client = PithosClient(
210 de73876b Stavros Sachtouris
            base_url=self.base_url,
211 234954d1 Stavros Sachtouris
            token=self.token,
212 234954d1 Stavros Sachtouris
            account=self.account,
213 7493ccb6 Stavros Sachtouris
            container=self.container)
214 7493ccb6 Stavros Sachtouris
215 1395c40e Stavros Sachtouris
    def main(self):
216 1395c40e Stavros Sachtouris
        self._run()
217 1395c40e Stavros Sachtouris
218 234954d1 Stavros Sachtouris
219 3ae60112 Stavros Sachtouris
class _file_account_command(_pithos_init):
220 7493ccb6 Stavros Sachtouris
    """Base class for account level storage commands"""
221 7493ccb6 Stavros Sachtouris
222 b4f69041 Stavros Sachtouris
    def __init__(self, arguments={}, auth_base=None, cloud=None):
223 b4f69041 Stavros Sachtouris
        super(_file_account_command, self).__init__(
224 b4f69041 Stavros Sachtouris
            arguments, auth_base, cloud)
225 439826ec Stavros Sachtouris
        self['account'] = ValueArgument(
226 201baa17 Stavros Sachtouris
            'Set user account (not permanent)', ('-A', '--account'))
227 7493ccb6 Stavros Sachtouris
228 3ed6dbde Stavros Sachtouris
    def _run(self, custom_account=None):
229 3ae60112 Stavros Sachtouris
        super(_file_account_command, self)._run()
230 3ed6dbde Stavros Sachtouris
        if custom_account:
231 3ed6dbde Stavros Sachtouris
            self.client.account = custom_account
232 3ed6dbde Stavros Sachtouris
        elif self['account']:
233 47ae7577 Stavros Sachtouris
            self.client.account = self['account']
234 7493ccb6 Stavros Sachtouris
235 1395c40e Stavros Sachtouris
    @errors.generic.all
236 1395c40e Stavros Sachtouris
    def main(self):
237 1395c40e Stavros Sachtouris
        self._run()
238 1395c40e Stavros Sachtouris
239 234954d1 Stavros Sachtouris
240 3ae60112 Stavros Sachtouris
class _file_container_command(_file_account_command):
241 7493ccb6 Stavros Sachtouris
    """Base class for container level storage commands"""
242 7493ccb6 Stavros Sachtouris
243 47ae7577 Stavros Sachtouris
    container = None
244 47ae7577 Stavros Sachtouris
    path = None
245 2d7ce81e Stavros Sachtouris
246 b4f69041 Stavros Sachtouris
    def __init__(self, arguments={}, auth_base=None, cloud=None):
247 b4f69041 Stavros Sachtouris
        super(_file_container_command, self).__init__(
248 b4f69041 Stavros Sachtouris
            arguments, auth_base, cloud)
249 439826ec Stavros Sachtouris
        self['container'] = ValueArgument(
250 201baa17 Stavros Sachtouris
            'Set container to work with (temporary)', ('-C', '--container'))
251 7493ccb6 Stavros Sachtouris
252 de73876b Stavros Sachtouris
    def extract_container_and_path(
253 24ff0a35 Stavros Sachtouris
            self,
254 24ff0a35 Stavros Sachtouris
            container_with_path,
255 24ff0a35 Stavros Sachtouris
            path_is_optional=True):
256 1395c40e Stavros Sachtouris
        """Contains all heuristics for deciding what should be used as
257 1395c40e Stavros Sachtouris
        container or path. Options are:
258 1395c40e Stavros Sachtouris
        * user string of the form container:path
259 1395c40e Stavros Sachtouris
        * self.container, self.path variables set by super constructor, or
260 1395c40e Stavros Sachtouris
        explicitly by the caller application
261 1395c40e Stavros Sachtouris
        Error handling is explicit as these error cases happen only here
262 1395c40e Stavros Sachtouris
        """
263 83ba5545 Stavros Sachtouris
        try:
264 83ba5545 Stavros Sachtouris
            assert isinstance(container_with_path, str)
265 83ba5545 Stavros Sachtouris
        except AssertionError as err:
266 edab7ba7 Stavros Sachtouris
            if self['container'] and path_is_optional:
267 edab7ba7 Stavros Sachtouris
                self.container = self['container']
268 edab7ba7 Stavros Sachtouris
                self.client.container = self['container']
269 edab7ba7 Stavros Sachtouris
                return
270 83ba5545 Stavros Sachtouris
            raiseCLIError(err)
271 447c9568 Stavros Sachtouris
272 1395c40e Stavros Sachtouris
        user_cont, sep, userpath = container_with_path.partition(':')
273 447c9568 Stavros Sachtouris
274 447c9568 Stavros Sachtouris
        if sep:
275 1395c40e Stavros Sachtouris
            if not user_cont:
276 2005b18e Stavros Sachtouris
                raiseCLIError(CLISyntaxError(
277 2005b18e Stavros Sachtouris
                    'Container is missing\n',
278 1395c40e Stavros Sachtouris
                    details=errors.pithos.container_howto))
279 47ae7577 Stavros Sachtouris
            alt_cont = self['container']
280 1395c40e Stavros Sachtouris
            if alt_cont and user_cont != alt_cont:
281 c1558584 Stavros Sachtouris
                raiseCLIError(CLISyntaxError(
282 1395c40e Stavros Sachtouris
                    'Conflict: 2 containers (%s, %s)' % (user_cont, alt_cont),
283 1395c40e Stavros Sachtouris
                    details=errors.pithos.container_howto)
284 47ae7577 Stavros Sachtouris
                )
285 1395c40e Stavros Sachtouris
            self.container = user_cont
286 1395c40e Stavros Sachtouris
            if not userpath:
287 c1558584 Stavros Sachtouris
                raiseCLIError(CLISyntaxError(
288 1395c40e Stavros Sachtouris
                    'Path is missing for object in container %s' % user_cont,
289 1395c40e Stavros Sachtouris
                    details=errors.pithos.container_howto)
290 47ae7577 Stavros Sachtouris
                )
291 1395c40e Stavros Sachtouris
            self.path = userpath
292 447c9568 Stavros Sachtouris
        else:
293 47ae7577 Stavros Sachtouris
            alt_cont = self['container'] or self.client.container
294 447c9568 Stavros Sachtouris
            if alt_cont:
295 447c9568 Stavros Sachtouris
                self.container = alt_cont
296 1395c40e Stavros Sachtouris
                self.path = user_cont
297 447c9568 Stavros Sachtouris
            elif path_is_optional:
298 1395c40e Stavros Sachtouris
                self.container = user_cont
299 7493ccb6 Stavros Sachtouris
                self.path = None
300 7493ccb6 Stavros Sachtouris
            else:
301 1395c40e Stavros Sachtouris
                self.container = user_cont
302 447c9568 Stavros Sachtouris
                raiseCLIError(CLISyntaxError(
303 c1558584 Stavros Sachtouris
                    'Both container and path are required',
304 1395c40e Stavros Sachtouris
                    details=errors.pithos.container_howto)
305 47ae7577 Stavros Sachtouris
                )
306 7493ccb6 Stavros Sachtouris
307 1395c40e Stavros Sachtouris
    @errors.generic.all
308 1395c40e Stavros Sachtouris
    def _run(self, container_with_path=None, path_is_optional=True):
309 3ae60112 Stavros Sachtouris
        super(_file_container_command, self)._run()
310 edab7ba7 Stavros Sachtouris
        if self['container']:
311 edab7ba7 Stavros Sachtouris
            self.client.container = self['container']
312 edab7ba7 Stavros Sachtouris
            if container_with_path:
313 edab7ba7 Stavros Sachtouris
                self.path = container_with_path
314 edab7ba7 Stavros Sachtouris
            elif not path_is_optional:
315 edab7ba7 Stavros Sachtouris
                raise CLISyntaxError(
316 edab7ba7 Stavros Sachtouris
                    'Both container and path are required',
317 edab7ba7 Stavros Sachtouris
                    details=errors.pithos.container_howto)
318 edab7ba7 Stavros Sachtouris
        elif container_with_path:
319 47ae7577 Stavros Sachtouris
            self.extract_container_and_path(
320 47ae7577 Stavros Sachtouris
                container_with_path,
321 234954d1 Stavros Sachtouris
                path_is_optional)
322 7493ccb6 Stavros Sachtouris
            self.client.container = self.container
323 7493ccb6 Stavros Sachtouris
        self.container = self.client.container
324 7493ccb6 Stavros Sachtouris
325 1395c40e Stavros Sachtouris
    def main(self, container_with_path=None, path_is_optional=True):
326 1395c40e Stavros Sachtouris
        self._run(container_with_path, path_is_optional)
327 1395c40e Stavros Sachtouris
328 7493ccb6 Stavros Sachtouris
329 d486baec Stavros Sachtouris
@command(pithos_cmds)
330 6d190dd1 Stavros Sachtouris
class file_list(_file_container_command, _optional_json, _name_filter):
331 7493ccb6 Stavros Sachtouris
    """List containers, object trees or objects in a directory
332 2703cceb Stavros Sachtouris
    Use with:
333 7ae842c2 Stavros Sachtouris
    1 no parameters : containers in current account
334 2703cceb Stavros Sachtouris
    2. one parameter (container) or --container : contents of container
335 2703cceb Stavros Sachtouris
    3. <container>:<prefix> or --container=<container> <prefix>: objects in
336 439826ec Stavros Sachtouris
    .   container starting with prefix
337 7493ccb6 Stavros Sachtouris
    """
338 7493ccb6 Stavros Sachtouris
339 47ae7577 Stavros Sachtouris
    arguments = dict(
340 f40f0cb7 Stavros Sachtouris
        detail=FlagArgument('detailed output', ('-l', '--list')),
341 f40f0cb7 Stavros Sachtouris
        limit=IntArgument('limit number of listed items', ('-n', '--number')),
342 f40f0cb7 Stavros Sachtouris
        marker=ValueArgument('output greater that marker', '--marker'),
343 47ae7577 Stavros Sachtouris
        delimiter=ValueArgument('show output up to delimiter', '--delimiter'),
344 47ae7577 Stavros Sachtouris
        path=ValueArgument(
345 201baa17 Stavros Sachtouris
            'show output starting with prefix up to /', '--path'),
346 47ae7577 Stavros Sachtouris
        meta=ValueArgument(
347 201baa17 Stavros Sachtouris
            'show output with specified meta keys', '--meta',
348 47ae7577 Stavros Sachtouris
            default=[]),
349 47ae7577 Stavros Sachtouris
        if_modified_since=ValueArgument(
350 201baa17 Stavros Sachtouris
            'show output modified since then', '--if-modified-since'),
351 47ae7577 Stavros Sachtouris
        if_unmodified_since=ValueArgument(
352 201baa17 Stavros Sachtouris
            'show output not modified since then', '--if-unmodified-since'),
353 47ae7577 Stavros Sachtouris
        until=DateArgument('show metadata until then', '--until'),
354 47ae7577 Stavros Sachtouris
        format=ValueArgument(
355 201baa17 Stavros Sachtouris
            'format to parse until data (default: d/m/Y H:M:S )', '--format'),
356 47ae7577 Stavros Sachtouris
        shared=FlagArgument('show only shared', '--shared'),
357 439826ec Stavros Sachtouris
        more=FlagArgument(
358 439826ec Stavros Sachtouris
            'output results in pages (-n to set items per page, default 10)',
359 eb18b8a7 Stavros Sachtouris
            '--more'),
360 eb18b8a7 Stavros Sachtouris
        exact_match=FlagArgument(
361 eb18b8a7 Stavros Sachtouris
            'Show only objects that match exactly with path',
362 ed9af02c Stavros Sachtouris
            '--exact-match'),
363 545c6c29 Stavros Sachtouris
        enum=FlagArgument('Enumerate results', '--enumerate')
364 47ae7577 Stavros Sachtouris
    )
365 c41a86b2 Stavros Sachtouris
366 7493ccb6 Stavros Sachtouris
    def print_objects(self, object_list):
367 0399ac7e Stavros Sachtouris
        if self['json_output']:
368 0399ac7e Stavros Sachtouris
            print_json(object_list)
369 0399ac7e Stavros Sachtouris
            return
370 439826ec Stavros Sachtouris
        limit = int(self['limit']) if self['limit'] > 0 else len(object_list)
371 234954d1 Stavros Sachtouris
        for index, obj in enumerate(object_list):
372 24ff0a35 Stavros Sachtouris
            if self['exact_match'] and self.path and not (
373 2005b18e Stavros Sachtouris
                    obj['name'] == self.path or 'content_type' in obj):
374 2005b18e Stavros Sachtouris
                continue
375 7493ccb6 Stavros Sachtouris
            pretty_obj = obj.copy()
376 7493ccb6 Stavros Sachtouris
            index += 1
377 234954d1 Stavros Sachtouris
            empty_space = ' ' * (len(str(len(object_list))) - len(str(index)))
378 a339a3ee Stavros Sachtouris
            if 'subdir' in obj:
379 a339a3ee Stavros Sachtouris
                continue
380 7493ccb6 Stavros Sachtouris
            if obj['content_type'] == 'application/directory':
381 7493ccb6 Stavros Sachtouris
                isDir = True
382 7493ccb6 Stavros Sachtouris
                size = 'D'
383 7493ccb6 Stavros Sachtouris
            else:
384 7493ccb6 Stavros Sachtouris
                isDir = False
385 7493ccb6 Stavros Sachtouris
                size = format_size(obj['bytes'])
386 234954d1 Stavros Sachtouris
                pretty_obj['bytes'] = '%s (%s)' % (obj['bytes'], size)
387 7493ccb6 Stavros Sachtouris
            oname = bold(obj['name'])
388 ed9af02c Stavros Sachtouris
            prfx = ('%s%s. ' % (empty_space, index)) if self['enum'] else ''
389 47ae7577 Stavros Sachtouris
            if self['detail']:
390 ed9af02c Stavros Sachtouris
                print('%s%s' % (prfx, oname))
391 0f383dcc Stavros Sachtouris
                print_dict(pretty_obj, exclude=('name'))
392 7493ccb6 Stavros Sachtouris
                print
393 7493ccb6 Stavros Sachtouris
            else:
394 ed9af02c Stavros Sachtouris
                oname = '%s%9s %s' % (prfx, size, oname)
395 7493ccb6 Stavros Sachtouris
                oname += '/' if isDir else ''
396 7493ccb6 Stavros Sachtouris
                print(oname)
397 439826ec Stavros Sachtouris
            if self['more']:
398 439826ec Stavros Sachtouris
                page_hold(index, limit, len(object_list))
399 7493ccb6 Stavros Sachtouris
400 7493ccb6 Stavros Sachtouris
    def print_containers(self, container_list):
401 0399ac7e Stavros Sachtouris
        if self['json_output']:
402 0399ac7e Stavros Sachtouris
            print_json(container_list)
403 0399ac7e Stavros Sachtouris
            return
404 439826ec Stavros Sachtouris
        limit = int(self['limit']) if self['limit'] > 0\
405 439826ec Stavros Sachtouris
            else len(container_list)
406 234954d1 Stavros Sachtouris
        for index, container in enumerate(container_list):
407 234954d1 Stavros Sachtouris
            if 'bytes' in container:
408 234954d1 Stavros Sachtouris
                size = format_size(container['bytes'])
409 ed9af02c Stavros Sachtouris
            prfx = ('%s. ' % (index + 1)) if self['enum'] else ''
410 ed9af02c Stavros Sachtouris
            cname = '%s%s' % (prfx, bold(container['name']))
411 47ae7577 Stavros Sachtouris
            if self['detail']:
412 7493ccb6 Stavros Sachtouris
                print(cname)
413 7493ccb6 Stavros Sachtouris
                pretty_c = container.copy()
414 234954d1 Stavros Sachtouris
                if 'bytes' in container:
415 234954d1 Stavros Sachtouris
                    pretty_c['bytes'] = '%s (%s)' % (container['bytes'], size)
416 0f383dcc Stavros Sachtouris
                print_dict(pretty_c, exclude=('name'))
417 7493ccb6 Stavros Sachtouris
                print
418 7493ccb6 Stavros Sachtouris
            else:
419 234954d1 Stavros Sachtouris
                if 'count' in container and 'bytes' in container:
420 de73876b Stavros Sachtouris
                    print('%s (%s, %s objects)' % (
421 de73876b Stavros Sachtouris
                        cname,
422 de73876b Stavros Sachtouris
                        size,
423 de73876b Stavros Sachtouris
                        container['count']))
424 7493ccb6 Stavros Sachtouris
                else:
425 7493ccb6 Stavros Sachtouris
                    print(cname)
426 439826ec Stavros Sachtouris
            if self['more']:
427 439826ec Stavros Sachtouris
                page_hold(index + 1, limit, len(container_list))
428 7493ccb6 Stavros Sachtouris
429 1395c40e Stavros Sachtouris
    @errors.generic.all
430 1395c40e Stavros Sachtouris
    @errors.pithos.connection
431 1395c40e Stavros Sachtouris
    @errors.pithos.object_path
432 1395c40e Stavros Sachtouris
    @errors.pithos.container
433 1395c40e Stavros Sachtouris
    def _run(self):
434 1395c40e Stavros Sachtouris
        if self.container is None:
435 1395c40e Stavros Sachtouris
            r = self.client.account_get(
436 1395c40e Stavros Sachtouris
                limit=False if self['more'] else self['limit'],
437 1395c40e Stavros Sachtouris
                marker=self['marker'],
438 1395c40e Stavros Sachtouris
                if_modified_since=self['if_modified_since'],
439 1395c40e Stavros Sachtouris
                if_unmodified_since=self['if_unmodified_since'],
440 1395c40e Stavros Sachtouris
                until=self['until'],
441 1395c40e Stavros Sachtouris
                show_only_shared=self['shared'])
442 6d190dd1 Stavros Sachtouris
            files = self._filter_by_name(r.json)
443 6d190dd1 Stavros Sachtouris
            self._print(files, self.print_containers)
444 1395c40e Stavros Sachtouris
        else:
445 d8ff7b56 Stavros Sachtouris
            prefix = (self.path and not self['name']) or self['name_pref']
446 1395c40e Stavros Sachtouris
            r = self.client.container_get(
447 1395c40e Stavros Sachtouris
                limit=False if self['more'] else self['limit'],
448 1395c40e Stavros Sachtouris
                marker=self['marker'],
449 1395c40e Stavros Sachtouris
                prefix=prefix,
450 1395c40e Stavros Sachtouris
                delimiter=self['delimiter'],
451 1395c40e Stavros Sachtouris
                path=self['path'],
452 1395c40e Stavros Sachtouris
                if_modified_since=self['if_modified_since'],
453 1395c40e Stavros Sachtouris
                if_unmodified_since=self['if_unmodified_since'],
454 1395c40e Stavros Sachtouris
                until=self['until'],
455 1395c40e Stavros Sachtouris
                meta=self['meta'],
456 1395c40e Stavros Sachtouris
                show_only_shared=self['shared'])
457 6d190dd1 Stavros Sachtouris
            files = self._filter_by_name(r.json)
458 6d190dd1 Stavros Sachtouris
            self._print(files, self.print_objects)
459 1395c40e Stavros Sachtouris
460 7493ccb6 Stavros Sachtouris
    def main(self, container____path__=None):
461 1395c40e Stavros Sachtouris
        super(self.__class__, self)._run(container____path__)
462 1395c40e Stavros Sachtouris
        self._run()
463 7493ccb6 Stavros Sachtouris
464 234954d1 Stavros Sachtouris
465 d486baec Stavros Sachtouris
@command(pithos_cmds)
466 915b99b5 Stavros Sachtouris
class file_mkdir(_file_container_command, _optional_output_cmd):
467 f17d6cb5 Stavros Sachtouris
    """Create a directory
468 f17d6cb5 Stavros Sachtouris
    Kamaki hanldes directories the same way as OOS Storage and Pithos+:
469 f17d6cb5 Stavros Sachtouris
    A directory  is   an  object  with  type  "application/directory"
470 f17d6cb5 Stavros Sachtouris
    An object with path  dir/name can exist even if  dir does not exist
471 f17d6cb5 Stavros Sachtouris
    or even if dir  is  a non  directory  object.  Users can modify dir '
472 f17d6cb5 Stavros Sachtouris
    without affecting the dir/name object in any way.
473 f17d6cb5 Stavros Sachtouris
    """
474 7493ccb6 Stavros Sachtouris
475 1395c40e Stavros Sachtouris
    @errors.generic.all
476 1395c40e Stavros Sachtouris
    @errors.pithos.connection
477 1395c40e Stavros Sachtouris
    @errors.pithos.container
478 1395c40e Stavros Sachtouris
    def _run(self):
479 915b99b5 Stavros Sachtouris
        self._optional_output(self.client.create_directory(self.path))
480 1395c40e Stavros Sachtouris
481 7493ccb6 Stavros Sachtouris
    def main(self, container___directory):
482 1395c40e Stavros Sachtouris
        super(self.__class__, self)._run(
483 1395c40e Stavros Sachtouris
            container___directory,
484 1395c40e Stavros Sachtouris
            path_is_optional=False)
485 1395c40e Stavros Sachtouris
        self._run()
486 7493ccb6 Stavros Sachtouris
487 234954d1 Stavros Sachtouris
488 d486baec Stavros Sachtouris
@command(pithos_cmds)
489 915b99b5 Stavros Sachtouris
class file_touch(_file_container_command, _optional_output_cmd):
490 1e29b9f6 Stavros Sachtouris
    """Create an empty object (file)
491 1e29b9f6 Stavros Sachtouris
    If object exists, this command will reset it to 0 length
492 1e29b9f6 Stavros Sachtouris
    """
493 1e29b9f6 Stavros Sachtouris
494 1e29b9f6 Stavros Sachtouris
    arguments = dict(
495 1e29b9f6 Stavros Sachtouris
        content_type=ValueArgument(
496 1e29b9f6 Stavros Sachtouris
            'Set content type (default: application/octet-stream)',
497 1e29b9f6 Stavros Sachtouris
            '--content-type',
498 915b99b5 Stavros Sachtouris
            default='application/octet-stream')
499 1e29b9f6 Stavros Sachtouris
    )
500 1e29b9f6 Stavros Sachtouris
501 1395c40e Stavros Sachtouris
    @errors.generic.all
502 1395c40e Stavros Sachtouris
    @errors.pithos.connection
503 1395c40e Stavros Sachtouris
    @errors.pithos.container
504 1395c40e Stavros Sachtouris
    def _run(self):
505 915b99b5 Stavros Sachtouris
        self._optional_output(
506 915b99b5 Stavros Sachtouris
            self.client.create_object(self.path, self['content_type']))
507 1395c40e Stavros Sachtouris
508 1e29b9f6 Stavros Sachtouris
    def main(self, container___path):
509 3ae60112 Stavros Sachtouris
        super(file_touch, self)._run(
510 52edad0a Stavros Sachtouris
            container___path,
511 52edad0a Stavros Sachtouris
            path_is_optional=False)
512 1395c40e Stavros Sachtouris
        self._run()
513 1e29b9f6 Stavros Sachtouris
514 1e29b9f6 Stavros Sachtouris
515 1e29b9f6 Stavros Sachtouris
@command(pithos_cmds)
516 915b99b5 Stavros Sachtouris
class file_create(_file_container_command, _optional_output_cmd):
517 1e29b9f6 Stavros Sachtouris
    """Create a container"""
518 7493ccb6 Stavros Sachtouris
519 2fe2672e Stavros Sachtouris
    arguments = dict(
520 2fe2672e Stavros Sachtouris
        versioning=ValueArgument(
521 201baa17 Stavros Sachtouris
            'set container versioning (auto/none)', '--versioning'),
522 3ed6dbde Stavros Sachtouris
        limit=IntArgument('set default container limit', '--limit'),
523 2fe2672e Stavros Sachtouris
        meta=KeyValueArgument(
524 201baa17 Stavros Sachtouris
            'set container metadata (can be repeated)', '--meta')
525 2fe2672e Stavros Sachtouris
    )
526 7493ccb6 Stavros Sachtouris
527 1395c40e Stavros Sachtouris
    @errors.generic.all
528 1395c40e Stavros Sachtouris
    @errors.pithos.connection
529 1395c40e Stavros Sachtouris
    @errors.pithos.container
530 94bedc5b Stavros Sachtouris
    def _run(self, container):
531 915b99b5 Stavros Sachtouris
        self._optional_output(self.client.create_container(
532 915b99b5 Stavros Sachtouris
            container=container,
533 915b99b5 Stavros Sachtouris
            sizelimit=self['limit'],
534 915b99b5 Stavros Sachtouris
            versioning=self['versioning'],
535 915b99b5 Stavros Sachtouris
            metadata=self['meta']))
536 1395c40e Stavros Sachtouris
537 edab7ba7 Stavros Sachtouris
    def main(self, container=None):
538 1395c40e Stavros Sachtouris
        super(self.__class__, self)._run(container)
539 edab7ba7 Stavros Sachtouris
        if container and self.container != container:
540 1395c40e Stavros Sachtouris
            raiseCLIError('Invalid container name %s' % container, details=[
541 edab7ba7 Stavros Sachtouris
                'Did you mean "%s" ?' % self.container,
542 52edad0a Stavros Sachtouris
                'Use --container for names containing :'])
543 94bedc5b Stavros Sachtouris
        self._run(container)
544 7493ccb6 Stavros Sachtouris
545 234954d1 Stavros Sachtouris
546 3ae60112 Stavros Sachtouris
class _source_destination_command(_file_container_command):
547 2fe2672e Stavros Sachtouris
548 2fe2672e Stavros Sachtouris
    arguments = dict(
549 f17d6cb5 Stavros Sachtouris
        destination_account=ValueArgument('', ('-a', '--dst-account')),
550 f40f0cb7 Stavros Sachtouris
        recursive=FlagArgument('', ('-R', '--recursive')),
551 761e0cbf Stavros Sachtouris
        prefix=FlagArgument('', '--with-prefix', default=''),
552 761e0cbf Stavros Sachtouris
        suffix=ValueArgument('', '--with-suffix', default=''),
553 761e0cbf Stavros Sachtouris
        add_prefix=ValueArgument('', '--add-prefix', default=''),
554 761e0cbf Stavros Sachtouris
        add_suffix=ValueArgument('', '--add-suffix', default=''),
555 761e0cbf Stavros Sachtouris
        prefix_replace=ValueArgument('', '--prefix-to-replace', default=''),
556 1d3f006b Stavros Sachtouris
        suffix_replace=ValueArgument('', '--suffix-to-replace', default=''),
557 2fe2672e Stavros Sachtouris
    )
558 7493ccb6 Stavros Sachtouris
559 b4f69041 Stavros Sachtouris
    def __init__(self, arguments={}, auth_base=None, cloud=None):
560 761e0cbf Stavros Sachtouris
        self.arguments.update(arguments)
561 f724cd35 Stavros Sachtouris
        super(_source_destination_command, self).__init__(
562 b4f69041 Stavros Sachtouris
            self.arguments, auth_base, cloud)
563 761e0cbf Stavros Sachtouris
564 300da0fb Stavros Sachtouris
    def _run(self, source_container___path, path_is_optional=False):
565 300da0fb Stavros Sachtouris
        super(_source_destination_command, self)._run(
566 300da0fb Stavros Sachtouris
            source_container___path,
567 300da0fb Stavros Sachtouris
            path_is_optional)
568 300da0fb Stavros Sachtouris
        self.dst_client = PithosClient(
569 300da0fb Stavros Sachtouris
            base_url=self.client.base_url,
570 300da0fb Stavros Sachtouris
            token=self.client.token,
571 300da0fb Stavros Sachtouris
            account=self['destination_account'] or self.client.account)
572 300da0fb Stavros Sachtouris
573 300da0fb Stavros Sachtouris
    @errors.generic.all
574 300da0fb Stavros Sachtouris
    @errors.pithos.account
575 300da0fb Stavros Sachtouris
    def _dest_container_path(self, dest_container_path):
576 300da0fb Stavros Sachtouris
        if self['destination_container']:
577 300da0fb Stavros Sachtouris
            self.dst_client.container = self['destination_container']
578 300da0fb Stavros Sachtouris
            return (self['destination_container'], dest_container_path)
579 300da0fb Stavros Sachtouris
        if dest_container_path:
580 300da0fb Stavros Sachtouris
            dst = dest_container_path.split(':')
581 300da0fb Stavros Sachtouris
            if len(dst) > 1:
582 300da0fb Stavros Sachtouris
                try:
583 300da0fb Stavros Sachtouris
                    self.dst_client.container = dst[0]
584 300da0fb Stavros Sachtouris
                    self.dst_client.get_container_info(dst[0])
585 300da0fb Stavros Sachtouris
                except ClientError as err:
586 300da0fb Stavros Sachtouris
                    if err.status in (404, 204):
587 300da0fb Stavros Sachtouris
                        raiseCLIError(
588 300da0fb Stavros Sachtouris
                            'Destination container %s not found' % dst[0])
589 300da0fb Stavros Sachtouris
                    raise
590 300da0fb Stavros Sachtouris
                else:
591 300da0fb Stavros Sachtouris
                    self.dst_client.container = dst[0]
592 300da0fb Stavros Sachtouris
                return (dst[0], dst[1])
593 300da0fb Stavros Sachtouris
            return(None, dst[0])
594 300da0fb Stavros Sachtouris
        raiseCLIError('No destination container:path provided')
595 300da0fb Stavros Sachtouris
596 ece4ae4b Stavros Sachtouris
    def _get_all(self, prefix):
597 ece4ae4b Stavros Sachtouris
        return self.client.container_get(prefix=prefix).json
598 ece4ae4b Stavros Sachtouris
599 1d3f006b Stavros Sachtouris
    def _get_src_objects(self, src_path, source_version=None):
600 6736f171 Stavros Sachtouris
        """Get a list of the source objects to be called
601 6736f171 Stavros Sachtouris

602 6736f171 Stavros Sachtouris
        :param src_path: (str) source path
603 6736f171 Stavros Sachtouris

604 6736f171 Stavros Sachtouris
        :returns: (method, params) a method that returns a list when called
605 6736f171 Stavros Sachtouris
        or (object) if it is a single object
606 6736f171 Stavros Sachtouris
        """
607 ece4ae4b Stavros Sachtouris
        if src_path and src_path[-1] == '/':
608 ece4ae4b Stavros Sachtouris
            src_path = src_path[:-1]
609 ece4ae4b Stavros Sachtouris
610 6736f171 Stavros Sachtouris
        if self['prefix']:
611 6736f171 Stavros Sachtouris
            return (self._get_all, dict(prefix=src_path))
612 ece4ae4b Stavros Sachtouris
        try:
613 1d3f006b Stavros Sachtouris
            srcobj = self.client.get_object_info(
614 1d3f006b Stavros Sachtouris
                src_path, version=source_version)
615 ece4ae4b Stavros Sachtouris
        except ClientError as srcerr:
616 6736f171 Stavros Sachtouris
            if srcerr.status == 404:
617 6736f171 Stavros Sachtouris
                raiseCLIError(
618 300da0fb Stavros Sachtouris
                    'Source object %s not in source container %s' % (
619 201baa17 Stavros Sachtouris
                        src_path, self.client.container),
620 6736f171 Stavros Sachtouris
                    details=['Hint: --with-prefix to match multiple objects'])
621 6736f171 Stavros Sachtouris
            elif srcerr.status not in (204,):
622 ece4ae4b Stavros Sachtouris
                raise
623 6736f171 Stavros Sachtouris
            return (self.client.list_objects, {})
624 300da0fb Stavros Sachtouris
625 6736f171 Stavros Sachtouris
        if self._is_dir(srcobj):
626 6736f171 Stavros Sachtouris
            if not self['recursive']:
627 6736f171 Stavros Sachtouris
                raiseCLIError(
628 300da0fb Stavros Sachtouris
                    'Object %s of cont. %s is a dir' % (
629 201baa17 Stavros Sachtouris
                        src_path, self.client.container),
630 6736f171 Stavros Sachtouris
                    details=['Use --recursive to access directories'])
631 6736f171 Stavros Sachtouris
            return (self._get_all, dict(prefix=src_path))
632 6736f171 Stavros Sachtouris
        srcobj['name'] = src_path
633 6736f171 Stavros Sachtouris
        return srcobj
634 6736f171 Stavros Sachtouris
635 1d3f006b Stavros Sachtouris
    def src_dst_pairs(self, dst_path, source_version=None):
636 1d3f006b Stavros Sachtouris
        src_iter = self._get_src_objects(self.path, source_version)
637 6736f171 Stavros Sachtouris
        src_N = isinstance(src_iter, tuple)
638 6736f171 Stavros Sachtouris
        add_prefix = self['add_prefix'].strip('/')
639 6736f171 Stavros Sachtouris
640 6736f171 Stavros Sachtouris
        if dst_path and dst_path.endswith('/'):
641 ece4ae4b Stavros Sachtouris
            dst_path = dst_path[:-1]
642 ece4ae4b Stavros Sachtouris
643 6736f171 Stavros Sachtouris
        try:
644 300da0fb Stavros Sachtouris
            dstobj = self.dst_client.get_object_info(dst_path)
645 6736f171 Stavros Sachtouris
        except ClientError as trgerr:
646 6736f171 Stavros Sachtouris
            if trgerr.status in (404,):
647 6736f171 Stavros Sachtouris
                if src_N:
648 6736f171 Stavros Sachtouris
                    raiseCLIError(
649 6736f171 Stavros Sachtouris
                        'Cannot merge multiple paths to path %s' % dst_path,
650 6736f171 Stavros Sachtouris
                        details=[
651 6736f171 Stavros Sachtouris
                            'Try to use / or a directory as destination',
652 3ae60112 Stavros Sachtouris
                            'or create the destination dir (/file mkdir)',
653 6736f171 Stavros Sachtouris
                            'or use a single object as source'])
654 6736f171 Stavros Sachtouris
            elif trgerr.status not in (204,):
655 6736f171 Stavros Sachtouris
                raise
656 6736f171 Stavros Sachtouris
        else:
657 6736f171 Stavros Sachtouris
            if self._is_dir(dstobj):
658 6736f171 Stavros Sachtouris
                add_prefix = '%s/%s' % (dst_path.strip('/'), add_prefix)
659 6736f171 Stavros Sachtouris
            elif src_N:
660 6736f171 Stavros Sachtouris
                raiseCLIError(
661 6736f171 Stavros Sachtouris
                    'Cannot merge multiple paths to path' % dst_path,
662 6736f171 Stavros Sachtouris
                    details=[
663 6736f171 Stavros Sachtouris
                        'Try to use / or a directory as destination',
664 3ae60112 Stavros Sachtouris
                        'or create the destination dir (/file mkdir)',
665 6736f171 Stavros Sachtouris
                        'or use a single object as source'])
666 6736f171 Stavros Sachtouris
667 6736f171 Stavros Sachtouris
        if src_N:
668 6736f171 Stavros Sachtouris
            (method, kwargs) = src_iter
669 6736f171 Stavros Sachtouris
            for obj in method(**kwargs):
670 6736f171 Stavros Sachtouris
                name = obj['name']
671 6736f171 Stavros Sachtouris
                if name.endswith(self['suffix']):
672 6736f171 Stavros Sachtouris
                    yield (name, self._get_new_object(name, add_prefix))
673 6736f171 Stavros Sachtouris
        elif src_iter['name'].endswith(self['suffix']):
674 6736f171 Stavros Sachtouris
            name = src_iter['name']
675 6736f171 Stavros Sachtouris
            yield (name, self._get_new_object(dst_path or name, add_prefix))
676 6736f171 Stavros Sachtouris
        else:
677 6736f171 Stavros Sachtouris
            raiseCLIError('Source path %s conflicts with suffix %s' % (
678 201baa17 Stavros Sachtouris
                src_iter['name'], self['suffix']))
679 ece4ae4b Stavros Sachtouris
680 6736f171 Stavros Sachtouris
    def _get_new_object(self, obj, add_prefix):
681 6736f171 Stavros Sachtouris
        if self['prefix_replace'] and obj.startswith(self['prefix_replace']):
682 6736f171 Stavros Sachtouris
            obj = obj[len(self['prefix_replace']):]
683 6736f171 Stavros Sachtouris
        if self['suffix_replace'] and obj.endswith(self['suffix_replace']):
684 6736f171 Stavros Sachtouris
            obj = obj[:-len(self['suffix_replace'])]
685 6736f171 Stavros Sachtouris
        return add_prefix + obj + self['add_suffix']
686 efdee310 Stavros Sachtouris
687 761e0cbf Stavros Sachtouris
688 761e0cbf Stavros Sachtouris
@command(pithos_cmds)
689 915b99b5 Stavros Sachtouris
class file_copy(_source_destination_command, _optional_output_cmd):
690 761e0cbf Stavros Sachtouris
    """Copy objects from container to (another) container
691 761e0cbf Stavros Sachtouris
    Semantics:
692 761e0cbf Stavros Sachtouris
    copy cont:path dir
693 761e0cbf Stavros Sachtouris
    .   transfer path as dir/path
694 761e0cbf Stavros Sachtouris
    copy cont:path cont2:
695 761e0cbf Stavros Sachtouris
    .   trasnfer all <obj> prefixed with path to container cont2
696 761e0cbf Stavros Sachtouris
    copy cont:path [cont2:]path2
697 761e0cbf Stavros Sachtouris
    .   transfer path to path2
698 761e0cbf Stavros Sachtouris
    Use options:
699 761e0cbf Stavros Sachtouris
    1. <container1>:<path1> [container2:]<path2> : if container2 is not given,
700 761e0cbf Stavros Sachtouris
    destination is container1:path2
701 761e0cbf Stavros Sachtouris
    2. <container>:<path1> <path2> : make a copy in the same container
702 761e0cbf Stavros Sachtouris
    3. Can use --container= instead of <container1>
703 761e0cbf Stavros Sachtouris
    """
704 761e0cbf Stavros Sachtouris
705 761e0cbf Stavros Sachtouris
    arguments = dict(
706 300da0fb Stavros Sachtouris
        destination_account=ValueArgument(
707 201baa17 Stavros Sachtouris
            'Account to copy to', ('-a', '--dst-account')),
708 761e0cbf Stavros Sachtouris
        destination_container=ValueArgument(
709 761e0cbf Stavros Sachtouris
            'use it if destination container name contains a : character',
710 f40f0cb7 Stavros Sachtouris
            ('-D', '--dst-container')),
711 761e0cbf Stavros Sachtouris
        public=ValueArgument('make object publicly accessible', '--public'),
712 761e0cbf Stavros Sachtouris
        content_type=ValueArgument(
713 201baa17 Stavros Sachtouris
            'change object\'s content type', '--content-type'),
714 761e0cbf Stavros Sachtouris
        recursive=FlagArgument(
715 201baa17 Stavros Sachtouris
            'copy directory and contents', ('-R', '--recursive')),
716 761e0cbf Stavros Sachtouris
        prefix=FlagArgument(
717 761e0cbf Stavros Sachtouris
            'Match objects prefixed with src path (feels like src_path*)',
718 761e0cbf Stavros Sachtouris
            '--with-prefix',
719 761e0cbf Stavros Sachtouris
            default=''),
720 761e0cbf Stavros Sachtouris
        suffix=ValueArgument(
721 201baa17 Stavros Sachtouris
            'Suffix of source objects (feels like *suffix)', '--with-suffix',
722 761e0cbf Stavros Sachtouris
            default=''),
723 761e0cbf Stavros Sachtouris
        add_prefix=ValueArgument('Prefix targets', '--add-prefix', default=''),
724 761e0cbf Stavros Sachtouris
        add_suffix=ValueArgument('Suffix targets', '--add-suffix', default=''),
725 761e0cbf Stavros Sachtouris
        prefix_replace=ValueArgument(
726 761e0cbf Stavros Sachtouris
            'Prefix of src to replace with dst path + add_prefix, if matched',
727 761e0cbf Stavros Sachtouris
            '--prefix-to-replace',
728 761e0cbf Stavros Sachtouris
            default=''),
729 761e0cbf Stavros Sachtouris
        suffix_replace=ValueArgument(
730 761e0cbf Stavros Sachtouris
            'Suffix of src to replace with add_suffix, if matched',
731 761e0cbf Stavros Sachtouris
            '--suffix-to-replace',
732 1d3f006b Stavros Sachtouris
            default=''),
733 1d3f006b Stavros Sachtouris
        source_version=ValueArgument(
734 201baa17 Stavros Sachtouris
            'copy specific version', ('-S', '--source-version'))
735 761e0cbf Stavros Sachtouris
    )
736 761e0cbf Stavros Sachtouris
737 1395c40e Stavros Sachtouris
    @errors.generic.all
738 1395c40e Stavros Sachtouris
    @errors.pithos.connection
739 1395c40e Stavros Sachtouris
    @errors.pithos.container
740 300da0fb Stavros Sachtouris
    @errors.pithos.account
741 300da0fb Stavros Sachtouris
    def _run(self, dst_path):
742 1395c40e Stavros Sachtouris
        no_source_object = True
743 300da0fb Stavros Sachtouris
        src_account = self.client.account if (
744 300da0fb Stavros Sachtouris
            self['destination_account']) else None
745 1d3f006b Stavros Sachtouris
        for src_obj, dst_obj in self.src_dst_pairs(
746 1d3f006b Stavros Sachtouris
                dst_path, self['source_version']):
747 1395c40e Stavros Sachtouris
            no_source_object = False
748 55c75058 Stavros Sachtouris
            r = self.dst_client.copy_object(
749 300da0fb Stavros Sachtouris
                src_container=self.client.container,
750 3a066af4 Stavros Sachtouris
                src_object=src_obj,
751 300da0fb Stavros Sachtouris
                dst_container=self.dst_client.container,
752 300da0fb Stavros Sachtouris
                dst_object=dst_obj,
753 300da0fb Stavros Sachtouris
                source_account=src_account,
754 1395c40e Stavros Sachtouris
                source_version=self['source_version'],
755 1395c40e Stavros Sachtouris
                public=self['public'],
756 1395c40e Stavros Sachtouris
                content_type=self['content_type'])
757 1395c40e Stavros Sachtouris
        if no_source_object:
758 1395c40e Stavros Sachtouris
            raiseCLIError('No object %s in container %s' % (
759 201baa17 Stavros Sachtouris
                self.path, self.container))
760 915b99b5 Stavros Sachtouris
        self._optional_output(r)
761 1395c40e Stavros Sachtouris
762 de73876b Stavros Sachtouris
    def main(
763 e2d7b883 Stavros Sachtouris
            self, source_container___path,
764 24ff0a35 Stavros Sachtouris
            destination_container___path=None):
765 3ae60112 Stavros Sachtouris
        super(file_copy, self)._run(
766 1395c40e Stavros Sachtouris
            source_container___path,
767 1395c40e Stavros Sachtouris
            path_is_optional=False)
768 1395c40e Stavros Sachtouris
        (dst_cont, dst_path) = self._dest_container_path(
769 0e4ee6d1 Stavros Sachtouris
            destination_container___path)
770 300da0fb Stavros Sachtouris
        self.dst_client.container = dst_cont or self.container
771 300da0fb Stavros Sachtouris
        self._run(dst_path=dst_path or '')
772 7493ccb6 Stavros Sachtouris
773 234954d1 Stavros Sachtouris
774 d486baec Stavros Sachtouris
@command(pithos_cmds)
775 915b99b5 Stavros Sachtouris
class file_move(_source_destination_command, _optional_output_cmd):
776 761e0cbf Stavros Sachtouris
    """Move/rename objects from container to (another) container
777 8249ee0f Stavros Sachtouris
    Semantics:
778 761e0cbf Stavros Sachtouris
    move cont:path dir
779 761e0cbf Stavros Sachtouris
    .   rename path as dir/path
780 8249ee0f Stavros Sachtouris
    move cont:path cont2:
781 761e0cbf Stavros Sachtouris
    .   trasnfer all <obj> prefixed with path to container cont2
782 761e0cbf Stavros Sachtouris
    move cont:path [cont2:]path2
783 761e0cbf Stavros Sachtouris
    .   transfer path to path2
784 2fe2672e Stavros Sachtouris
    Use options:
785 761e0cbf Stavros Sachtouris
    1. <container1>:<path1> [container2:]<path2> : if container2 is not given,
786 795bf206 Stavros Sachtouris
    destination is container1:path2
787 761e0cbf Stavros Sachtouris
    2. <container>:<path1> <path2> : move in the same container
788 8249ee0f Stavros Sachtouris
    3. Can use --container= instead of <container1>
789 2fe2672e Stavros Sachtouris
    """
790 2fe2672e Stavros Sachtouris
791 2fe2672e Stavros Sachtouris
    arguments = dict(
792 300da0fb Stavros Sachtouris
        destination_account=ValueArgument(
793 201baa17 Stavros Sachtouris
            'Account to move to', ('-a', '--dst-account')),
794 0e4ee6d1 Stavros Sachtouris
        destination_container=ValueArgument(
795 0e4ee6d1 Stavros Sachtouris
            'use it if destination container name contains a : character',
796 f40f0cb7 Stavros Sachtouris
            ('-D', '--dst-container')),
797 761e0cbf Stavros Sachtouris
        public=ValueArgument('make object publicly accessible', '--public'),
798 761e0cbf Stavros Sachtouris
        content_type=ValueArgument(
799 201baa17 Stavros Sachtouris
            'change object\'s content type', '--content-type'),
800 761e0cbf Stavros Sachtouris
        recursive=FlagArgument(
801 201baa17 Stavros Sachtouris
            'copy directory and contents', ('-R', '--recursive')),
802 761e0cbf Stavros Sachtouris
        prefix=FlagArgument(
803 761e0cbf Stavros Sachtouris
            'Match objects prefixed with src path (feels like src_path*)',
804 761e0cbf Stavros Sachtouris
            '--with-prefix',
805 761e0cbf Stavros Sachtouris
            default=''),
806 761e0cbf Stavros Sachtouris
        suffix=ValueArgument(
807 201baa17 Stavros Sachtouris
            'Suffix of source objects (feels like *suffix)', '--with-suffix',
808 761e0cbf Stavros Sachtouris
            default=''),
809 761e0cbf Stavros Sachtouris
        add_prefix=ValueArgument('Prefix targets', '--add-prefix', default=''),
810 761e0cbf Stavros Sachtouris
        add_suffix=ValueArgument('Suffix targets', '--add-suffix', default=''),
811 761e0cbf Stavros Sachtouris
        prefix_replace=ValueArgument(
812 761e0cbf Stavros Sachtouris
            'Prefix of src to replace with dst path + add_prefix, if matched',
813 761e0cbf Stavros Sachtouris
            '--prefix-to-replace',
814 761e0cbf Stavros Sachtouris
            default=''),
815 761e0cbf Stavros Sachtouris
        suffix_replace=ValueArgument(
816 761e0cbf Stavros Sachtouris
            'Suffix of src to replace with add_suffix, if matched',
817 761e0cbf Stavros Sachtouris
            '--suffix-to-replace',
818 915b99b5 Stavros Sachtouris
            default='')
819 2fe2672e Stavros Sachtouris
    )
820 7493ccb6 Stavros Sachtouris
821 1395c40e Stavros Sachtouris
    @errors.generic.all
822 1395c40e Stavros Sachtouris
    @errors.pithos.connection
823 1395c40e Stavros Sachtouris
    @errors.pithos.container
824 300da0fb Stavros Sachtouris
    def _run(self, dst_path):
825 1395c40e Stavros Sachtouris
        no_source_object = True
826 300da0fb Stavros Sachtouris
        src_account = self.client.account if (
827 300da0fb Stavros Sachtouris
            self['destination_account']) else None
828 300da0fb Stavros Sachtouris
        for src_obj, dst_obj in self.src_dst_pairs(dst_path):
829 1395c40e Stavros Sachtouris
            no_source_object = False
830 55c75058 Stavros Sachtouris
            r = self.dst_client.move_object(
831 1395c40e Stavros Sachtouris
                src_container=self.container,
832 300da0fb Stavros Sachtouris
                src_object=src_obj,
833 300da0fb Stavros Sachtouris
                dst_container=self.dst_client.container,
834 300da0fb Stavros Sachtouris
                dst_object=dst_obj,
835 4f266635 Stavros Sachtouris
                source_account=src_account,
836 1395c40e Stavros Sachtouris
                public=self['public'],
837 1395c40e Stavros Sachtouris
                content_type=self['content_type'])
838 1395c40e Stavros Sachtouris
        if no_source_object:
839 1395c40e Stavros Sachtouris
            raiseCLIError('No object %s in container %s' % (
840 1395c40e Stavros Sachtouris
                self.path,
841 1395c40e Stavros Sachtouris
                self.container))
842 915b99b5 Stavros Sachtouris
        self._optional_output(r)
843 1395c40e Stavros Sachtouris
844 de73876b Stavros Sachtouris
    def main(
845 e2d7b883 Stavros Sachtouris
            self, source_container___path,
846 24ff0a35 Stavros Sachtouris
            destination_container___path=None):
847 1395c40e Stavros Sachtouris
        super(self.__class__, self)._run(
848 1395c40e Stavros Sachtouris
            source_container___path,
849 1395c40e Stavros Sachtouris
            path_is_optional=False)
850 45b70023 Stavros Sachtouris
        (dst_cont, dst_path) = self._dest_container_path(
851 1395c40e Stavros Sachtouris
            destination_container___path)
852 300da0fb Stavros Sachtouris
        (dst_cont, dst_path) = self._dest_container_path(
853 300da0fb Stavros Sachtouris
            destination_container___path)
854 300da0fb Stavros Sachtouris
        self.dst_client.container = dst_cont or self.container
855 300da0fb Stavros Sachtouris
        self._run(dst_path=dst_path or '')
856 7493ccb6 Stavros Sachtouris
857 234954d1 Stavros Sachtouris
858 d486baec Stavros Sachtouris
@command(pithos_cmds)
859 915b99b5 Stavros Sachtouris
class file_append(_file_container_command, _optional_output_cmd):
860 aaca2ef4 Stavros Sachtouris
    """Append local file to (existing) remote object
861 aaca2ef4 Stavros Sachtouris
    The remote object should exist.
862 aaca2ef4 Stavros Sachtouris
    If the remote object is a directory, it is transformed into a file.
863 aaca2ef4 Stavros Sachtouris
    In the later case, objects under the directory remain intact.
864 aaca2ef4 Stavros Sachtouris
    """
865 7493ccb6 Stavros Sachtouris
866 2fe2672e Stavros Sachtouris
    arguments = dict(
867 2fe2672e Stavros Sachtouris
        progress_bar=ProgressBarArgument(
868 2fe2672e Stavros Sachtouris
            'do not show progress bar',
869 f40f0cb7 Stavros Sachtouris
            ('-N', '--no-progress-bar'),
870 915b99b5 Stavros Sachtouris
            default=False)
871 2fe2672e Stavros Sachtouris
    )
872 486f7af1 Stavros Sachtouris
873 ca092af4 Stavros Sachtouris
    @errors.generic.all
874 ca092af4 Stavros Sachtouris
    @errors.pithos.connection
875 ca092af4 Stavros Sachtouris
    @errors.pithos.container
876 ca092af4 Stavros Sachtouris
    @errors.pithos.object_path
877 ca092af4 Stavros Sachtouris
    def _run(self, local_path):
878 ca092af4 Stavros Sachtouris
        (progress_bar, upload_cb) = self._safe_progress_bar('Appending')
879 7493ccb6 Stavros Sachtouris
        try:
880 e876ac62 Stavros Sachtouris
            f = open(local_path, 'rb')
881 915b99b5 Stavros Sachtouris
            self._optional_output(
882 915b99b5 Stavros Sachtouris
                self.client.append_object(self.path, f, upload_cb))
883 ca092af4 Stavros Sachtouris
        except Exception:
884 ca092af4 Stavros Sachtouris
            self._safe_progress_bar_finish(progress_bar)
885 ca092af4 Stavros Sachtouris
            raise
886 852a22e7 Stavros Sachtouris
        finally:
887 ca092af4 Stavros Sachtouris
            self._safe_progress_bar_finish(progress_bar)
888 ca092af4 Stavros Sachtouris
889 ca092af4 Stavros Sachtouris
    def main(self, local_path, container___path):
890 ca092af4 Stavros Sachtouris
        super(self.__class__, self)._run(
891 201baa17 Stavros Sachtouris
            container___path, path_is_optional=False)
892 ca092af4 Stavros Sachtouris
        self._run(local_path)
893 7493ccb6 Stavros Sachtouris
894 234954d1 Stavros Sachtouris
895 d486baec Stavros Sachtouris
@command(pithos_cmds)
896 915b99b5 Stavros Sachtouris
class file_truncate(_file_container_command, _optional_output_cmd):
897 aaca2ef4 Stavros Sachtouris
    """Truncate remote file up to a size (default is 0)"""
898 7493ccb6 Stavros Sachtouris
899 ca092af4 Stavros Sachtouris
    @errors.generic.all
900 ca092af4 Stavros Sachtouris
    @errors.pithos.connection
901 ca092af4 Stavros Sachtouris
    @errors.pithos.container
902 ca092af4 Stavros Sachtouris
    @errors.pithos.object_path
903 ca092af4 Stavros Sachtouris
    @errors.pithos.object_size
904 ca092af4 Stavros Sachtouris
    def _run(self, size=0):
905 915b99b5 Stavros Sachtouris
        self._optional_output(self.client.truncate_object(self.path, size))
906 ca092af4 Stavros Sachtouris
907 7493ccb6 Stavros Sachtouris
    def main(self, container___path, size=0):
908 ca092af4 Stavros Sachtouris
        super(self.__class__, self)._run(container___path)
909 ca092af4 Stavros Sachtouris
        self._run(size=size)
910 7493ccb6 Stavros Sachtouris
911 234954d1 Stavros Sachtouris
912 d486baec Stavros Sachtouris
@command(pithos_cmds)
913 915b99b5 Stavros Sachtouris
class file_overwrite(_file_container_command, _optional_output_cmd):
914 aaca2ef4 Stavros Sachtouris
    """Overwrite part (from start to end) of a remote file
915 aaca2ef4 Stavros Sachtouris
    overwrite local-path container 10 20
916 aaca2ef4 Stavros Sachtouris
    .   will overwrite bytes from 10 to 20 of a remote file with the same name
917 aaca2ef4 Stavros Sachtouris
    .   as local-path basename
918 aaca2ef4 Stavros Sachtouris
    overwrite local-path container:path 10 20
919 aaca2ef4 Stavros Sachtouris
    .   will overwrite as above, but the remote file is named path
920 aaca2ef4 Stavros Sachtouris
    """
921 7493ccb6 Stavros Sachtouris
922 2fe2672e Stavros Sachtouris
    arguments = dict(
923 2fe2672e Stavros Sachtouris
        progress_bar=ProgressBarArgument(
924 2fe2672e Stavros Sachtouris
            'do not show progress bar',
925 f40f0cb7 Stavros Sachtouris
            ('-N', '--no-progress-bar'),
926 2fe2672e Stavros Sachtouris
            default=False)
927 2fe2672e Stavros Sachtouris
    )
928 486f7af1 Stavros Sachtouris
929 ca092af4 Stavros Sachtouris
    def _open_file(self, local_path, start):
930 ca092af4 Stavros Sachtouris
        f = open(path.abspath(local_path), 'rb')
931 ca092af4 Stavros Sachtouris
        f.seek(0, 2)
932 ca092af4 Stavros Sachtouris
        f_size = f.tell()
933 ca092af4 Stavros Sachtouris
        f.seek(start, 0)
934 ca092af4 Stavros Sachtouris
        return (f, f_size)
935 ca092af4 Stavros Sachtouris
936 ca092af4 Stavros Sachtouris
    @errors.generic.all
937 ca092af4 Stavros Sachtouris
    @errors.pithos.connection
938 ca092af4 Stavros Sachtouris
    @errors.pithos.container
939 ca092af4 Stavros Sachtouris
    @errors.pithos.object_path
940 ca092af4 Stavros Sachtouris
    @errors.pithos.object_size
941 ca092af4 Stavros Sachtouris
    def _run(self, local_path, start, end):
942 ca092af4 Stavros Sachtouris
        (start, end) = (int(start), int(end))
943 ca092af4 Stavros Sachtouris
        (f, f_size) = self._open_file(local_path, start)
944 ca092af4 Stavros Sachtouris
        (progress_bar, upload_cb) = self._safe_progress_bar(
945 ca092af4 Stavros Sachtouris
            'Overwrite %s bytes' % (end - start))
946 aaca2ef4 Stavros Sachtouris
        try:
947 915b99b5 Stavros Sachtouris
            self._optional_output(self.client.overwrite_object(
948 8fa6ef6a Stavros Sachtouris
                obj=self.path,
949 234954d1 Stavros Sachtouris
                start=start,
950 234954d1 Stavros Sachtouris
                end=end,
951 234954d1 Stavros Sachtouris
                source_file=f,
952 915b99b5 Stavros Sachtouris
                upload_cb=upload_cb))
953 852a22e7 Stavros Sachtouris
        finally:
954 ca092af4 Stavros Sachtouris
            self._safe_progress_bar_finish(progress_bar)
955 ca092af4 Stavros Sachtouris
956 52edad0a Stavros Sachtouris
    def main(self, local_path, container___path, start, end):
957 52edad0a Stavros Sachtouris
        super(self.__class__, self)._run(
958 201baa17 Stavros Sachtouris
            container___path, path_is_optional=None)
959 52edad0a Stavros Sachtouris
        self.path = self.path or path.basename(local_path)
960 ca092af4 Stavros Sachtouris
        self._run(local_path=local_path, start=start, end=end)
961 7493ccb6 Stavros Sachtouris
962 234954d1 Stavros Sachtouris
963 d486baec Stavros Sachtouris
@command(pithos_cmds)
964 915b99b5 Stavros Sachtouris
class file_manifest(_file_container_command, _optional_output_cmd):
965 8fa6ef6a Stavros Sachtouris
    """Create a remote file of uploaded parts by manifestation
966 35b52b0e Stavros Sachtouris
    Remains functional for compatibility with OOS Storage. Users are advised
967 35b52b0e Stavros Sachtouris
    to use the upload command instead.
968 35b52b0e Stavros Sachtouris
    Manifestation is a compliant process for uploading large files. The files
969 35b52b0e Stavros Sachtouris
    have to be chunked in smalled files and uploaded as <prefix><increment>
970 35b52b0e Stavros Sachtouris
    where increment is 1, 2, ...
971 35b52b0e Stavros Sachtouris
    Finally, the manifest command glues partial files together in one file
972 35b52b0e Stavros Sachtouris
    named <prefix>
973 35b52b0e Stavros Sachtouris
    The upload command is faster, easier and more intuitive than manifest
974 8fa6ef6a Stavros Sachtouris
    """
975 486f7af1 Stavros Sachtouris
976 2fe2672e Stavros Sachtouris
    arguments = dict(
977 2fe2672e Stavros Sachtouris
        etag=ValueArgument('check written data', '--etag'),
978 2fe2672e Stavros Sachtouris
        content_encoding=ValueArgument(
979 201baa17 Stavros Sachtouris
            'set MIME content type', '--content-encoding'),
980 2fe2672e Stavros Sachtouris
        content_disposition=ValueArgument(
981 201baa17 Stavros Sachtouris
            'the presentation style of the object', '--content-disposition'),
982 8fa6ef6a Stavros Sachtouris
        content_type=ValueArgument(
983 201baa17 Stavros Sachtouris
            'specify content type', '--content-type',
984 8fa6ef6a Stavros Sachtouris
            default='application/octet-stream'),
985 2fe2672e Stavros Sachtouris
        sharing=SharingArgument(
986 de73876b Stavros Sachtouris
            '\n'.join([
987 de73876b Stavros Sachtouris
                'define object sharing policy',
988 de73876b Stavros Sachtouris
                '    ( "read=user1,grp1,user2,... write=user1,grp2,..." )']),
989 2fe2672e Stavros Sachtouris
            '--sharing'),
990 2fe2672e Stavros Sachtouris
        public=FlagArgument('make object publicly accessible', '--public')
991 2fe2672e Stavros Sachtouris
    )
992 234954d1 Stavros Sachtouris
993 68858765 Stavros Sachtouris
    @errors.generic.all
994 68858765 Stavros Sachtouris
    @errors.pithos.connection
995 68858765 Stavros Sachtouris
    @errors.pithos.container
996 68858765 Stavros Sachtouris
    @errors.pithos.object_path
997 68858765 Stavros Sachtouris
    def _run(self):
998 abff3366 Stavros Sachtouris
        ctype, cenc = guess_mime_type(self.path)
999 915b99b5 Stavros Sachtouris
        self._optional_output(self.client.create_object_by_manifestation(
1000 68858765 Stavros Sachtouris
            self.path,
1001 f8426b5c Stavros Sachtouris
            content_encoding=self['content_encoding'] or cenc,
1002 68858765 Stavros Sachtouris
            content_disposition=self['content_disposition'],
1003 abff3366 Stavros Sachtouris
            content_type=self['content_type'] or ctype,
1004 68858765 Stavros Sachtouris
            sharing=self['sharing'],
1005 915b99b5 Stavros Sachtouris
            public=self['public']))
1006 68858765 Stavros Sachtouris
1007 7493ccb6 Stavros Sachtouris
    def main(self, container___path):
1008 68858765 Stavros Sachtouris
        super(self.__class__, self)._run(
1009 201baa17 Stavros Sachtouris
            container___path, path_is_optional=False)
1010 68858765 Stavros Sachtouris
        self.run()
1011 7493ccb6 Stavros Sachtouris
1012 234954d1 Stavros Sachtouris
1013 d486baec Stavros Sachtouris
@command(pithos_cmds)
1014 915b99b5 Stavros Sachtouris
class file_upload(_file_container_command, _optional_output_cmd):
1015 7493ccb6 Stavros Sachtouris
    """Upload a file"""
1016 7493ccb6 Stavros Sachtouris
1017 2fe2672e Stavros Sachtouris
    arguments = dict(
1018 2fe2672e Stavros Sachtouris
        use_hashes=FlagArgument(
1019 201baa17 Stavros Sachtouris
            'provide hashmap file instead of data', '--use-hashes'),
1020 2fe2672e Stavros Sachtouris
        etag=ValueArgument('check written data', '--etag'),
1021 2fe2672e Stavros Sachtouris
        unchunked=FlagArgument('avoid chunked transfer mode', '--unchunked'),
1022 2fe2672e Stavros Sachtouris
        content_encoding=ValueArgument(
1023 201baa17 Stavros Sachtouris
            'set MIME content type', '--content-encoding'),
1024 2fe2672e Stavros Sachtouris
        content_disposition=ValueArgument(
1025 201baa17 Stavros Sachtouris
            'specify objects presentation style', '--content-disposition'),
1026 2fe2672e Stavros Sachtouris
        content_type=ValueArgument('specify content type', '--content-type'),
1027 2fe2672e Stavros Sachtouris
        sharing=SharingArgument(
1028 de73876b Stavros Sachtouris
            help='\n'.join([
1029 de73876b Stavros Sachtouris
                'define sharing object policy',
1030 de73876b Stavros Sachtouris
                '( "read=user1,grp1,user2,... write=user1,grp2,... )']),
1031 2fe2672e Stavros Sachtouris
            parsed_name='--sharing'),
1032 2fe2672e Stavros Sachtouris
        public=FlagArgument('make object publicly accessible', '--public'),
1033 2fe2672e Stavros Sachtouris
        poolsize=IntArgument('set pool size', '--with-pool-size'),
1034 2fe2672e Stavros Sachtouris
        progress_bar=ProgressBarArgument(
1035 2fe2672e Stavros Sachtouris
            'do not show progress bar',
1036 8741c407 Stavros Sachtouris
            ('-N', '--no-progress-bar'),
1037 706fc940 Stavros Sachtouris
            default=False),
1038 2d158d8b Stavros Sachtouris
        overwrite=FlagArgument('Force (over)write', ('-f', '--force')),
1039 2d158d8b Stavros Sachtouris
        recursive=FlagArgument(
1040 2d158d8b Stavros Sachtouris
            'Recursively upload directory *contents* + subdirectories',
1041 915b99b5 Stavros Sachtouris
            ('-R', '--recursive'))
1042 2fe2672e Stavros Sachtouris
    )
1043 7493ccb6 Stavros Sachtouris
1044 14b25e00 Stavros Sachtouris
    def _check_container_limit(self, path):
1045 14b25e00 Stavros Sachtouris
        cl_dict = self.client.get_container_limit()
1046 14b25e00 Stavros Sachtouris
        container_limit = int(cl_dict['x-container-policy-quota'])
1047 2b74fc1d Stavros Sachtouris
        r = self.client.container_get()
1048 2b74fc1d Stavros Sachtouris
        used_bytes = sum(int(o['bytes']) for o in r.json)
1049 14b25e00 Stavros Sachtouris
        path_size = get_path_size(path)
1050 c8d8c6c9 Stavros Sachtouris
        if container_limit and path_size > (container_limit - used_bytes):
1051 2b74fc1d Stavros Sachtouris
            raiseCLIError(
1052 2b74fc1d Stavros Sachtouris
                'Container(%s) (limit(%s) - used(%s)) < size(%s) of %s' % (
1053 14b25e00 Stavros Sachtouris
                    self.client.container,
1054 14b25e00 Stavros Sachtouris
                    format_size(container_limit),
1055 2b74fc1d Stavros Sachtouris
                    format_size(used_bytes),
1056 14b25e00 Stavros Sachtouris
                    format_size(path_size),
1057 14b25e00 Stavros Sachtouris
                    path),
1058 14b25e00 Stavros Sachtouris
                importance=1, details=[
1059 14b25e00 Stavros Sachtouris
                    'Check accound limit: /file quota',
1060 14b25e00 Stavros Sachtouris
                    'Check container limit:',
1061 14b25e00 Stavros Sachtouris
                    '\t/file containerlimit get %s' % self.client.container,
1062 14b25e00 Stavros Sachtouris
                    'Increase container limit:',
1063 14b25e00 Stavros Sachtouris
                    '\t/file containerlimit set <new limit> %s' % (
1064 14b25e00 Stavros Sachtouris
                        self.client.container)])
1065 14b25e00 Stavros Sachtouris
1066 b666ef82 Stavros Sachtouris
    def _path_pairs(self, local_path, remote_path):
1067 b666ef82 Stavros Sachtouris
        """Get pairs of local and remote paths"""
1068 b666ef82 Stavros Sachtouris
        lpath = path.abspath(local_path)
1069 b666ef82 Stavros Sachtouris
        short_path = lpath.split(path.sep)[-1]
1070 b666ef82 Stavros Sachtouris
        rpath = remote_path or short_path
1071 b666ef82 Stavros Sachtouris
        if path.isdir(lpath):
1072 2d158d8b Stavros Sachtouris
            if not self['recursive']:
1073 2d158d8b Stavros Sachtouris
                raiseCLIError('%s is a directory' % lpath, details=[
1074 2d158d8b Stavros Sachtouris
                    'Use -R to upload directory contents'])
1075 b666ef82 Stavros Sachtouris
            robj = self.client.container_get(path=rpath)
1076 b666ef82 Stavros Sachtouris
            if robj.json and not self['overwrite']:
1077 b666ef82 Stavros Sachtouris
                raiseCLIError(
1078 b666ef82 Stavros Sachtouris
                    'Objects prefixed with %s already exist' % rpath,
1079 b666ef82 Stavros Sachtouris
                    importance=1,
1080 b666ef82 Stavros Sachtouris
                    details=['Existing objects:'] + ['\t%s:\t%s' % (
1081 b666ef82 Stavros Sachtouris
                        o['content_type'][12:],
1082 b666ef82 Stavros Sachtouris
                        o['name']) for o in robj.json] + [
1083 b666ef82 Stavros Sachtouris
                        'Use -f to add, overwrite or resume'])
1084 b666ef82 Stavros Sachtouris
            if not self['overwrite']:
1085 b666ef82 Stavros Sachtouris
                try:
1086 b666ef82 Stavros Sachtouris
                    topobj = self.client.get_object_info(rpath)
1087 b666ef82 Stavros Sachtouris
                    if not self._is_dir(topobj):
1088 b666ef82 Stavros Sachtouris
                        raiseCLIError(
1089 b666ef82 Stavros Sachtouris
                            'Object %s exists but it is not a dir' % rpath,
1090 b666ef82 Stavros Sachtouris
                            importance=1, details=['Use -f to overwrite'])
1091 b666ef82 Stavros Sachtouris
                except ClientError as ce:
1092 b666ef82 Stavros Sachtouris
                    if ce.status != 404:
1093 b666ef82 Stavros Sachtouris
                        raise
1094 2d158d8b Stavros Sachtouris
            self._check_container_limit(lpath)
1095 b666ef82 Stavros Sachtouris
            prev = ''
1096 b666ef82 Stavros Sachtouris
            for top, subdirs, files in walk(lpath):
1097 b666ef82 Stavros Sachtouris
                if top != prev:
1098 b666ef82 Stavros Sachtouris
                    prev = top
1099 b666ef82 Stavros Sachtouris
                    try:
1100 b666ef82 Stavros Sachtouris
                        rel_path = rpath + top.split(lpath)[1]
1101 b666ef82 Stavros Sachtouris
                    except IndexError:
1102 b666ef82 Stavros Sachtouris
                        rel_path = rpath
1103 b666ef82 Stavros Sachtouris
                    print('mkdir %s:%s' % (self.client.container, rel_path))
1104 b666ef82 Stavros Sachtouris
                    self.client.create_directory(rel_path)
1105 b666ef82 Stavros Sachtouris
                for f in files:
1106 b666ef82 Stavros Sachtouris
                    fpath = path.join(top, f)
1107 b666ef82 Stavros Sachtouris
                    if path.isfile(fpath):
1108 14d15eca Stavros Sachtouris
                        rel_path = rel_path.replace(path.sep, '/')
1109 14d15eca Stavros Sachtouris
                        pathfix = f.replace(path.sep, '/')
1110 14d15eca Stavros Sachtouris
                        yield open(fpath, 'rb'), '%s/%s' % (rel_path, pathfix)
1111 b666ef82 Stavros Sachtouris
                    else:
1112 b666ef82 Stavros Sachtouris
                        print('%s is not a regular file' % fpath)
1113 b666ef82 Stavros Sachtouris
        else:
1114 14b25e00 Stavros Sachtouris
            if not path.isfile(lpath):
1115 9d3cd179 Stavros Sachtouris
                raiseCLIError(('%s is not a regular file' % lpath) if (
1116 a0a61f30 Stavros Sachtouris
                    path.exists(lpath)) else '%s does not exist' % lpath)
1117 b666ef82 Stavros Sachtouris
            try:
1118 b666ef82 Stavros Sachtouris
                robj = self.client.get_object_info(rpath)
1119 b666ef82 Stavros Sachtouris
                if remote_path and self._is_dir(robj):
1120 14d15eca Stavros Sachtouris
                    rpath += '/%s' % (short_path.replace(path.sep, '/'))
1121 b666ef82 Stavros Sachtouris
                    self.client.get_object_info(rpath)
1122 b666ef82 Stavros Sachtouris
                if not self['overwrite']:
1123 b666ef82 Stavros Sachtouris
                    raiseCLIError(
1124 b666ef82 Stavros Sachtouris
                        'Object %s already exists' % rpath,
1125 b666ef82 Stavros Sachtouris
                        importance=1,
1126 b666ef82 Stavros Sachtouris
                        details=['use -f to overwrite or resume'])
1127 b666ef82 Stavros Sachtouris
            except ClientError as ce:
1128 b666ef82 Stavros Sachtouris
                if ce.status != 404:
1129 b666ef82 Stavros Sachtouris
                    raise
1130 2d158d8b Stavros Sachtouris
            self._check_container_limit(lpath)
1131 b666ef82 Stavros Sachtouris
            yield open(lpath, 'rb'), rpath
1132 706fc940 Stavros Sachtouris
1133 68858765 Stavros Sachtouris
    @errors.generic.all
1134 68858765 Stavros Sachtouris
    @errors.pithos.connection
1135 68858765 Stavros Sachtouris
    @errors.pithos.container
1136 68858765 Stavros Sachtouris
    @errors.pithos.object_path
1137 68858765 Stavros Sachtouris
    @errors.pithos.local_path
1138 68858765 Stavros Sachtouris
    def _run(self, local_path, remote_path):
1139 2fe2672e Stavros Sachtouris
        poolsize = self['poolsize']
1140 72952f4f Stavros Sachtouris
        if poolsize > 0:
1141 16b0afe6 Stavros Sachtouris
            self.client.MAX_THREADS = int(poolsize)
1142 72952f4f Stavros Sachtouris
        params = dict(
1143 72952f4f Stavros Sachtouris
            content_encoding=self['content_encoding'],
1144 2fe2672e Stavros Sachtouris
            content_type=self['content_type'],
1145 2fe2672e Stavros Sachtouris
            content_disposition=self['content_disposition'],
1146 2fe2672e Stavros Sachtouris
            sharing=self['sharing'],
1147 2fe2672e Stavros Sachtouris
            public=self['public'])
1148 0e728dcb Stavros Sachtouris
        uploaded = []
1149 74c65e80 Stavros Sachtouris
        container_info_cache = dict()
1150 b666ef82 Stavros Sachtouris
        for f, rpath in self._path_pairs(local_path, remote_path):
1151 b666ef82 Stavros Sachtouris
            print('%s --> %s:%s' % (f.name, self.client.container, rpath))
1152 f8426b5c Stavros Sachtouris
            if not (self['content_type'] and self['content_encoding']):
1153 f8426b5c Stavros Sachtouris
                ctype, cenc = guess_mime_type(f.name)
1154 f8426b5c Stavros Sachtouris
                params['content_type'] = self['content_type'] or ctype
1155 f8426b5c Stavros Sachtouris
                params['content_encoding'] = self['content_encoding'] or cenc
1156 68858765 Stavros Sachtouris
            if self['unchunked']:
1157 0e728dcb Stavros Sachtouris
                r = self.client.upload_object_unchunked(
1158 b666ef82 Stavros Sachtouris
                    rpath, f,
1159 b666ef82 Stavros Sachtouris
                    etag=self['etag'], withHashFile=self['use_hashes'],
1160 68858765 Stavros Sachtouris
                    **params)
1161 5655d560 Stavros Sachtouris
                if self['with_output'] or self['json_output']:
1162 0e728dcb Stavros Sachtouris
                    r['name'] = '%s: %s' % (self.client.container, rpath)
1163 0e728dcb Stavros Sachtouris
                    uploaded.append(r)
1164 68858765 Stavros Sachtouris
            else:
1165 68858765 Stavros Sachtouris
                try:
1166 68858765 Stavros Sachtouris
                    (progress_bar, upload_cb) = self._safe_progress_bar(
1167 b666ef82 Stavros Sachtouris
                        'Uploading %s' % f.name.split(path.sep)[-1])
1168 68858765 Stavros Sachtouris
                    if progress_bar:
1169 68858765 Stavros Sachtouris
                        hash_bar = progress_bar.clone()
1170 68858765 Stavros Sachtouris
                        hash_cb = hash_bar.get_generator(
1171 278c9018 Stavros Sachtouris
                            'Calculating block hashes')
1172 68858765 Stavros Sachtouris
                    else:
1173 68858765 Stavros Sachtouris
                        hash_cb = None
1174 0e728dcb Stavros Sachtouris
                    r = self.client.upload_object(
1175 b666ef82 Stavros Sachtouris
                        rpath, f,
1176 74c65e80 Stavros Sachtouris
                        hash_cb=hash_cb,
1177 74c65e80 Stavros Sachtouris
                        upload_cb=upload_cb,
1178 74c65e80 Stavros Sachtouris
                        container_info_cache=container_info_cache,
1179 852a22e7 Stavros Sachtouris
                        **params)
1180 5655d560 Stavros Sachtouris
                    if self['with_output'] or self['json_output']:
1181 0e728dcb Stavros Sachtouris
                        r['name'] = '%s: %s' % (self.client.container, rpath)
1182 0e728dcb Stavros Sachtouris
                        uploaded.append(r)
1183 68858765 Stavros Sachtouris
                except Exception:
1184 68858765 Stavros Sachtouris
                    self._safe_progress_bar_finish(progress_bar)
1185 68858765 Stavros Sachtouris
                    raise
1186 68858765 Stavros Sachtouris
                finally:
1187 68858765 Stavros Sachtouris
                    self._safe_progress_bar_finish(progress_bar)
1188 d9301a7a Stavros Sachtouris
        self._optional_output(uploaded)
1189 915b99b5 Stavros Sachtouris
        print('Upload completed')
1190 7493ccb6 Stavros Sachtouris
1191 68858765 Stavros Sachtouris
    def main(self, local_path, container____path__=None):
1192 68858765 Stavros Sachtouris
        super(self.__class__, self)._run(container____path__)
1193 9e0a1a4c Stavros Sachtouris
        remote_path = self.path or path.basename(path.abspath(local_path))
1194 68858765 Stavros Sachtouris
        self._run(local_path=local_path, remote_path=remote_path)
1195 68858765 Stavros Sachtouris
1196 234954d1 Stavros Sachtouris
1197 d486baec Stavros Sachtouris
@command(pithos_cmds)
1198 3ae60112 Stavros Sachtouris
class file_cat(_file_container_command):
1199 72952f4f Stavros Sachtouris
    """Print remote file contents to console"""
1200 9ceec15a Stavros Sachtouris
1201 2fe2672e Stavros Sachtouris
    arguments = dict(
1202 2fe2672e Stavros Sachtouris
        range=RangeArgument('show range of data', '--range'),
1203 2fe2672e Stavros Sachtouris
        if_match=ValueArgument('show output if ETags match', '--if-match'),
1204 2fe2672e Stavros Sachtouris
        if_none_match=ValueArgument(
1205 201baa17 Stavros Sachtouris
            'show output if ETags match', '--if-none-match'),
1206 2fe2672e Stavros Sachtouris
        if_modified_since=DateArgument(
1207 201baa17 Stavros Sachtouris
            'show output modified since then', '--if-modified-since'),
1208 2fe2672e Stavros Sachtouris
        if_unmodified_since=DateArgument(
1209 201baa17 Stavros Sachtouris
            'show output unmodified since then', '--if-unmodified-since'),
1210 2fe2672e Stavros Sachtouris
        object_version=ValueArgument(
1211 201baa17 Stavros Sachtouris
            'get the specific version', ('-O', '--object-version'))
1212 2fe2672e Stavros Sachtouris
    )
1213 2fe2672e Stavros Sachtouris
1214 68858765 Stavros Sachtouris
    @errors.generic.all
1215 68858765 Stavros Sachtouris
    @errors.pithos.connection
1216 68858765 Stavros Sachtouris
    @errors.pithos.container
1217 68858765 Stavros Sachtouris
    @errors.pithos.object_path
1218 68858765 Stavros Sachtouris
    def _run(self):
1219 68858765 Stavros Sachtouris
        self.client.download_object(
1220 68858765 Stavros Sachtouris
            self.path,
1221 68858765 Stavros Sachtouris
            stdout,
1222 3d568c09 Stavros Sachtouris
            range_str=self['range'],
1223 2fe2672e Stavros Sachtouris
            version=self['object_version'],
1224 2fe2672e Stavros Sachtouris
            if_match=self['if_match'],
1225 2fe2672e Stavros Sachtouris
            if_none_match=self['if_none_match'],
1226 2fe2672e Stavros Sachtouris
            if_modified_since=self['if_modified_since'],
1227 2fe2672e Stavros Sachtouris
            if_unmodified_since=self['if_unmodified_since'])
1228 68858765 Stavros Sachtouris
1229 68858765 Stavros Sachtouris
    def main(self, container___path):
1230 68858765 Stavros Sachtouris
        super(self.__class__, self)._run(
1231 201baa17 Stavros Sachtouris
            container___path, path_is_optional=False)
1232 68858765 Stavros Sachtouris
        self._run()
1233 9ceec15a Stavros Sachtouris
1234 234954d1 Stavros Sachtouris
1235 d486baec Stavros Sachtouris
@command(pithos_cmds)
1236 3ae60112 Stavros Sachtouris
class file_download(_file_container_command):
1237 ae99b37d Stavros Sachtouris
    """Download remote object as local file
1238 ae99b37d Stavros Sachtouris
    If local destination is a directory:
1239 f40f0cb7 Stavros Sachtouris
    *   download <container>:<path> <local dir> -R
1240 ae99b37d Stavros Sachtouris
    will download all files on <container> prefixed as <path>,
1241 c626151a Stavros Sachtouris
    to <local dir>/<full path> (or <local dir>\<full path> in windows)
1242 ae99b37d Stavros Sachtouris
    *   download <container>:<path> <local dir> --exact-match
1243 ae99b37d Stavros Sachtouris
    will download only one file, exactly matching <path>
1244 f6c09d14 Stavros Sachtouris
    ATTENTION: to download cont:dir1/dir2/file there must exist objects
1245 f6c09d14 Stavros Sachtouris
    cont:dir1 and cont:dir1/dir2 of type application/directory
1246 3ae60112 Stavros Sachtouris
    To create directory objects, use /file mkdir
1247 ae99b37d Stavros Sachtouris
    """
1248 7493ccb6 Stavros Sachtouris
1249 2fe2672e Stavros Sachtouris
    arguments = dict(
1250 f40f0cb7 Stavros Sachtouris
        resume=FlagArgument('Resume instead of overwrite', ('-r', '--resume')),
1251 2fe2672e Stavros Sachtouris
        range=RangeArgument('show range of data', '--range'),
1252 2fe2672e Stavros Sachtouris
        if_match=ValueArgument('show output if ETags match', '--if-match'),
1253 2fe2672e Stavros Sachtouris
        if_none_match=ValueArgument(
1254 201baa17 Stavros Sachtouris
            'show output if ETags match', '--if-none-match'),
1255 2fe2672e Stavros Sachtouris
        if_modified_since=DateArgument(
1256 201baa17 Stavros Sachtouris
            'show output modified since then', '--if-modified-since'),
1257 2fe2672e Stavros Sachtouris
        if_unmodified_since=DateArgument(
1258 201baa17 Stavros Sachtouris
            'show output unmodified since then', '--if-unmodified-since'),
1259 2fe2672e Stavros Sachtouris
        object_version=ValueArgument(
1260 201baa17 Stavros Sachtouris
            'get the specific version', ('-O', '--object-version')),
1261 2fe2672e Stavros Sachtouris
        poolsize=IntArgument('set pool size', '--with-pool-size'),
1262 2fe2672e Stavros Sachtouris
        progress_bar=ProgressBarArgument(
1263 2fe2672e Stavros Sachtouris
            'do not show progress bar',
1264 f40f0cb7 Stavros Sachtouris
            ('-N', '--no-progress-bar'),
1265 ae99b37d Stavros Sachtouris
            default=False),
1266 f6c09d14 Stavros Sachtouris
        recursive=FlagArgument(
1267 a3ba3bce Stavros Sachtouris
            'Download a remote path and all its contents',
1268 f40f0cb7 Stavros Sachtouris
            ('-R', '--recursive'))
1269 2fe2672e Stavros Sachtouris
    )
1270 7493ccb6 Stavros Sachtouris
1271 f6c09d14 Stavros Sachtouris
    def _outputs(self, local_path):
1272 a3ba3bce Stavros Sachtouris
        """:returns: (local_file, remote_path)"""
1273 a3ba3bce Stavros Sachtouris
        remotes = []
1274 a3ba3bce Stavros Sachtouris
        if self['recursive']:
1275 a3ba3bce Stavros Sachtouris
            r = self.client.container_get(
1276 a3ba3bce Stavros Sachtouris
                prefix=self.path or '/',
1277 f6c09d14 Stavros Sachtouris
                if_modified_since=self['if_modified_since'],
1278 f6c09d14 Stavros Sachtouris
                if_unmodified_since=self['if_unmodified_since'])
1279 a3ba3bce Stavros Sachtouris
            dirlist = dict()
1280 a3ba3bce Stavros Sachtouris
            for remote in r.json:
1281 a3ba3bce Stavros Sachtouris
                rname = remote['name'].strip('/')
1282 a3ba3bce Stavros Sachtouris
                tmppath = ''
1283 a3ba3bce Stavros Sachtouris
                for newdir in rname.strip('/').split('/')[:-1]:
1284 a3ba3bce Stavros Sachtouris
                    tmppath = '/'.join([tmppath, newdir])
1285 a3ba3bce Stavros Sachtouris
                    dirlist.update({tmppath.strip('/'): True})
1286 3ae60112 Stavros Sachtouris
                remotes.append((rname, file_download._is_dir(remote)))
1287 a3ba3bce Stavros Sachtouris
            dir_remotes = [r[0] for r in remotes if r[1]]
1288 a3ba3bce Stavros Sachtouris
            if not set(dirlist).issubset(dir_remotes):
1289 a3ba3bce Stavros Sachtouris
                badguys = [bg.strip('/') for bg in set(
1290 a3ba3bce Stavros Sachtouris
                    dirlist).difference(dir_remotes)]
1291 a3ba3bce Stavros Sachtouris
                raiseCLIError(
1292 a3ba3bce Stavros Sachtouris
                    'Some remote paths contain non existing directories',
1293 a3ba3bce Stavros Sachtouris
                    details=['Missing remote directories:'] + badguys)
1294 a3ba3bce Stavros Sachtouris
        elif self.path:
1295 a3ba3bce Stavros Sachtouris
            r = self.client.get_object_info(
1296 a3ba3bce Stavros Sachtouris
                self.path,
1297 a3ba3bce Stavros Sachtouris
                version=self['object_version'])
1298 3ae60112 Stavros Sachtouris
            if file_download._is_dir(r):
1299 a3ba3bce Stavros Sachtouris
                raiseCLIError(
1300 a3ba3bce Stavros Sachtouris
                    'Illegal download: Remote object %s is a directory' % (
1301 a3ba3bce Stavros Sachtouris
                        self.path),
1302 14d15eca Stavros Sachtouris
                    details=['To download a directory, try --recursive or -R'])
1303 a3ba3bce Stavros Sachtouris
            if '/' in self.path.strip('/') and not local_path:
1304 a3ba3bce Stavros Sachtouris
                raiseCLIError(
1305 a3ba3bce Stavros Sachtouris
                    'Illegal download: remote object %s contains "/"' % (
1306 a3ba3bce Stavros Sachtouris
                        self.path),
1307 a3ba3bce Stavros Sachtouris
                    details=[
1308 a3ba3bce Stavros Sachtouris
                        'To download an object containing "/" characters',
1309 a3ba3bce Stavros Sachtouris
                        'either create the remote directories or',
1310 a3ba3bce Stavros Sachtouris
                        'specify a non-directory local path for this object'])
1311 a3ba3bce Stavros Sachtouris
            remotes = [(self.path, False)]
1312 a3ba3bce Stavros Sachtouris
        if not remotes:
1313 a3ba3bce Stavros Sachtouris
            if self.path:
1314 a3ba3bce Stavros Sachtouris
                raiseCLIError(
1315 a3ba3bce Stavros Sachtouris
                    'No matching path %s on container %s' % (
1316 14d15eca Stavros Sachtouris
                        self.path, self.container),
1317 a3ba3bce Stavros Sachtouris
                    details=[
1318 a3ba3bce Stavros Sachtouris
                        'To list the contents of %s, try:' % self.container,
1319 3ae60112 Stavros Sachtouris
                        '   /file list %s' % self.container])
1320 a3ba3bce Stavros Sachtouris
            raiseCLIError(
1321 a3ba3bce Stavros Sachtouris
                'Illegal download of container %s' % self.container,
1322 a3ba3bce Stavros Sachtouris
                details=[
1323 a3ba3bce Stavros Sachtouris
                    'To download a whole container, try:',
1324 3ae60112 Stavros Sachtouris
                    '   /file download --recursive <container>'])
1325 a3ba3bce Stavros Sachtouris
1326 a3ba3bce Stavros Sachtouris
        lprefix = path.abspath(local_path or path.curdir)
1327 a3ba3bce Stavros Sachtouris
        if path.isdir(lprefix):
1328 a3ba3bce Stavros Sachtouris
            for rpath, remote_is_dir in remotes:
1329 14d15eca Stavros Sachtouris
                lpath = path.sep.join([
1330 14d15eca Stavros Sachtouris
                    lprefix[:-1] if lprefix.endswith(path.sep) else lprefix,
1331 14d15eca Stavros Sachtouris
                    rpath.strip('/').replace('/', path.sep)])
1332 a3ba3bce Stavros Sachtouris
                if remote_is_dir:
1333 a3ba3bce Stavros Sachtouris
                    if path.exists(lpath) and path.isdir(lpath):
1334 a3ba3bce Stavros Sachtouris
                        continue
1335 a3ba3bce Stavros Sachtouris
                    makedirs(lpath)
1336 a3ba3bce Stavros Sachtouris
                elif path.exists(lpath):
1337 a3ba3bce Stavros Sachtouris
                    if not self['resume']:
1338 a3ba3bce Stavros Sachtouris
                        print('File %s exists, aborting...' % lpath)
1339 a3ba3bce Stavros Sachtouris
                        continue
1340 a3ba3bce Stavros Sachtouris
                    with open(lpath, 'rwb+') as f:
1341 a3ba3bce Stavros Sachtouris
                        yield (f, rpath)
1342 a3ba3bce Stavros Sachtouris
                else:
1343 a3ba3bce Stavros Sachtouris
                    with open(lpath, 'wb+') as f:
1344 a3ba3bce Stavros Sachtouris
                        yield (f, rpath)
1345 a3ba3bce Stavros Sachtouris
        elif path.exists(lprefix):
1346 a3ba3bce Stavros Sachtouris
            if len(remotes) > 1:
1347 a3ba3bce Stavros Sachtouris
                raiseCLIError(
1348 a3ba3bce Stavros Sachtouris
                    '%s remote objects cannot be merged in local file %s' % (
1349 a3ba3bce Stavros Sachtouris
                        len(remotes),
1350 a3ba3bce Stavros Sachtouris
                        local_path),
1351 a3ba3bce Stavros Sachtouris
                    details=[
1352 a3ba3bce Stavros Sachtouris
                        'To download multiple objects, local path should be',
1353 a3ba3bce Stavros Sachtouris
                        'a directory, or use download without a local path'])
1354 a3ba3bce Stavros Sachtouris
            (rpath, remote_is_dir) = remotes[0]
1355 a3ba3bce Stavros Sachtouris
            if remote_is_dir:
1356 a3ba3bce Stavros Sachtouris
                raiseCLIError(
1357 a3ba3bce Stavros Sachtouris
                    'Remote directory %s should not replace local file %s' % (
1358 a3ba3bce Stavros Sachtouris
                        rpath,
1359 a3ba3bce Stavros Sachtouris
                        local_path))
1360 a3ba3bce Stavros Sachtouris
            if self['resume']:
1361 a3ba3bce Stavros Sachtouris
                with open(lprefix, 'rwb+') as f:
1362 a3ba3bce Stavros Sachtouris
                    yield (f, rpath)
1363 a3ba3bce Stavros Sachtouris
            else:
1364 a3ba3bce Stavros Sachtouris
                raiseCLIError(
1365 db36a6a7 Stavros Sachtouris
                    'Local file %s already exist' % local_path,
1366 db36a6a7 Stavros Sachtouris
                    details=['Try --resume to overwrite it'])
1367 a3ba3bce Stavros Sachtouris
        else:
1368 a3ba3bce Stavros Sachtouris
            if len(remotes) > 1 or remotes[0][1]:
1369 a3ba3bce Stavros Sachtouris
                raiseCLIError(
1370 a3ba3bce Stavros Sachtouris
                    'Local directory %s does not exist' % local_path)
1371 a3ba3bce Stavros Sachtouris
            with open(lprefix, 'wb+') as f:
1372 a3ba3bce Stavros Sachtouris
                yield (f, remotes[0][0])
1373 7493ccb6 Stavros Sachtouris
1374 68858765 Stavros Sachtouris
    @errors.generic.all
1375 68858765 Stavros Sachtouris
    @errors.pithos.connection
1376 68858765 Stavros Sachtouris
    @errors.pithos.container
1377 68858765 Stavros Sachtouris
    @errors.pithos.object_path
1378 68858765 Stavros Sachtouris
    @errors.pithos.local_path
1379 68858765 Stavros Sachtouris
    def _run(self, local_path):
1380 2fe2672e Stavros Sachtouris
        poolsize = self['poolsize']
1381 68858765 Stavros Sachtouris
        if poolsize:
1382 16b0afe6 Stavros Sachtouris
            self.client.MAX_THREADS = int(poolsize)
1383 f6c09d14 Stavros Sachtouris
        progress_bar = None
1384 ae99b37d Stavros Sachtouris
        try:
1385 a3ba3bce Stavros Sachtouris
            for f, rpath in self._outputs(local_path):
1386 3d568c09 Stavros Sachtouris
                (
1387 3d568c09 Stavros Sachtouris
                    progress_bar,
1388 a3ba3bce Stavros Sachtouris
                    download_cb) = self._safe_progress_bar(
1389 a3ba3bce Stavros Sachtouris
                        'Download %s' % rpath)
1390 ae99b37d Stavros Sachtouris
                self.client.download_object(
1391 5655d560 Stavros Sachtouris
                    rpath, f,
1392 ae99b37d Stavros Sachtouris
                    download_cb=download_cb,
1393 3d568c09 Stavros Sachtouris
                    range_str=self['range'],
1394 ae99b37d Stavros Sachtouris
                    version=self['object_version'],
1395 ae99b37d Stavros Sachtouris
                    if_match=self['if_match'],
1396 ae99b37d Stavros Sachtouris
                    resume=self['resume'],
1397 ae99b37d Stavros Sachtouris
                    if_none_match=self['if_none_match'],
1398 ae99b37d Stavros Sachtouris
                    if_modified_since=self['if_modified_since'],
1399 ae99b37d Stavros Sachtouris
                    if_unmodified_since=self['if_unmodified_since'])
1400 7493ccb6 Stavros Sachtouris
        except KeyboardInterrupt:
1401 b78ee581 Stavros Sachtouris
            from threading import activeCount, enumerate as activethreads
1402 cae76f25 Stavros Sachtouris
            timeout = 0.5
1403 b78ee581 Stavros Sachtouris
            while activeCount() > 1:
1404 cae76f25 Stavros Sachtouris
                stdout.write('\nCancel %s threads: ' % (activeCount() - 1))
1405 cae76f25 Stavros Sachtouris
                stdout.flush()
1406 b78ee581 Stavros Sachtouris
                for thread in activethreads():
1407 b78ee581 Stavros Sachtouris
                    try:
1408 cae76f25 Stavros Sachtouris
                        thread.join(timeout)
1409 cae76f25 Stavros Sachtouris
                        stdout.write('.' if thread.isAlive() else '*')
1410 b78ee581 Stavros Sachtouris
                    except RuntimeError:
1411 b78ee581 Stavros Sachtouris
                        continue
1412 cae76f25 Stavros Sachtouris
                    finally:
1413 cae76f25 Stavros Sachtouris
                        stdout.flush()
1414 cae76f25 Stavros Sachtouris
                        timeout += 0.1
1415 b78ee581 Stavros Sachtouris
            print('\nDownload canceled by user')
1416 7493ccb6 Stavros Sachtouris
            if local_path is not None:
1417 624ee36f Stavros Sachtouris
                print('to resume, re-run with --resume')
1418 68858765 Stavros Sachtouris
        except Exception:
1419 68858765 Stavros Sachtouris
            self._safe_progress_bar_finish(progress_bar)
1420 68858765 Stavros Sachtouris
            raise
1421 68858765 Stavros Sachtouris
        finally:
1422 68858765 Stavros Sachtouris
            self._safe_progress_bar_finish(progress_bar)
1423 68858765 Stavros Sachtouris
1424 68858765 Stavros Sachtouris
    def main(self, container___path, local_path=None):
1425 a3ba3bce Stavros Sachtouris
        super(self.__class__, self)._run(container___path)
1426 68858765 Stavros Sachtouris
        self._run(local_path=local_path)
1427 7493ccb6 Stavros Sachtouris
1428 234954d1 Stavros Sachtouris
1429 d486baec Stavros Sachtouris
@command(pithos_cmds)
1430 545c6c29 Stavros Sachtouris
class file_hashmap(_file_container_command, _optional_json):
1431 72952f4f Stavros Sachtouris
    """Get the hash-map of an object"""
1432 7493ccb6 Stavros Sachtouris
1433 2fe2672e Stavros Sachtouris
    arguments = dict(
1434 2fe2672e Stavros Sachtouris
        if_match=ValueArgument('show output if ETags match', '--if-match'),
1435 2fe2672e Stavros Sachtouris
        if_none_match=ValueArgument(
1436 545c6c29 Stavros Sachtouris
            'show output if ETags match', '--if-none-match'),
1437 2fe2672e Stavros Sachtouris
        if_modified_since=DateArgument(
1438 545c6c29 Stavros Sachtouris
            'show output modified since then', '--if-modified-since'),
1439 2fe2672e Stavros Sachtouris
        if_unmodified_since=DateArgument(
1440 545c6c29 Stavros Sachtouris
            'show output unmodified since then', '--if-unmodified-since'),
1441 2fe2672e Stavros Sachtouris
        object_version=ValueArgument(
1442 545c6c29 Stavros Sachtouris
            'get the specific version', ('-O', '--object-version'))
1443 2fe2672e Stavros Sachtouris
    )
1444 7493ccb6 Stavros Sachtouris
1445 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1446 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
1447 b4cf92b8 Stavros Sachtouris
    @errors.pithos.container
1448 b4cf92b8 Stavros Sachtouris
    @errors.pithos.object_path
1449 b4cf92b8 Stavros Sachtouris
    def _run(self):
1450 545c6c29 Stavros Sachtouris
        self._print(self.client.get_object_hashmap(
1451 b4cf92b8 Stavros Sachtouris
            self.path,
1452 b4cf92b8 Stavros Sachtouris
            version=self['object_version'],
1453 b4cf92b8 Stavros Sachtouris
            if_match=self['if_match'],
1454 b4cf92b8 Stavros Sachtouris
            if_none_match=self['if_none_match'],
1455 b4cf92b8 Stavros Sachtouris
            if_modified_since=self['if_modified_since'],
1456 545c6c29 Stavros Sachtouris
            if_unmodified_since=self['if_unmodified_since']), print_dict)
1457 b4cf92b8 Stavros Sachtouris
1458 7493ccb6 Stavros Sachtouris
    def main(self, container___path):
1459 b4cf92b8 Stavros Sachtouris
        super(self.__class__, self)._run(
1460 72952f4f Stavros Sachtouris
            container___path,
1461 72952f4f Stavros Sachtouris
            path_is_optional=False)
1462 b4cf92b8 Stavros Sachtouris
        self._run()
1463 7493ccb6 Stavros Sachtouris
1464 234954d1 Stavros Sachtouris
1465 d486baec Stavros Sachtouris
@command(pithos_cmds)
1466 915b99b5 Stavros Sachtouris
class file_delete(_file_container_command, _optional_output_cmd):
1467 72952f4f Stavros Sachtouris
    """Delete a container [or an object]
1468 72952f4f Stavros Sachtouris
    How to delete a non-empty container:
1469 3ae60112 Stavros Sachtouris
    - empty the container:  /file delete -R <container>
1470 3ae60112 Stavros Sachtouris
    - delete it:            /file delete <container>
1471 72952f4f Stavros Sachtouris
    .
1472 72952f4f Stavros Sachtouris
    Semantics of directory deletion:
1473 3ae60112 Stavros Sachtouris
    .a preserve the contents: /file delete <container>:<directory>
1474 72952f4f Stavros Sachtouris
    .    objects of the form dir/filename can exist with a dir object
1475 3ae60112 Stavros Sachtouris
    .b delete contents:       /file delete -R <container>:<directory>
1476 72952f4f Stavros Sachtouris
    .    all dir/* objects are affected, even if dir does not exist
1477 72952f4f Stavros Sachtouris
    .
1478 72952f4f Stavros Sachtouris
    To restore a deleted object OBJ in a container CONT:
1479 3ae60112 Stavros Sachtouris
    - get object versions: /file versions CONT:OBJ
1480 72952f4f Stavros Sachtouris
    .   and choose the version to be restored
1481 3ae60112 Stavros Sachtouris
    - restore the object:  /file copy --source-version=<version> CONT:OBJ OBJ
1482 72952f4f Stavros Sachtouris
    """
1483 7493ccb6 Stavros Sachtouris
1484 2fe2672e Stavros Sachtouris
    arguments = dict(
1485 439826ec Stavros Sachtouris
        until=DateArgument('remove history until that date', '--until'),
1486 7147e1ca Stavros Sachtouris
        yes=FlagArgument('Do not prompt for permission', '--yes'),
1487 2fe2672e Stavros Sachtouris
        recursive=FlagArgument(
1488 234954d1 Stavros Sachtouris
            'empty dir or container and delete (if dir)',
1489 915b99b5 Stavros Sachtouris
            ('-R', '--recursive'))
1490 2fe2672e Stavros Sachtouris
    )
1491 2fe2672e Stavros Sachtouris
1492 b4f69041 Stavros Sachtouris
    def __init__(self, arguments={}, auth_base=None, cloud=None):
1493 b4f69041 Stavros Sachtouris
        super(self.__class__, self).__init__(arguments,  auth_base, cloud)
1494 439826ec Stavros Sachtouris
        self['delimiter'] = DelimiterArgument(
1495 2fe2672e Stavros Sachtouris
            self,
1496 234954d1 Stavros Sachtouris
            parsed_name='--delimiter',
1497 234954d1 Stavros Sachtouris
            help='delete objects prefixed with <object><delimiter>')
1498 7493ccb6 Stavros Sachtouris
1499 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1500 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
1501 b4cf92b8 Stavros Sachtouris
    @errors.pithos.container
1502 b4cf92b8 Stavros Sachtouris
    @errors.pithos.object_path
1503 b4cf92b8 Stavros Sachtouris
    def _run(self):
1504 b4cf92b8 Stavros Sachtouris
        if self.path:
1505 24ff0a35 Stavros Sachtouris
            if self['yes'] or ask_user(
1506 24ff0a35 Stavros Sachtouris
                    'Delete %s:%s ?' % (self.container, self.path)):
1507 915b99b5 Stavros Sachtouris
                self._optional_output(self.client.del_object(
1508 b4cf92b8 Stavros Sachtouris
                    self.path,
1509 915b99b5 Stavros Sachtouris
                    until=self['until'], delimiter=self['delimiter']))
1510 7493ccb6 Stavros Sachtouris
            else:
1511 b4cf92b8 Stavros Sachtouris
                print('Aborted')
1512 cf115aed Stavros Sachtouris
        elif self.container:
1513 24ff0a35 Stavros Sachtouris
            if self['recursive']:
1514 de73876b Stavros Sachtouris
                ask_msg = 'Delete container contents'
1515 de73876b Stavros Sachtouris
            else:
1516 de73876b Stavros Sachtouris
                ask_msg = 'Delete container'
1517 b4cf92b8 Stavros Sachtouris
            if self['yes'] or ask_user('%s %s ?' % (ask_msg, self.container)):
1518 915b99b5 Stavros Sachtouris
                self._optional_output(self.client.del_container(
1519 915b99b5 Stavros Sachtouris
                    until=self['until'], delimiter=self['delimiter']))
1520 b4cf92b8 Stavros Sachtouris
            else:
1521 b4cf92b8 Stavros Sachtouris
                print('Aborted')
1522 cf115aed Stavros Sachtouris
        else:
1523 cf115aed Stavros Sachtouris
            raiseCLIError('Nothing to delete, please provide container[:path]')
1524 b4cf92b8 Stavros Sachtouris
1525 edab7ba7 Stavros Sachtouris
    def main(self, container____path__=None):
1526 b4cf92b8 Stavros Sachtouris
        super(self.__class__, self)._run(container____path__)
1527 b4cf92b8 Stavros Sachtouris
        self._run()
1528 7493ccb6 Stavros Sachtouris
1529 234954d1 Stavros Sachtouris
1530 d486baec Stavros Sachtouris
@command(pithos_cmds)
1531 915b99b5 Stavros Sachtouris
class file_purge(_file_container_command, _optional_output_cmd):
1532 72952f4f Stavros Sachtouris
    """Delete a container and release related data blocks
1533 72952f4f Stavros Sachtouris
    Non-empty containers can not purged.
1534 72952f4f Stavros Sachtouris
    To purge a container with content:
1535 3ae60112 Stavros Sachtouris
    .   /file delete -R <container>
1536 72952f4f Stavros Sachtouris
    .      objects are deleted, but data blocks remain on server
1537 3ae60112 Stavros Sachtouris
    .   /file purge <container>
1538 72952f4f Stavros Sachtouris
    .      container and data blocks are released and deleted
1539 2fe2672e Stavros Sachtouris
    """
1540 234954d1 Stavros Sachtouris
1541 7147e1ca Stavros Sachtouris
    arguments = dict(
1542 7147e1ca Stavros Sachtouris
        yes=FlagArgument('Do not prompt for permission', '--yes'),
1543 915b99b5 Stavros Sachtouris
        force=FlagArgument('purge even if not empty', ('-F', '--force'))
1544 7147e1ca Stavros Sachtouris
    )
1545 7147e1ca Stavros Sachtouris
1546 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1547 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
1548 b4cf92b8 Stavros Sachtouris
    @errors.pithos.container
1549 b4cf92b8 Stavros Sachtouris
    def _run(self):
1550 b4cf92b8 Stavros Sachtouris
        if self['yes'] or ask_user('Purge container %s?' % self.container):
1551 be4a8ccd Stavros Sachtouris
            try:
1552 5655d560 Stavros Sachtouris
                r = self.client.purge_container()
1553 be4a8ccd Stavros Sachtouris
            except ClientError as ce:
1554 be4a8ccd Stavros Sachtouris
                if ce.status in (409,):
1555 be4a8ccd Stavros Sachtouris
                    if self['force']:
1556 be4a8ccd Stavros Sachtouris
                        self.client.del_container(delimiter='/')
1557 5655d560 Stavros Sachtouris
                        r = self.client.purge_container()
1558 be4a8ccd Stavros Sachtouris
                    else:
1559 be4a8ccd Stavros Sachtouris
                        raiseCLIError(ce, details=['Try -F to force-purge'])
1560 be4a8ccd Stavros Sachtouris
                else:
1561 be4a8ccd Stavros Sachtouris
                    raise
1562 915b99b5 Stavros Sachtouris
            self._optional_output(r)
1563 b4cf92b8 Stavros Sachtouris
        else:
1564 b4cf92b8 Stavros Sachtouris
            print('Aborted')
1565 b4cf92b8 Stavros Sachtouris
1566 52edad0a Stavros Sachtouris
    def main(self, container=None):
1567 b4cf92b8 Stavros Sachtouris
        super(self.__class__, self)._run(container)
1568 52edad0a Stavros Sachtouris
        if container and self.container != container:
1569 52edad0a Stavros Sachtouris
            raiseCLIError('Invalid container name %s' % container, details=[
1570 52edad0a Stavros Sachtouris
                'Did you mean "%s" ?' % self.container,
1571 52edad0a Stavros Sachtouris
                'Use --container for names containing :'])
1572 b4cf92b8 Stavros Sachtouris
        self._run()
1573 7493ccb6 Stavros Sachtouris
1574 234954d1 Stavros Sachtouris
1575 d486baec Stavros Sachtouris
@command(pithos_cmds)
1576 3ae60112 Stavros Sachtouris
class file_publish(_file_container_command):
1577 2fe2672e Stavros Sachtouris
    """Publish the object and print the public url"""
1578 7493ccb6 Stavros Sachtouris
1579 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1580 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
1581 b4cf92b8 Stavros Sachtouris
    @errors.pithos.container
1582 b4cf92b8 Stavros Sachtouris
    @errors.pithos.object_path
1583 b4cf92b8 Stavros Sachtouris
    def _run(self):
1584 fa382f9e Stavros Sachtouris
        print self.client.publish_object(self.path)
1585 b4cf92b8 Stavros Sachtouris
1586 7493ccb6 Stavros Sachtouris
    def main(self, container___path):
1587 b4cf92b8 Stavros Sachtouris
        super(self.__class__, self)._run(
1588 201baa17 Stavros Sachtouris
            container___path, path_is_optional=False)
1589 b4cf92b8 Stavros Sachtouris
        self._run()
1590 7493ccb6 Stavros Sachtouris
1591 234954d1 Stavros Sachtouris
1592 d486baec Stavros Sachtouris
@command(pithos_cmds)
1593 915b99b5 Stavros Sachtouris
class file_unpublish(_file_container_command, _optional_output_cmd):
1594 7493ccb6 Stavros Sachtouris
    """Unpublish an object"""
1595 7493ccb6 Stavros Sachtouris
1596 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1597 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
1598 b4cf92b8 Stavros Sachtouris
    @errors.pithos.container
1599 b4cf92b8 Stavros Sachtouris
    @errors.pithos.object_path
1600 b4cf92b8 Stavros Sachtouris
    def _run(self):
1601 915b99b5 Stavros Sachtouris
            self._optional_output(self.client.unpublish_object(self.path))
1602 b4cf92b8 Stavros Sachtouris
1603 7493ccb6 Stavros Sachtouris
    def main(self, container___path):
1604 b4cf92b8 Stavros Sachtouris
        super(self.__class__, self)._run(
1605 201baa17 Stavros Sachtouris
            container___path, path_is_optional=False)
1606 b4cf92b8 Stavros Sachtouris
        self._run()
1607 7493ccb6 Stavros Sachtouris
1608 234954d1 Stavros Sachtouris
1609 d486baec Stavros Sachtouris
@command(pithos_cmds)
1610 5655d560 Stavros Sachtouris
class file_permissions(_pithos_init):
1611 5655d560 Stavros Sachtouris
    """Manage user and group accessibility for objects
1612 5655d560 Stavros Sachtouris
    Permissions are lists of users and user groups. There are read and write
1613 72952f4f Stavros Sachtouris
    permissions. Users and groups with write permission have also read
1614 72952f4f Stavros Sachtouris
    permission.
1615 72952f4f Stavros Sachtouris
    """
1616 7493ccb6 Stavros Sachtouris
1617 5655d560 Stavros Sachtouris
1618 545c6c29 Stavros Sachtouris
def print_permissions(permissions_dict):
1619 545c6c29 Stavros Sachtouris
    expected_keys = ('read', 'write')
1620 545c6c29 Stavros Sachtouris
    if set(permissions_dict).issubset(expected_keys):
1621 545c6c29 Stavros Sachtouris
        print_dict(permissions_dict)
1622 545c6c29 Stavros Sachtouris
    else:
1623 545c6c29 Stavros Sachtouris
        invalid_keys = set(permissions_dict.keys()).difference(expected_keys)
1624 545c6c29 Stavros Sachtouris
        raiseCLIError(
1625 545c6c29 Stavros Sachtouris
            'Illegal permission keys: %s' % ', '.join(invalid_keys),
1626 545c6c29 Stavros Sachtouris
            importance=1, details=[
1627 545c6c29 Stavros Sachtouris
                'Valid permission types: %s' % ' '.join(expected_keys)])
1628 545c6c29 Stavros Sachtouris
1629 545c6c29 Stavros Sachtouris
1630 5655d560 Stavros Sachtouris
@command(pithos_cmds)
1631 545c6c29 Stavros Sachtouris
class file_permissions_get(_file_container_command, _optional_json):
1632 5655d560 Stavros Sachtouris
    """Get read and write permissions of an object"""
1633 5655d560 Stavros Sachtouris
1634 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1635 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
1636 b4cf92b8 Stavros Sachtouris
    @errors.pithos.container
1637 b4cf92b8 Stavros Sachtouris
    @errors.pithos.object_path
1638 b4cf92b8 Stavros Sachtouris
    def _run(self):
1639 545c6c29 Stavros Sachtouris
        self._print(
1640 545c6c29 Stavros Sachtouris
            self.client.get_object_sharing(self.path), print_permissions)
1641 b4cf92b8 Stavros Sachtouris
1642 7493ccb6 Stavros Sachtouris
    def main(self, container___path):
1643 b4cf92b8 Stavros Sachtouris
        super(self.__class__, self)._run(
1644 201baa17 Stavros Sachtouris
            container___path, path_is_optional=False)
1645 b4cf92b8 Stavros Sachtouris
        self._run()
1646 7493ccb6 Stavros Sachtouris
1647 234954d1 Stavros Sachtouris
1648 d486baec Stavros Sachtouris
@command(pithos_cmds)
1649 915b99b5 Stavros Sachtouris
class file_permissions_set(_file_container_command, _optional_output_cmd):
1650 72952f4f Stavros Sachtouris
    """Set permissions for an object
1651 72952f4f Stavros Sachtouris
    New permissions overwrite existing permissions.
1652 72952f4f Stavros Sachtouris
    Permission format:
1653 72952f4f Stavros Sachtouris
    -   read=<username>[,usergroup[,...]]
1654 72952f4f Stavros Sachtouris
    -   write=<username>[,usegroup[,...]]
1655 72952f4f Stavros Sachtouris
    E.g. to give read permissions for file F to users A and B and write for C:
1656 5655d560 Stavros Sachtouris
    .       /file permissions set F read=A,B write=C
1657 72952f4f Stavros Sachtouris
    """
1658 7493ccb6 Stavros Sachtouris
1659 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1660 00336c85 Stavros Sachtouris
    def format_permission_dict(self, permissions):
1661 7493ccb6 Stavros Sachtouris
        read = False
1662 7493ccb6 Stavros Sachtouris
        write = False
1663 3dabe5d2 Stavros Sachtouris
        for perms in permissions:
1664 7493ccb6 Stavros Sachtouris
            splstr = perms.split('=')
1665 7493ccb6 Stavros Sachtouris
            if 'read' == splstr[0]:
1666 24ff0a35 Stavros Sachtouris
                read = [ug.strip() for ug in splstr[1].split(',')]
1667 7493ccb6 Stavros Sachtouris
            elif 'write' == splstr[0]:
1668 24ff0a35 Stavros Sachtouris
                write = [ug.strip() for ug in splstr[1].split(',')]
1669 7493ccb6 Stavros Sachtouris
            else:
1670 24ff0a35 Stavros Sachtouris
                msg = 'Usage:\tread=<groups,users> write=<groups,users>'
1671 24ff0a35 Stavros Sachtouris
                raiseCLIError(None, msg)
1672 234954d1 Stavros Sachtouris
        return (read, write)
1673 7493ccb6 Stavros Sachtouris
1674 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1675 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
1676 b4cf92b8 Stavros Sachtouris
    @errors.pithos.container
1677 b4cf92b8 Stavros Sachtouris
    @errors.pithos.object_path
1678 b4cf92b8 Stavros Sachtouris
    def _run(self, read, write):
1679 915b99b5 Stavros Sachtouris
        self._optional_output(self.client.set_object_sharing(
1680 201baa17 Stavros Sachtouris
            self.path, read_permission=read, write_permission=write))
1681 b4cf92b8 Stavros Sachtouris
1682 3dabe5d2 Stavros Sachtouris
    def main(self, container___path, *permissions):
1683 b4cf92b8 Stavros Sachtouris
        super(self.__class__, self)._run(
1684 201baa17 Stavros Sachtouris
            container___path, path_is_optional=False)
1685 201baa17 Stavros Sachtouris
        read, write = self.format_permission_dict(permissions)
1686 b4cf92b8 Stavros Sachtouris
        self._run(read, write)
1687 7493ccb6 Stavros Sachtouris
1688 234954d1 Stavros Sachtouris
1689 d486baec Stavros Sachtouris
@command(pithos_cmds)
1690 915b99b5 Stavros Sachtouris
class file_permissions_delete(_file_container_command, _optional_output_cmd):
1691 72952f4f Stavros Sachtouris
    """Delete all permissions set on object
1692 5655d560 Stavros Sachtouris
    To modify permissions, use /file permissions set
1693 72952f4f Stavros Sachtouris
    """
1694 7493ccb6 Stavros Sachtouris
1695 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1696 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
1697 b4cf92b8 Stavros Sachtouris
    @errors.pithos.container
1698 b4cf92b8 Stavros Sachtouris
    @errors.pithos.object_path
1699 b4cf92b8 Stavros Sachtouris
    def _run(self):
1700 915b99b5 Stavros Sachtouris
        self._optional_output(self.client.del_object_sharing(self.path))
1701 b4cf92b8 Stavros Sachtouris
1702 7493ccb6 Stavros Sachtouris
    def main(self, container___path):
1703 b4cf92b8 Stavros Sachtouris
        super(self.__class__, self)._run(
1704 201baa17 Stavros Sachtouris
            container___path, path_is_optional=False)
1705 b4cf92b8 Stavros Sachtouris
        self._run()
1706 7493ccb6 Stavros Sachtouris
1707 234954d1 Stavros Sachtouris
1708 d486baec Stavros Sachtouris
@command(pithos_cmds)
1709 545c6c29 Stavros Sachtouris
class file_info(_file_container_command, _optional_json):
1710 72952f4f Stavros Sachtouris
    """Get detailed information for user account, containers or objects
1711 3ae60112 Stavros Sachtouris
    to get account info:    /file info
1712 3ae60112 Stavros Sachtouris
    to get container info:  /file info <container>
1713 3ae60112 Stavros Sachtouris
    to get object info:     /file info <container>:<path>
1714 72952f4f Stavros Sachtouris
    """
1715 7493ccb6 Stavros Sachtouris
1716 2fe2672e Stavros Sachtouris
    arguments = dict(
1717 2fe2672e Stavros Sachtouris
        object_version=ValueArgument(
1718 2fe2672e Stavros Sachtouris
            'show specific version \ (applies only for objects)',
1719 545c6c29 Stavros Sachtouris
            ('-O', '--object-version'))
1720 2fe2672e Stavros Sachtouris
    )
1721 6ac7f90f Stavros Sachtouris
1722 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1723 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
1724 b4cf92b8 Stavros Sachtouris
    @errors.pithos.container
1725 b4cf92b8 Stavros Sachtouris
    @errors.pithos.object_path
1726 b4cf92b8 Stavros Sachtouris
    def _run(self):
1727 b4cf92b8 Stavros Sachtouris
        if self.container is None:
1728 b4cf92b8 Stavros Sachtouris
            r = self.client.get_account_info()
1729 b4cf92b8 Stavros Sachtouris
        elif self.path is None:
1730 b4cf92b8 Stavros Sachtouris
            r = self.client.get_container_info(self.container)
1731 b4cf92b8 Stavros Sachtouris
        else:
1732 b4cf92b8 Stavros Sachtouris
            r = self.client.get_object_info(
1733 201baa17 Stavros Sachtouris
                self.path, version=self['object_version'])
1734 545c6c29 Stavros Sachtouris
        self._print(r, print_dict)
1735 b4cf92b8 Stavros Sachtouris
1736 7493ccb6 Stavros Sachtouris
    def main(self, container____path__=None):
1737 b4cf92b8 Stavros Sachtouris
        super(self.__class__, self)._run(container____path__)
1738 b4cf92b8 Stavros Sachtouris
        self._run()
1739 7493ccb6 Stavros Sachtouris
1740 234954d1 Stavros Sachtouris
1741 d486baec Stavros Sachtouris
@command(pithos_cmds)
1742 5655d560 Stavros Sachtouris
class file_metadata(_pithos_init):
1743 5655d560 Stavros Sachtouris
    """Metadata are attached on objects. They are formed as key:value pairs.
1744 5655d560 Stavros Sachtouris
    They can have arbitary values.
1745 5655d560 Stavros Sachtouris
    """
1746 5655d560 Stavros Sachtouris
1747 5655d560 Stavros Sachtouris
1748 5655d560 Stavros Sachtouris
@command(pithos_cmds)
1749 545c6c29 Stavros Sachtouris
class file_metadata_get(_file_container_command, _optional_json):
1750 72952f4f Stavros Sachtouris
    """Get metadata for account, containers or objects"""
1751 7493ccb6 Stavros Sachtouris
1752 2fe2672e Stavros Sachtouris
    arguments = dict(
1753 f40f0cb7 Stavros Sachtouris
        detail=FlagArgument('show detailed output', ('-l', '--details')),
1754 2fe2672e Stavros Sachtouris
        until=DateArgument('show metadata until then', '--until'),
1755 2fe2672e Stavros Sachtouris
        object_version=ValueArgument(
1756 c626151a Stavros Sachtouris
            'show specific version (applies only for objects)',
1757 545c6c29 Stavros Sachtouris
            ('-O', '--object-version'))
1758 2fe2672e Stavros Sachtouris
    )
1759 7493ccb6 Stavros Sachtouris
1760 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1761 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
1762 b4cf92b8 Stavros Sachtouris
    @errors.pithos.container
1763 b4cf92b8 Stavros Sachtouris
    @errors.pithos.object_path
1764 b4cf92b8 Stavros Sachtouris
    def _run(self):
1765 b4cf92b8 Stavros Sachtouris
        until = self['until']
1766 545c6c29 Stavros Sachtouris
        r = None
1767 b4cf92b8 Stavros Sachtouris
        if self.container is None:
1768 0f383dcc Stavros Sachtouris
            r = self.client.get_account_info(until=until)
1769 b4cf92b8 Stavros Sachtouris
        elif self.path is None:
1770 b4cf92b8 Stavros Sachtouris
            if self['detail']:
1771 b4cf92b8 Stavros Sachtouris
                r = self.client.get_container_info(until=until)
1772 b4cf92b8 Stavros Sachtouris
            else:
1773 b4cf92b8 Stavros Sachtouris
                cmeta = self.client.get_container_meta(until=until)
1774 b4cf92b8 Stavros Sachtouris
                ometa = self.client.get_container_object_meta(until=until)
1775 b4cf92b8 Stavros Sachtouris
                r = {}
1776 b4cf92b8 Stavros Sachtouris
                if cmeta:
1777 0f383dcc Stavros Sachtouris
                    r['container-meta'] = cmeta
1778 b4cf92b8 Stavros Sachtouris
                if ometa:
1779 0f383dcc Stavros Sachtouris
                    r['object-meta'] = ometa
1780 b4cf92b8 Stavros Sachtouris
        else:
1781 b4cf92b8 Stavros Sachtouris
            if self['detail']:
1782 de73876b Stavros Sachtouris
                r = self.client.get_object_info(
1783 de73876b Stavros Sachtouris
                    self.path,
1784 b4cf92b8 Stavros Sachtouris
                    version=self['object_version'])
1785 b4cf92b8 Stavros Sachtouris
            else:
1786 de73876b Stavros Sachtouris
                r = self.client.get_object_meta(
1787 de73876b Stavros Sachtouris
                    self.path,
1788 b4cf92b8 Stavros Sachtouris
                    version=self['object_version'])
1789 b4cf92b8 Stavros Sachtouris
        if r:
1790 545c6c29 Stavros Sachtouris
            self._print(r, print_dict)
1791 b4cf92b8 Stavros Sachtouris
1792 b4cf92b8 Stavros Sachtouris
    def main(self, container____path__=None):
1793 b4cf92b8 Stavros Sachtouris
        super(self.__class__, self)._run(container____path__)
1794 b4cf92b8 Stavros Sachtouris
        self._run()
1795 7493ccb6 Stavros Sachtouris
1796 234954d1 Stavros Sachtouris
1797 d486baec Stavros Sachtouris
@command(pithos_cmds)
1798 915b99b5 Stavros Sachtouris
class file_metadata_set(_file_container_command, _optional_output_cmd):
1799 5655d560 Stavros Sachtouris
    """Set a piece of metadata for account, container or object"""
1800 7493ccb6 Stavros Sachtouris
1801 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1802 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
1803 b4cf92b8 Stavros Sachtouris
    @errors.pithos.container
1804 b4cf92b8 Stavros Sachtouris
    @errors.pithos.object_path
1805 b4cf92b8 Stavros Sachtouris
    def _run(self, metakey, metaval):
1806 b4cf92b8 Stavros Sachtouris
        if not self.container:
1807 915b99b5 Stavros Sachtouris
            r = self.client.set_account_meta({metakey: metaval})
1808 b4cf92b8 Stavros Sachtouris
        elif not self.path:
1809 915b99b5 Stavros Sachtouris
            r = self.client.set_container_meta({metakey: metaval})
1810 b4cf92b8 Stavros Sachtouris
        else:
1811 915b99b5 Stavros Sachtouris
            r = self.client.set_object_meta(self.path, {metakey: metaval})
1812 915b99b5 Stavros Sachtouris
        self._optional_output(r)
1813 b4cf92b8 Stavros Sachtouris
1814 b4cf92b8 Stavros Sachtouris
    def main(self, metakey, metaval, container____path__=None):
1815 b4cf92b8 Stavros Sachtouris
        super(self.__class__, self)._run(container____path__)
1816 b4cf92b8 Stavros Sachtouris
        self._run(metakey=metakey, metaval=metaval)
1817 7493ccb6 Stavros Sachtouris
1818 234954d1 Stavros Sachtouris
1819 d486baec Stavros Sachtouris
@command(pithos_cmds)
1820 915b99b5 Stavros Sachtouris
class file_metadata_delete(_file_container_command, _optional_output_cmd):
1821 72952f4f Stavros Sachtouris
    """Delete metadata with given key from account, container or object
1822 5655d560 Stavros Sachtouris
    - to get metadata of current account: /file metadata get
1823 5655d560 Stavros Sachtouris
    - to get metadata of a container:     /file metadata get <container>
1824 5655d560 Stavros Sachtouris
    - to get metadata of an object:       /file metadata get <container>:<path>
1825 72952f4f Stavros Sachtouris
    """
1826 7493ccb6 Stavros Sachtouris
1827 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1828 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
1829 b4cf92b8 Stavros Sachtouris
    @errors.pithos.container
1830 b4cf92b8 Stavros Sachtouris
    @errors.pithos.object_path
1831 b4cf92b8 Stavros Sachtouris
    def _run(self, metakey):
1832 b4cf92b8 Stavros Sachtouris
        if self.container is None:
1833 915b99b5 Stavros Sachtouris
            r = self.client.del_account_meta(metakey)
1834 b4cf92b8 Stavros Sachtouris
        elif self.path is None:
1835 915b99b5 Stavros Sachtouris
            r = self.client.del_container_meta(metakey)
1836 b4cf92b8 Stavros Sachtouris
        else:
1837 915b99b5 Stavros Sachtouris
            r = self.client.del_object_meta(self.path, metakey)
1838 915b99b5 Stavros Sachtouris
        self._optional_output(r)
1839 b4cf92b8 Stavros Sachtouris
1840 7493ccb6 Stavros Sachtouris
    def main(self, metakey, container____path__=None):
1841 b4cf92b8 Stavros Sachtouris
        super(self.__class__, self)._run(container____path__)
1842 b4cf92b8 Stavros Sachtouris
        self._run(metakey)
1843 7493ccb6 Stavros Sachtouris
1844 234954d1 Stavros Sachtouris
1845 d486baec Stavros Sachtouris
@command(pithos_cmds)
1846 545c6c29 Stavros Sachtouris
class file_quota(_file_account_command, _optional_json):
1847 3ed6dbde Stavros Sachtouris
    """Get account quota"""
1848 001200c3 Stavros Sachtouris
1849 001200c3 Stavros Sachtouris
    arguments = dict(
1850 001200c3 Stavros Sachtouris
        in_bytes=FlagArgument('Show result in bytes', ('-b', '--bytes'))
1851 de73876b Stavros Sachtouris
    )
1852 7493ccb6 Stavros Sachtouris
1853 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1854 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
1855 b4cf92b8 Stavros Sachtouris
    def _run(self):
1856 545c6c29 Stavros Sachtouris
1857 545c6c29 Stavros Sachtouris
        def pretty_print(output):
1858 545c6c29 Stavros Sachtouris
            if not self['in_bytes']:
1859 545c6c29 Stavros Sachtouris
                for k in output:
1860 545c6c29 Stavros Sachtouris
                    output[k] = format_size(output[k])
1861 0f383dcc Stavros Sachtouris
            print_dict(output, '-')
1862 545c6c29 Stavros Sachtouris
1863 545c6c29 Stavros Sachtouris
        self._print(self.client.get_account_quota(), pretty_print)
1864 7493ccb6 Stavros Sachtouris
1865 3ed6dbde Stavros Sachtouris
    def main(self, custom_uuid=None):
1866 3ed6dbde Stavros Sachtouris
        super(self.__class__, self)._run(custom_account=custom_uuid)
1867 b4cf92b8 Stavros Sachtouris
        self._run()
1868 b4cf92b8 Stavros Sachtouris
1869 234954d1 Stavros Sachtouris
1870 d486baec Stavros Sachtouris
@command(pithos_cmds)
1871 326a79b9 Stavros Sachtouris
class file_containerlimit(_pithos_init):
1872 326a79b9 Stavros Sachtouris
    """Container size limit commands"""
1873 326a79b9 Stavros Sachtouris
1874 326a79b9 Stavros Sachtouris
1875 326a79b9 Stavros Sachtouris
@command(pithos_cmds)
1876 545c6c29 Stavros Sachtouris
class file_containerlimit_get(_file_container_command, _optional_json):
1877 3ed6dbde Stavros Sachtouris
    """Get container size limit"""
1878 3ed6dbde Stavros Sachtouris
1879 3ed6dbde Stavros Sachtouris
    arguments = dict(
1880 3ed6dbde Stavros Sachtouris
        in_bytes=FlagArgument('Show result in bytes', ('-b', '--bytes'))
1881 3ed6dbde Stavros Sachtouris
    )
1882 3ed6dbde Stavros Sachtouris
1883 3ed6dbde Stavros Sachtouris
    @errors.generic.all
1884 3ed6dbde Stavros Sachtouris
    @errors.pithos.container
1885 3ed6dbde Stavros Sachtouris
    def _run(self):
1886 545c6c29 Stavros Sachtouris
1887 545c6c29 Stavros Sachtouris
        def pretty_print(output):
1888 545c6c29 Stavros Sachtouris
            if not self['in_bytes']:
1889 545c6c29 Stavros Sachtouris
                for k, v in output.items():
1890 545c6c29 Stavros Sachtouris
                    output[k] = 'unlimited' if '0' == v else format_size(v)
1891 0f383dcc Stavros Sachtouris
            print_dict(output, '-')
1892 545c6c29 Stavros Sachtouris
1893 545c6c29 Stavros Sachtouris
        self._print(
1894 545c6c29 Stavros Sachtouris
            self.client.get_container_limit(self.container), pretty_print)
1895 3ed6dbde Stavros Sachtouris
1896 3ed6dbde Stavros Sachtouris
    def main(self, container=None):
1897 3ed6dbde Stavros Sachtouris
        super(self.__class__, self)._run()
1898 3ed6dbde Stavros Sachtouris
        self.container = container
1899 3ed6dbde Stavros Sachtouris
        self._run()
1900 3ed6dbde Stavros Sachtouris
1901 3ed6dbde Stavros Sachtouris
1902 3ed6dbde Stavros Sachtouris
@command(pithos_cmds)
1903 545c6c29 Stavros Sachtouris
class file_containerlimit_set(_file_account_command, _optional_output_cmd):
1904 326a79b9 Stavros Sachtouris
    """Set new storage limit for a container
1905 326a79b9 Stavros Sachtouris
    By default, the limit is set in bytes
1906 001200c3 Stavros Sachtouris
    Users may specify a different unit, e.g:
1907 326a79b9 Stavros Sachtouris
    /file containerlimit set 2.3GB mycontainer
1908 3ed6dbde Stavros Sachtouris
    Valid units: B, KiB (1024 B), KB (1000 B), MiB, MB, GiB, GB, TiB, TB
1909 9f783a51 Stavros Sachtouris
    To set container limit to "unlimited", use 0
1910 001200c3 Stavros Sachtouris
    """
1911 001200c3 Stavros Sachtouris
1912 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1913 326a79b9 Stavros Sachtouris
    def _calculate_limit(self, user_input):
1914 326a79b9 Stavros Sachtouris
        limit = 0
1915 001200c3 Stavros Sachtouris
        try:
1916 326a79b9 Stavros Sachtouris
            limit = int(user_input)
1917 001200c3 Stavros Sachtouris
        except ValueError:
1918 001200c3 Stavros Sachtouris
            index = 0
1919 001200c3 Stavros Sachtouris
            digits = [str(num) for num in range(0, 10)] + ['.']
1920 001200c3 Stavros Sachtouris
            while user_input[index] in digits:
1921 001200c3 Stavros Sachtouris
                index += 1
1922 326a79b9 Stavros Sachtouris
            limit = user_input[:index]
1923 001200c3 Stavros Sachtouris
            format = user_input[index:]
1924 001200c3 Stavros Sachtouris
            try:
1925 326a79b9 Stavros Sachtouris
                return to_bytes(limit, format)
1926 001200c3 Stavros Sachtouris
            except Exception as qe:
1927 de73876b Stavros Sachtouris
                msg = 'Failed to convert %s to bytes' % user_input,
1928 de73876b Stavros Sachtouris
                raiseCLIError(qe, msg, details=[
1929 326a79b9 Stavros Sachtouris
                    'Syntax: containerlimit set <limit>[format] [container]',
1930 326a79b9 Stavros Sachtouris
                    'e.g.: containerlimit set 2.3GB mycontainer',
1931 326a79b9 Stavros Sachtouris
                    'Valid formats:',
1932 de73876b Stavros Sachtouris
                    '(*1024): B, KiB, MiB, GiB, TiB',
1933 de73876b Stavros Sachtouris
                    '(*1000): B, KB, MB, GB, TB'])
1934 326a79b9 Stavros Sachtouris
        return limit
1935 7493ccb6 Stavros Sachtouris
1936 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1937 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
1938 b4cf92b8 Stavros Sachtouris
    @errors.pithos.container
1939 326a79b9 Stavros Sachtouris
    def _run(self, limit):
1940 b4cf92b8 Stavros Sachtouris
        if self.container:
1941 b4cf92b8 Stavros Sachtouris
            self.client.container = self.container
1942 915b99b5 Stavros Sachtouris
        self._optional_output(self.client.set_container_limit(limit))
1943 b4cf92b8 Stavros Sachtouris
1944 326a79b9 Stavros Sachtouris
    def main(self, limit, container=None):
1945 b4cf92b8 Stavros Sachtouris
        super(self.__class__, self)._run()
1946 326a79b9 Stavros Sachtouris
        limit = self._calculate_limit(limit)
1947 b4cf92b8 Stavros Sachtouris
        self.container = container
1948 326a79b9 Stavros Sachtouris
        self._run(limit)
1949 7493ccb6 Stavros Sachtouris
1950 234954d1 Stavros Sachtouris
1951 d486baec Stavros Sachtouris
@command(pithos_cmds)
1952 915b99b5 Stavros Sachtouris
class file_versioning(_pithos_init):
1953 915b99b5 Stavros Sachtouris
    """Manage the versioning scheme of current pithos user account"""
1954 915b99b5 Stavros Sachtouris
1955 915b99b5 Stavros Sachtouris
1956 915b99b5 Stavros Sachtouris
@command(pithos_cmds)
1957 545c6c29 Stavros Sachtouris
class file_versioning_get(_file_account_command, _optional_json):
1958 776eee69 Stavros Sachtouris
    """Get  versioning for account or container"""
1959 7493ccb6 Stavros Sachtouris
1960 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1961 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
1962 b4cf92b8 Stavros Sachtouris
    @errors.pithos.container
1963 b4cf92b8 Stavros Sachtouris
    def _run(self):
1964 545c6c29 Stavros Sachtouris
        self._print(
1965 df0045d8 Stavros Sachtouris
            self.client.get_container_versioning(self.container), print_dict)
1966 b4cf92b8 Stavros Sachtouris
1967 df0045d8 Stavros Sachtouris
    def main(self, container):
1968 b4cf92b8 Stavros Sachtouris
        super(self.__class__, self)._run()
1969 b4cf92b8 Stavros Sachtouris
        self.container = container
1970 b4cf92b8 Stavros Sachtouris
        self._run()
1971 7493ccb6 Stavros Sachtouris
1972 234954d1 Stavros Sachtouris
1973 d486baec Stavros Sachtouris
@command(pithos_cmds)
1974 915b99b5 Stavros Sachtouris
class file_versioning_set(_file_account_command, _optional_output_cmd):
1975 776eee69 Stavros Sachtouris
    """Set versioning mode (auto, none) for account or container"""
1976 7493ccb6 Stavros Sachtouris
1977 b4cf92b8 Stavros Sachtouris
    def _check_versioning(self, versioning):
1978 b4cf92b8 Stavros Sachtouris
        if versioning and versioning.lower() in ('auto', 'none'):
1979 b4cf92b8 Stavros Sachtouris
            return versioning.lower()
1980 b4cf92b8 Stavros Sachtouris
        raiseCLIError('Invalid versioning %s' % versioning, details=[
1981 b4cf92b8 Stavros Sachtouris
            'Versioning can be auto or none'])
1982 b4cf92b8 Stavros Sachtouris
1983 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1984 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
1985 b4cf92b8 Stavros Sachtouris
    @errors.pithos.container
1986 b4cf92b8 Stavros Sachtouris
    def _run(self, versioning):
1987 df0045d8 Stavros Sachtouris
        self.client.container = self.container
1988 df0045d8 Stavros Sachtouris
        r = self.client.set_container_versioning(versioning)
1989 915b99b5 Stavros Sachtouris
        self._optional_output(r)
1990 b4cf92b8 Stavros Sachtouris
1991 df0045d8 Stavros Sachtouris
    def main(self, versioning, container):
1992 b4cf92b8 Stavros Sachtouris
        super(self.__class__, self)._run()
1993 b4cf92b8 Stavros Sachtouris
        self._run(self._check_versioning(versioning))
1994 7493ccb6 Stavros Sachtouris
1995 234954d1 Stavros Sachtouris
1996 d486baec Stavros Sachtouris
@command(pithos_cmds)
1997 915b99b5 Stavros Sachtouris
class file_group(_pithos_init):
1998 915b99b5 Stavros Sachtouris
    """Manage access groups and group members"""
1999 915b99b5 Stavros Sachtouris
2000 915b99b5 Stavros Sachtouris
2001 915b99b5 Stavros Sachtouris
@command(pithos_cmds)
2002 545c6c29 Stavros Sachtouris
class file_group_list(_file_account_command, _optional_json):
2003 545c6c29 Stavros Sachtouris
    """list all groups and group members"""
2004 7493ccb6 Stavros Sachtouris
2005 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
2006 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
2007 b4cf92b8 Stavros Sachtouris
    def _run(self):
2008 0f383dcc Stavros Sachtouris
        self._print(self.client.get_account_group(), print_dict, delim='-')
2009 b4cf92b8 Stavros Sachtouris
2010 7493ccb6 Stavros Sachtouris
    def main(self):
2011 b4cf92b8 Stavros Sachtouris
        super(self.__class__, self)._run()
2012 b4cf92b8 Stavros Sachtouris
        self._run()
2013 7493ccb6 Stavros Sachtouris
2014 234954d1 Stavros Sachtouris
2015 d486baec Stavros Sachtouris
@command(pithos_cmds)
2016 915b99b5 Stavros Sachtouris
class file_group_set(_file_account_command, _optional_output_cmd):
2017 4fcc38a2 Stavros Sachtouris
    """Set a user group"""
2018 7493ccb6 Stavros Sachtouris
2019 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
2020 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
2021 b4cf92b8 Stavros Sachtouris
    def _run(self, groupname, *users):
2022 915b99b5 Stavros Sachtouris
        self._optional_output(self.client.set_account_group(groupname, users))
2023 b4cf92b8 Stavros Sachtouris
2024 7493ccb6 Stavros Sachtouris
    def main(self, groupname, *users):
2025 b4cf92b8 Stavros Sachtouris
        super(self.__class__, self)._run()
2026 b4cf92b8 Stavros Sachtouris
        if users:
2027 b4cf92b8 Stavros Sachtouris
            self._run(groupname, *users)
2028 b4cf92b8 Stavros Sachtouris
        else:
2029 b4cf92b8 Stavros Sachtouris
            raiseCLIError('No users to add in group %s' % groupname)
2030 7493ccb6 Stavros Sachtouris
2031 234954d1 Stavros Sachtouris
2032 d486baec Stavros Sachtouris
@command(pithos_cmds)
2033 915b99b5 Stavros Sachtouris
class file_group_delete(_file_account_command, _optional_output_cmd):
2034 4fcc38a2 Stavros Sachtouris
    """Delete a user group"""
2035 7493ccb6 Stavros Sachtouris
2036 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
2037 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
2038 b4cf92b8 Stavros Sachtouris
    def _run(self, groupname):
2039 915b99b5 Stavros Sachtouris
        self._optional_output(self.client.del_account_group(groupname))
2040 b4cf92b8 Stavros Sachtouris
2041 7493ccb6 Stavros Sachtouris
    def main(self, groupname):
2042 b4cf92b8 Stavros Sachtouris
        super(self.__class__, self)._run()
2043 b4cf92b8 Stavros Sachtouris
        self._run(groupname)
2044 a23f6ffe Stavros Sachtouris
2045 234954d1 Stavros Sachtouris
2046 d486baec Stavros Sachtouris
@command(pithos_cmds)
2047 545c6c29 Stavros Sachtouris
class file_sharers(_file_account_command, _optional_json):
2048 4fcc38a2 Stavros Sachtouris
    """List the accounts that share objects with current user"""
2049 a23f6ffe Stavros Sachtouris
2050 2fe2672e Stavros Sachtouris
    arguments = dict(
2051 f40f0cb7 Stavros Sachtouris
        detail=FlagArgument('show detailed output', ('-l', '--details')),
2052 2fe2672e Stavros Sachtouris
        marker=ValueArgument('show output greater then marker', '--marker')
2053 2fe2672e Stavros Sachtouris
    )
2054 a23f6ffe Stavros Sachtouris
2055 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
2056 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
2057 b4cf92b8 Stavros Sachtouris
    def _run(self):
2058 b4cf92b8 Stavros Sachtouris
        accounts = self.client.get_sharing_accounts(marker=self['marker'])
2059 cf115aed Stavros Sachtouris
        if not self['json_output']:
2060 cf115aed Stavros Sachtouris
            usernames = self._uuids2usernames(
2061 cf115aed Stavros Sachtouris
                [acc['name'] for acc in accounts])
2062 cf115aed Stavros Sachtouris
            for item in accounts:
2063 cf115aed Stavros Sachtouris
                uuid = item['name']
2064 cf115aed Stavros Sachtouris
                item['id'], item['name'] = uuid, usernames[uuid]
2065 cf115aed Stavros Sachtouris
                if not self['detail']:
2066 cf115aed Stavros Sachtouris
                    item.pop('last_modified')
2067 cf115aed Stavros Sachtouris
        self._print(accounts)
2068 a23f6ffe Stavros Sachtouris
2069 b4cf92b8 Stavros Sachtouris
    def main(self):
2070 b4cf92b8 Stavros Sachtouris
        super(self.__class__, self)._run()
2071 b4cf92b8 Stavros Sachtouris
        self._run()
2072 38dc5d2f Stavros Sachtouris
2073 234954d1 Stavros Sachtouris
2074 545c6c29 Stavros Sachtouris
def version_print(versions):
2075 545c6c29 Stavros Sachtouris
    print_items([dict(id=vitem[0], created=strftime(
2076 545c6c29 Stavros Sachtouris
        '%d-%m-%Y %H:%M:%S',
2077 545c6c29 Stavros Sachtouris
        localtime(float(vitem[1])))) for vitem in versions])
2078 545c6c29 Stavros Sachtouris
2079 545c6c29 Stavros Sachtouris
2080 d486baec Stavros Sachtouris
@command(pithos_cmds)
2081 545c6c29 Stavros Sachtouris
class file_versions(_file_container_command, _optional_json):
2082 4fcc38a2 Stavros Sachtouris
    """Get the list of object versions
2083 4fcc38a2 Stavros Sachtouris
    Deleted objects may still have versions that can be used to restore it and
2084 4fcc38a2 Stavros Sachtouris
    get information about its previous state.
2085 4fcc38a2 Stavros Sachtouris
    The version number can be used in a number of other commands, like info,
2086 4fcc38a2 Stavros Sachtouris
    copy, move, meta. See these commands for more information, e.g.
2087 3ae60112 Stavros Sachtouris
    /file info -h
2088 4fcc38a2 Stavros Sachtouris
    """
2089 38dc5d2f Stavros Sachtouris
2090 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
2091 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
2092 b4cf92b8 Stavros Sachtouris
    @errors.pithos.container
2093 b4cf92b8 Stavros Sachtouris
    @errors.pithos.object_path
2094 b4cf92b8 Stavros Sachtouris
    def _run(self):
2095 545c6c29 Stavros Sachtouris
        self._print(
2096 545c6c29 Stavros Sachtouris
            self.client.get_object_versionlist(self.path), version_print)
2097 b4cf92b8 Stavros Sachtouris
2098 38dc5d2f Stavros Sachtouris
    def main(self, container___path):
2099 3ae60112 Stavros Sachtouris
        super(file_versions, self)._run(
2100 b4cf92b8 Stavros Sachtouris
            container___path,
2101 b4cf92b8 Stavros Sachtouris
            path_is_optional=False)
2102 b4cf92b8 Stavros Sachtouris
        self._run()