Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / commands / pithos_cli.py @ 45b70023

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

551 6736f171 Stavros Sachtouris
        :param src_cnt: (str) source container
552 6736f171 Stavros Sachtouris

553 6736f171 Stavros Sachtouris
        :param src_path: (str) source path
554 6736f171 Stavros Sachtouris

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