Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / commands / pithos_cli.py @ 16b0afe6

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

565 6736f171 Stavros Sachtouris
        :param src_path: (str) source path
566 6736f171 Stavros Sachtouris

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