Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / commands / pithos.py @ 6c068db6

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

630 6736f171 Stavros Sachtouris
        :param src_path: (str) source path
631 6736f171 Stavros Sachtouris

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