Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / commands / pithos.py @ 54b6be76

History | View | Annotate | Download (77.1 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 f724cd35 Stavros Sachtouris
        self.account = self.auth_base.user_term('uuid', self.token)
183 1f5debf7 Stavros Sachtouris
184 234954d1 Stavros Sachtouris
185 3ae60112 Stavros Sachtouris
class _file_account_command(_pithos_init):
186 7493ccb6 Stavros Sachtouris
    """Base class for account level storage commands"""
187 7493ccb6 Stavros Sachtouris
188 f724cd35 Stavros Sachtouris
    def __init__(self, arguments={}, auth_base=None):
189 f724cd35 Stavros Sachtouris
        super(_file_account_command, self).__init__(arguments, auth_base)
190 439826ec Stavros Sachtouris
        self['account'] = ValueArgument(
191 47ae7577 Stavros Sachtouris
            'Set user account (not permanent)',
192 f40f0cb7 Stavros Sachtouris
            ('-A', '--account'))
193 7493ccb6 Stavros Sachtouris
194 3ed6dbde Stavros Sachtouris
    def _run(self, custom_account=None):
195 3ae60112 Stavros Sachtouris
        super(_file_account_command, self)._run()
196 3ed6dbde Stavros Sachtouris
        if custom_account:
197 3ed6dbde Stavros Sachtouris
            self.client.account = custom_account
198 3ed6dbde Stavros Sachtouris
        elif self['account']:
199 47ae7577 Stavros Sachtouris
            self.client.account = self['account']
200 7493ccb6 Stavros Sachtouris
201 1395c40e Stavros Sachtouris
    @errors.generic.all
202 1395c40e Stavros Sachtouris
    def main(self):
203 1395c40e Stavros Sachtouris
        self._run()
204 1395c40e Stavros Sachtouris
205 234954d1 Stavros Sachtouris
206 3ae60112 Stavros Sachtouris
class _file_container_command(_file_account_command):
207 7493ccb6 Stavros Sachtouris
    """Base class for container level storage commands"""
208 7493ccb6 Stavros Sachtouris
209 47ae7577 Stavros Sachtouris
    container = None
210 47ae7577 Stavros Sachtouris
    path = None
211 2d7ce81e Stavros Sachtouris
212 f724cd35 Stavros Sachtouris
    def __init__(self, arguments={}, auth_base=None):
213 f724cd35 Stavros Sachtouris
        super(_file_container_command, self).__init__(arguments, auth_base)
214 439826ec Stavros Sachtouris
        self['container'] = ValueArgument(
215 47ae7577 Stavros Sachtouris
            'Set container to work with (temporary)',
216 f40f0cb7 Stavros Sachtouris
            ('-C', '--container'))
217 7493ccb6 Stavros Sachtouris
218 de73876b Stavros Sachtouris
    def extract_container_and_path(
219 24ff0a35 Stavros Sachtouris
            self,
220 24ff0a35 Stavros Sachtouris
            container_with_path,
221 24ff0a35 Stavros Sachtouris
            path_is_optional=True):
222 1395c40e Stavros Sachtouris
        """Contains all heuristics for deciding what should be used as
223 1395c40e Stavros Sachtouris
        container or path. Options are:
224 1395c40e Stavros Sachtouris
        * user string of the form container:path
225 1395c40e Stavros Sachtouris
        * self.container, self.path variables set by super constructor, or
226 1395c40e Stavros Sachtouris
        explicitly by the caller application
227 1395c40e Stavros Sachtouris
        Error handling is explicit as these error cases happen only here
228 1395c40e Stavros Sachtouris
        """
229 83ba5545 Stavros Sachtouris
        try:
230 83ba5545 Stavros Sachtouris
            assert isinstance(container_with_path, str)
231 83ba5545 Stavros Sachtouris
        except AssertionError as err:
232 edab7ba7 Stavros Sachtouris
            if self['container'] and path_is_optional:
233 edab7ba7 Stavros Sachtouris
                self.container = self['container']
234 edab7ba7 Stavros Sachtouris
                self.client.container = self['container']
235 edab7ba7 Stavros Sachtouris
                return
236 83ba5545 Stavros Sachtouris
            raiseCLIError(err)
237 447c9568 Stavros Sachtouris
238 1395c40e Stavros Sachtouris
        user_cont, sep, userpath = container_with_path.partition(':')
239 447c9568 Stavros Sachtouris
240 447c9568 Stavros Sachtouris
        if sep:
241 1395c40e Stavros Sachtouris
            if not user_cont:
242 2005b18e Stavros Sachtouris
                raiseCLIError(CLISyntaxError(
243 2005b18e Stavros Sachtouris
                    'Container is missing\n',
244 1395c40e Stavros Sachtouris
                    details=errors.pithos.container_howto))
245 47ae7577 Stavros Sachtouris
            alt_cont = self['container']
246 1395c40e Stavros Sachtouris
            if alt_cont and user_cont != alt_cont:
247 c1558584 Stavros Sachtouris
                raiseCLIError(CLISyntaxError(
248 1395c40e Stavros Sachtouris
                    'Conflict: 2 containers (%s, %s)' % (user_cont, alt_cont),
249 1395c40e Stavros Sachtouris
                    details=errors.pithos.container_howto)
250 47ae7577 Stavros Sachtouris
                )
251 1395c40e Stavros Sachtouris
            self.container = user_cont
252 1395c40e Stavros Sachtouris
            if not userpath:
253 c1558584 Stavros Sachtouris
                raiseCLIError(CLISyntaxError(
254 1395c40e Stavros Sachtouris
                    'Path is missing for object in container %s' % user_cont,
255 1395c40e Stavros Sachtouris
                    details=errors.pithos.container_howto)
256 47ae7577 Stavros Sachtouris
                )
257 1395c40e Stavros Sachtouris
            self.path = userpath
258 447c9568 Stavros Sachtouris
        else:
259 47ae7577 Stavros Sachtouris
            alt_cont = self['container'] or self.client.container
260 447c9568 Stavros Sachtouris
            if alt_cont:
261 447c9568 Stavros Sachtouris
                self.container = alt_cont
262 1395c40e Stavros Sachtouris
                self.path = user_cont
263 447c9568 Stavros Sachtouris
            elif path_is_optional:
264 1395c40e Stavros Sachtouris
                self.container = user_cont
265 7493ccb6 Stavros Sachtouris
                self.path = None
266 7493ccb6 Stavros Sachtouris
            else:
267 1395c40e Stavros Sachtouris
                self.container = user_cont
268 447c9568 Stavros Sachtouris
                raiseCLIError(CLISyntaxError(
269 c1558584 Stavros Sachtouris
                    'Both container and path are required',
270 1395c40e Stavros Sachtouris
                    details=errors.pithos.container_howto)
271 47ae7577 Stavros Sachtouris
                )
272 7493ccb6 Stavros Sachtouris
273 1395c40e Stavros Sachtouris
    @errors.generic.all
274 1395c40e Stavros Sachtouris
    def _run(self, container_with_path=None, path_is_optional=True):
275 3ae60112 Stavros Sachtouris
        super(_file_container_command, self)._run()
276 edab7ba7 Stavros Sachtouris
        if self['container']:
277 edab7ba7 Stavros Sachtouris
            self.client.container = self['container']
278 edab7ba7 Stavros Sachtouris
            if container_with_path:
279 edab7ba7 Stavros Sachtouris
                self.path = container_with_path
280 edab7ba7 Stavros Sachtouris
            elif not path_is_optional:
281 edab7ba7 Stavros Sachtouris
                raise CLISyntaxError(
282 edab7ba7 Stavros Sachtouris
                    'Both container and path are required',
283 edab7ba7 Stavros Sachtouris
                    details=errors.pithos.container_howto)
284 edab7ba7 Stavros Sachtouris
        elif container_with_path:
285 47ae7577 Stavros Sachtouris
            self.extract_container_and_path(
286 47ae7577 Stavros Sachtouris
                container_with_path,
287 234954d1 Stavros Sachtouris
                path_is_optional)
288 7493ccb6 Stavros Sachtouris
            self.client.container = self.container
289 7493ccb6 Stavros Sachtouris
        self.container = self.client.container
290 7493ccb6 Stavros Sachtouris
291 1395c40e Stavros Sachtouris
    def main(self, container_with_path=None, path_is_optional=True):
292 1395c40e Stavros Sachtouris
        self._run(container_with_path, path_is_optional)
293 1395c40e Stavros Sachtouris
294 7493ccb6 Stavros Sachtouris
295 d486baec Stavros Sachtouris
@command(pithos_cmds)
296 545c6c29 Stavros Sachtouris
class file_list(_file_container_command, _optional_json):
297 7493ccb6 Stavros Sachtouris
    """List containers, object trees or objects in a directory
298 2703cceb Stavros Sachtouris
    Use with:
299 7ae842c2 Stavros Sachtouris
    1 no parameters : containers in current account
300 2703cceb Stavros Sachtouris
    2. one parameter (container) or --container : contents of container
301 2703cceb Stavros Sachtouris
    3. <container>:<prefix> or --container=<container> <prefix>: objects in
302 439826ec Stavros Sachtouris
    .   container starting with prefix
303 7493ccb6 Stavros Sachtouris
    """
304 7493ccb6 Stavros Sachtouris
305 47ae7577 Stavros Sachtouris
    arguments = dict(
306 f40f0cb7 Stavros Sachtouris
        detail=FlagArgument('detailed output', ('-l', '--list')),
307 f40f0cb7 Stavros Sachtouris
        limit=IntArgument('limit number of listed items', ('-n', '--number')),
308 f40f0cb7 Stavros Sachtouris
        marker=ValueArgument('output greater that marker', '--marker'),
309 f40f0cb7 Stavros Sachtouris
        prefix=ValueArgument('output starting with prefix', '--prefix'),
310 47ae7577 Stavros Sachtouris
        delimiter=ValueArgument('show output up to delimiter', '--delimiter'),
311 47ae7577 Stavros Sachtouris
        path=ValueArgument(
312 47ae7577 Stavros Sachtouris
            'show output starting with prefix up to /',
313 47ae7577 Stavros Sachtouris
            '--path'),
314 47ae7577 Stavros Sachtouris
        meta=ValueArgument(
315 47ae7577 Stavros Sachtouris
            'show output with specified meta keys',
316 47ae7577 Stavros Sachtouris
            '--meta',
317 47ae7577 Stavros Sachtouris
            default=[]),
318 47ae7577 Stavros Sachtouris
        if_modified_since=ValueArgument(
319 47ae7577 Stavros Sachtouris
            'show output modified since then',
320 47ae7577 Stavros Sachtouris
            '--if-modified-since'),
321 47ae7577 Stavros Sachtouris
        if_unmodified_since=ValueArgument(
322 47ae7577 Stavros Sachtouris
            'show output not modified since then',
323 47ae7577 Stavros Sachtouris
            '--if-unmodified-since'),
324 47ae7577 Stavros Sachtouris
        until=DateArgument('show metadata until then', '--until'),
325 47ae7577 Stavros Sachtouris
        format=ValueArgument(
326 47ae7577 Stavros Sachtouris
            'format to parse until data (default: d/m/Y H:M:S )',
327 47ae7577 Stavros Sachtouris
            '--format'),
328 47ae7577 Stavros Sachtouris
        shared=FlagArgument('show only shared', '--shared'),
329 439826ec Stavros Sachtouris
        more=FlagArgument(
330 439826ec Stavros Sachtouris
            'output results in pages (-n to set items per page, default 10)',
331 eb18b8a7 Stavros Sachtouris
            '--more'),
332 eb18b8a7 Stavros Sachtouris
        exact_match=FlagArgument(
333 eb18b8a7 Stavros Sachtouris
            'Show only objects that match exactly with path',
334 ed9af02c Stavros Sachtouris
            '--exact-match'),
335 545c6c29 Stavros Sachtouris
        enum=FlagArgument('Enumerate results', '--enumerate')
336 47ae7577 Stavros Sachtouris
    )
337 c41a86b2 Stavros Sachtouris
338 7493ccb6 Stavros Sachtouris
    def print_objects(self, object_list):
339 0399ac7e Stavros Sachtouris
        if self['json_output']:
340 0399ac7e Stavros Sachtouris
            print_json(object_list)
341 0399ac7e Stavros Sachtouris
            return
342 439826ec Stavros Sachtouris
        limit = int(self['limit']) if self['limit'] > 0 else len(object_list)
343 234954d1 Stavros Sachtouris
        for index, obj in enumerate(object_list):
344 24ff0a35 Stavros Sachtouris
            if self['exact_match'] and self.path and not (
345 2005b18e Stavros Sachtouris
                    obj['name'] == self.path or 'content_type' in obj):
346 2005b18e Stavros Sachtouris
                continue
347 7493ccb6 Stavros Sachtouris
            pretty_obj = obj.copy()
348 7493ccb6 Stavros Sachtouris
            index += 1
349 234954d1 Stavros Sachtouris
            empty_space = ' ' * (len(str(len(object_list))) - len(str(index)))
350 7493ccb6 Stavros Sachtouris
            if obj['content_type'] == 'application/directory':
351 7493ccb6 Stavros Sachtouris
                isDir = True
352 7493ccb6 Stavros Sachtouris
                size = 'D'
353 7493ccb6 Stavros Sachtouris
            else:
354 7493ccb6 Stavros Sachtouris
                isDir = False
355 7493ccb6 Stavros Sachtouris
                size = format_size(obj['bytes'])
356 234954d1 Stavros Sachtouris
                pretty_obj['bytes'] = '%s (%s)' % (obj['bytes'], size)
357 7493ccb6 Stavros Sachtouris
            oname = bold(obj['name'])
358 ed9af02c Stavros Sachtouris
            prfx = ('%s%s. ' % (empty_space, index)) if self['enum'] else ''
359 47ae7577 Stavros Sachtouris
            if self['detail']:
360 ed9af02c Stavros Sachtouris
                print('%s%s' % (prfx, oname))
361 7493ccb6 Stavros Sachtouris
                print_dict(pretty_keys(pretty_obj), exclude=('name'))
362 7493ccb6 Stavros Sachtouris
                print
363 7493ccb6 Stavros Sachtouris
            else:
364 ed9af02c Stavros Sachtouris
                oname = '%s%9s %s' % (prfx, size, oname)
365 7493ccb6 Stavros Sachtouris
                oname += '/' if isDir else ''
366 7493ccb6 Stavros Sachtouris
                print(oname)
367 439826ec Stavros Sachtouris
            if self['more']:
368 439826ec Stavros Sachtouris
                page_hold(index, limit, len(object_list))
369 7493ccb6 Stavros Sachtouris
370 7493ccb6 Stavros Sachtouris
    def print_containers(self, container_list):
371 0399ac7e Stavros Sachtouris
        if self['json_output']:
372 0399ac7e Stavros Sachtouris
            print_json(container_list)
373 0399ac7e Stavros Sachtouris
            return
374 439826ec Stavros Sachtouris
        limit = int(self['limit']) if self['limit'] > 0\
375 439826ec Stavros Sachtouris
            else len(container_list)
376 234954d1 Stavros Sachtouris
        for index, container in enumerate(container_list):
377 234954d1 Stavros Sachtouris
            if 'bytes' in container:
378 234954d1 Stavros Sachtouris
                size = format_size(container['bytes'])
379 ed9af02c Stavros Sachtouris
            prfx = ('%s. ' % (index + 1)) if self['enum'] else ''
380 ed9af02c Stavros Sachtouris
            cname = '%s%s' % (prfx, bold(container['name']))
381 47ae7577 Stavros Sachtouris
            if self['detail']:
382 7493ccb6 Stavros Sachtouris
                print(cname)
383 7493ccb6 Stavros Sachtouris
                pretty_c = container.copy()
384 234954d1 Stavros Sachtouris
                if 'bytes' in container:
385 234954d1 Stavros Sachtouris
                    pretty_c['bytes'] = '%s (%s)' % (container['bytes'], size)
386 7493ccb6 Stavros Sachtouris
                print_dict(pretty_keys(pretty_c), exclude=('name'))
387 7493ccb6 Stavros Sachtouris
                print
388 7493ccb6 Stavros Sachtouris
            else:
389 234954d1 Stavros Sachtouris
                if 'count' in container and 'bytes' in container:
390 de73876b Stavros Sachtouris
                    print('%s (%s, %s objects)' % (
391 de73876b Stavros Sachtouris
                        cname,
392 de73876b Stavros Sachtouris
                        size,
393 de73876b Stavros Sachtouris
                        container['count']))
394 7493ccb6 Stavros Sachtouris
                else:
395 7493ccb6 Stavros Sachtouris
                    print(cname)
396 439826ec Stavros Sachtouris
            if self['more']:
397 439826ec Stavros Sachtouris
                page_hold(index + 1, limit, len(container_list))
398 7493ccb6 Stavros Sachtouris
399 1395c40e Stavros Sachtouris
    @errors.generic.all
400 1395c40e Stavros Sachtouris
    @errors.pithos.connection
401 1395c40e Stavros Sachtouris
    @errors.pithos.object_path
402 1395c40e Stavros Sachtouris
    @errors.pithos.container
403 1395c40e Stavros Sachtouris
    def _run(self):
404 1395c40e Stavros Sachtouris
        if self.container is None:
405 1395c40e Stavros Sachtouris
            r = self.client.account_get(
406 1395c40e Stavros Sachtouris
                limit=False if self['more'] else self['limit'],
407 1395c40e Stavros Sachtouris
                marker=self['marker'],
408 1395c40e Stavros Sachtouris
                if_modified_since=self['if_modified_since'],
409 1395c40e Stavros Sachtouris
                if_unmodified_since=self['if_unmodified_since'],
410 1395c40e Stavros Sachtouris
                until=self['until'],
411 1395c40e Stavros Sachtouris
                show_only_shared=self['shared'])
412 545c6c29 Stavros Sachtouris
            self._print(r.json, self.print_containers)
413 1395c40e Stavros Sachtouris
        else:
414 52edad0a Stavros Sachtouris
            prefix = self.path or self['prefix']
415 1395c40e Stavros Sachtouris
            r = self.client.container_get(
416 1395c40e Stavros Sachtouris
                limit=False if self['more'] else self['limit'],
417 1395c40e Stavros Sachtouris
                marker=self['marker'],
418 1395c40e Stavros Sachtouris
                prefix=prefix,
419 1395c40e Stavros Sachtouris
                delimiter=self['delimiter'],
420 1395c40e Stavros Sachtouris
                path=self['path'],
421 1395c40e Stavros Sachtouris
                if_modified_since=self['if_modified_since'],
422 1395c40e Stavros Sachtouris
                if_unmodified_since=self['if_unmodified_since'],
423 1395c40e Stavros Sachtouris
                until=self['until'],
424 1395c40e Stavros Sachtouris
                meta=self['meta'],
425 1395c40e Stavros Sachtouris
                show_only_shared=self['shared'])
426 545c6c29 Stavros Sachtouris
            self._print(r.json, self.print_objects)
427 1395c40e Stavros Sachtouris
428 7493ccb6 Stavros Sachtouris
    def main(self, container____path__=None):
429 1395c40e Stavros Sachtouris
        super(self.__class__, self)._run(container____path__)
430 1395c40e Stavros Sachtouris
        self._run()
431 7493ccb6 Stavros Sachtouris
432 234954d1 Stavros Sachtouris
433 d486baec Stavros Sachtouris
@command(pithos_cmds)
434 915b99b5 Stavros Sachtouris
class file_mkdir(_file_container_command, _optional_output_cmd):
435 f5d9bc54 Stavros Sachtouris
    """Create a directory"""
436 1e29b9f6 Stavros Sachtouris
437 3d568c09 Stavros Sachtouris
    __doc__ += '\n. '.join([
438 3d568c09 Stavros Sachtouris
        'Kamaki hanldes directories the same way as OOS Storage and Pithos+:',
439 3d568c09 Stavros Sachtouris
        'A   directory  is   an  object  with  type  "application/directory"',
440 3d568c09 Stavros Sachtouris
        'An object with path  dir/name can exist even if  dir does not exist',
441 3d568c09 Stavros Sachtouris
        'or even if dir  is  a non  directory  object.  Users can modify dir',
442 3d568c09 Stavros Sachtouris
        'without affecting the dir/name object in any way.'])
443 7493ccb6 Stavros Sachtouris
444 1395c40e Stavros Sachtouris
    @errors.generic.all
445 1395c40e Stavros Sachtouris
    @errors.pithos.connection
446 1395c40e Stavros Sachtouris
    @errors.pithos.container
447 1395c40e Stavros Sachtouris
    def _run(self):
448 915b99b5 Stavros Sachtouris
        self._optional_output(self.client.create_directory(self.path))
449 1395c40e Stavros Sachtouris
450 7493ccb6 Stavros Sachtouris
    def main(self, container___directory):
451 1395c40e Stavros Sachtouris
        super(self.__class__, self)._run(
452 1395c40e Stavros Sachtouris
            container___directory,
453 1395c40e Stavros Sachtouris
            path_is_optional=False)
454 1395c40e Stavros Sachtouris
        self._run()
455 7493ccb6 Stavros Sachtouris
456 234954d1 Stavros Sachtouris
457 d486baec Stavros Sachtouris
@command(pithos_cmds)
458 915b99b5 Stavros Sachtouris
class file_touch(_file_container_command, _optional_output_cmd):
459 1e29b9f6 Stavros Sachtouris
    """Create an empty object (file)
460 1e29b9f6 Stavros Sachtouris
    If object exists, this command will reset it to 0 length
461 1e29b9f6 Stavros Sachtouris
    """
462 1e29b9f6 Stavros Sachtouris
463 1e29b9f6 Stavros Sachtouris
    arguments = dict(
464 1e29b9f6 Stavros Sachtouris
        content_type=ValueArgument(
465 1e29b9f6 Stavros Sachtouris
            'Set content type (default: application/octet-stream)',
466 1e29b9f6 Stavros Sachtouris
            '--content-type',
467 915b99b5 Stavros Sachtouris
            default='application/octet-stream')
468 1e29b9f6 Stavros Sachtouris
    )
469 1e29b9f6 Stavros Sachtouris
470 1395c40e Stavros Sachtouris
    @errors.generic.all
471 1395c40e Stavros Sachtouris
    @errors.pithos.connection
472 1395c40e Stavros Sachtouris
    @errors.pithos.container
473 1395c40e Stavros Sachtouris
    def _run(self):
474 915b99b5 Stavros Sachtouris
        self._optional_output(
475 915b99b5 Stavros Sachtouris
            self.client.create_object(self.path, self['content_type']))
476 1395c40e Stavros Sachtouris
477 1e29b9f6 Stavros Sachtouris
    def main(self, container___path):
478 3ae60112 Stavros Sachtouris
        super(file_touch, self)._run(
479 52edad0a Stavros Sachtouris
            container___path,
480 52edad0a Stavros Sachtouris
            path_is_optional=False)
481 1395c40e Stavros Sachtouris
        self._run()
482 1e29b9f6 Stavros Sachtouris
483 1e29b9f6 Stavros Sachtouris
484 1e29b9f6 Stavros Sachtouris
@command(pithos_cmds)
485 915b99b5 Stavros Sachtouris
class file_create(_file_container_command, _optional_output_cmd):
486 1e29b9f6 Stavros Sachtouris
    """Create a container"""
487 7493ccb6 Stavros Sachtouris
488 2fe2672e Stavros Sachtouris
    arguments = dict(
489 2fe2672e Stavros Sachtouris
        versioning=ValueArgument(
490 2fe2672e Stavros Sachtouris
            'set container versioning (auto/none)',
491 2fe2672e Stavros Sachtouris
            '--versioning'),
492 3ed6dbde Stavros Sachtouris
        limit=IntArgument('set default container limit', '--limit'),
493 2fe2672e Stavros Sachtouris
        meta=KeyValueArgument(
494 2fe2672e Stavros Sachtouris
            'set container metadata (can be repeated)',
495 915b99b5 Stavros Sachtouris
            '--meta')
496 2fe2672e Stavros Sachtouris
    )
497 7493ccb6 Stavros Sachtouris
498 1395c40e Stavros Sachtouris
    @errors.generic.all
499 1395c40e Stavros Sachtouris
    @errors.pithos.connection
500 1395c40e Stavros Sachtouris
    @errors.pithos.container
501 94bedc5b Stavros Sachtouris
    def _run(self, container):
502 915b99b5 Stavros Sachtouris
        self._optional_output(self.client.create_container(
503 915b99b5 Stavros Sachtouris
            container=container,
504 915b99b5 Stavros Sachtouris
            sizelimit=self['limit'],
505 915b99b5 Stavros Sachtouris
            versioning=self['versioning'],
506 915b99b5 Stavros Sachtouris
            metadata=self['meta']))
507 1395c40e Stavros Sachtouris
508 edab7ba7 Stavros Sachtouris
    def main(self, container=None):
509 1395c40e Stavros Sachtouris
        super(self.__class__, self)._run(container)
510 edab7ba7 Stavros Sachtouris
        if container and self.container != container:
511 1395c40e Stavros Sachtouris
            raiseCLIError('Invalid container name %s' % container, details=[
512 edab7ba7 Stavros Sachtouris
                'Did you mean "%s" ?' % self.container,
513 52edad0a Stavros Sachtouris
                'Use --container for names containing :'])
514 94bedc5b Stavros Sachtouris
        self._run(container)
515 7493ccb6 Stavros Sachtouris
516 234954d1 Stavros Sachtouris
517 3ae60112 Stavros Sachtouris
class _source_destination_command(_file_container_command):
518 2fe2672e Stavros Sachtouris
519 2fe2672e Stavros Sachtouris
    arguments = dict(
520 f40f0cb7 Stavros Sachtouris
        destination_account=ValueArgument('', ('a', '--dst-account')),
521 f40f0cb7 Stavros Sachtouris
        recursive=FlagArgument('', ('-R', '--recursive')),
522 761e0cbf Stavros Sachtouris
        prefix=FlagArgument('', '--with-prefix', default=''),
523 761e0cbf Stavros Sachtouris
        suffix=ValueArgument('', '--with-suffix', default=''),
524 761e0cbf Stavros Sachtouris
        add_prefix=ValueArgument('', '--add-prefix', default=''),
525 761e0cbf Stavros Sachtouris
        add_suffix=ValueArgument('', '--add-suffix', default=''),
526 761e0cbf Stavros Sachtouris
        prefix_replace=ValueArgument('', '--prefix-to-replace', default=''),
527 1d3f006b Stavros Sachtouris
        suffix_replace=ValueArgument('', '--suffix-to-replace', default=''),
528 2fe2672e Stavros Sachtouris
    )
529 7493ccb6 Stavros Sachtouris
530 f724cd35 Stavros Sachtouris
    def __init__(self, arguments={}, auth_base=None):
531 761e0cbf Stavros Sachtouris
        self.arguments.update(arguments)
532 f724cd35 Stavros Sachtouris
        super(_source_destination_command, self).__init__(
533 f724cd35 Stavros Sachtouris
            self.arguments, auth_base)
534 761e0cbf Stavros Sachtouris
535 300da0fb Stavros Sachtouris
    def _run(self, source_container___path, path_is_optional=False):
536 300da0fb Stavros Sachtouris
        super(_source_destination_command, self)._run(
537 300da0fb Stavros Sachtouris
            source_container___path,
538 300da0fb Stavros Sachtouris
            path_is_optional)
539 300da0fb Stavros Sachtouris
        self.dst_client = PithosClient(
540 300da0fb Stavros Sachtouris
            base_url=self.client.base_url,
541 300da0fb Stavros Sachtouris
            token=self.client.token,
542 300da0fb Stavros Sachtouris
            account=self['destination_account'] or self.client.account)
543 300da0fb Stavros Sachtouris
544 300da0fb Stavros Sachtouris
    @errors.generic.all
545 300da0fb Stavros Sachtouris
    @errors.pithos.account
546 300da0fb Stavros Sachtouris
    def _dest_container_path(self, dest_container_path):
547 300da0fb Stavros Sachtouris
        if self['destination_container']:
548 300da0fb Stavros Sachtouris
            self.dst_client.container = self['destination_container']
549 300da0fb Stavros Sachtouris
            return (self['destination_container'], dest_container_path)
550 300da0fb Stavros Sachtouris
        if dest_container_path:
551 300da0fb Stavros Sachtouris
            dst = dest_container_path.split(':')
552 300da0fb Stavros Sachtouris
            if len(dst) > 1:
553 300da0fb Stavros Sachtouris
                try:
554 300da0fb Stavros Sachtouris
                    self.dst_client.container = dst[0]
555 300da0fb Stavros Sachtouris
                    self.dst_client.get_container_info(dst[0])
556 300da0fb Stavros Sachtouris
                except ClientError as err:
557 300da0fb Stavros Sachtouris
                    if err.status in (404, 204):
558 300da0fb Stavros Sachtouris
                        raiseCLIError(
559 300da0fb Stavros Sachtouris
                            'Destination container %s not found' % dst[0])
560 300da0fb Stavros Sachtouris
                    raise
561 300da0fb Stavros Sachtouris
                else:
562 300da0fb Stavros Sachtouris
                    self.dst_client.container = dst[0]
563 300da0fb Stavros Sachtouris
                return (dst[0], dst[1])
564 300da0fb Stavros Sachtouris
            return(None, dst[0])
565 300da0fb Stavros Sachtouris
        raiseCLIError('No destination container:path provided')
566 300da0fb Stavros Sachtouris
567 ece4ae4b Stavros Sachtouris
    def _get_all(self, prefix):
568 ece4ae4b Stavros Sachtouris
        return self.client.container_get(prefix=prefix).json
569 ece4ae4b Stavros Sachtouris
570 1d3f006b Stavros Sachtouris
    def _get_src_objects(self, src_path, source_version=None):
571 6736f171 Stavros Sachtouris
        """Get a list of the source objects to be called
572 6736f171 Stavros Sachtouris

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

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