Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (66.9 kB)

1 e3f01d64 Stavros Sachtouris
# Copyright 2011-2013 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 time import localtime, strftime
35 fa9c0c38 Stavros Sachtouris
from io import StringIO
36 76f58e2e Stavros Sachtouris
from pydoc import pager
37 edc1182f Stavros Sachtouris
from os import path, walk, makedirs
38 1395c40e Stavros Sachtouris
39 effa4b8f Stavros Sachtouris
from kamaki.clients.pithos import PithosClient, ClientError
40 1395c40e Stavros Sachtouris
41 234954d1 Stavros Sachtouris
from kamaki.cli import command
42 d486baec Stavros Sachtouris
from kamaki.cli.command_tree import CommandTree
43 6d190dd1 Stavros Sachtouris
from kamaki.cli.commands import (
44 cec2dfcd Stavros Sachtouris
    _command_init, errors, addLogSettings, DontRaiseKeyError, _optional_json,
45 cec2dfcd Stavros Sachtouris
    _name_filter, _optional_output_cmd)
46 8694bdad Stavros Sachtouris
from kamaki.cli.errors import (
47 bfd0f8db Stavros Sachtouris
    CLIBaseUrlError, CLIError, CLIInvalidArgument, raiseCLIError,
48 bfd0f8db Stavros Sachtouris
    CLISyntaxError)
49 cec2dfcd Stavros Sachtouris
from kamaki.cli.argument import (
50 bfa33995 Stavros Sachtouris
    FlagArgument, IntArgument, ValueArgument, DateArgument, KeyValueArgument,
51 7b109aa7 Stavros Sachtouris
    ProgressBarArgument, RepeatableArgument, DataSizeArgument)
52 7147e1ca Stavros Sachtouris
from kamaki.cli.utils import (
53 edc1182f Stavros Sachtouris
    format_size, bold, get_path_size, guess_mime_type)
54 234954d1 Stavros Sachtouris
55 cec2dfcd Stavros Sachtouris
file_cmds = CommandTree('file', 'Pithos+/Storage object level API commands')
56 cec2dfcd Stavros Sachtouris
container_cmds = CommandTree(
57 cec2dfcd Stavros Sachtouris
    'container', 'Pithos+/Storage container level API commands')
58 bfd0f8db Stavros Sachtouris
sharer_cmds = CommandTree('sharer', 'Pithos+/Storage sharers')
59 bfd0f8db Stavros Sachtouris
group_cmds = CommandTree('group', 'Pithos+/Storage user groups')
60 bfd0f8db Stavros Sachtouris
_commands = [file_cmds, container_cmds, sharer_cmds, group_cmds]
61 234954d1 Stavros Sachtouris
62 e3d4d442 Stavros Sachtouris
63 5eae854d Stavros Sachtouris
class _pithos_init(_command_init):
64 cec2dfcd Stavros Sachtouris
    """Initilize a pithos+ client
65 cec2dfcd Stavros Sachtouris
    There is always a default account (current user uuid)
66 cec2dfcd Stavros Sachtouris
    There is always a default container (pithos)
67 cec2dfcd Stavros Sachtouris
    """
68 ece4ae4b Stavros Sachtouris
69 b4f69041 Stavros Sachtouris
    @DontRaiseKeyError
70 b4f69041 Stavros Sachtouris
    def _custom_container(self):
71 144b3551 Stavros Sachtouris
        return self.config.get_cloud(self.cloud, 'pithos_container')
72 b4f69041 Stavros Sachtouris
73 b4f69041 Stavros Sachtouris
    @DontRaiseKeyError
74 b4f69041 Stavros Sachtouris
    def _custom_uuid(self):
75 144b3551 Stavros Sachtouris
        return self.config.get_cloud(self.cloud, 'pithos_uuid')
76 b4f69041 Stavros Sachtouris
77 b4f69041 Stavros Sachtouris
    def _set_account(self):
78 b4f69041 Stavros Sachtouris
        self.account = self._custom_uuid()
79 b4f69041 Stavros Sachtouris
        if self.account:
80 b4f69041 Stavros Sachtouris
            return
81 cec2dfcd Stavros Sachtouris
        astakos = getattr(self, 'auth_base', None)
82 cec2dfcd Stavros Sachtouris
        if astakos:
83 cec2dfcd Stavros Sachtouris
            self.account = astakos.user_term('id', self.token)
84 b4f69041 Stavros Sachtouris
        else:
85 cec2dfcd Stavros Sachtouris
            raise CLIBaseUrlError(service='astakos')
86 b4f69041 Stavros Sachtouris
87 1395c40e Stavros Sachtouris
    @errors.generic.all
88 b4f69041 Stavros Sachtouris
    @addLogSettings
89 1395c40e Stavros Sachtouris
    def _run(self):
90 cec2dfcd Stavros Sachtouris
        cloud = getattr(self, 'cloud', None)
91 cec2dfcd Stavros Sachtouris
        if cloud:
92 b4f69041 Stavros Sachtouris
            self.base_url = self._custom_url('pithos')
93 b4f69041 Stavros Sachtouris
        else:
94 b4f69041 Stavros Sachtouris
            self.cloud = 'default'
95 b4f69041 Stavros Sachtouris
        self.token = self._custom_token('pithos')
96 cec2dfcd Stavros Sachtouris
        self.container = self._custom_container() or 'pithos'
97 8cec3671 Stavros Sachtouris
98 cec2dfcd Stavros Sachtouris
        astakos = getattr(self, 'auth_base', None)
99 cec2dfcd Stavros Sachtouris
        if astakos:
100 cec2dfcd Stavros Sachtouris
            self.token = self.token or astakos.token
101 b4f69041 Stavros Sachtouris
            if not self.base_url:
102 cec2dfcd Stavros Sachtouris
                pithos_endpoints = astakos.get_service_endpoints(
103 b4f69041 Stavros Sachtouris
                    self._custom_type('pithos') or 'object-store',
104 b4f69041 Stavros Sachtouris
                    self._custom_version('pithos') or '')
105 b4f69041 Stavros Sachtouris
                self.base_url = pithos_endpoints['publicURL']
106 cec2dfcd Stavros Sachtouris
        else:
107 cec2dfcd Stavros Sachtouris
            raise CLIBaseUrlError(service='astakos')
108 8cec3671 Stavros Sachtouris
109 1f5debf7 Stavros Sachtouris
        self._set_account()
110 de73876b Stavros Sachtouris
        self.client = PithosClient(
111 cec2dfcd Stavros Sachtouris
            self.base_url, self.token, self.account, self.container)
112 7493ccb6 Stavros Sachtouris
113 1395c40e Stavros Sachtouris
    def main(self):
114 1395c40e Stavros Sachtouris
        self._run()
115 1395c40e Stavros Sachtouris
116 234954d1 Stavros Sachtouris
117 cec2dfcd Stavros Sachtouris
class _pithos_account(_pithos_init):
118 cec2dfcd Stavros Sachtouris
    """Setup account"""
119 7493ccb6 Stavros Sachtouris
120 b4f69041 Stavros Sachtouris
    def __init__(self, arguments={}, auth_base=None, cloud=None):
121 effa4b8f Stavros Sachtouris
        super(_pithos_account, self).__init__(arguments, auth_base, cloud)
122 439826ec Stavros Sachtouris
        self['account'] = ValueArgument(
123 cec2dfcd Stavros Sachtouris
            'Use (a different) user uuid', ('-A', '--account'))
124 7493ccb6 Stavros Sachtouris
125 7b109aa7 Stavros Sachtouris
    def print_objects(self, object_list):
126 7b109aa7 Stavros Sachtouris
        for index, obj in enumerate(object_list):
127 7b109aa7 Stavros Sachtouris
            pretty_obj = obj.copy()
128 7b109aa7 Stavros Sachtouris
            index += 1
129 7b109aa7 Stavros Sachtouris
            empty_space = ' ' * (len(str(len(object_list))) - len(str(index)))
130 7b109aa7 Stavros Sachtouris
            if 'subdir' in obj:
131 7b109aa7 Stavros Sachtouris
                continue
132 7b109aa7 Stavros Sachtouris
            if self._is_dir(obj):
133 7b109aa7 Stavros Sachtouris
                size = 'D'
134 7b109aa7 Stavros Sachtouris
            else:
135 7b109aa7 Stavros Sachtouris
                size = format_size(obj['bytes'])
136 7b109aa7 Stavros Sachtouris
                pretty_obj['bytes'] = '%s (%s)' % (obj['bytes'], size)
137 7b109aa7 Stavros Sachtouris
            oname = obj['name'] if self['more'] else bold(obj['name'])
138 7b109aa7 Stavros Sachtouris
            prfx = ('%s%s. ' % (empty_space, index)) if self['enum'] else ''
139 7b109aa7 Stavros Sachtouris
            if self['detail']:
140 7b109aa7 Stavros Sachtouris
                self.writeln('%s%s' % (prfx, oname))
141 7b109aa7 Stavros Sachtouris
                self.print_dict(pretty_obj, exclude=('name'))
142 7b109aa7 Stavros Sachtouris
                self.writeln()
143 7b109aa7 Stavros Sachtouris
            else:
144 7b109aa7 Stavros Sachtouris
                oname = '%s%9s %s' % (prfx, size, oname)
145 7b109aa7 Stavros Sachtouris
                oname += '/' if self._is_dir(obj) else u''
146 7b109aa7 Stavros Sachtouris
                self.writeln(oname)
147 7493ccb6 Stavros Sachtouris
148 7b109aa7 Stavros Sachtouris
    @staticmethod
149 7b109aa7 Stavros Sachtouris
    def _is_dir(remote_dict):
150 7b109aa7 Stavros Sachtouris
        return 'application/directory' == remote_dict.get(
151 7b109aa7 Stavros Sachtouris
            'content_type', remote_dict.get('content-type', ''))
152 1395c40e Stavros Sachtouris
153 cec2dfcd Stavros Sachtouris
    def _run(self):
154 cec2dfcd Stavros Sachtouris
        super(_pithos_account, self)._run()
155 cec2dfcd Stavros Sachtouris
        self.client.account = self['account'] or getattr(
156 cec2dfcd Stavros Sachtouris
            self, 'account', getattr(self.client, 'account', None))
157 234954d1 Stavros Sachtouris
158 7493ccb6 Stavros Sachtouris
159 cec2dfcd Stavros Sachtouris
class _pithos_container(_pithos_account):
160 cec2dfcd Stavros Sachtouris
    """Setup container"""
161 2d7ce81e Stavros Sachtouris
162 b4f69041 Stavros Sachtouris
    def __init__(self, arguments={}, auth_base=None, cloud=None):
163 effa4b8f Stavros Sachtouris
        super(_pithos_container, self).__init__(arguments, auth_base, cloud)
164 439826ec Stavros Sachtouris
        self['container'] = ValueArgument(
165 cec2dfcd Stavros Sachtouris
            'Use this container (default: pithos)', ('-C', '--container'))
166 7493ccb6 Stavros Sachtouris
167 effa4b8f Stavros Sachtouris
    @staticmethod
168 effa4b8f Stavros Sachtouris
    def _resolve_pithos_url(url):
169 cec2dfcd Stavros Sachtouris
        """Match urls of one of the following formats:
170 cec2dfcd Stavros Sachtouris
        pithos://ACCOUNT/CONTAINER/OBJECT_PATH
171 cec2dfcd Stavros Sachtouris
        /CONTAINER/OBJECT_PATH
172 effa4b8f Stavros Sachtouris
        return account, container, path
173 1395c40e Stavros Sachtouris
        """
174 edc1182f Stavros Sachtouris
        account, container, obj_path, prefix = '', '', url, 'pithos://'
175 cec2dfcd Stavros Sachtouris
        if url.startswith(prefix):
176 effa4b8f Stavros Sachtouris
            account, sep, url = url[len(prefix):].partition('/')
177 cec2dfcd Stavros Sachtouris
            url = '/%s' % url
178 cec2dfcd Stavros Sachtouris
        if url.startswith('/'):
179 edc1182f Stavros Sachtouris
            container, sep, obj_path = url[1:].partition('/')
180 edc1182f Stavros Sachtouris
        return account, container, obj_path
181 447c9568 Stavros Sachtouris
182 cec2dfcd Stavros Sachtouris
    def _run(self, url=None):
183 effa4b8f Stavros Sachtouris
        acc, con, self.path = self._resolve_pithos_url(url or '')
184 432cea25 Stavros Sachtouris
        #  self.account = acc or getattr(self, 'account', '')
185 cec2dfcd Stavros Sachtouris
        super(_pithos_container, self)._run()
186 effa4b8f Stavros Sachtouris
        self.container = con or self['container'] or getattr(
187 cec2dfcd Stavros Sachtouris
            self, 'container', None) or getattr(self.client, 'container', '')
188 432cea25 Stavros Sachtouris
        self.client.account = acc or self.client.account
189 effa4b8f Stavros Sachtouris
        self.client.container = self.container
190 447c9568 Stavros Sachtouris
191 1395c40e Stavros Sachtouris
192 cec2dfcd Stavros Sachtouris
@command(file_cmds)
193 20206179 Stavros Sachtouris
class file_info(_pithos_container, _optional_json):
194 20206179 Stavros Sachtouris
    """Get information/details about a file"""
195 20206179 Stavros Sachtouris
196 20206179 Stavros Sachtouris
    arguments = dict(
197 20206179 Stavros Sachtouris
        object_version=ValueArgument(
198 20206179 Stavros Sachtouris
            'download a file of a specific version', '--object-version'),
199 20206179 Stavros Sachtouris
        hashmap=FlagArgument(
200 20206179 Stavros Sachtouris
            'Get file hashmap instead of details', '--hashmap'),
201 20206179 Stavros Sachtouris
        matching_etag=ValueArgument(
202 20206179 Stavros Sachtouris
            'show output if ETags match', '--if-match'),
203 20206179 Stavros Sachtouris
        non_matching_etag=ValueArgument(
204 20206179 Stavros Sachtouris
            'show output if ETags DO NOT match', '--if-none-match'),
205 20206179 Stavros Sachtouris
        modified_since_date=DateArgument(
206 20206179 Stavros Sachtouris
            'show output modified since then', '--if-modified-since'),
207 20206179 Stavros Sachtouris
        unmodified_since_date=DateArgument(
208 20206179 Stavros Sachtouris
            'show output unmodified since then', '--if-unmodified-since'),
209 bfa33995 Stavros Sachtouris
        sharing=FlagArgument(
210 bfa33995 Stavros Sachtouris
            'show object permissions and sharing information', '--sharing'),
211 bfa33995 Stavros Sachtouris
        metadata=FlagArgument('show only object metadata', '--metadata'),
212 bfa33995 Stavros Sachtouris
        versions=FlagArgument(
213 bfa33995 Stavros Sachtouris
            'show the list of versions for the file', '--object-versions')
214 20206179 Stavros Sachtouris
    )
215 20206179 Stavros Sachtouris
216 bfa33995 Stavros Sachtouris
    def version_print(self, versions):
217 bfa33995 Stavros Sachtouris
        return {'/%s/%s' % (self.container, self.path): [
218 bfa33995 Stavros Sachtouris
            dict(version_id=vitem[0], created=strftime(
219 bfa33995 Stavros Sachtouris
                '%d-%m-%Y %H:%M:%S',
220 bfa33995 Stavros Sachtouris
                localtime(float(vitem[1])))) for vitem in versions]}
221 7493ccb6 Stavros Sachtouris
222 1395c40e Stavros Sachtouris
    @errors.generic.all
223 20206179 Stavros Sachtouris
    @errors.pithos.connection
224 20206179 Stavros Sachtouris
    @errors.pithos.container
225 20206179 Stavros Sachtouris
    @errors.pithos.object_path
226 20206179 Stavros Sachtouris
    def _run(self):
227 20206179 Stavros Sachtouris
        if self['hashmap']:
228 20206179 Stavros Sachtouris
            r = self.client.get_object_hashmap(
229 20206179 Stavros Sachtouris
                self.path,
230 20206179 Stavros Sachtouris
                version=self['object_version'],
231 20206179 Stavros Sachtouris
                if_match=self['matching_etag'],
232 20206179 Stavros Sachtouris
                if_none_match=self['non_matching_etag'],
233 20206179 Stavros Sachtouris
                if_modified_since=self['modified_since_date'],
234 20206179 Stavros Sachtouris
                if_unmodified_since=self['unmodified_since_date'])
235 bfa33995 Stavros Sachtouris
        elif self['sharing']:
236 20206179 Stavros Sachtouris
            r = self.client.get_object_sharing(self.path)
237 bfa33995 Stavros Sachtouris
            r['public url'] = self.client.get_object_info(
238 bfa33995 Stavros Sachtouris
                self.path, version=self['object_version']).get(
239 bfa33995 Stavros Sachtouris
                    'x-object-public', None)
240 bfa33995 Stavros Sachtouris
        elif self['metadata']:
241 bfa33995 Stavros Sachtouris
            r, preflen = dict(), len('x-object-meta-')
242 bfa33995 Stavros Sachtouris
            for k, v in self.client.get_object_meta(self.path).items():
243 bfa33995 Stavros Sachtouris
                r[k[preflen:]] = v
244 bfa33995 Stavros Sachtouris
        elif self['versions']:
245 bfa33995 Stavros Sachtouris
            r = self.version_print(
246 bfa33995 Stavros Sachtouris
                self.client.get_object_versionlist(self.path))
247 20206179 Stavros Sachtouris
        else:
248 20206179 Stavros Sachtouris
            r = self.client.get_object_info(
249 20206179 Stavros Sachtouris
                self.path, version=self['object_version'])
250 20206179 Stavros Sachtouris
        self._print(r, self.print_dict)
251 20206179 Stavros Sachtouris
252 20206179 Stavros Sachtouris
    def main(self, path_or_url):
253 20206179 Stavros Sachtouris
        super(self.__class__, self)._run(path_or_url)
254 20206179 Stavros Sachtouris
        self._run()
255 20206179 Stavros Sachtouris
256 20206179 Stavros Sachtouris
257 20206179 Stavros Sachtouris
@command(file_cmds)
258 cec2dfcd Stavros Sachtouris
class file_list(_pithos_container, _optional_json, _name_filter):
259 cec2dfcd Stavros Sachtouris
    """List all objects in a container or a directory object"""
260 7493ccb6 Stavros Sachtouris
261 47ae7577 Stavros Sachtouris
    arguments = dict(
262 f40f0cb7 Stavros Sachtouris
        detail=FlagArgument('detailed output', ('-l', '--list')),
263 f40f0cb7 Stavros Sachtouris
        limit=IntArgument('limit number of listed items', ('-n', '--number')),
264 f40f0cb7 Stavros Sachtouris
        marker=ValueArgument('output greater that marker', '--marker'),
265 47ae7577 Stavros Sachtouris
        delimiter=ValueArgument('show output up to delimiter', '--delimiter'),
266 47ae7577 Stavros Sachtouris
        meta=ValueArgument(
267 201baa17 Stavros Sachtouris
            'show output with specified meta keys', '--meta',
268 47ae7577 Stavros Sachtouris
            default=[]),
269 47ae7577 Stavros Sachtouris
        if_modified_since=ValueArgument(
270 201baa17 Stavros Sachtouris
            'show output modified since then', '--if-modified-since'),
271 47ae7577 Stavros Sachtouris
        if_unmodified_since=ValueArgument(
272 201baa17 Stavros Sachtouris
            'show output not modified since then', '--if-unmodified-since'),
273 47ae7577 Stavros Sachtouris
        until=DateArgument('show metadata until then', '--until'),
274 47ae7577 Stavros Sachtouris
        format=ValueArgument(
275 201baa17 Stavros Sachtouris
            'format to parse until data (default: d/m/Y H:M:S )', '--format'),
276 47ae7577 Stavros Sachtouris
        shared=FlagArgument('show only shared', '--shared'),
277 fa9c0c38 Stavros Sachtouris
        more=FlagArgument('read long results', '--more'),
278 8694bdad Stavros Sachtouris
        enum=FlagArgument('Enumerate results', '--enumerate'),
279 8694bdad Stavros Sachtouris
        recursive=FlagArgument(
280 8694bdad Stavros Sachtouris
            'Recursively list containers and their contents',
281 8694bdad Stavros Sachtouris
            ('-R', '--recursive'))
282 47ae7577 Stavros Sachtouris
    )
283 c41a86b2 Stavros Sachtouris
284 1395c40e Stavros Sachtouris
    @errors.generic.all
285 1395c40e Stavros Sachtouris
    @errors.pithos.connection
286 1395c40e Stavros Sachtouris
    @errors.pithos.container
287 cec2dfcd Stavros Sachtouris
    @errors.pithos.object_path
288 1395c40e Stavros Sachtouris
    def _run(self):
289 cec2dfcd Stavros Sachtouris
        r = self.client.container_get(
290 cec2dfcd Stavros Sachtouris
            limit=False if self['more'] else self['limit'],
291 cec2dfcd Stavros Sachtouris
            marker=self['marker'],
292 7b109aa7 Stavros Sachtouris
            prefix=self['name_pref'],
293 cec2dfcd Stavros Sachtouris
            delimiter=self['delimiter'],
294 cec2dfcd Stavros Sachtouris
            path=self.path or '',
295 cec2dfcd Stavros Sachtouris
            if_modified_since=self['if_modified_since'],
296 cec2dfcd Stavros Sachtouris
            if_unmodified_since=self['if_unmodified_since'],
297 cec2dfcd Stavros Sachtouris
            until=self['until'],
298 cec2dfcd Stavros Sachtouris
            meta=self['meta'],
299 cec2dfcd Stavros Sachtouris
            show_only_shared=self['shared'])
300 cec2dfcd Stavros Sachtouris
        files = self._filter_by_name(r.json)
301 1757c616 Stavros Sachtouris
        if self['more']:
302 1757c616 Stavros Sachtouris
            outbu, self._out = self._out, StringIO()
303 1757c616 Stavros Sachtouris
        try:
304 f76c6bbc Stavros Sachtouris
            if self['json_output'] or self['output_format']:
305 1757c616 Stavros Sachtouris
                self._print(files)
306 1757c616 Stavros Sachtouris
            else:
307 cec2dfcd Stavros Sachtouris
                self.print_objects(files)
308 1757c616 Stavros Sachtouris
        finally:
309 1757c616 Stavros Sachtouris
            if self['more']:
310 1757c616 Stavros Sachtouris
                pager(self._out.getvalue())
311 1757c616 Stavros Sachtouris
                self._out = outbu
312 1395c40e Stavros Sachtouris
313 7b109aa7 Stavros Sachtouris
    def main(self, path_or_url=''):
314 cec2dfcd Stavros Sachtouris
        super(self.__class__, self)._run(path_or_url)
315 1395c40e Stavros Sachtouris
        self._run()
316 7493ccb6 Stavros Sachtouris
317 234954d1 Stavros Sachtouris
318 cec2dfcd Stavros Sachtouris
@command(file_cmds)
319 20206179 Stavros Sachtouris
class file_modify(_pithos_container):
320 20206179 Stavros Sachtouris
    """Modify the attributes of a file or directory object"""
321 20206179 Stavros Sachtouris
322 20206179 Stavros Sachtouris
    arguments = dict(
323 20206179 Stavros Sachtouris
        publish=FlagArgument(
324 20206179 Stavros Sachtouris
            'Make an object public (returns the public URL)', '--publish'),
325 20206179 Stavros Sachtouris
        unpublish=FlagArgument(
326 20206179 Stavros Sachtouris
            'Make an object unpublic', '--unpublish'),
327 20206179 Stavros Sachtouris
        uuid_for_read_permission=RepeatableArgument(
328 20206179 Stavros Sachtouris
            'Give read access to user/group (can be repeated, accumulative). '
329 20206179 Stavros Sachtouris
            'Format for users: UUID . Format for groups: UUID:GROUP . '
330 20206179 Stavros Sachtouris
            'Use * for all users/groups', '--read-permission'),
331 20206179 Stavros Sachtouris
        uuid_for_write_permission=RepeatableArgument(
332 20206179 Stavros Sachtouris
            'Give write access to user/group (can be repeated, accumulative). '
333 20206179 Stavros Sachtouris
            'Format for users: UUID . Format for groups: UUID:GROUP . '
334 20206179 Stavros Sachtouris
            'Use * for all users/groups', '--write-permission'),
335 bfa33995 Stavros Sachtouris
        no_permissions=FlagArgument('Remove permissions', '--no-permissions'),
336 bfa33995 Stavros Sachtouris
        metadata_to_set=KeyValueArgument(
337 bfa33995 Stavros Sachtouris
            'Add metadata (KEY=VALUE) to an object (can be repeated)',
338 bfa33995 Stavros Sachtouris
            '--metadata-add'),
339 bfa33995 Stavros Sachtouris
        metadata_key_to_delete=RepeatableArgument(
340 bfa33995 Stavros Sachtouris
            'Delete object metadata (can be repeated)', '--metadata-del'),
341 20206179 Stavros Sachtouris
    )
342 20206179 Stavros Sachtouris
    required = [
343 bfa33995 Stavros Sachtouris
        'publish', 'unpublish', 'uuid_for_read_permission', 'metadata_to_set',
344 bfa33995 Stavros Sachtouris
        'uuid_for_write_permission', 'no_permissions',
345 bfa33995 Stavros Sachtouris
        'metadata_key_to_delete']
346 7493ccb6 Stavros Sachtouris
347 1395c40e Stavros Sachtouris
    @errors.generic.all
348 1395c40e Stavros Sachtouris
    @errors.pithos.connection
349 1395c40e Stavros Sachtouris
    @errors.pithos.container
350 20206179 Stavros Sachtouris
    @errors.pithos.object_path
351 1395c40e Stavros Sachtouris
    def _run(self):
352 20206179 Stavros Sachtouris
        if self['publish']:
353 20206179 Stavros Sachtouris
            self.writeln(self.client.publish_object(self.path))
354 20206179 Stavros Sachtouris
        if self['unpublish']:
355 20206179 Stavros Sachtouris
            self.client.unpublish_object(self.path)
356 20206179 Stavros Sachtouris
        if self['uuid_for_read_permission'] or self[
357 20206179 Stavros Sachtouris
                'uuid_for_write_permission']:
358 20206179 Stavros Sachtouris
            perms = self.client.get_object_sharing(self.path)
359 20206179 Stavros Sachtouris
            read, write = perms.get('read', ''), perms.get('write', '')
360 20206179 Stavros Sachtouris
            read = read.split(',') if read else []
361 20206179 Stavros Sachtouris
            write = write.split(',') if write else []
362 20206179 Stavros Sachtouris
            read += self['uuid_for_read_permission']
363 20206179 Stavros Sachtouris
            write += self['uuid_for_write_permission']
364 20206179 Stavros Sachtouris
            self.client.set_object_sharing(
365 20206179 Stavros Sachtouris
                self.path, read_permission=read, write_permission=write)
366 20206179 Stavros Sachtouris
            self.print_dict(self.client.get_object_sharing(self.path))
367 20206179 Stavros Sachtouris
        if self['no_permissions']:
368 20206179 Stavros Sachtouris
            self.client.del_object_sharing(self.path)
369 bfa33995 Stavros Sachtouris
        metadata = self['metadata_to_set'] or dict()
370 bfa33995 Stavros Sachtouris
        for k in self['metadata_key_to_delete']:
371 bfa33995 Stavros Sachtouris
            metadata[k] = ''
372 bfa33995 Stavros Sachtouris
        if metadata:
373 bfa33995 Stavros Sachtouris
            self.client.set_object_meta(self.path, metadata)
374 bfa33995 Stavros Sachtouris
            self.print_dict(self.client.get_object_meta(self.path))
375 20206179 Stavros Sachtouris
376 20206179 Stavros Sachtouris
    def main(self, path_or_url):
377 20206179 Stavros Sachtouris
        super(self.__class__, self)._run(path_or_url)
378 20206179 Stavros Sachtouris
        if self['publish'] and self['unpublish']:
379 20206179 Stavros Sachtouris
            raise CLIInvalidArgument(
380 20206179 Stavros Sachtouris
                'Arguments %s and %s cannot be used together' % (
381 eb647cfe Stavros Sachtouris
                    self.arguments['publish'].lvalue,
382 eb647cfe Stavros Sachtouris
                    self.arguments['publish'].lvalue))
383 20206179 Stavros Sachtouris
        if self['no_permissions'] and (
384 20206179 Stavros Sachtouris
                self['uuid_for_read_permission'] or self[
385 20206179 Stavros Sachtouris
                    'uuid_for_write_permission']):
386 20206179 Stavros Sachtouris
            raise CLIInvalidArgument(
387 eb647cfe Stavros Sachtouris
                '%s cannot be used with other permission arguments' % (
388 eb647cfe Stavros Sachtouris
                    self.arguments['no_permissions'].lvalue))
389 1395c40e Stavros Sachtouris
        self._run()
390 7493ccb6 Stavros Sachtouris
391 234954d1 Stavros Sachtouris
392 20206179 Stavros Sachtouris
@command(file_cmds)
393 cec2dfcd Stavros Sachtouris
class file_create(_pithos_container, _optional_output_cmd):
394 effa4b8f Stavros Sachtouris
    """Create an empty file"""
395 1e29b9f6 Stavros Sachtouris
396 1e29b9f6 Stavros Sachtouris
    arguments = dict(
397 1e29b9f6 Stavros Sachtouris
        content_type=ValueArgument(
398 1e29b9f6 Stavros Sachtouris
            'Set content type (default: application/octet-stream)',
399 1e29b9f6 Stavros Sachtouris
            '--content-type',
400 915b99b5 Stavros Sachtouris
            default='application/octet-stream')
401 1e29b9f6 Stavros Sachtouris
    )
402 1e29b9f6 Stavros Sachtouris
403 1395c40e Stavros Sachtouris
    @errors.generic.all
404 1395c40e Stavros Sachtouris
    @errors.pithos.connection
405 1395c40e Stavros Sachtouris
    @errors.pithos.container
406 1395c40e Stavros Sachtouris
    def _run(self):
407 915b99b5 Stavros Sachtouris
        self._optional_output(
408 915b99b5 Stavros Sachtouris
            self.client.create_object(self.path, self['content_type']))
409 1395c40e Stavros Sachtouris
410 cec2dfcd Stavros Sachtouris
    def main(self, path_or_url):
411 cec2dfcd Stavros Sachtouris
        super(self.__class__, self)._run(path_or_url)
412 b4cf92b8 Stavros Sachtouris
        self._run()
413 effa4b8f Stavros Sachtouris
414 effa4b8f Stavros Sachtouris
415 effa4b8f Stavros Sachtouris
@command(file_cmds)
416 effa4b8f Stavros Sachtouris
class file_mkdir(_pithos_container, _optional_output_cmd):
417 effa4b8f Stavros Sachtouris
    """Create a directory: /file create --content-type='applcation/directory'
418 effa4b8f Stavros Sachtouris
    """
419 effa4b8f Stavros Sachtouris
420 effa4b8f Stavros Sachtouris
    @errors.generic.all
421 effa4b8f Stavros Sachtouris
    @errors.pithos.connection
422 effa4b8f Stavros Sachtouris
    @errors.pithos.container
423 effa4b8f Stavros Sachtouris
    def _run(self):
424 effa4b8f Stavros Sachtouris
        self._optional_output(self.client.create_directory(self.path))
425 effa4b8f Stavros Sachtouris
426 74b7c6dc Stavros Sachtouris
    def main(self, path_or_url):
427 74b7c6dc Stavros Sachtouris
        super(self.__class__, self)._run(path_or_url)
428 1395c40e Stavros Sachtouris
        self._run()
429 1e29b9f6 Stavros Sachtouris
430 1e29b9f6 Stavros Sachtouris
431 20206179 Stavros Sachtouris
@command(file_cmds)
432 7b109aa7 Stavros Sachtouris
class file_delete(_pithos_container):
433 20206179 Stavros Sachtouris
    """Delete a file or directory object"""
434 7493ccb6 Stavros Sachtouris
435 2fe2672e Stavros Sachtouris
    arguments = dict(
436 20206179 Stavros Sachtouris
        until_date=DateArgument('remove history until then', '--until'),
437 20206179 Stavros Sachtouris
        yes=FlagArgument('Do not prompt for permission', '--yes'),
438 20206179 Stavros Sachtouris
        recursive=FlagArgument(
439 20206179 Stavros Sachtouris
            'If a directory, empty first', ('-r', '--recursive')),
440 20206179 Stavros Sachtouris
        delimiter=ValueArgument(
441 20206179 Stavros Sachtouris
            'delete objects prefixed with <object><delimiter>', '--delimiter')
442 2fe2672e Stavros Sachtouris
    )
443 7493ccb6 Stavros Sachtouris
444 1395c40e Stavros Sachtouris
    @errors.generic.all
445 1395c40e Stavros Sachtouris
    @errors.pithos.connection
446 1395c40e Stavros Sachtouris
    @errors.pithos.container
447 20206179 Stavros Sachtouris
    @errors.pithos.object_path
448 20206179 Stavros Sachtouris
    def _run(self):
449 20206179 Stavros Sachtouris
        if self.path:
450 20206179 Stavros Sachtouris
            if self['yes'] or self.ask_user(
451 20206179 Stavros Sachtouris
                    'Delete /%s/%s ?' % (self.container, self.path)):
452 7b109aa7 Stavros Sachtouris
                self.client.del_object(
453 20206179 Stavros Sachtouris
                    self.path,
454 20206179 Stavros Sachtouris
                    until=self['until_date'],
455 7b109aa7 Stavros Sachtouris
                    delimiter='/' if self['recursive'] else self['delimiter'])
456 20206179 Stavros Sachtouris
            else:
457 20206179 Stavros Sachtouris
                self.error('Aborted')
458 20206179 Stavros Sachtouris
        else:
459 7b109aa7 Stavros Sachtouris
            if self['yes'] or self.ask_user(
460 7b109aa7 Stavros Sachtouris
                    'Empty container /%s ?' % self.container):
461 7b109aa7 Stavros Sachtouris
                self.client.container_delete(self.container, delimiter='/')
462 7b109aa7 Stavros Sachtouris
            else:
463 7b109aa7 Stavros Sachtouris
                self.error('Aborted')
464 1395c40e Stavros Sachtouris
465 20206179 Stavros Sachtouris
    def main(self, path_or_url):
466 20206179 Stavros Sachtouris
        super(self.__class__, self)._run(path_or_url)
467 20206179 Stavros Sachtouris
        self._run()
468 7493ccb6 Stavros Sachtouris
469 234954d1 Stavros Sachtouris
470 effa4b8f Stavros Sachtouris
class _source_destination(_pithos_container, _optional_output_cmd):
471 2fe2672e Stavros Sachtouris
472 de932277 Stavros Sachtouris
    sd_arguments = dict(
473 effa4b8f Stavros Sachtouris
        destination_user_uuid=ValueArgument(
474 effa4b8f Stavros Sachtouris
            'default: current user uuid', '--to-account'),
475 effa4b8f Stavros Sachtouris
        destination_container=ValueArgument(
476 effa4b8f Stavros Sachtouris
            'default: pithos', '--to-container'),
477 effa4b8f Stavros Sachtouris
        source_prefix=FlagArgument(
478 effa4b8f Stavros Sachtouris
            'Transfer all files that are prefixed with SOURCE PATH If the '
479 effa4b8f Stavros Sachtouris
            'destination path is specified, replace SOURCE_PATH with '
480 effa4b8f Stavros Sachtouris
            'DESTINATION_PATH',
481 de932277 Stavros Sachtouris
            ('-r', '--recursive')),
482 effa4b8f Stavros Sachtouris
        force=FlagArgument(
483 bfa33995 Stavros Sachtouris
            'Overwrite destination objects, if needed', ('-f', '--force')),
484 bfa33995 Stavros Sachtouris
        source_version=ValueArgument(
485 bfa33995 Stavros Sachtouris
            'The version of the source object', '--source-version')
486 2fe2672e Stavros Sachtouris
    )
487 7493ccb6 Stavros Sachtouris
488 b4f69041 Stavros Sachtouris
    def __init__(self, arguments={}, auth_base=None, cloud=None):
489 761e0cbf Stavros Sachtouris
        self.arguments.update(arguments)
490 de932277 Stavros Sachtouris
        self.arguments.update(self.sd_arguments)
491 de932277 Stavros Sachtouris
        super(_source_destination, self).__init__(
492 b4f69041 Stavros Sachtouris
            self.arguments, auth_base, cloud)
493 761e0cbf Stavros Sachtouris
494 de932277 Stavros Sachtouris
    def _report_transfer(self, src, dst, transfer_name):
495 de932277 Stavros Sachtouris
        if not dst:
496 de932277 Stavros Sachtouris
            if transfer_name in ('move', ):
497 de932277 Stavros Sachtouris
                self.error('  delete source directory %s' % src)
498 de932277 Stavros Sachtouris
            return
499 de932277 Stavros Sachtouris
        dst_prf = '' if self.account == self.dst_client.account else (
500 de932277 Stavros Sachtouris
                'pithos://%s' % self.dst_client.account)
501 de932277 Stavros Sachtouris
        if src:
502 de932277 Stavros Sachtouris
            src_prf = '' if self.account == self.dst_client.account else (
503 de932277 Stavros Sachtouris
                    'pithos://%s' % self.account)
504 de932277 Stavros Sachtouris
            self.error('  %s %s/%s/%s\n  -->  %s/%s/%s' % (
505 de932277 Stavros Sachtouris
                transfer_name,
506 de932277 Stavros Sachtouris
                src_prf, self.container, src,
507 de932277 Stavros Sachtouris
                dst_prf, self.dst_client.container, dst))
508 de932277 Stavros Sachtouris
        else:
509 de932277 Stavros Sachtouris
            self.error('  mkdir %s/%s/%s' % (
510 de932277 Stavros Sachtouris
                dst_prf, self.dst_client.container, dst))
511 300da0fb Stavros Sachtouris
512 300da0fb Stavros Sachtouris
    @errors.generic.all
513 300da0fb Stavros Sachtouris
    @errors.pithos.account
514 effa4b8f Stavros Sachtouris
    def _src_dst(self, version=None):
515 effa4b8f Stavros Sachtouris
        """Preconditions:
516 effa4b8f Stavros Sachtouris
        self.account, self.container, self.path
517 effa4b8f Stavros Sachtouris
        self.dst_acc, self.dst_con, self.dst_path
518 effa4b8f Stavros Sachtouris
        They should all be configured properly
519 effa4b8f Stavros Sachtouris
        :returns: [(src_path, dst_path), ...], if src_path is None, create
520 effa4b8f Stavros Sachtouris
            destination directory
521 6736f171 Stavros Sachtouris
        """
522 effa4b8f Stavros Sachtouris
        src_objects, dst_objects, pairs = dict(), dict(), []
523 ece4ae4b Stavros Sachtouris
        try:
524 effa4b8f Stavros Sachtouris
            for obj in self.dst_client.list_objects(
525 effa4b8f Stavros Sachtouris
                    prefix=self.dst_path or self.path or '/'):
526 effa4b8f Stavros Sachtouris
                dst_objects[obj['name']] = obj
527 effa4b8f Stavros Sachtouris
        except ClientError as ce:
528 effa4b8f Stavros Sachtouris
            if ce.status in (404, ):
529 effa4b8f Stavros Sachtouris
                raise CLIError(
530 effa4b8f Stavros Sachtouris
                    'Destination container pithos://%s/%s not found' % (
531 effa4b8f Stavros Sachtouris
                        self.dst_client.account, self.dst_client.container))
532 de932277 Stavros Sachtouris
            raise ce
533 effa4b8f Stavros Sachtouris
        if self['source_prefix']:
534 effa4b8f Stavros Sachtouris
            #  Copy and replace prefixes
535 7b109aa7 Stavros Sachtouris
            for src_obj in self.client.list_objects(prefix=self.path):
536 effa4b8f Stavros Sachtouris
                src_objects[src_obj['name']] = src_obj
537 effa4b8f Stavros Sachtouris
            for src_path, src_obj in src_objects.items():
538 effa4b8f Stavros Sachtouris
                dst_path = '%s%s' % (
539 effa4b8f Stavros Sachtouris
                    self.dst_path or self.path, src_path[len(self.path):])
540 effa4b8f Stavros Sachtouris
                dst_obj = dst_objects.get(dst_path, None)
541 effa4b8f Stavros Sachtouris
                if self['force'] or not dst_obj:
542 effa4b8f Stavros Sachtouris
                    #  Just do it
543 de932277 Stavros Sachtouris
                    pairs.append((
544 de932277 Stavros Sachtouris
                        None if self._is_dir(src_obj) else src_path, dst_path))
545 de932277 Stavros Sachtouris
                    if self._is_dir(src_obj):
546 de932277 Stavros Sachtouris
                        pairs.append((self.path or dst_path, None))
547 effa4b8f Stavros Sachtouris
                elif not (self._is_dir(dst_obj) and self._is_dir(src_obj)):
548 effa4b8f Stavros Sachtouris
                    raise CLIError(
549 effa4b8f Stavros Sachtouris
                        'Destination object exists', importance=2, details=[
550 effa4b8f Stavros Sachtouris
                            'Failed while transfering:',
551 effa4b8f Stavros Sachtouris
                            '    pithos://%s/%s/%s' % (
552 effa4b8f Stavros Sachtouris
                                    self.account,
553 effa4b8f Stavros Sachtouris
                                    self.container,
554 effa4b8f Stavros Sachtouris
                                    src_path),
555 effa4b8f Stavros Sachtouris
                            '--> pithos://%s/%s/%s' % (
556 effa4b8f Stavros Sachtouris
                                    self.dst_client.account,
557 effa4b8f Stavros Sachtouris
                                    self.dst_client.container,
558 effa4b8f Stavros Sachtouris
                                    dst_path),
559 eb647cfe Stavros Sachtouris
                            'Use %s to transfer overwrite' % (
560 eb647cfe Stavros Sachtouris
                                    self.arguments['force'].lvalue)])
561 effa4b8f Stavros Sachtouris
        else:
562 de932277 Stavros Sachtouris
            #  One object transfer
563 de932277 Stavros Sachtouris
            try:
564 bfa33995 Stavros Sachtouris
                src_version_arg = self.arguments.get('source_version', None)
565 bfa33995 Stavros Sachtouris
                src_obj = self.client.get_object_info(
566 bfa33995 Stavros Sachtouris
                    self.path,
567 bfa33995 Stavros Sachtouris
                    version=src_version_arg.value if src_version_arg else None)
568 de932277 Stavros Sachtouris
            except ClientError as ce:
569 de932277 Stavros Sachtouris
                if ce.status in (204, ):
570 de932277 Stavros Sachtouris
                    raise CLIError(
571 de932277 Stavros Sachtouris
                        'Missing specific path container %s' % self.container,
572 de932277 Stavros Sachtouris
                        importance=2, details=[
573 de932277 Stavros Sachtouris
                            'To transfer container contents %s' % (
574 eb647cfe Stavros Sachtouris
                                self.arguments['source_prefix'].lvalue)])
575 ece4ae4b Stavros Sachtouris
                raise
576 effa4b8f Stavros Sachtouris
            dst_path = self.dst_path or self.path
577 74b7c6dc Stavros Sachtouris
            dst_obj = dst_objects.get(dst_path or self.path, None)
578 effa4b8f Stavros Sachtouris
            if self['force'] or not dst_obj:
579 effa4b8f Stavros Sachtouris
                pairs.append(
580 de932277 Stavros Sachtouris
                    (None if self._is_dir(src_obj) else self.path, dst_path))
581 de932277 Stavros Sachtouris
                if self._is_dir(src_obj):
582 de932277 Stavros Sachtouris
                    pairs.append((self.path or dst_path, None))
583 effa4b8f Stavros Sachtouris
            elif self._is_dir(src_obj):
584 effa4b8f Stavros Sachtouris
                raise CLIError(
585 effa4b8f Stavros Sachtouris
                    'Cannot transfer an application/directory object',
586 effa4b8f Stavros Sachtouris
                    importance=2, details=[
587 effa4b8f Stavros Sachtouris
                        'The object pithos://%s/%s/%s is a directory' % (
588 effa4b8f Stavros Sachtouris
                            self.account,
589 effa4b8f Stavros Sachtouris
                            self.container,
590 de932277 Stavros Sachtouris
                            self.path),
591 effa4b8f Stavros Sachtouris
                        'To recursively copy a directory, use',
592 eb647cfe Stavros Sachtouris
                        '  %s' % self.arguments['source_prefix'].lvalue,
593 effa4b8f Stavros Sachtouris
                        'To create a file, use',
594 effa4b8f Stavros Sachtouris
                        '  /file create  (general purpose)',
595 effa4b8f Stavros Sachtouris
                        '  /file mkdir   (a directory object)'])
596 effa4b8f Stavros Sachtouris
            else:
597 effa4b8f Stavros Sachtouris
                raise CLIError(
598 effa4b8f Stavros Sachtouris
                    'Destination object exists',
599 effa4b8f Stavros Sachtouris
                    importance=2, details=[
600 effa4b8f Stavros Sachtouris
                        'Failed while transfering:',
601 effa4b8f Stavros Sachtouris
                        '    pithos://%s/%s/%s' % (
602 effa4b8f Stavros Sachtouris
                                self.account,
603 effa4b8f Stavros Sachtouris
                                self.container,
604 de932277 Stavros Sachtouris
                                self.path),
605 effa4b8f Stavros Sachtouris
                        '--> pithos://%s/%s/%s' % (
606 effa4b8f Stavros Sachtouris
                                self.dst_client.account,
607 effa4b8f Stavros Sachtouris
                                self.dst_client.container,
608 effa4b8f Stavros Sachtouris
                                dst_path),
609 eb647cfe Stavros Sachtouris
                        'Use %s to transfer overwrite' % (
610 eb647cfe Stavros Sachtouris
                                self.arguments['force'].lvalue)])
611 effa4b8f Stavros Sachtouris
        return pairs
612 effa4b8f Stavros Sachtouris
613 effa4b8f Stavros Sachtouris
    def _run(self, source_path_or_url, destination_path_or_url=''):
614 effa4b8f Stavros Sachtouris
        super(_source_destination, self)._run(source_path_or_url)
615 effa4b8f Stavros Sachtouris
        dst_acc, dst_con, dst_path = self._resolve_pithos_url(
616 effa4b8f Stavros Sachtouris
            destination_path_or_url)
617 effa4b8f Stavros Sachtouris
        self.dst_client = PithosClient(
618 effa4b8f Stavros Sachtouris
            base_url=self.client.base_url, token=self.client.token,
619 effa4b8f Stavros Sachtouris
            container=self[
620 effa4b8f Stavros Sachtouris
                'destination_container'] or dst_con or self.client.container,
621 effa4b8f Stavros Sachtouris
            account=self[
622 432cea25 Stavros Sachtouris
                'destination_user_uuid'] or dst_acc or self.account)
623 effa4b8f Stavros Sachtouris
        self.dst_path = dst_path or self.path
624 300da0fb Stavros Sachtouris
625 ece4ae4b Stavros Sachtouris
626 effa4b8f Stavros Sachtouris
@command(file_cmds)
627 effa4b8f Stavros Sachtouris
class file_copy(_source_destination):
628 effa4b8f Stavros Sachtouris
    """Copy objects, even between different accounts or containers"""
629 761e0cbf Stavros Sachtouris
630 761e0cbf Stavros Sachtouris
    arguments = dict(
631 effa4b8f Stavros Sachtouris
        public=ValueArgument('publish new object', '--public'),
632 761e0cbf Stavros Sachtouris
        content_type=ValueArgument(
633 201baa17 Stavros Sachtouris
            'change object\'s content type', '--content-type'),
634 1d3f006b Stavros Sachtouris
        source_version=ValueArgument(
635 bfa33995 Stavros Sachtouris
            'The version of the source object', '--object-version')
636 761e0cbf Stavros Sachtouris
    )
637 761e0cbf Stavros Sachtouris
638 1395c40e Stavros Sachtouris
    @errors.generic.all
639 1395c40e Stavros Sachtouris
    @errors.pithos.connection
640 1395c40e Stavros Sachtouris
    @errors.pithos.container
641 300da0fb Stavros Sachtouris
    @errors.pithos.account
642 effa4b8f Stavros Sachtouris
    def _run(self):
643 effa4b8f Stavros Sachtouris
        for src, dst in self._src_dst(self['source_version']):
644 de932277 Stavros Sachtouris
            self._report_transfer(src, dst, 'copy')
645 de932277 Stavros Sachtouris
            if src and dst:
646 effa4b8f Stavros Sachtouris
                self.dst_client.copy_object(
647 effa4b8f Stavros Sachtouris
                    src_container=self.client.container,
648 effa4b8f Stavros Sachtouris
                    src_object=src,
649 effa4b8f Stavros Sachtouris
                    dst_container=self.dst_client.container,
650 effa4b8f Stavros Sachtouris
                    dst_object=dst,
651 432cea25 Stavros Sachtouris
                    source_account=self.client.account,
652 effa4b8f Stavros Sachtouris
                    source_version=self['source_version'],
653 effa4b8f Stavros Sachtouris
                    public=self['public'],
654 effa4b8f Stavros Sachtouris
                    content_type=self['content_type'])
655 de932277 Stavros Sachtouris
            elif dst:
656 de932277 Stavros Sachtouris
                self.dst_client.create_directory(dst)
657 effa4b8f Stavros Sachtouris
658 effa4b8f Stavros Sachtouris
    def main(self, source_path_or_url, destination_path_or_url=None):
659 3ae60112 Stavros Sachtouris
        super(file_copy, self)._run(
660 effa4b8f Stavros Sachtouris
            source_path_or_url, destination_path_or_url or '')
661 effa4b8f Stavros Sachtouris
        self._run()
662 effa4b8f Stavros Sachtouris
663 effa4b8f Stavros Sachtouris
664 effa4b8f Stavros Sachtouris
@command(file_cmds)
665 effa4b8f Stavros Sachtouris
class file_move(_source_destination):
666 effa4b8f Stavros Sachtouris
    """Move objects, even between different accounts or containers"""
667 2fe2672e Stavros Sachtouris
668 2fe2672e Stavros Sachtouris
    arguments = dict(
669 effa4b8f Stavros Sachtouris
        public=ValueArgument('publish new object', '--public'),
670 761e0cbf Stavros Sachtouris
        content_type=ValueArgument(
671 effa4b8f Stavros Sachtouris
            'change object\'s content type', '--content-type')
672 2fe2672e Stavros Sachtouris
    )
673 7493ccb6 Stavros Sachtouris
674 1395c40e Stavros Sachtouris
    @errors.generic.all
675 1395c40e Stavros Sachtouris
    @errors.pithos.connection
676 1395c40e Stavros Sachtouris
    @errors.pithos.container
677 effa4b8f Stavros Sachtouris
    @errors.pithos.account
678 effa4b8f Stavros Sachtouris
    def _run(self):
679 effa4b8f Stavros Sachtouris
        for src, dst in self._src_dst():
680 de932277 Stavros Sachtouris
            self._report_transfer(src, dst, 'move')
681 de932277 Stavros Sachtouris
            if src and dst:
682 effa4b8f Stavros Sachtouris
                self.dst_client.move_object(
683 effa4b8f Stavros Sachtouris
                    src_container=self.client.container,
684 effa4b8f Stavros Sachtouris
                    src_object=src,
685 effa4b8f Stavros Sachtouris
                    dst_container=self.dst_client.container,
686 effa4b8f Stavros Sachtouris
                    dst_object=dst,
687 effa4b8f Stavros Sachtouris
                    source_account=self.account,
688 effa4b8f Stavros Sachtouris
                    public=self['public'],
689 effa4b8f Stavros Sachtouris
                    content_type=self['content_type'])
690 de932277 Stavros Sachtouris
            elif dst:
691 de932277 Stavros Sachtouris
                self.dst_client.create_directory(dst)
692 effa4b8f Stavros Sachtouris
            else:
693 de932277 Stavros Sachtouris
                self.client.del_object(src)
694 effa4b8f Stavros Sachtouris
695 effa4b8f Stavros Sachtouris
    def main(self, source_path_or_url, destination_path_or_url=None):
696 effa4b8f Stavros Sachtouris
        super(file_move, self)._run(
697 effa4b8f Stavros Sachtouris
            source_path_or_url, destination_path_or_url or '')
698 effa4b8f Stavros Sachtouris
        self._run()
699 edc1182f Stavros Sachtouris
700 edc1182f Stavros Sachtouris
701 edc1182f Stavros Sachtouris
@command(file_cmds)
702 edc1182f Stavros Sachtouris
class file_append(_pithos_container, _optional_output_cmd):
703 aaca2ef4 Stavros Sachtouris
    """Append local file to (existing) remote object
704 aaca2ef4 Stavros Sachtouris
    The remote object should exist.
705 aaca2ef4 Stavros Sachtouris
    If the remote object is a directory, it is transformed into a file.
706 aaca2ef4 Stavros Sachtouris
    In the later case, objects under the directory remain intact.
707 aaca2ef4 Stavros Sachtouris
    """
708 7493ccb6 Stavros Sachtouris
709 2fe2672e Stavros Sachtouris
    arguments = dict(
710 2fe2672e Stavros Sachtouris
        progress_bar=ProgressBarArgument(
711 ff1c0296 Stavros Sachtouris
            'do not show progress bar', ('-N', '--no-progress-bar'),
712 edc1182f Stavros Sachtouris
            default=False),
713 edc1182f Stavros Sachtouris
        max_threads=IntArgument('default: 1', '--threads'),
714 2fe2672e Stavros Sachtouris
    )
715 486f7af1 Stavros Sachtouris
716 ca092af4 Stavros Sachtouris
    @errors.generic.all
717 ca092af4 Stavros Sachtouris
    @errors.pithos.connection
718 ca092af4 Stavros Sachtouris
    @errors.pithos.container
719 ca092af4 Stavros Sachtouris
    @errors.pithos.object_path
720 ca092af4 Stavros Sachtouris
    def _run(self, local_path):
721 edc1182f Stavros Sachtouris
        if self['max_threads'] > 0:
722 edc1182f Stavros Sachtouris
            self.client.MAX_THREADS = int(self['max_threads'])
723 ca092af4 Stavros Sachtouris
        (progress_bar, upload_cb) = self._safe_progress_bar('Appending')
724 7493ccb6 Stavros Sachtouris
        try:
725 ff1c0296 Stavros Sachtouris
            with open(local_path, 'rb') as f:
726 ff1c0296 Stavros Sachtouris
                self._optional_output(
727 ff1c0296 Stavros Sachtouris
                    self.client.append_object(self.path, f, upload_cb))
728 852a22e7 Stavros Sachtouris
        finally:
729 ca092af4 Stavros Sachtouris
            self._safe_progress_bar_finish(progress_bar)
730 ca092af4 Stavros Sachtouris
731 edc1182f Stavros Sachtouris
    def main(self, local_path, remote_path_or_url):
732 edc1182f Stavros Sachtouris
        super(self.__class__, self)._run(remote_path_or_url)
733 ca092af4 Stavros Sachtouris
        self._run(local_path)
734 7493ccb6 Stavros Sachtouris
735 234954d1 Stavros Sachtouris
736 edc1182f Stavros Sachtouris
@command(file_cmds)
737 edc1182f Stavros Sachtouris
class file_truncate(_pithos_container, _optional_output_cmd):
738 edc1182f Stavros Sachtouris
    """Truncate remote file up to size"""
739 edc1182f Stavros Sachtouris
740 edc1182f Stavros Sachtouris
    arguments = dict(
741 edc1182f Stavros Sachtouris
        size_in_bytes=IntArgument('Length of file after truncation', '--size')
742 edc1182f Stavros Sachtouris
    )
743 edc1182f Stavros Sachtouris
    required = ('size_in_bytes', )
744 7493ccb6 Stavros Sachtouris
745 ca092af4 Stavros Sachtouris
    @errors.generic.all
746 ca092af4 Stavros Sachtouris
    @errors.pithos.connection
747 ca092af4 Stavros Sachtouris
    @errors.pithos.container
748 ca092af4 Stavros Sachtouris
    @errors.pithos.object_path
749 ca092af4 Stavros Sachtouris
    @errors.pithos.object_size
750 edc1182f Stavros Sachtouris
    def _run(self, size):
751 915b99b5 Stavros Sachtouris
        self._optional_output(self.client.truncate_object(self.path, size))
752 ca092af4 Stavros Sachtouris
753 edc1182f Stavros Sachtouris
    def main(self, path_or_url):
754 edc1182f Stavros Sachtouris
        super(self.__class__, self)._run(path_or_url)
755 edc1182f Stavros Sachtouris
        self._run(size=self['size_in_bytes'])
756 7493ccb6 Stavros Sachtouris
757 234954d1 Stavros Sachtouris
758 edc1182f Stavros Sachtouris
@command(file_cmds)
759 edc1182f Stavros Sachtouris
class file_overwrite(_pithos_container, _optional_output_cmd):
760 edc1182f Stavros Sachtouris
    """Overwrite part of a remote file"""
761 7493ccb6 Stavros Sachtouris
762 2fe2672e Stavros Sachtouris
    arguments = dict(
763 2fe2672e Stavros Sachtouris
        progress_bar=ProgressBarArgument(
764 ff1c0296 Stavros Sachtouris
            'do not show progress bar', ('-N', '--no-progress-bar'),
765 edc1182f Stavros Sachtouris
            default=False),
766 edc1182f Stavros Sachtouris
        start_position=IntArgument('File position in bytes', '--from'),
767 edc1182f Stavros Sachtouris
        end_position=IntArgument('File position in bytes', '--to')
768 2fe2672e Stavros Sachtouris
    )
769 edc1182f Stavros Sachtouris
    required = ('start_position', 'end_position')
770 486f7af1 Stavros Sachtouris
771 ca092af4 Stavros Sachtouris
    @errors.generic.all
772 ca092af4 Stavros Sachtouris
    @errors.pithos.connection
773 ca092af4 Stavros Sachtouris
    @errors.pithos.container
774 ca092af4 Stavros Sachtouris
    @errors.pithos.object_path
775 ca092af4 Stavros Sachtouris
    @errors.pithos.object_size
776 ca092af4 Stavros Sachtouris
    def _run(self, local_path, start, end):
777 ff1c0296 Stavros Sachtouris
        start, end = int(start), int(end)
778 ca092af4 Stavros Sachtouris
        (progress_bar, upload_cb) = self._safe_progress_bar(
779 ca092af4 Stavros Sachtouris
            'Overwrite %s bytes' % (end - start))
780 aaca2ef4 Stavros Sachtouris
        try:
781 ff1c0296 Stavros Sachtouris
            with open(path.abspath(local_path), 'rb') as f:
782 ff1c0296 Stavros Sachtouris
                self._optional_output(self.client.overwrite_object(
783 ff1c0296 Stavros Sachtouris
                    obj=self.path,
784 ff1c0296 Stavros Sachtouris
                    start=start,
785 ff1c0296 Stavros Sachtouris
                    end=end,
786 ff1c0296 Stavros Sachtouris
                    source_file=f,
787 ff1c0296 Stavros Sachtouris
                    upload_cb=upload_cb))
788 852a22e7 Stavros Sachtouris
        finally:
789 ca092af4 Stavros Sachtouris
            self._safe_progress_bar_finish(progress_bar)
790 ca092af4 Stavros Sachtouris
791 edc1182f Stavros Sachtouris
    def main(self, local_path, path_or_url):
792 edc1182f Stavros Sachtouris
        super(self.__class__, self)._run(path_or_url)
793 52edad0a Stavros Sachtouris
        self.path = self.path or path.basename(local_path)
794 edc1182f Stavros Sachtouris
        self._run(
795 edc1182f Stavros Sachtouris
            local_path=local_path,
796 edc1182f Stavros Sachtouris
            start=self['start_position'],
797 edc1182f Stavros Sachtouris
            end=self['end_position'])
798 68858765 Stavros Sachtouris
799 7493ccb6 Stavros Sachtouris
800 edc1182f Stavros Sachtouris
@command(file_cmds)
801 edc1182f Stavros Sachtouris
class file_upload(_pithos_container, _optional_output_cmd):
802 7493ccb6 Stavros Sachtouris
    """Upload a file"""
803 7493ccb6 Stavros Sachtouris
804 2fe2672e Stavros Sachtouris
    arguments = dict(
805 edc1182f Stavros Sachtouris
        max_threads=IntArgument('default: 5', '--threads'),
806 2fe2672e Stavros Sachtouris
        content_encoding=ValueArgument(
807 201baa17 Stavros Sachtouris
            'set MIME content type', '--content-encoding'),
808 2fe2672e Stavros Sachtouris
        content_disposition=ValueArgument(
809 201baa17 Stavros Sachtouris
            'specify objects presentation style', '--content-disposition'),
810 2fe2672e Stavros Sachtouris
        content_type=ValueArgument('specify content type', '--content-type'),
811 edc1182f Stavros Sachtouris
        uuid_for_read_permission=RepeatableArgument(
812 20206179 Stavros Sachtouris
            'Give read access to a user or group (can be repeated) '
813 20206179 Stavros Sachtouris
            'Use * for all users',
814 edc1182f Stavros Sachtouris
            '--read-permission'),
815 edc1182f Stavros Sachtouris
        uuid_for_write_permission=RepeatableArgument(
816 20206179 Stavros Sachtouris
            'Give write access to a user or group (can be repeated) '
817 20206179 Stavros Sachtouris
            'Use * for all users',
818 edc1182f Stavros Sachtouris
            '--write-permission'),
819 2fe2672e Stavros Sachtouris
        public=FlagArgument('make object publicly accessible', '--public'),
820 2fe2672e Stavros Sachtouris
        progress_bar=ProgressBarArgument(
821 2fe2672e Stavros Sachtouris
            'do not show progress bar',
822 8741c407 Stavros Sachtouris
            ('-N', '--no-progress-bar'),
823 706fc940 Stavros Sachtouris
            default=False),
824 2d158d8b Stavros Sachtouris
        overwrite=FlagArgument('Force (over)write', ('-f', '--force')),
825 2d158d8b Stavros Sachtouris
        recursive=FlagArgument(
826 2d158d8b Stavros Sachtouris
            'Recursively upload directory *contents* + subdirectories',
827 edc1182f Stavros Sachtouris
            ('-r', '--recursive')),
828 edc1182f Stavros Sachtouris
        unchunked=FlagArgument(
829 edc1182f Stavros Sachtouris
            'Upload file as one block (not recommended)', '--unchunked'),
830 edc1182f Stavros Sachtouris
        md5_checksum=ValueArgument(
831 edc1182f Stavros Sachtouris
            'Confirm upload with a custom checksum (MD5)', '--etag'),
832 edc1182f Stavros Sachtouris
        use_hashes=FlagArgument(
833 edc1182f Stavros Sachtouris
            'Source file contains hashmap not data', '--source-is-hashmap'),
834 2fe2672e Stavros Sachtouris
    )
835 7493ccb6 Stavros Sachtouris
836 edc1182f Stavros Sachtouris
    def _sharing(self):
837 edc1182f Stavros Sachtouris
        sharing = dict()
838 edc1182f Stavros Sachtouris
        readlist = self['uuid_for_read_permission']
839 edc1182f Stavros Sachtouris
        if readlist:
840 edc1182f Stavros Sachtouris
            sharing['read'] = self['uuid_for_read_permission']
841 edc1182f Stavros Sachtouris
        writelist = self['uuid_for_write_permission']
842 edc1182f Stavros Sachtouris
        if writelist:
843 edc1182f Stavros Sachtouris
            sharing['write'] = self['uuid_for_write_permission']
844 edc1182f Stavros Sachtouris
        return sharing or None
845 edc1182f Stavros Sachtouris
846 14b25e00 Stavros Sachtouris
    def _check_container_limit(self, path):
847 14b25e00 Stavros Sachtouris
        cl_dict = self.client.get_container_limit()
848 14b25e00 Stavros Sachtouris
        container_limit = int(cl_dict['x-container-policy-quota'])
849 2b74fc1d Stavros Sachtouris
        r = self.client.container_get()
850 2b74fc1d Stavros Sachtouris
        used_bytes = sum(int(o['bytes']) for o in r.json)
851 14b25e00 Stavros Sachtouris
        path_size = get_path_size(path)
852 c8d8c6c9 Stavros Sachtouris
        if container_limit and path_size > (container_limit - used_bytes):
853 edc1182f Stavros Sachtouris
            raise CLIError(
854 edc1182f Stavros Sachtouris
                'Container %s (limit(%s) - used(%s)) < (size(%s) of %s)' % (
855 14b25e00 Stavros Sachtouris
                    self.client.container,
856 14b25e00 Stavros Sachtouris
                    format_size(container_limit),
857 2b74fc1d Stavros Sachtouris
                    format_size(used_bytes),
858 14b25e00 Stavros Sachtouris
                    format_size(path_size),
859 14b25e00 Stavros Sachtouris
                    path),
860 edc1182f Stavros Sachtouris
                details=[
861 14b25e00 Stavros Sachtouris
                    'Check accound limit: /file quota',
862 14b25e00 Stavros Sachtouris
                    'Check container limit:',
863 14b25e00 Stavros Sachtouris
                    '\t/file containerlimit get %s' % self.client.container,
864 14b25e00 Stavros Sachtouris
                    'Increase container limit:',
865 14b25e00 Stavros Sachtouris
                    '\t/file containerlimit set <new limit> %s' % (
866 14b25e00 Stavros Sachtouris
                        self.client.container)])
867 14b25e00 Stavros Sachtouris
868 edc1182f Stavros Sachtouris
    def _src_dst(self, local_path, remote_path, objlist=None):
869 b666ef82 Stavros Sachtouris
        lpath = path.abspath(local_path)
870 edc1182f Stavros Sachtouris
        short_path = path.basename(path.abspath(local_path))
871 b666ef82 Stavros Sachtouris
        rpath = remote_path or short_path
872 b666ef82 Stavros Sachtouris
        if path.isdir(lpath):
873 2d158d8b Stavros Sachtouris
            if not self['recursive']:
874 edc1182f Stavros Sachtouris
                raise CLIError('%s is a directory' % lpath, details=[
875 eb647cfe Stavros Sachtouris
                    'Use %s to upload directories & contents' % (
876 eb647cfe Stavros Sachtouris
                        self.arguments['recursive'].lvalue)])
877 b666ef82 Stavros Sachtouris
            robj = self.client.container_get(path=rpath)
878 b666ef82 Stavros Sachtouris
            if not self['overwrite']:
879 edc1182f Stavros Sachtouris
                if robj.json:
880 edc1182f Stavros Sachtouris
                    raise CLIError(
881 edc1182f Stavros Sachtouris
                        'Objects/files prefixed as %s already exist' % rpath,
882 7b109aa7 Stavros Sachtouris
                        details=['Existing objects:'] + ['\t/%s/\t%s' % (
883 edc1182f Stavros Sachtouris
                            o['name'],
884 edc1182f Stavros Sachtouris
                            o['content_type'][12:]) for o in robj.json] + [
885 edc1182f Stavros Sachtouris
                            'Use -f to add, overwrite or resume'])
886 edc1182f Stavros Sachtouris
                else:
887 edc1182f Stavros Sachtouris
                    try:
888 edc1182f Stavros Sachtouris
                        topobj = self.client.get_object_info(rpath)
889 edc1182f Stavros Sachtouris
                        if not self._is_dir(topobj):
890 edc1182f Stavros Sachtouris
                            raise CLIError(
891 edc1182f Stavros Sachtouris
                                'Object /%s/%s exists but not a directory' % (
892 edc1182f Stavros Sachtouris
                                    self.container, rpath),
893 edc1182f Stavros Sachtouris
                                details=['Use -f to overwrite'])
894 edc1182f Stavros Sachtouris
                    except ClientError as ce:
895 edc1182f Stavros Sachtouris
                        if ce.status not in (404, ):
896 edc1182f Stavros Sachtouris
                            raise
897 2d158d8b Stavros Sachtouris
            self._check_container_limit(lpath)
898 b666ef82 Stavros Sachtouris
            prev = ''
899 b666ef82 Stavros Sachtouris
            for top, subdirs, files in walk(lpath):
900 b666ef82 Stavros Sachtouris
                if top != prev:
901 b666ef82 Stavros Sachtouris
                    prev = top
902 b666ef82 Stavros Sachtouris
                    try:
903 b666ef82 Stavros Sachtouris
                        rel_path = rpath + top.split(lpath)[1]
904 b666ef82 Stavros Sachtouris
                    except IndexError:
905 b666ef82 Stavros Sachtouris
                        rel_path = rpath
906 7b109aa7 Stavros Sachtouris
                    self.error('mkdir /%s/%s' % (
907 ff1c0296 Stavros Sachtouris
                        self.client.container, rel_path))
908 b666ef82 Stavros Sachtouris
                    self.client.create_directory(rel_path)
909 b666ef82 Stavros Sachtouris
                for f in files:
910 b666ef82 Stavros Sachtouris
                    fpath = path.join(top, f)
911 b666ef82 Stavros Sachtouris
                    if path.isfile(fpath):
912 14d15eca Stavros Sachtouris
                        rel_path = rel_path.replace(path.sep, '/')
913 14d15eca Stavros Sachtouris
                        pathfix = f.replace(path.sep, '/')
914 14d15eca Stavros Sachtouris
                        yield open(fpath, 'rb'), '%s/%s' % (rel_path, pathfix)
915 b666ef82 Stavros Sachtouris
                    else:
916 ff1c0296 Stavros Sachtouris
                        self.error('%s is not a regular file' % fpath)
917 b666ef82 Stavros Sachtouris
        else:
918 14b25e00 Stavros Sachtouris
            if not path.isfile(lpath):
919 edc1182f Stavros Sachtouris
                raise CLIError(('%s is not a regular file' % lpath) if (
920 a0a61f30 Stavros Sachtouris
                    path.exists(lpath)) else '%s does not exist' % lpath)
921 b666ef82 Stavros Sachtouris
            try:
922 b666ef82 Stavros Sachtouris
                robj = self.client.get_object_info(rpath)
923 b666ef82 Stavros Sachtouris
                if remote_path and self._is_dir(robj):
924 14d15eca Stavros Sachtouris
                    rpath += '/%s' % (short_path.replace(path.sep, '/'))
925 b666ef82 Stavros Sachtouris
                    self.client.get_object_info(rpath)
926 b666ef82 Stavros Sachtouris
                if not self['overwrite']:
927 edc1182f Stavros Sachtouris
                    raise CLIError(
928 edc1182f Stavros Sachtouris
                        'Object /%s/%s already exists' % (
929 edc1182f Stavros Sachtouris
                            self.container, rpath),
930 edc1182f Stavros Sachtouris
                        details=['use -f to overwrite / resume'])
931 b666ef82 Stavros Sachtouris
            except ClientError as ce:
932 ff1c0296 Stavros Sachtouris
                if ce.status not in (404, ):
933 b666ef82 Stavros Sachtouris
                    raise
934 2d158d8b Stavros Sachtouris
            self._check_container_limit(lpath)
935 b666ef82 Stavros Sachtouris
            yield open(lpath, 'rb'), rpath
936 706fc940 Stavros Sachtouris
937 68858765 Stavros Sachtouris
    def _run(self, local_path, remote_path):
938 ec5d658f Stavros Sachtouris
        self.client.MAX_THREADS = int(self['max_threads'] or 5)
939 72952f4f Stavros Sachtouris
        params = dict(
940 72952f4f Stavros Sachtouris
            content_encoding=self['content_encoding'],
941 2fe2672e Stavros Sachtouris
            content_type=self['content_type'],
942 2fe2672e Stavros Sachtouris
            content_disposition=self['content_disposition'],
943 edc1182f Stavros Sachtouris
            sharing=self._sharing(),
944 2fe2672e Stavros Sachtouris
            public=self['public'])
945 edc1182f Stavros Sachtouris
        uploaded, container_info_cache = list, dict()
946 edc1182f Stavros Sachtouris
        rpref = 'pithos://%s' if self['account'] else ''
947 edc1182f Stavros Sachtouris
        for f, rpath in self._src_dst(local_path, remote_path):
948 edc1182f Stavros Sachtouris
            self.error('%s --> %s/%s/%s' % (
949 edc1182f Stavros Sachtouris
                f.name, rpref, self.client.container, rpath))
950 f8426b5c Stavros Sachtouris
            if not (self['content_type'] and self['content_encoding']):
951 f8426b5c Stavros Sachtouris
                ctype, cenc = guess_mime_type(f.name)
952 f8426b5c Stavros Sachtouris
                params['content_type'] = self['content_type'] or ctype
953 f8426b5c Stavros Sachtouris
                params['content_encoding'] = self['content_encoding'] or cenc
954 68858765 Stavros Sachtouris
            if self['unchunked']:
955 0e728dcb Stavros Sachtouris
                r = self.client.upload_object_unchunked(
956 b666ef82 Stavros Sachtouris
                    rpath, f,
957 edc1182f Stavros Sachtouris
                    etag=self['md5_checksum'], withHashFile=self['use_hashes'],
958 68858765 Stavros Sachtouris
                    **params)
959 8fb0acd2 Stavros Sachtouris
                if self['with_output'] or self['json_output']:
960 edc1182f Stavros Sachtouris
                    r['name'] = '/%s/%s' % (self.client.container, rpath)
961 0e728dcb Stavros Sachtouris
                    uploaded.append(r)
962 68858765 Stavros Sachtouris
            else:
963 68858765 Stavros Sachtouris
                try:
964 68858765 Stavros Sachtouris
                    (progress_bar, upload_cb) = self._safe_progress_bar(
965 b666ef82 Stavros Sachtouris
                        'Uploading %s' % f.name.split(path.sep)[-1])
966 68858765 Stavros Sachtouris
                    if progress_bar:
967 68858765 Stavros Sachtouris
                        hash_bar = progress_bar.clone()
968 68858765 Stavros Sachtouris
                        hash_cb = hash_bar.get_generator(
969 278c9018 Stavros Sachtouris
                            'Calculating block hashes')
970 68858765 Stavros Sachtouris
                    else:
971 68858765 Stavros Sachtouris
                        hash_cb = None
972 0e728dcb Stavros Sachtouris
                    r = self.client.upload_object(
973 b666ef82 Stavros Sachtouris
                        rpath, f,
974 74c65e80 Stavros Sachtouris
                        hash_cb=hash_cb,
975 74c65e80 Stavros Sachtouris
                        upload_cb=upload_cb,
976 74c65e80 Stavros Sachtouris
                        container_info_cache=container_info_cache,
977 852a22e7 Stavros Sachtouris
                        **params)
978 8fb0acd2 Stavros Sachtouris
                    if self['with_output'] or self['json_output']:
979 edc1182f Stavros Sachtouris
                        r['name'] = '/%s/%s' % (self.client.container, rpath)
980 0e728dcb Stavros Sachtouris
                        uploaded.append(r)
981 68858765 Stavros Sachtouris
                except Exception:
982 68858765 Stavros Sachtouris
                    self._safe_progress_bar_finish(progress_bar)
983 68858765 Stavros Sachtouris
                    raise
984 68858765 Stavros Sachtouris
                finally:
985 68858765 Stavros Sachtouris
                    self._safe_progress_bar_finish(progress_bar)
986 d9301a7a Stavros Sachtouris
        self._optional_output(uploaded)
987 ff1c0296 Stavros Sachtouris
        self.error('Upload completed')
988 7493ccb6 Stavros Sachtouris
989 edc1182f Stavros Sachtouris
    def main(self, local_path, remote_path_or_url):
990 edc1182f Stavros Sachtouris
        super(self.__class__, self)._run(remote_path_or_url)
991 9e0a1a4c Stavros Sachtouris
        remote_path = self.path or path.basename(path.abspath(local_path))
992 68858765 Stavros Sachtouris
        self._run(local_path=local_path, remote_path=remote_path)
993 68858765 Stavros Sachtouris
994 234954d1 Stavros Sachtouris
995 edc1182f Stavros Sachtouris
class RangeArgument(ValueArgument):
996 edc1182f Stavros Sachtouris
    """
997 edc1182f Stavros Sachtouris
    :value type: string of the form <start>-<end> where <start> and <end> are
998 edc1182f Stavros Sachtouris
        integers
999 edc1182f Stavros Sachtouris
    :value returns: the input string, after type checking <start> and <end>
1000 edc1182f Stavros Sachtouris
    """
1001 edc1182f Stavros Sachtouris
1002 edc1182f Stavros Sachtouris
    @property
1003 edc1182f Stavros Sachtouris
    def value(self):
1004 edc1182f Stavros Sachtouris
        return getattr(self, '_value', self.default)
1005 edc1182f Stavros Sachtouris
1006 edc1182f Stavros Sachtouris
    @value.setter
1007 edc1182f Stavros Sachtouris
    def value(self, newvalues):
1008 edc1182f Stavros Sachtouris
        if newvalues:
1009 edc1182f Stavros Sachtouris
            self._value = getattr(self, '_value', self.default)
1010 edc1182f Stavros Sachtouris
            for newvalue in newvalues.split(','):
1011 edc1182f Stavros Sachtouris
                self._value = ('%s,' % self._value) if self._value else ''
1012 edc1182f Stavros Sachtouris
                start, sep, end = newvalue.partition('-')
1013 edc1182f Stavros Sachtouris
                if sep:
1014 edc1182f Stavros Sachtouris
                    if start:
1015 edc1182f Stavros Sachtouris
                        start, end = (int(start), int(end))
1016 edc1182f Stavros Sachtouris
                        if start > end:
1017 edc1182f Stavros Sachtouris
                            raise CLIInvalidArgument(
1018 edc1182f Stavros Sachtouris
                                'Invalid range %s' % newvalue, details=[
1019 edc1182f Stavros Sachtouris
                                'Valid range formats',
1020 edc1182f Stavros Sachtouris
                                '  START-END', '  UP_TO', '  -FROM',
1021 edc1182f Stavros Sachtouris
                                'where all values are integers'])
1022 edc1182f Stavros Sachtouris
                        self._value += '%s-%s' % (start, end)
1023 edc1182f Stavros Sachtouris
                    else:
1024 edc1182f Stavros Sachtouris
                        self._value += '-%s' % int(end)
1025 edc1182f Stavros Sachtouris
                else:
1026 edc1182f Stavros Sachtouris
                    self._value += '%s' % int(start)
1027 edc1182f Stavros Sachtouris
1028 edc1182f Stavros Sachtouris
1029 edc1182f Stavros Sachtouris
@command(file_cmds)
1030 edc1182f Stavros Sachtouris
class file_cat(_pithos_container):
1031 edc1182f Stavros Sachtouris
    """Fetch remote file contents"""
1032 9ceec15a Stavros Sachtouris
1033 2fe2672e Stavros Sachtouris
    arguments = dict(
1034 2fe2672e Stavros Sachtouris
        range=RangeArgument('show range of data', '--range'),
1035 2fe2672e Stavros Sachtouris
        if_match=ValueArgument('show output if ETags match', '--if-match'),
1036 2fe2672e Stavros Sachtouris
        if_none_match=ValueArgument(
1037 201baa17 Stavros Sachtouris
            'show output if ETags match', '--if-none-match'),
1038 2fe2672e Stavros Sachtouris
        if_modified_since=DateArgument(
1039 201baa17 Stavros Sachtouris
            'show output modified since then', '--if-modified-since'),
1040 2fe2672e Stavros Sachtouris
        if_unmodified_since=DateArgument(
1041 201baa17 Stavros Sachtouris
            'show output unmodified since then', '--if-unmodified-since'),
1042 2fe2672e Stavros Sachtouris
        object_version=ValueArgument(
1043 edc1182f Stavros Sachtouris
            'Get contents of the chosen version', '--object-version')
1044 2fe2672e Stavros Sachtouris
    )
1045 2fe2672e Stavros Sachtouris
1046 68858765 Stavros Sachtouris
    @errors.generic.all
1047 68858765 Stavros Sachtouris
    @errors.pithos.connection
1048 68858765 Stavros Sachtouris
    @errors.pithos.container
1049 68858765 Stavros Sachtouris
    @errors.pithos.object_path
1050 68858765 Stavros Sachtouris
    def _run(self):
1051 68858765 Stavros Sachtouris
        self.client.download_object(
1052 ff1c0296 Stavros Sachtouris
            self.path, self._out,
1053 3d568c09 Stavros Sachtouris
            range_str=self['range'],
1054 2fe2672e Stavros Sachtouris
            version=self['object_version'],
1055 2fe2672e Stavros Sachtouris
            if_match=self['if_match'],
1056 2fe2672e Stavros Sachtouris
            if_none_match=self['if_none_match'],
1057 2fe2672e Stavros Sachtouris
            if_modified_since=self['if_modified_since'],
1058 2fe2672e Stavros Sachtouris
            if_unmodified_since=self['if_unmodified_since'])
1059 68858765 Stavros Sachtouris
1060 edc1182f Stavros Sachtouris
    def main(self, path_or_url):
1061 edc1182f Stavros Sachtouris
        super(self.__class__, self)._run(path_or_url)
1062 68858765 Stavros Sachtouris
        self._run()
1063 9ceec15a Stavros Sachtouris
1064 234954d1 Stavros Sachtouris
1065 74b7c6dc Stavros Sachtouris
@command(file_cmds)
1066 74b7c6dc Stavros Sachtouris
class file_download(_pithos_container):
1067 74b7c6dc Stavros Sachtouris
    """Download a remove file or directory object to local file system"""
1068 7493ccb6 Stavros Sachtouris
1069 2fe2672e Stavros Sachtouris
    arguments = dict(
1070 74b7c6dc Stavros Sachtouris
        resume=FlagArgument(
1071 74b7c6dc Stavros Sachtouris
            'Resume/Overwrite (attempt resume, else overwrite)',
1072 74b7c6dc Stavros Sachtouris
            ('-f', '--resume')),
1073 74b7c6dc Stavros Sachtouris
        range=RangeArgument('Download only that range of data', '--range'),
1074 74b7c6dc Stavros Sachtouris
        matching_etag=ValueArgument('download iff ETag match', '--if-match'),
1075 74b7c6dc Stavros Sachtouris
        non_matching_etag=ValueArgument(
1076 74b7c6dc Stavros Sachtouris
            'download iff ETags DO NOT match', '--if-none-match'),
1077 74b7c6dc Stavros Sachtouris
        modified_since_date=DateArgument(
1078 74b7c6dc Stavros Sachtouris
            'download iff remote file is modified since then',
1079 74b7c6dc Stavros Sachtouris
            '--if-modified-since'),
1080 74b7c6dc Stavros Sachtouris
        unmodified_since_date=DateArgument(
1081 74b7c6dc Stavros Sachtouris
            'show output iff remote file is unmodified since then',
1082 74b7c6dc Stavros Sachtouris
            '--if-unmodified-since'),
1083 2fe2672e Stavros Sachtouris
        object_version=ValueArgument(
1084 20206179 Stavros Sachtouris
            'download a file of a specific version', '--object-version'),
1085 74b7c6dc Stavros Sachtouris
        max_threads=IntArgument('default: 5', '--threads'),
1086 2fe2672e Stavros Sachtouris
        progress_bar=ProgressBarArgument(
1087 ff1c0296 Stavros Sachtouris
            'do not show progress bar', ('-N', '--no-progress-bar'),
1088 ae99b37d Stavros Sachtouris
            default=False),
1089 f6c09d14 Stavros Sachtouris
        recursive=FlagArgument(
1090 74b7c6dc Stavros Sachtouris
            'Download a remote directory object and its contents',
1091 74b7c6dc Stavros Sachtouris
            ('-r', '--recursive'))
1092 74b7c6dc Stavros Sachtouris
        )
1093 74b7c6dc Stavros Sachtouris
1094 74b7c6dc Stavros Sachtouris
    def _src_dst(self, local_path):
1095 74b7c6dc Stavros Sachtouris
        """Create a list of (src, dst) where src is a remote location and dst
1096 74b7c6dc Stavros Sachtouris
        is an open file descriptor. Directories are denoted as (None, dirpath)
1097 74b7c6dc Stavros Sachtouris
        and they are pretended to other objects in a very strict order (shorter
1098 74b7c6dc Stavros Sachtouris
        to longer path)."""
1099 74b7c6dc Stavros Sachtouris
        ret = []
1100 74b7c6dc Stavros Sachtouris
        try:
1101 a3ba3bce Stavros Sachtouris
            if self.path:
1102 606f5b54 Stavros Sachtouris
                obj = self.client.get_object_info(
1103 606f5b54 Stavros Sachtouris
                    self.path, version=self['object_version'])
1104 606f5b54 Stavros Sachtouris
                obj.setdefault('name', self.path.strip('/'))
1105 606f5b54 Stavros Sachtouris
            else:
1106 606f5b54 Stavros Sachtouris
                obj = None
1107 74b7c6dc Stavros Sachtouris
        except ClientError as ce:
1108 74b7c6dc Stavros Sachtouris
            if ce.status in (404, ):
1109 74b7c6dc Stavros Sachtouris
                raiseCLIError(ce, details=[
1110 606f5b54 Stavros Sachtouris
                    'To download an object, it must exist either as a file or'
1111 606f5b54 Stavros Sachtouris
                    ' as a directory.',
1112 74b7c6dc Stavros Sachtouris
                    'For example, to download everything under prefix/ the '
1113 74b7c6dc Stavros Sachtouris
                    'directory "prefix" must exist.',
1114 74b7c6dc Stavros Sachtouris
                    'To see if an remote object is actually there:',
1115 74b7c6dc Stavros Sachtouris
                    '  /file info [/CONTAINER/]OBJECT',
1116 74b7c6dc Stavros Sachtouris
                    'To create a directory object:',
1117 74b7c6dc Stavros Sachtouris
                    '  /file mkdir [/CONTAINER/]OBJECT'])
1118 74b7c6dc Stavros Sachtouris
            if ce.status in (204, ):
1119 74b7c6dc Stavros Sachtouris
                raise CLIError(
1120 74b7c6dc Stavros Sachtouris
                    'No file or directory objects to download',
1121 a3ba3bce Stavros Sachtouris
                    details=[
1122 74b7c6dc Stavros Sachtouris
                        'To download a container (e.g., %s):' % self.container,
1123 74b7c6dc Stavros Sachtouris
                        '  [kamaki] container download %s [LOCAL_PATH]' % (
1124 74b7c6dc Stavros Sachtouris
                            self.container)])
1125 74b7c6dc Stavros Sachtouris
            raise
1126 74b7c6dc Stavros Sachtouris
        rpath = self.path.strip('/')
1127 606f5b54 Stavros Sachtouris
        if local_path and self.path and local_path.endswith('/'):
1128 606f5b54 Stavros Sachtouris
            local_path = local_path[-1:]
1129 74b7c6dc Stavros Sachtouris
1130 606f5b54 Stavros Sachtouris
        if (not obj) or self._is_dir(obj):
1131 74b7c6dc Stavros Sachtouris
            if self['recursive']:
1132 606f5b54 Stavros Sachtouris
                if not (self.path or local_path.endswith('/')):
1133 606f5b54 Stavros Sachtouris
                    #  Download the whole container
1134 606f5b54 Stavros Sachtouris
                    local_path = '' if local_path in ('.', ) else local_path
1135 606f5b54 Stavros Sachtouris
                    local_path = '%s/' % (local_path or self.container)
1136 606f5b54 Stavros Sachtouris
                obj = obj or dict(
1137 606f5b54 Stavros Sachtouris
                    name='', content_type='application/directory')
1138 74b7c6dc Stavros Sachtouris
                dirs, files = [obj, ], []
1139 74b7c6dc Stavros Sachtouris
                objects = self.client.container_get(
1140 606f5b54 Stavros Sachtouris
                    path=self.path,
1141 74b7c6dc Stavros Sachtouris
                    if_modified_since=self['modified_since_date'],
1142 74b7c6dc Stavros Sachtouris
                    if_unmodified_since=self['unmodified_since_date'])
1143 606f5b54 Stavros Sachtouris
                for o in objects.json:
1144 606f5b54 Stavros Sachtouris
                    (dirs if self._is_dir(o) else files).append(o)
1145 74b7c6dc Stavros Sachtouris
1146 74b7c6dc Stavros Sachtouris
                #  Put the directories on top of the list
1147 74b7c6dc Stavros Sachtouris
                for dpath in sorted(['%s%s' % (
1148 74b7c6dc Stavros Sachtouris
                        local_path, d['name'][len(rpath):]) for d in dirs]):
1149 74b7c6dc Stavros Sachtouris
                    if path.exists(dpath):
1150 74b7c6dc Stavros Sachtouris
                        if path.isdir(dpath):
1151 74b7c6dc Stavros Sachtouris
                            continue
1152 74b7c6dc Stavros Sachtouris
                        raise CLIError(
1153 74b7c6dc Stavros Sachtouris
                            'Cannot replace local file %s with a directory '
1154 74b7c6dc Stavros Sachtouris
                            'of the same name' % dpath,
1155 74b7c6dc Stavros Sachtouris
                            details=[
1156 74b7c6dc Stavros Sachtouris
                                'Either remove the file or specify a'
1157 74b7c6dc Stavros Sachtouris
                                'different target location'])
1158 74b7c6dc Stavros Sachtouris
                    ret.append((None, dpath, None))
1159 74b7c6dc Stavros Sachtouris
1160 74b7c6dc Stavros Sachtouris
                #  Append the file objects
1161 74b7c6dc Stavros Sachtouris
                for opath in [o['name'] for o in files]:
1162 74b7c6dc Stavros Sachtouris
                    lpath = '%s%s' % (local_path, opath[len(rpath):])
1163 74b7c6dc Stavros Sachtouris
                    if self['resume']:
1164 74b7c6dc Stavros Sachtouris
                        fxists = path.exists(lpath)
1165 74b7c6dc Stavros Sachtouris
                        if fxists and path.isdir(lpath):
1166 74b7c6dc Stavros Sachtouris
                            raise CLIError(
1167 74b7c6dc Stavros Sachtouris
                                'Cannot change local dir %s info file' % (
1168 74b7c6dc Stavros Sachtouris
                                    lpath),
1169 74b7c6dc Stavros Sachtouris
                                details=[
1170 74b7c6dc Stavros Sachtouris
                                    'Either remove the file or specify a'
1171 74b7c6dc Stavros Sachtouris
                                    'different target location'])
1172 74b7c6dc Stavros Sachtouris
                        ret.append((opath, lpath, fxists))
1173 74b7c6dc Stavros Sachtouris
                    elif path.exists(lpath):
1174 74b7c6dc Stavros Sachtouris
                        raise CLIError(
1175 74b7c6dc Stavros Sachtouris
                            'Cannot overwrite %s' % lpath,
1176 eb647cfe Stavros Sachtouris
                            details=['To overwrite/resume, use  %s' % (
1177 eb647cfe Stavros Sachtouris
                                self.arguments['resume'].lvalue)])
1178 74b7c6dc Stavros Sachtouris
                    else:
1179 74b7c6dc Stavros Sachtouris
                        ret.append((opath, lpath, None))
1180 606f5b54 Stavros Sachtouris
            elif self.path:
1181 74b7c6dc Stavros Sachtouris
                raise CLIError(
1182 74b7c6dc Stavros Sachtouris
                    'Remote object /%s/%s is a directory' % (
1183 74b7c6dc Stavros Sachtouris
                        self.container, local_path),
1184 eb647cfe Stavros Sachtouris
                    details=['Use %s to download directories' % (
1185 eb647cfe Stavros Sachtouris
                        self.arguments['recursive'].lvalue)])
1186 a3ba3bce Stavros Sachtouris
            else:
1187 eb647cfe Stavros Sachtouris
                parsed_name = self.arguments['recursive'].lvalue
1188 606f5b54 Stavros Sachtouris
                raise CLIError(
1189 606f5b54 Stavros Sachtouris
                    'Cannot download container %s' % self.container,
1190 606f5b54 Stavros Sachtouris
                    details=[
1191 606f5b54 Stavros Sachtouris
                        'Use %s to download containers' % parsed_name,
1192 606f5b54 Stavros Sachtouris
                        '  [kamaki] file download %s /%s [LOCAL_PATH]' % (
1193 606f5b54 Stavros Sachtouris
                            parsed_name, self.container)])
1194 a3ba3bce Stavros Sachtouris
        else:
1195 74b7c6dc Stavros Sachtouris
            #  Remote object is just a file
1196 74b7c6dc Stavros Sachtouris
            if path.exists(local_path) and not self['resume']:
1197 74b7c6dc Stavros Sachtouris
                raise CLIError(
1198 74b7c6dc Stavros Sachtouris
                    'Cannot overwrite local file %s' % (lpath),
1199 eb647cfe Stavros Sachtouris
                    details=['To overwrite/resume, use  %s' % (
1200 eb647cfe Stavros Sachtouris
                        self.arguments['resume'].lvalue)])
1201 74b7c6dc Stavros Sachtouris
            ret.append((rpath, local_path, self['resume']))
1202 74b7c6dc Stavros Sachtouris
        for r, l, resume in ret:
1203 74b7c6dc Stavros Sachtouris
            if r:
1204 74b7c6dc Stavros Sachtouris
                with open(l, 'rwb+' if resume else 'wb+') as f:
1205 74b7c6dc Stavros Sachtouris
                    yield (r, f)
1206 74b7c6dc Stavros Sachtouris
            else:
1207 74b7c6dc Stavros Sachtouris
                yield (r, l)
1208 7493ccb6 Stavros Sachtouris
1209 68858765 Stavros Sachtouris
    @errors.generic.all
1210 68858765 Stavros Sachtouris
    @errors.pithos.connection
1211 68858765 Stavros Sachtouris
    @errors.pithos.container
1212 68858765 Stavros Sachtouris
    @errors.pithos.object_path
1213 68858765 Stavros Sachtouris
    @errors.pithos.local_path
1214 606f5b54 Stavros Sachtouris
    @errors.pithos.local_path_download
1215 68858765 Stavros Sachtouris
    def _run(self, local_path):
1216 ec5d658f Stavros Sachtouris
        self.client.MAX_THREADS = int(self['max_threads'] or 5)
1217 f6c09d14 Stavros Sachtouris
        progress_bar = None
1218 ae99b37d Stavros Sachtouris
        try:
1219 74b7c6dc Stavros Sachtouris
            for rpath, output_file in self._src_dst(local_path):
1220 74b7c6dc Stavros Sachtouris
                if not rpath:
1221 74b7c6dc Stavros Sachtouris
                    self.error('Create local directory %s' % output_file)
1222 74b7c6dc Stavros Sachtouris
                    makedirs(output_file)
1223 74b7c6dc Stavros Sachtouris
                    continue
1224 74b7c6dc Stavros Sachtouris
                self.error('/%s/%s --> %s' % (
1225 74b7c6dc Stavros Sachtouris
                    self.container, rpath, output_file.name))
1226 74b7c6dc Stavros Sachtouris
                progress_bar, download_cb = self._safe_progress_bar(
1227 74b7c6dc Stavros Sachtouris
                    '  download')
1228 ae99b37d Stavros Sachtouris
                self.client.download_object(
1229 74b7c6dc Stavros Sachtouris
                    rpath, output_file,
1230 ae99b37d Stavros Sachtouris
                    download_cb=download_cb,
1231 3d568c09 Stavros Sachtouris
                    range_str=self['range'],
1232 ae99b37d Stavros Sachtouris
                    version=self['object_version'],
1233 74b7c6dc Stavros Sachtouris
                    if_match=self['matching_etag'],
1234 ae99b37d Stavros Sachtouris
                    resume=self['resume'],
1235 74b7c6dc Stavros Sachtouris
                    if_none_match=self['non_matching_etag'],
1236 74b7c6dc Stavros Sachtouris
                    if_modified_since=self['modified_since_date'],
1237 74b7c6dc Stavros Sachtouris
                    if_unmodified_since=self['unmodified_since_date'])
1238 7493ccb6 Stavros Sachtouris
        except KeyboardInterrupt:
1239 b78ee581 Stavros Sachtouris
            from threading import activeCount, enumerate as activethreads
1240 cae76f25 Stavros Sachtouris
            timeout = 0.5
1241 b78ee581 Stavros Sachtouris
            while activeCount() > 1:
1242 1757c616 Stavros Sachtouris
                self._out.write('\nCancel %s threads: ' % (activeCount() - 1))
1243 1757c616 Stavros Sachtouris
                self._out.flush()
1244 b78ee581 Stavros Sachtouris
                for thread in activethreads():
1245 b78ee581 Stavros Sachtouris
                    try:
1246 cae76f25 Stavros Sachtouris
                        thread.join(timeout)
1247 1757c616 Stavros Sachtouris
                        self._out.write('.' if thread.isAlive() else '*')
1248 b78ee581 Stavros Sachtouris
                    except RuntimeError:
1249 b78ee581 Stavros Sachtouris
                        continue
1250 cae76f25 Stavros Sachtouris
                    finally:
1251 1757c616 Stavros Sachtouris
                        self._out.flush()
1252 cae76f25 Stavros Sachtouris
                        timeout += 0.1
1253 ff1c0296 Stavros Sachtouris
            self.error('\nDownload canceled by user')
1254 7493ccb6 Stavros Sachtouris
            if local_path is not None:
1255 ff1c0296 Stavros Sachtouris
                self.error('to resume, re-run with --resume')
1256 68858765 Stavros Sachtouris
        except Exception:
1257 68858765 Stavros Sachtouris
            self._safe_progress_bar_finish(progress_bar)
1258 68858765 Stavros Sachtouris
            raise
1259 68858765 Stavros Sachtouris
        finally:
1260 68858765 Stavros Sachtouris
            self._safe_progress_bar_finish(progress_bar)
1261 68858765 Stavros Sachtouris
1262 74b7c6dc Stavros Sachtouris
    def main(self, remote_path_or_url, local_path=None):
1263 74b7c6dc Stavros Sachtouris
        super(self.__class__, self)._run(remote_path_or_url)
1264 74b7c6dc Stavros Sachtouris
        local_path = local_path or self.path or '.'
1265 68858765 Stavros Sachtouris
        self._run(local_path=local_path)
1266 7493ccb6 Stavros Sachtouris
1267 234954d1 Stavros Sachtouris
1268 7b109aa7 Stavros Sachtouris
@command(container_cmds)
1269 7b109aa7 Stavros Sachtouris
class container_info(_pithos_account, _optional_json):
1270 7b109aa7 Stavros Sachtouris
    """Get information about a container"""
1271 7493ccb6 Stavros Sachtouris
1272 2fe2672e Stavros Sachtouris
    arguments = dict(
1273 7b109aa7 Stavros Sachtouris
        until_date=DateArgument('show metadata until then', '--until'),
1274 7b109aa7 Stavros Sachtouris
        metadata=FlagArgument('Show only container metadata', '--metadata'),
1275 7b109aa7 Stavros Sachtouris
        sizelimit=FlagArgument(
1276 7b109aa7 Stavros Sachtouris
            'Show the maximum size limit for container', '--size-limit'),
1277 7b109aa7 Stavros Sachtouris
        in_bytes=FlagArgument('Show size limit in bytes', ('-b', '--bytes'))
1278 2fe2672e Stavros Sachtouris
    )
1279 7493ccb6 Stavros Sachtouris
1280 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1281 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
1282 b4cf92b8 Stavros Sachtouris
    @errors.pithos.container
1283 b4cf92b8 Stavros Sachtouris
    @errors.pithos.object_path
1284 b4cf92b8 Stavros Sachtouris
    def _run(self):
1285 7b109aa7 Stavros Sachtouris
        if self['metadata']:
1286 7b109aa7 Stavros Sachtouris
            r, preflen = dict(), len('x-container-meta-')
1287 7b109aa7 Stavros Sachtouris
            for k, v in self.client.get_container_meta(
1288 7b109aa7 Stavros Sachtouris
                    until=self['until_date']).items():
1289 7b109aa7 Stavros Sachtouris
                r[k[preflen:]] = v
1290 7b109aa7 Stavros Sachtouris
        elif self['sizelimit']:
1291 7b109aa7 Stavros Sachtouris
            r = self.client.get_container_limit(
1292 7b109aa7 Stavros Sachtouris
                self.container)['x-container-policy-quota']
1293 7b109aa7 Stavros Sachtouris
            r = {'size limit': 'unlimited' if r in ('0', ) else (
1294 7b109aa7 Stavros Sachtouris
                int(r) if self['in_bytes'] else format_size(r))}
1295 76f58e2e Stavros Sachtouris
        else:
1296 7b109aa7 Stavros Sachtouris
            r = self.client.get_container_info(self.container)
1297 7b109aa7 Stavros Sachtouris
        self._print(r, self.print_dict)
1298 b4cf92b8 Stavros Sachtouris
1299 7b109aa7 Stavros Sachtouris
    def main(self, container):
1300 7b109aa7 Stavros Sachtouris
        super(self.__class__, self)._run()
1301 7b109aa7 Stavros Sachtouris
        self.container, self.client.container = container, container
1302 b4cf92b8 Stavros Sachtouris
        self._run()
1303 7493ccb6 Stavros Sachtouris
1304 234954d1 Stavros Sachtouris
1305 7b109aa7 Stavros Sachtouris
class VersioningArgument(ValueArgument):
1306 7493ccb6 Stavros Sachtouris
1307 7b109aa7 Stavros Sachtouris
    schemes = ('auto', 'none')
1308 7493ccb6 Stavros Sachtouris
1309 7b109aa7 Stavros Sachtouris
    @property
1310 7b109aa7 Stavros Sachtouris
    def value(self):
1311 7b109aa7 Stavros Sachtouris
        return getattr(self, '_value', None)
1312 b4cf92b8 Stavros Sachtouris
1313 7b109aa7 Stavros Sachtouris
    @value.setter
1314 7b109aa7 Stavros Sachtouris
    def value(self, new_scheme):
1315 7b109aa7 Stavros Sachtouris
        if new_scheme:
1316 7b109aa7 Stavros Sachtouris
            new_scheme = new_scheme.lower()
1317 7b109aa7 Stavros Sachtouris
            if new_scheme not in self.schemes:
1318 7b109aa7 Stavros Sachtouris
                raise CLIInvalidArgument('Invalid versioning value', details=[
1319 7b109aa7 Stavros Sachtouris
                    'Valid versioning values are %s' % ', '.join(
1320 7b109aa7 Stavros Sachtouris
                        self.schemes)])
1321 7b109aa7 Stavros Sachtouris
            self._value = new_scheme
1322 7493ccb6 Stavros Sachtouris
1323 234954d1 Stavros Sachtouris
1324 7b109aa7 Stavros Sachtouris
@command(container_cmds)
1325 7b109aa7 Stavros Sachtouris
class container_modify(_pithos_account, _optional_json):
1326 7b109aa7 Stavros Sachtouris
    """Modify the properties of a container"""
1327 7493ccb6 Stavros Sachtouris
1328 2fe2672e Stavros Sachtouris
    arguments = dict(
1329 7b109aa7 Stavros Sachtouris
        metadata_to_add=KeyValueArgument(
1330 7b109aa7 Stavros Sachtouris
            'Add metadata in the form KEY=VALUE (can be repeated)',
1331 7b109aa7 Stavros Sachtouris
            '--metadata-add'),
1332 7b109aa7 Stavros Sachtouris
        metadata_to_delete=RepeatableArgument(
1333 7b109aa7 Stavros Sachtouris
            'Delete metadata by KEY (can be repeated)', '--metadata-del'),
1334 7b109aa7 Stavros Sachtouris
        sizelimit=DataSizeArgument(
1335 7b109aa7 Stavros Sachtouris
            'Set max size limit (0 for unlimited, '
1336 7b109aa7 Stavros Sachtouris
            'use units B, KiB, KB, etc.)', '--size-limit'),
1337 7b109aa7 Stavros Sachtouris
        versioning=VersioningArgument(
1338 7b109aa7 Stavros Sachtouris
            'Set a versioning scheme (%s)' % ', '.join(
1339 7b109aa7 Stavros Sachtouris
                VersioningArgument.schemes), '--versioning')
1340 2fe2672e Stavros Sachtouris
    )
1341 f084bdc8 Stavros Sachtouris
    required = [
1342 f084bdc8 Stavros Sachtouris
        'metadata_to_add', 'metadata_to_delete', 'sizelimit', 'versioning']
1343 6ac7f90f Stavros Sachtouris
1344 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1345 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
1346 b4cf92b8 Stavros Sachtouris
    @errors.pithos.container
1347 7b109aa7 Stavros Sachtouris
    def _run(self, container):
1348 7b109aa7 Stavros Sachtouris
        metadata = self['metadata_to_add']
1349 f084bdc8 Stavros Sachtouris
        for k in (self['metadata_to_delete'] or []):
1350 7b109aa7 Stavros Sachtouris
            metadata[k] = ''
1351 7b109aa7 Stavros Sachtouris
        if metadata:
1352 7b109aa7 Stavros Sachtouris
            self.client.set_container_meta(metadata)
1353 7b109aa7 Stavros Sachtouris
            self._print(self.client.get_container_meta(), self.print_dict)
1354 7b109aa7 Stavros Sachtouris
        if self['sizelimit'] is not None:
1355 7b109aa7 Stavros Sachtouris
            self.client.set_container_limit(self['sizelimit'])
1356 7b109aa7 Stavros Sachtouris
            r = self.client.get_container_limit()['x-container-policy-quota']
1357 7b109aa7 Stavros Sachtouris
            r = 'unlimited' if r in ('0', ) else format_size(r)
1358 7b109aa7 Stavros Sachtouris
            self.writeln('new size limit: %s' % r)
1359 7b109aa7 Stavros Sachtouris
        if self['versioning']:
1360 7b109aa7 Stavros Sachtouris
            self.client.set_container_versioning(self['versioning'])
1361 7b109aa7 Stavros Sachtouris
            self.writeln('new versioning scheme: %s' % (
1362 7b109aa7 Stavros Sachtouris
                self.client.get_container_versioning(self.container)[
1363 7b109aa7 Stavros Sachtouris
                    'x-container-policy-versioning']))
1364 234954d1 Stavros Sachtouris
1365 7b109aa7 Stavros Sachtouris
    def main(self, container):
1366 7b109aa7 Stavros Sachtouris
        super(self.__class__, self)._run()
1367 7b109aa7 Stavros Sachtouris
        self.client.container, self.container = container, container
1368 7b109aa7 Stavros Sachtouris
        self._run(container=container)
1369 5655d560 Stavros Sachtouris
1370 5655d560 Stavros Sachtouris
1371 7b109aa7 Stavros Sachtouris
@command(container_cmds)
1372 7b109aa7 Stavros Sachtouris
class container_list(_pithos_account, _optional_json, _name_filter):
1373 7b109aa7 Stavros Sachtouris
    """List all containers, or their contents"""
1374 7493ccb6 Stavros Sachtouris
1375 2fe2672e Stavros Sachtouris
    arguments = dict(
1376 7b109aa7 Stavros Sachtouris
        detail=FlagArgument('Containers with details', ('-l', '--list')),
1377 7b109aa7 Stavros Sachtouris
        limit=IntArgument('limit number of listed items', ('-n', '--number')),
1378 7b109aa7 Stavros Sachtouris
        marker=ValueArgument('output greater that marker', '--marker'),
1379 7b109aa7 Stavros Sachtouris
        modified_since_date=ValueArgument(
1380 7b109aa7 Stavros Sachtouris
            'show output modified since then', '--if-modified-since'),
1381 7b109aa7 Stavros Sachtouris
        unmodified_since_date=ValueArgument(
1382 7b109aa7 Stavros Sachtouris
            'show output not modified since then', '--if-unmodified-since'),
1383 7b109aa7 Stavros Sachtouris
        until_date=DateArgument('show metadata until then', '--until'),
1384 7b109aa7 Stavros Sachtouris
        shared=FlagArgument('show only shared', '--shared'),
1385 7b109aa7 Stavros Sachtouris
        more=FlagArgument('read long results', '--more'),
1386 7b109aa7 Stavros Sachtouris
        enum=FlagArgument('Enumerate results', '--enumerate'),
1387 7b109aa7 Stavros Sachtouris
        recursive=FlagArgument(
1388 7b109aa7 Stavros Sachtouris
            'Recursively list containers and their contents',
1389 7b109aa7 Stavros Sachtouris
            ('-r', '--recursive'))
1390 2fe2672e Stavros Sachtouris
    )
1391 7493ccb6 Stavros Sachtouris
1392 7b109aa7 Stavros Sachtouris
    def print_containers(self, container_list):
1393 7b109aa7 Stavros Sachtouris
        for index, container in enumerate(container_list):
1394 7b109aa7 Stavros Sachtouris
            if 'bytes' in container:
1395 7b109aa7 Stavros Sachtouris
                size = format_size(container['bytes'])
1396 7b109aa7 Stavros Sachtouris
            prfx = ('%s. ' % (index + 1)) if self['enum'] else ''
1397 7b109aa7 Stavros Sachtouris
            _cname = container['name'] if (
1398 7b109aa7 Stavros Sachtouris
                self['more']) else bold(container['name'])
1399 7b109aa7 Stavros Sachtouris
            cname = u'%s%s' % (prfx, _cname)
1400 b4cf92b8 Stavros Sachtouris
            if self['detail']:
1401 7b109aa7 Stavros Sachtouris
                self.writeln(cname)
1402 7b109aa7 Stavros Sachtouris
                pretty_c = container.copy()
1403 7b109aa7 Stavros Sachtouris
                if 'bytes' in container:
1404 7b109aa7 Stavros Sachtouris
                    pretty_c['bytes'] = '%s (%s)' % (container['bytes'], size)
1405 7b109aa7 Stavros Sachtouris
                self.print_dict(pretty_c, exclude=('name'))
1406 7b109aa7 Stavros Sachtouris
                self.writeln()
1407 b4cf92b8 Stavros Sachtouris
            else:
1408 7b109aa7 Stavros Sachtouris
                if 'count' in container and 'bytes' in container:
1409 7b109aa7 Stavros Sachtouris
                    self.writeln('%s (%s, %s objects)' % (
1410 7b109aa7 Stavros Sachtouris
                        cname, size, container['count']))
1411 7b109aa7 Stavros Sachtouris
                else:
1412 7b109aa7 Stavros Sachtouris
                    self.writeln(cname)
1413 7b109aa7 Stavros Sachtouris
            objects = container.get('objects', [])
1414 7b109aa7 Stavros Sachtouris
            if objects:
1415 7b109aa7 Stavros Sachtouris
                self.print_objects(objects)
1416 7b109aa7 Stavros Sachtouris
                self.writeln('')
1417 234954d1 Stavros Sachtouris
1418 7b109aa7 Stavros Sachtouris
    def _create_object_forest(self, container_list):
1419 7b109aa7 Stavros Sachtouris
        try:
1420 7b109aa7 Stavros Sachtouris
            for container in container_list:
1421 7b109aa7 Stavros Sachtouris
                self.client.container = container['name']
1422 7b109aa7 Stavros Sachtouris
                objects = self.client.container_get(
1423 7b109aa7 Stavros Sachtouris
                    limit=False if self['more'] else self['limit'],
1424 7b109aa7 Stavros Sachtouris
                    if_modified_since=self['modified_since_date'],
1425 7b109aa7 Stavros Sachtouris
                    if_unmodified_since=self['unmodified_since_date'],
1426 7b109aa7 Stavros Sachtouris
                    until=self['until_date'],
1427 7b109aa7 Stavros Sachtouris
                    show_only_shared=self['shared'])
1428 7b109aa7 Stavros Sachtouris
                container['objects'] = objects.json
1429 7b109aa7 Stavros Sachtouris
        finally:
1430 7b109aa7 Stavros Sachtouris
            self.client.container = None
1431 7493ccb6 Stavros Sachtouris
1432 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1433 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
1434 b4cf92b8 Stavros Sachtouris
    @errors.pithos.object_path
1435 b4cf92b8 Stavros Sachtouris
    @errors.pithos.container
1436 7b109aa7 Stavros Sachtouris
    def _run(self, container):
1437 7b109aa7 Stavros Sachtouris
        if container:
1438 7b109aa7 Stavros Sachtouris
            r = self.client.container_get(
1439 7b109aa7 Stavros Sachtouris
                limit=False if self['more'] else self['limit'],
1440 7b109aa7 Stavros Sachtouris
                marker=self['marker'],
1441 7b109aa7 Stavros Sachtouris
                if_modified_since=self['modified_since_date'],
1442 7b109aa7 Stavros Sachtouris
                if_unmodified_since=self['unmodified_since_date'],
1443 7b109aa7 Stavros Sachtouris
                until=self['until_date'],
1444 7b109aa7 Stavros Sachtouris
                show_only_shared=self['shared'])
1445 b4cf92b8 Stavros Sachtouris
        else:
1446 7b109aa7 Stavros Sachtouris
            r = self.client.account_get(
1447 7b109aa7 Stavros Sachtouris
                limit=False if self['more'] else self['limit'],
1448 7b109aa7 Stavros Sachtouris
                marker=self['marker'],
1449 7b109aa7 Stavros Sachtouris
                if_modified_since=self['modified_since_date'],
1450 7b109aa7 Stavros Sachtouris
                if_unmodified_since=self['unmodified_since_date'],
1451 7b109aa7 Stavros Sachtouris
                until=self['until_date'],
1452 7b109aa7 Stavros Sachtouris
                show_only_shared=self['shared'])
1453 7b109aa7 Stavros Sachtouris
        files = self._filter_by_name(r.json)
1454 7b109aa7 Stavros Sachtouris
        if self['recursive'] and not container:
1455 7b109aa7 Stavros Sachtouris
            self._create_object_forest(files)
1456 7b109aa7 Stavros Sachtouris
        if self['more']:
1457 7b109aa7 Stavros Sachtouris
            outbu, self._out = self._out, StringIO()
1458 7b109aa7 Stavros Sachtouris
        try:
1459 7b109aa7 Stavros Sachtouris
            if self['json_output'] or self['output_format']:
1460 7b109aa7 Stavros Sachtouris
                self._print(files)
1461 7b109aa7 Stavros Sachtouris
            else:
1462 7b109aa7 Stavros Sachtouris
                (self.print_objects if container else self.print_containers)(
1463 7b109aa7 Stavros Sachtouris
                    files)
1464 7b109aa7 Stavros Sachtouris
        finally:
1465 7b109aa7 Stavros Sachtouris
            if self['more']:
1466 7b109aa7 Stavros Sachtouris
                pager(self._out.getvalue())
1467 7b109aa7 Stavros Sachtouris
                self._out = outbu
1468 b4cf92b8 Stavros Sachtouris
1469 7b109aa7 Stavros Sachtouris
    def main(self, container=None):
1470 7b109aa7 Stavros Sachtouris
        super(self.__class__, self)._run()
1471 7b109aa7 Stavros Sachtouris
        self.client.container, self.container = container, container
1472 7b109aa7 Stavros Sachtouris
        self._run(container)
1473 7493ccb6 Stavros Sachtouris
1474 234954d1 Stavros Sachtouris
1475 7b109aa7 Stavros Sachtouris
@command(container_cmds)
1476 7b109aa7 Stavros Sachtouris
class container_create(_pithos_account):
1477 7b109aa7 Stavros Sachtouris
    """Create a new container"""
1478 001200c3 Stavros Sachtouris
1479 001200c3 Stavros Sachtouris
    arguments = dict(
1480 7b109aa7 Stavros Sachtouris
        versioning=ValueArgument(
1481 7b109aa7 Stavros Sachtouris
            'set container versioning (auto/none)', '--versioning'),
1482 7b109aa7 Stavros Sachtouris
        limit=IntArgument('set default container limit', '--limit'),
1483 7b109aa7 Stavros Sachtouris
        meta=KeyValueArgument(
1484 7b109aa7 Stavros Sachtouris
            'set container metadata (can be repeated)', '--meta')
1485 de73876b Stavros Sachtouris
    )
1486 7493ccb6 Stavros Sachtouris
1487 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1488 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
1489 7b109aa7 Stavros Sachtouris
    @errors.pithos.container
1490 7b109aa7 Stavros Sachtouris
    def _run(self, container):
1491 7b109aa7 Stavros Sachtouris
        try:
1492 7b109aa7 Stavros Sachtouris
            self.client.create_container(
1493 7b109aa7 Stavros Sachtouris
                container=container,
1494 7b109aa7 Stavros Sachtouris
                sizelimit=self['limit'],
1495 7b109aa7 Stavros Sachtouris
                versioning=self['versioning'],
1496 7b109aa7 Stavros Sachtouris
                metadata=self['meta'],
1497 7b109aa7 Stavros Sachtouris
                success=(201, ))
1498 7b109aa7 Stavros Sachtouris
        except ClientError as ce:
1499 7b109aa7 Stavros Sachtouris
            if ce.status in (202, ):
1500 7b109aa7 Stavros Sachtouris
                raise CLIError(
1501 7b109aa7 Stavros Sachtouris
                    'Container %s alread exists' % container, details=[
1502 7b109aa7 Stavros Sachtouris
                    'Either delete %s or choose another name' % (container)])
1503 7b109aa7 Stavros Sachtouris
            raise
1504 234954d1 Stavros Sachtouris
1505 7b109aa7 Stavros Sachtouris
    def main(self, new_container):
1506 7b109aa7 Stavros Sachtouris
        super(self.__class__, self)._run()
1507 7b109aa7 Stavros Sachtouris
        self._run(container=new_container)
1508 326a79b9 Stavros Sachtouris
1509 326a79b9 Stavros Sachtouris
1510 7b109aa7 Stavros Sachtouris
@command(container_cmds)
1511 7b109aa7 Stavros Sachtouris
class container_delete(_pithos_account):
1512 7b109aa7 Stavros Sachtouris
    """Delete a container"""
1513 3ed6dbde Stavros Sachtouris
1514 3ed6dbde Stavros Sachtouris
    arguments = dict(
1515 7b109aa7 Stavros Sachtouris
        yes=FlagArgument('Do not prompt for permission', '--yes'),
1516 7b109aa7 Stavros Sachtouris
        recursive=FlagArgument(
1517 7b109aa7 Stavros Sachtouris
            'delete container even if not empty', ('-r', '--recursive'))
1518 3ed6dbde Stavros Sachtouris
    )
1519 3ed6dbde Stavros Sachtouris
1520 3ed6dbde Stavros Sachtouris
    @errors.generic.all
1521 7b109aa7 Stavros Sachtouris
    @errors.pithos.connection
1522 3ed6dbde Stavros Sachtouris
    @errors.pithos.container
1523 7b109aa7 Stavros Sachtouris
    def _run(self, container):
1524 7b109aa7 Stavros Sachtouris
        num_of_contents = int(self.client.get_container_info(container)[
1525 7b109aa7 Stavros Sachtouris
            'x-container-object-count'])
1526 7b109aa7 Stavros Sachtouris
        delimiter, msg = None, 'Delete container %s ?' % container
1527 7b109aa7 Stavros Sachtouris
        if self['recursive']:
1528 7b109aa7 Stavros Sachtouris
            delimiter, msg = '/', 'Empty and d%s' % msg[1:]
1529 7b109aa7 Stavros Sachtouris
        elif num_of_contents:
1530 7b109aa7 Stavros Sachtouris
            raise CLIError('Container %s is not empty' % container, details=[
1531 eb647cfe Stavros Sachtouris
                'Use %s to delete non-empty containers' % (
1532 eb647cfe Stavros Sachtouris
                    self.arguments['recursive'].lvalue)])
1533 7b109aa7 Stavros Sachtouris
        if self['yes'] or self.ask_user(msg):
1534 7b109aa7 Stavros Sachtouris
            if num_of_contents:
1535 7b109aa7 Stavros Sachtouris
                self.client.del_container(delimiter=delimiter)
1536 7b109aa7 Stavros Sachtouris
            self.client.purge_container()
1537 3ed6dbde Stavros Sachtouris
1538 7b109aa7 Stavros Sachtouris
    def main(self, container):
1539 3ed6dbde Stavros Sachtouris
        super(self.__class__, self)._run()
1540 7b109aa7 Stavros Sachtouris
        self.container, self.client.container = container, container
1541 7b109aa7 Stavros Sachtouris
        self._run(container)
1542 3ed6dbde Stavros Sachtouris
1543 3ed6dbde Stavros Sachtouris
1544 7b109aa7 Stavros Sachtouris
@command(container_cmds)
1545 7b109aa7 Stavros Sachtouris
class container_empty(_pithos_account):
1546 7b109aa7 Stavros Sachtouris
    """Empty a container"""
1547 001200c3 Stavros Sachtouris
1548 7b109aa7 Stavros Sachtouris
    arguments = dict(yes=FlagArgument('Do not prompt for permission', '--yes'))
1549 7493ccb6 Stavros Sachtouris
1550 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1551 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
1552 b4cf92b8 Stavros Sachtouris
    @errors.pithos.container
1553 7b109aa7 Stavros Sachtouris
    def _run(self, container):
1554 7b109aa7 Stavros Sachtouris
        if self['yes'] or self.ask_user('Empty container %s ?' % container):
1555 7b109aa7 Stavros Sachtouris
            self.client.del_container(delimiter='/')
1556 b4cf92b8 Stavros Sachtouris
1557 7b109aa7 Stavros Sachtouris
    def main(self, container):
1558 b4cf92b8 Stavros Sachtouris
        super(self.__class__, self)._run()
1559 7b109aa7 Stavros Sachtouris
        self.container, self.client.container = container, container
1560 7b109aa7 Stavros Sachtouris
        self._run(container)
1561 234954d1 Stavros Sachtouris
1562 915b99b5 Stavros Sachtouris
1563 bfd0f8db Stavros Sachtouris
@command(sharer_cmds)
1564 bfd0f8db Stavros Sachtouris
class sharer_list(_pithos_account, _optional_json):
1565 bfd0f8db Stavros Sachtouris
    """List accounts who share file objects with current user"""
1566 915b99b5 Stavros Sachtouris
1567 bfd0f8db Stavros Sachtouris
    arguments = dict(
1568 bfd0f8db Stavros Sachtouris
        detail=FlagArgument('show detailed output', ('-l', '--details')),
1569 bfd0f8db Stavros Sachtouris
        marker=ValueArgument('show output greater then marker', '--marker')
1570 bfd0f8db Stavros Sachtouris
    )
1571 7493ccb6 Stavros Sachtouris
1572 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1573 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
1574 b4cf92b8 Stavros Sachtouris
    def _run(self):
1575 bfd0f8db Stavros Sachtouris
        accounts = self.client.get_sharing_accounts(marker=self['marker'])
1576 bfd0f8db Stavros Sachtouris
        if not (self['json_output'] or self['output_format']):
1577 bfd0f8db Stavros Sachtouris
            usernames = self._uuids2usernames(
1578 bfd0f8db Stavros Sachtouris
                [acc['name'] for acc in accounts])
1579 bfd0f8db Stavros Sachtouris
            for item in accounts:
1580 bfd0f8db Stavros Sachtouris
                uuid = item['name']
1581 bfd0f8db Stavros Sachtouris
                item['id'], item['name'] = uuid, usernames[uuid]
1582 bfd0f8db Stavros Sachtouris
                if not self['detail']:
1583 bfd0f8db Stavros Sachtouris
                    item.pop('last_modified')
1584 bfd0f8db Stavros Sachtouris
        self._print(accounts)
1585 b4cf92b8 Stavros Sachtouris
1586 bfd0f8db Stavros Sachtouris
    def main(self):
1587 b4cf92b8 Stavros Sachtouris
        super(self.__class__, self)._run()
1588 b4cf92b8 Stavros Sachtouris
        self._run()
1589 7493ccb6 Stavros Sachtouris
1590 234954d1 Stavros Sachtouris
1591 bfd0f8db Stavros Sachtouris
@command(sharer_cmds)
1592 bfd0f8db Stavros Sachtouris
class sharer_info(_pithos_account, _optional_json):
1593 bfd0f8db Stavros Sachtouris
    """Details on a Pithos+ sharer account (default: current account)"""
1594 b4cf92b8 Stavros Sachtouris
1595 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1596 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
1597 bfd0f8db Stavros Sachtouris
    def _run(self):
1598 bfd0f8db Stavros Sachtouris
        self._print(self.client.get_account_info(), self.print_dict)
1599 b4cf92b8 Stavros Sachtouris
1600 bfd0f8db Stavros Sachtouris
    def main(self, account_uuid=None):
1601 b4cf92b8 Stavros Sachtouris
        super(self.__class__, self)._run()
1602 bfd0f8db Stavros Sachtouris
        if account_uuid:
1603 bfd0f8db Stavros Sachtouris
            self.client.account, self.account = account_uuid, account_uuid
1604 bfd0f8db Stavros Sachtouris
        self._run()
1605 7493ccb6 Stavros Sachtouris
1606 234954d1 Stavros Sachtouris
1607 bfd0f8db Stavros Sachtouris
class _pithos_group(_pithos_account):
1608 bfd0f8db Stavros Sachtouris
    prefix = 'x-account-group-'
1609 bfd0f8db Stavros Sachtouris
    preflen = len(prefix)
1610 915b99b5 Stavros Sachtouris
1611 bfd0f8db Stavros Sachtouris
    def _groups(self):
1612 bfd0f8db Stavros Sachtouris
        groups = dict()
1613 bfd0f8db Stavros Sachtouris
        for k, v in self.client.get_account_group().items():
1614 bfd0f8db Stavros Sachtouris
            groups[k[self.preflen:]] = v
1615 bfd0f8db Stavros Sachtouris
        return groups
1616 915b99b5 Stavros Sachtouris
1617 bfd0f8db Stavros Sachtouris
1618 bfd0f8db Stavros Sachtouris
@command(group_cmds)
1619 bfd0f8db Stavros Sachtouris
class group_list(_pithos_group, _optional_json):
1620 545c6c29 Stavros Sachtouris
    """list all groups and group members"""
1621 7493ccb6 Stavros Sachtouris
1622 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1623 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
1624 b4cf92b8 Stavros Sachtouris
    def _run(self):
1625 bfd0f8db Stavros Sachtouris
        self._print(self._groups(), self.print_dict)
1626 b4cf92b8 Stavros Sachtouris
1627 7493ccb6 Stavros Sachtouris
    def main(self):
1628 b4cf92b8 Stavros Sachtouris
        super(self.__class__, self)._run()
1629 b4cf92b8 Stavros Sachtouris
        self._run()
1630 7493ccb6 Stavros Sachtouris
1631 234954d1 Stavros Sachtouris
1632 bfd0f8db Stavros Sachtouris
@command(group_cmds)
1633 bfd0f8db Stavros Sachtouris
class group_create(_pithos_group, _optional_json):
1634 bfd0f8db Stavros Sachtouris
    """Create a group of users"""
1635 bfd0f8db Stavros Sachtouris
1636 bfd0f8db Stavros Sachtouris
    arguments = dict(
1637 bfd0f8db Stavros Sachtouris
        user_uuid=RepeatableArgument('Add a user to the group', '--uuid'),
1638 bfd0f8db Stavros Sachtouris
        username=RepeatableArgument('Add a user to the group', '--username')
1639 bfd0f8db Stavros Sachtouris
    )
1640 bfd0f8db Stavros Sachtouris
    required = ['user_uuid', 'user_name']
1641 7493ccb6 Stavros Sachtouris
1642 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1643 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
1644 b4cf92b8 Stavros Sachtouris
    def _run(self, groupname, *users):
1645 bfd0f8db Stavros Sachtouris
        if groupname in self._groups() and not self.ask_user(
1646 bfd0f8db Stavros Sachtouris
                'Group %s already exists, overwrite?' % groupname):
1647 bfd0f8db Stavros Sachtouris
            self.error('Aborted')
1648 bfd0f8db Stavros Sachtouris
            return
1649 bfd0f8db Stavros Sachtouris
        self.client.set_account_group(groupname, users)
1650 bfd0f8db Stavros Sachtouris
        self._print(self._groups(), self.print_dict)
1651 b4cf92b8 Stavros Sachtouris
1652 bfd0f8db Stavros Sachtouris
    def main(self, groupname):
1653 b4cf92b8 Stavros Sachtouris
        super(self.__class__, self)._run()
1654 f084bdc8 Stavros Sachtouris
        users = (self['user_uuid'] or []) + self._usernames2uuids(
1655 f084bdc8 Stavros Sachtouris
            self['username'] or []).values()
1656 b4cf92b8 Stavros Sachtouris
        if users:
1657 b4cf92b8 Stavros Sachtouris
            self._run(groupname, *users)
1658 b4cf92b8 Stavros Sachtouris
        else:
1659 bfd0f8db Stavros Sachtouris
            raise CLISyntaxError(
1660 bfd0f8db Stavros Sachtouris
                'No valid users specified, use %s or %s' % (
1661 eb647cfe Stavros Sachtouris
                    self.arguments['user_uuid'].lvalue,
1662 eb647cfe Stavros Sachtouris
                    self.arguments['username'].lvalue),
1663 bfd0f8db Stavros Sachtouris
                details=[
1664 f3a239f6 Stavros Sachtouris
                    'Check if a username or uuid is valid with',
1665 f3a239f6 Stavros Sachtouris
                    '  user uuid2username', 'OR', '  user username2uuid'])
1666 7493ccb6 Stavros Sachtouris
1667 234954d1 Stavros Sachtouris
1668 bfd0f8db Stavros Sachtouris
@command(group_cmds)
1669 bfd0f8db Stavros Sachtouris
class group_delete(_pithos_group, _optional_json):
1670 4fcc38a2 Stavros Sachtouris
    """Delete a user group"""
1671 7493ccb6 Stavros Sachtouris
1672 b4cf92b8 Stavros Sachtouris
    @errors.generic.all
1673 b4cf92b8 Stavros Sachtouris
    @errors.pithos.connection
1674 b4cf92b8 Stavros Sachtouris
    def _run(self, groupname):
1675 bfd0f8db Stavros Sachtouris
        self.client.del_account_group(groupname)
1676 bfd0f8db Stavros Sachtouris
        self._print(self._groups(), self.print_dict)
1677 b4cf92b8 Stavros Sachtouris
1678 7493ccb6 Stavros Sachtouris
    def main(self, groupname):
1679 b4cf92b8 Stavros Sachtouris
        super(self.__class__, self)._run()
1680 b4cf92b8 Stavros Sachtouris
        self._run(groupname)