Statistics
| Branch: | Tag: | Revision:

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

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