Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / commands / pithos.py @ 8c54338a

History | View | Annotate | Download (77.5 kB)

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

580 6736f171 Stavros Sachtouris
        :param src_path: (str) source path
581 6736f171 Stavros Sachtouris

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