Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (77.8 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 f8426b5c Stavros Sachtouris
    page_hold, bold, ask_user, get_path_size, print_json, guess_mime_type)
44 e3d4d442 Stavros Sachtouris
from kamaki.cli.argument import FlagArgument, ValueArgument, IntArgument
45 04d01cd4 Stavros Sachtouris
from kamaki.cli.argument import KeyValueArgument, DateArgument
46 fd1f1d96 Stavros Sachtouris
from kamaki.cli.argument import ProgressBarArgument
47 545c6c29 Stavros Sachtouris
from kamaki.cli.commands import _command_init, errors
48 b4f69041 Stavros Sachtouris
from kamaki.cli.commands import addLogSettings, DontRaiseKeyError
49 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 a339a3ee Stavros Sachtouris
            if 'subdir' in obj:
369 a339a3ee Stavros Sachtouris
                continue
370 7493ccb6 Stavros Sachtouris
            if obj['content_type'] == 'application/directory':
371 7493ccb6 Stavros Sachtouris
                isDir = True
372 7493ccb6 Stavros Sachtouris
                size = 'D'
373 7493ccb6 Stavros Sachtouris
            else:
374 7493ccb6 Stavros Sachtouris
                isDir = False
375 7493ccb6 Stavros Sachtouris
                size = format_size(obj['bytes'])
376 234954d1 Stavros Sachtouris
                pretty_obj['bytes'] = '%s (%s)' % (obj['bytes'], size)
377 7493ccb6 Stavros Sachtouris
            oname = bold(obj['name'])
378 ed9af02c Stavros Sachtouris
            prfx = ('%s%s. ' % (empty_space, index)) if self['enum'] else ''
379 47ae7577 Stavros Sachtouris
            if self['detail']:
380 ed9af02c Stavros Sachtouris
                print('%s%s' % (prfx, oname))
381 7493ccb6 Stavros Sachtouris
                print_dict(pretty_keys(pretty_obj), exclude=('name'))
382 7493ccb6 Stavros Sachtouris
                print
383 7493ccb6 Stavros Sachtouris
            else:
384 ed9af02c Stavros Sachtouris
                oname = '%s%9s %s' % (prfx, size, oname)
385 7493ccb6 Stavros Sachtouris
                oname += '/' if isDir else ''
386 7493ccb6 Stavros Sachtouris
                print(oname)
387 439826ec Stavros Sachtouris
            if self['more']:
388 439826ec Stavros Sachtouris
                page_hold(index, limit, len(object_list))
389 7493ccb6 Stavros Sachtouris
390 7493ccb6 Stavros Sachtouris
    def print_containers(self, container_list):
391 0399ac7e Stavros Sachtouris
        if self['json_output']:
392 0399ac7e Stavros Sachtouris
            print_json(container_list)
393 0399ac7e Stavros Sachtouris
            return
394 439826ec Stavros Sachtouris
        limit = int(self['limit']) if self['limit'] > 0\
395 439826ec Stavros Sachtouris
            else len(container_list)
396 234954d1 Stavros Sachtouris
        for index, container in enumerate(container_list):
397 234954d1 Stavros Sachtouris
            if 'bytes' in container:
398 234954d1 Stavros Sachtouris
                size = format_size(container['bytes'])
399 ed9af02c Stavros Sachtouris
            prfx = ('%s. ' % (index + 1)) if self['enum'] else ''
400 ed9af02c Stavros Sachtouris
            cname = '%s%s' % (prfx, bold(container['name']))
401 47ae7577 Stavros Sachtouris
            if self['detail']:
402 7493ccb6 Stavros Sachtouris
                print(cname)
403 7493ccb6 Stavros Sachtouris
                pretty_c = container.copy()
404 234954d1 Stavros Sachtouris
                if 'bytes' in container:
405 234954d1 Stavros Sachtouris
                    pretty_c['bytes'] = '%s (%s)' % (container['bytes'], size)
406 7493ccb6 Stavros Sachtouris
                print_dict(pretty_keys(pretty_c), exclude=('name'))
407 7493ccb6 Stavros Sachtouris
                print
408 7493ccb6 Stavros Sachtouris
            else:
409 234954d1 Stavros Sachtouris
                if 'count' in container and 'bytes' in container:
410 de73876b Stavros Sachtouris
                    print('%s (%s, %s objects)' % (
411 de73876b Stavros Sachtouris
                        cname,
412 de73876b Stavros Sachtouris
                        size,
413 de73876b Stavros Sachtouris
                        container['count']))
414 7493ccb6 Stavros Sachtouris
                else:
415 7493ccb6 Stavros Sachtouris
                    print(cname)
416 439826ec Stavros Sachtouris
            if self['more']:
417 439826ec Stavros Sachtouris
                page_hold(index + 1, limit, len(container_list))
418 7493ccb6 Stavros Sachtouris
419 1395c40e Stavros Sachtouris
    @errors.generic.all
420 1395c40e Stavros Sachtouris
    @errors.pithos.connection
421 1395c40e Stavros Sachtouris
    @errors.pithos.object_path
422 1395c40e Stavros Sachtouris
    @errors.pithos.container
423 1395c40e Stavros Sachtouris
    def _run(self):
424 1395c40e Stavros Sachtouris
        if self.container is None:
425 1395c40e Stavros Sachtouris
            r = self.client.account_get(
426 1395c40e Stavros Sachtouris
                limit=False if self['more'] else self['limit'],
427 1395c40e Stavros Sachtouris
                marker=self['marker'],
428 1395c40e Stavros Sachtouris
                if_modified_since=self['if_modified_since'],
429 1395c40e Stavros Sachtouris
                if_unmodified_since=self['if_unmodified_since'],
430 1395c40e Stavros Sachtouris
                until=self['until'],
431 1395c40e Stavros Sachtouris
                show_only_shared=self['shared'])
432 545c6c29 Stavros Sachtouris
            self._print(r.json, self.print_containers)
433 1395c40e Stavros Sachtouris
        else:
434 52edad0a Stavros Sachtouris
            prefix = self.path or self['prefix']
435 1395c40e Stavros Sachtouris
            r = self.client.container_get(
436 1395c40e Stavros Sachtouris
                limit=False if self['more'] else self['limit'],
437 1395c40e Stavros Sachtouris
                marker=self['marker'],
438 1395c40e Stavros Sachtouris
                prefix=prefix,
439 1395c40e Stavros Sachtouris
                delimiter=self['delimiter'],
440 1395c40e Stavros Sachtouris
                path=self['path'],
441 1395c40e Stavros Sachtouris
                if_modified_since=self['if_modified_since'],
442 1395c40e Stavros Sachtouris
                if_unmodified_since=self['if_unmodified_since'],
443 1395c40e Stavros Sachtouris
                until=self['until'],
444 1395c40e Stavros Sachtouris
                meta=self['meta'],
445 1395c40e Stavros Sachtouris
                show_only_shared=self['shared'])
446 545c6c29 Stavros Sachtouris
            self._print(r.json, self.print_objects)
447 1395c40e Stavros Sachtouris
448 7493ccb6 Stavros Sachtouris
    def main(self, container____path__=None):
449 1395c40e Stavros Sachtouris
        super(self.__class__, self)._run(container____path__)
450 1395c40e Stavros Sachtouris
        self._run()
451 7493ccb6 Stavros Sachtouris
452 234954d1 Stavros Sachtouris
453 d486baec Stavros Sachtouris
@command(pithos_cmds)
454 915b99b5 Stavros Sachtouris
class file_mkdir(_file_container_command, _optional_output_cmd):
455 f17d6cb5 Stavros Sachtouris
    """Create a directory
456 f17d6cb5 Stavros Sachtouris
    Kamaki hanldes directories the same way as OOS Storage and Pithos+:
457 f17d6cb5 Stavros Sachtouris
    A directory  is   an  object  with  type  "application/directory"
458 f17d6cb5 Stavros Sachtouris
    An object with path  dir/name can exist even if  dir does not exist
459 f17d6cb5 Stavros Sachtouris
    or even if dir  is  a non  directory  object.  Users can modify dir '
460 f17d6cb5 Stavros Sachtouris
    without affecting the dir/name object in any way.
461 f17d6cb5 Stavros Sachtouris
    """
462 7493ccb6 Stavros Sachtouris
463 1395c40e Stavros Sachtouris
    @errors.generic.all
464 1395c40e Stavros Sachtouris
    @errors.pithos.connection
465 1395c40e Stavros Sachtouris
    @errors.pithos.container
466 1395c40e Stavros Sachtouris
    def _run(self):
467 915b99b5 Stavros Sachtouris
        self._optional_output(self.client.create_directory(self.path))
468 1395c40e Stavros Sachtouris
469 7493ccb6 Stavros Sachtouris
    def main(self, container___directory):
470 1395c40e Stavros Sachtouris
        super(self.__class__, self)._run(
471 1395c40e Stavros Sachtouris
            container___directory,
472 1395c40e Stavros Sachtouris
            path_is_optional=False)
473 1395c40e Stavros Sachtouris
        self._run()
474 7493ccb6 Stavros Sachtouris
475 234954d1 Stavros Sachtouris
476 d486baec Stavros Sachtouris
@command(pithos_cmds)
477 915b99b5 Stavros Sachtouris
class file_touch(_file_container_command, _optional_output_cmd):
478 1e29b9f6 Stavros Sachtouris
    """Create an empty object (file)
479 1e29b9f6 Stavros Sachtouris
    If object exists, this command will reset it to 0 length
480 1e29b9f6 Stavros Sachtouris
    """
481 1e29b9f6 Stavros Sachtouris
482 1e29b9f6 Stavros Sachtouris
    arguments = dict(
483 1e29b9f6 Stavros Sachtouris
        content_type=ValueArgument(
484 1e29b9f6 Stavros Sachtouris
            'Set content type (default: application/octet-stream)',
485 1e29b9f6 Stavros Sachtouris
            '--content-type',
486 915b99b5 Stavros Sachtouris
            default='application/octet-stream')
487 1e29b9f6 Stavros Sachtouris
    )
488 1e29b9f6 Stavros Sachtouris
489 1395c40e Stavros Sachtouris
    @errors.generic.all
490 1395c40e Stavros Sachtouris
    @errors.pithos.connection
491 1395c40e Stavros Sachtouris
    @errors.pithos.container
492 1395c40e Stavros Sachtouris
    def _run(self):
493 915b99b5 Stavros Sachtouris
        self._optional_output(
494 915b99b5 Stavros Sachtouris
            self.client.create_object(self.path, self['content_type']))
495 1395c40e Stavros Sachtouris
496 1e29b9f6 Stavros Sachtouris
    def main(self, container___path):
497 3ae60112 Stavros Sachtouris
        super(file_touch, self)._run(
498 52edad0a Stavros Sachtouris
            container___path,
499 52edad0a Stavros Sachtouris
            path_is_optional=False)
500 1395c40e Stavros Sachtouris
        self._run()
501 1e29b9f6 Stavros Sachtouris
502 1e29b9f6 Stavros Sachtouris
503 1e29b9f6 Stavros Sachtouris
@command(pithos_cmds)
504 915b99b5 Stavros Sachtouris
class file_create(_file_container_command, _optional_output_cmd):
505 1e29b9f6 Stavros Sachtouris
    """Create a container"""
506 7493ccb6 Stavros Sachtouris
507 2fe2672e Stavros Sachtouris
    arguments = dict(
508 2fe2672e Stavros Sachtouris
        versioning=ValueArgument(
509 201baa17 Stavros Sachtouris
            'set container versioning (auto/none)', '--versioning'),
510 3ed6dbde Stavros Sachtouris
        limit=IntArgument('set default container limit', '--limit'),
511 2fe2672e Stavros Sachtouris
        meta=KeyValueArgument(
512 201baa17 Stavros Sachtouris
            'set container metadata (can be repeated)', '--meta')
513 2fe2672e Stavros Sachtouris
    )
514 7493ccb6 Stavros Sachtouris
515 1395c40e Stavros Sachtouris
    @errors.generic.all
516 1395c40e Stavros Sachtouris
    @errors.pithos.connection
517 1395c40e Stavros Sachtouris
    @errors.pithos.container
518 94bedc5b Stavros Sachtouris
    def _run(self, container):
519 915b99b5 Stavros Sachtouris
        self._optional_output(self.client.create_container(
520 915b99b5 Stavros Sachtouris
            container=container,
521 915b99b5 Stavros Sachtouris
            sizelimit=self['limit'],
522 915b99b5 Stavros Sachtouris
            versioning=self['versioning'],
523 915b99b5 Stavros Sachtouris
            metadata=self['meta']))
524 1395c40e Stavros Sachtouris
525 edab7ba7 Stavros Sachtouris
    def main(self, container=None):
526 1395c40e Stavros Sachtouris
        super(self.__class__, self)._run(container)
527 edab7ba7 Stavros Sachtouris
        if container and self.container != container:
528 1395c40e Stavros Sachtouris
            raiseCLIError('Invalid container name %s' % container, details=[
529 edab7ba7 Stavros Sachtouris
                'Did you mean "%s" ?' % self.container,
530 52edad0a Stavros Sachtouris
                'Use --container for names containing :'])
531 94bedc5b Stavros Sachtouris
        self._run(container)
532 7493ccb6 Stavros Sachtouris
533 234954d1 Stavros Sachtouris
534 3ae60112 Stavros Sachtouris
class _source_destination_command(_file_container_command):
535 2fe2672e Stavros Sachtouris
536 2fe2672e Stavros Sachtouris
    arguments = dict(
537 f17d6cb5 Stavros Sachtouris
        destination_account=ValueArgument('', ('-a', '--dst-account')),
538 f40f0cb7 Stavros Sachtouris
        recursive=FlagArgument('', ('-R', '--recursive')),
539 761e0cbf Stavros Sachtouris
        prefix=FlagArgument('', '--with-prefix', default=''),
540 761e0cbf Stavros Sachtouris
        suffix=ValueArgument('', '--with-suffix', default=''),
541 761e0cbf Stavros Sachtouris
        add_prefix=ValueArgument('', '--add-prefix', default=''),
542 761e0cbf Stavros Sachtouris
        add_suffix=ValueArgument('', '--add-suffix', default=''),
543 761e0cbf Stavros Sachtouris
        prefix_replace=ValueArgument('', '--prefix-to-replace', default=''),
544 1d3f006b Stavros Sachtouris
        suffix_replace=ValueArgument('', '--suffix-to-replace', default=''),
545 2fe2672e Stavros Sachtouris
    )
546 7493ccb6 Stavros Sachtouris
547 b4f69041 Stavros Sachtouris
    def __init__(self, arguments={}, auth_base=None, cloud=None):
548 761e0cbf Stavros Sachtouris
        self.arguments.update(arguments)
549 f724cd35 Stavros Sachtouris
        super(_source_destination_command, self).__init__(
550 b4f69041 Stavros Sachtouris
            self.arguments, auth_base, cloud)
551 761e0cbf Stavros Sachtouris
552 300da0fb Stavros Sachtouris
    def _run(self, source_container___path, path_is_optional=False):
553 300da0fb Stavros Sachtouris
        super(_source_destination_command, self)._run(
554 300da0fb Stavros Sachtouris
            source_container___path,
555 300da0fb Stavros Sachtouris
            path_is_optional)
556 300da0fb Stavros Sachtouris
        self.dst_client = PithosClient(
557 300da0fb Stavros Sachtouris
            base_url=self.client.base_url,
558 300da0fb Stavros Sachtouris
            token=self.client.token,
559 300da0fb Stavros Sachtouris
            account=self['destination_account'] or self.client.account)
560 300da0fb Stavros Sachtouris
561 300da0fb Stavros Sachtouris
    @errors.generic.all
562 300da0fb Stavros Sachtouris
    @errors.pithos.account
563 300da0fb Stavros Sachtouris
    def _dest_container_path(self, dest_container_path):
564 300da0fb Stavros Sachtouris
        if self['destination_container']:
565 300da0fb Stavros Sachtouris
            self.dst_client.container = self['destination_container']
566 300da0fb Stavros Sachtouris
            return (self['destination_container'], dest_container_path)
567 300da0fb Stavros Sachtouris
        if dest_container_path:
568 300da0fb Stavros Sachtouris
            dst = dest_container_path.split(':')
569 300da0fb Stavros Sachtouris
            if len(dst) > 1:
570 300da0fb Stavros Sachtouris
                try:
571 300da0fb Stavros Sachtouris
                    self.dst_client.container = dst[0]
572 300da0fb Stavros Sachtouris
                    self.dst_client.get_container_info(dst[0])
573 300da0fb Stavros Sachtouris
                except ClientError as err:
574 300da0fb Stavros Sachtouris
                    if err.status in (404, 204):
575 300da0fb Stavros Sachtouris
                        raiseCLIError(
576 300da0fb Stavros Sachtouris
                            'Destination container %s not found' % dst[0])
577 300da0fb Stavros Sachtouris
                    raise
578 300da0fb Stavros Sachtouris
                else:
579 300da0fb Stavros Sachtouris
                    self.dst_client.container = dst[0]
580 300da0fb Stavros Sachtouris
                return (dst[0], dst[1])
581 300da0fb Stavros Sachtouris
            return(None, dst[0])
582 300da0fb Stavros Sachtouris
        raiseCLIError('No destination container:path provided')
583 300da0fb Stavros Sachtouris
584 ece4ae4b Stavros Sachtouris
    def _get_all(self, prefix):
585 ece4ae4b Stavros Sachtouris
        return self.client.container_get(prefix=prefix).json
586 ece4ae4b Stavros Sachtouris
587 1d3f006b Stavros Sachtouris
    def _get_src_objects(self, src_path, source_version=None):
588 6736f171 Stavros Sachtouris
        """Get a list of the source objects to be called
589 6736f171 Stavros Sachtouris

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

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