Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / commands / pithos.py @ 16d7b9ff

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

574 6736f171 Stavros Sachtouris
        :param src_path: (str) source path
575 6736f171 Stavros Sachtouris

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