Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (74.4 kB)

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

561 6736f171 Stavros Sachtouris
        :param src_path: (str) source path
562 6736f171 Stavros Sachtouris

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