Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / commands / pithos.py @ 3042fac1

History | View | Annotate | Download (69.5 kB)

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