Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / commands / pithos.py @ 556e6916

History | View | Annotate | Download (77.3 kB)

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

589 6736f171 Stavros Sachtouris
        :param src_path: (str) source path
590 6736f171 Stavros Sachtouris

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