Statistics
| Branch: | Tag: | Revision:

root / tools / store @ 961f2fbe

History | View | Annotate | Download (23.3 kB)

1 cfac048c Giorgos Verigakis
#!/usr/bin/env python
2 cfac048c Giorgos Verigakis
3 a4c10cbc Sofia Papagiannaki
# Copyright 2011 GRNET S.A. All rights reserved.
4 a4c10cbc Sofia Papagiannaki
# 
5 a4c10cbc Sofia Papagiannaki
# Redistribution and use in source and binary forms, with or
6 a4c10cbc Sofia Papagiannaki
# without modification, are permitted provided that the following
7 a4c10cbc Sofia Papagiannaki
# conditions are met:
8 a4c10cbc Sofia Papagiannaki
# 
9 a4c10cbc Sofia Papagiannaki
#   1. Redistributions of source code must retain the above
10 a4c10cbc Sofia Papagiannaki
#      copyright notice, this list of conditions and the following
11 a4c10cbc Sofia Papagiannaki
#      disclaimer.
12 a4c10cbc Sofia Papagiannaki
# 
13 a4c10cbc Sofia Papagiannaki
#   2. Redistributions in binary form must reproduce the above
14 a4c10cbc Sofia Papagiannaki
#      copyright notice, this list of conditions and the following
15 a4c10cbc Sofia Papagiannaki
#      disclaimer in the documentation and/or other materials
16 a4c10cbc Sofia Papagiannaki
#      provided with the distribution.
17 a4c10cbc Sofia Papagiannaki
# 
18 a4c10cbc Sofia Papagiannaki
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
19 a4c10cbc Sofia Papagiannaki
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 a4c10cbc Sofia Papagiannaki
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 a4c10cbc Sofia Papagiannaki
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
22 a4c10cbc Sofia Papagiannaki
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 a4c10cbc Sofia Papagiannaki
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 a4c10cbc Sofia Papagiannaki
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
25 a4c10cbc Sofia Papagiannaki
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 a4c10cbc Sofia Papagiannaki
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 a4c10cbc Sofia Papagiannaki
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 a4c10cbc Sofia Papagiannaki
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 a4c10cbc Sofia Papagiannaki
# POSSIBILITY OF SUCH DAMAGE.
30 a4c10cbc Sofia Papagiannaki
# 
31 a4c10cbc Sofia Papagiannaki
# The views and conclusions contained in the software and
32 a4c10cbc Sofia Papagiannaki
# documentation are those of the authors and should not be
33 a4c10cbc Sofia Papagiannaki
# interpreted as representing official policies, either expressed
34 a4c10cbc Sofia Papagiannaki
# or implied, of GRNET S.A.
35 a4c10cbc Sofia Papagiannaki
36 cfac048c Giorgos Verigakis
from getpass import getuser
37 cfac048c Giorgos Verigakis
from optparse import OptionParser
38 cfac048c Giorgos Verigakis
from os.path import basename
39 f07c5a53 Sofia Papagiannaki
from sys import argv, exit, stdin, stdout
40 3f5b02c7 Sofia Papagiannaki
from pithos.lib.client import Client, Fault
41 d2d5c360 Sofia Papagiannaki
from datetime import datetime
42 cfac048c Giorgos Verigakis
43 cfac048c Giorgos Verigakis
import json
44 cfac048c Giorgos Verigakis
import logging
45 f07c5a53 Sofia Papagiannaki
import types
46 d2d5c360 Sofia Papagiannaki
import re
47 d2d5c360 Sofia Papagiannaki
import time as _time
48 cfac048c Giorgos Verigakis
49 e5cd3e33 Sofia Papagiannaki
DEFAULT_HOST = 'pithos.dev.grnet.gr'
50 cfac048c Giorgos Verigakis
DEFAULT_API = 'v1'
51 cfac048c Giorgos Verigakis
52 cfac048c Giorgos Verigakis
_cli_commands = {}
53 cfac048c Giorgos Verigakis
54 cfac048c Giorgos Verigakis
def cli_command(*args):
55 cfac048c Giorgos Verigakis
    def decorator(cls):
56 cfac048c Giorgos Verigakis
        cls.commands = args
57 cfac048c Giorgos Verigakis
        for name in args:
58 cfac048c Giorgos Verigakis
            _cli_commands[name] = cls
59 cfac048c Giorgos Verigakis
        return cls
60 cfac048c Giorgos Verigakis
    return decorator
61 cfac048c Giorgos Verigakis
62 cfac048c Giorgos Verigakis
def class_for_cli_command(name):
63 cfac048c Giorgos Verigakis
    return _cli_commands[name]
64 cfac048c Giorgos Verigakis
65 cfac048c Giorgos Verigakis
class Command(object):
66 cfac048c Giorgos Verigakis
    def __init__(self, argv):
67 cfac048c Giorgos Verigakis
        parser = OptionParser()
68 f07c5a53 Sofia Papagiannaki
        parser.add_option('--host', dest='host', metavar='HOST',
69 f07c5a53 Sofia Papagiannaki
                          default=DEFAULT_HOST, help='use server HOST')
70 f07c5a53 Sofia Papagiannaki
        parser.add_option('--user', dest='user', metavar='USERNAME',
71 f07c5a53 Sofia Papagiannaki
                          default=getuser(), help='use account USERNAME')
72 f07c5a53 Sofia Papagiannaki
        parser.add_option('--api', dest='api', metavar='API',
73 f07c5a53 Sofia Papagiannaki
                          default=DEFAULT_API, help='use api API')
74 f07c5a53 Sofia Papagiannaki
        parser.add_option('-v', action='store_true', dest='verbose',
75 f07c5a53 Sofia Papagiannaki
                          default=False, help='use verbose output')
76 f07c5a53 Sofia Papagiannaki
        parser.add_option('-d', action='store_true', dest='debug',
77 f07c5a53 Sofia Papagiannaki
                          default=False, help='use debug output')
78 cfac048c Giorgos Verigakis
        self.add_options(parser)
79 cfac048c Giorgos Verigakis
        options, args = parser.parse_args(argv)
80 cfac048c Giorgos Verigakis
        
81 cfac048c Giorgos Verigakis
        # Add options to self
82 cfac048c Giorgos Verigakis
        for opt in parser.option_list:
83 cfac048c Giorgos Verigakis
            key = opt.dest
84 cfac048c Giorgos Verigakis
            if key:
85 cfac048c Giorgos Verigakis
                val = getattr(options, key)
86 cfac048c Giorgos Verigakis
                setattr(self, key, val)
87 cfac048c Giorgos Verigakis
        
88 f07c5a53 Sofia Papagiannaki
        self.client = Client(self.host, self.user, self.api, self.verbose,
89 f07c5a53 Sofia Papagiannaki
                             self.debug)
90 cfac048c Giorgos Verigakis
        
91 cfac048c Giorgos Verigakis
        self.parser = parser
92 cfac048c Giorgos Verigakis
        self.args = args
93 f7ab99df Sofia Papagiannaki
        
94 cfac048c Giorgos Verigakis
    def add_options(self, parser):
95 cfac048c Giorgos Verigakis
        pass
96 f7ab99df Sofia Papagiannaki
    
97 cfac048c Giorgos Verigakis
    def execute(self, *args):
98 cfac048c Giorgos Verigakis
        pass
99 cfac048c Giorgos Verigakis
100 cfac048c Giorgos Verigakis
@cli_command('list', 'ls')
101 cfac048c Giorgos Verigakis
class List(Command):
102 f07c5a53 Sofia Papagiannaki
    syntax = '[<container>[/<object>]]'
103 cfac048c Giorgos Verigakis
    description = 'list containers or objects'
104 cfac048c Giorgos Verigakis
    
105 cfac048c Giorgos Verigakis
    def add_options(self, parser):
106 3f5b02c7 Sofia Papagiannaki
        parser.add_option('-l', action='store_true', dest='detail',
107 3f5b02c7 Sofia Papagiannaki
                          default=False, help='show detailed output')
108 3f5b02c7 Sofia Papagiannaki
        parser.add_option('-n', action='store', type='int', dest='limit',
109 3f5b02c7 Sofia Papagiannaki
                          default=1000, help='show limited output')
110 3f5b02c7 Sofia Papagiannaki
        parser.add_option('--marker', action='store', type='str',
111 3f5b02c7 Sofia Papagiannaki
                          dest='marker', default=None,
112 3f5b02c7 Sofia Papagiannaki
                          help='show output greater then marker')
113 3f5b02c7 Sofia Papagiannaki
        parser.add_option('--prefix', action='store', type='str',
114 3f5b02c7 Sofia Papagiannaki
                          dest='prefix', default=None,
115 3f5b02c7 Sofia Papagiannaki
                          help='show output starting with prefix')
116 3f5b02c7 Sofia Papagiannaki
        parser.add_option('--delimiter', action='store', type='str',
117 3f5b02c7 Sofia Papagiannaki
                          dest='delimiter', default=None,
118 3f5b02c7 Sofia Papagiannaki
                          help='show output up to the delimiter')
119 3f5b02c7 Sofia Papagiannaki
        parser.add_option('--path', action='store', type='str',
120 3f5b02c7 Sofia Papagiannaki
                          dest='path', default=None,
121 3f5b02c7 Sofia Papagiannaki
                          help='show output starting with prefix up to /')
122 3f5b02c7 Sofia Papagiannaki
        parser.add_option('--meta', action='store', type='str',
123 3f5b02c7 Sofia Papagiannaki
                          dest='meta', default=None,
124 3f5b02c7 Sofia Papagiannaki
                          help='show output having the specified meta keys')
125 3f5b02c7 Sofia Papagiannaki
        parser.add_option('--if-modified-since', action='store', type='str',
126 3f5b02c7 Sofia Papagiannaki
                          dest='if_modified_since', default=None,
127 3f5b02c7 Sofia Papagiannaki
                          help='show output if modified since then')
128 3f5b02c7 Sofia Papagiannaki
        parser.add_option('--if-unmodified-since', action='store', type='str',
129 3f5b02c7 Sofia Papagiannaki
                          dest='if_unmodified_since', default=None,
130 3f5b02c7 Sofia Papagiannaki
                          help='show output if not modified since then')
131 d2d5c360 Sofia Papagiannaki
        parser.add_option('--until', action='store', dest='until',
132 d2d5c360 Sofia Papagiannaki
                          default=False, help='show metadata until that date')
133 d2d5c360 Sofia Papagiannaki
        parser.add_option('--format', action='store', dest='format',
134 d2d5c360 Sofia Papagiannaki
                          default='%d/%m/%Y', help='format to parse until date')
135 f7ab99df Sofia Papagiannaki
    
136 cfac048c Giorgos Verigakis
    def execute(self, container=None):
137 cfac048c Giorgos Verigakis
        if container:
138 cfac048c Giorgos Verigakis
            self.list_objects(container)
139 cfac048c Giorgos Verigakis
        else:
140 cfac048c Giorgos Verigakis
            self.list_containers()
141 f7ab99df Sofia Papagiannaki
    
142 cfac048c Giorgos Verigakis
    def list_containers(self):
143 f07c5a53 Sofia Papagiannaki
        params = {'limit':self.limit, 'marker':self.marker}
144 f07c5a53 Sofia Papagiannaki
        headers = {'IF_MODIFIED_SINCE':self.if_modified_since,
145 f07c5a53 Sofia Papagiannaki
                   'IF_UNMODIFIED_SINCE':self.if_unmodified_since}
146 d2d5c360 Sofia Papagiannaki
        
147 d2d5c360 Sofia Papagiannaki
        if self.until:
148 d2d5c360 Sofia Papagiannaki
            t = _time.strptime(self.until, self.format)
149 d2d5c360 Sofia Papagiannaki
            params['until'] = int(_time.mktime(t))
150 d2d5c360 Sofia Papagiannaki
        
151 f07c5a53 Sofia Papagiannaki
        l = self.client.list_containers(self.detail, params, headers)
152 f07c5a53 Sofia Papagiannaki
        print_list(l)
153 f7ab99df Sofia Papagiannaki
    
154 cfac048c Giorgos Verigakis
    def list_objects(self, container):
155 f07c5a53 Sofia Papagiannaki
        params = {'limit':self.limit, 'marker':self.marker,
156 f07c5a53 Sofia Papagiannaki
                  'prefix':self.prefix, 'delimiter':self.delimiter,
157 f07c5a53 Sofia Papagiannaki
                  'path':self.path, 'meta':self.meta}
158 f07c5a53 Sofia Papagiannaki
        headers = {'IF_MODIFIED_SINCE':self.if_modified_since,
159 f07c5a53 Sofia Papagiannaki
                   'IF_UNMODIFIED_SINCE':self.if_unmodified_since}
160 d2d5c360 Sofia Papagiannaki
        container, sep, object = container.partition('/')
161 d2d5c360 Sofia Papagiannaki
        if object:
162 d2d5c360 Sofia Papagiannaki
            return
163 d2d5c360 Sofia Papagiannaki
        
164 d2d5c360 Sofia Papagiannaki
        if self.until:
165 d2d5c360 Sofia Papagiannaki
            t = _time.strptime(self.until, self.format)
166 d2d5c360 Sofia Papagiannaki
            params['until'] = int(_time.mktime(t))
167 d2d5c360 Sofia Papagiannaki
        
168 a4c10cbc Sofia Papagiannaki
        detail = 'json'
169 a4c10cbc Sofia Papagiannaki
        l = self.client.list_objects(container, detail, params, headers)
170 a4c10cbc Sofia Papagiannaki
        print_list(l, detail=self.detail)
171 cfac048c Giorgos Verigakis
172 cfac048c Giorgos Verigakis
@cli_command('meta')
173 cfac048c Giorgos Verigakis
class Meta(Command):
174 cfac048c Giorgos Verigakis
    syntax = '[<container>[/<object>]]'
175 cfac048c Giorgos Verigakis
    description = 'get the metadata of an account, a container or an object'
176 0ea1dcc4 Sofia Papagiannaki
    
177 0ea1dcc4 Sofia Papagiannaki
    def add_options(self, parser):
178 0ea1dcc4 Sofia Papagiannaki
        parser.add_option('-r', action='store_true', dest='restricted',
179 0ea1dcc4 Sofia Papagiannaki
                          default=False, help='show only user defined metadata')
180 d2d5c360 Sofia Papagiannaki
        parser.add_option('--until', action='store', dest='until',
181 d2d5c360 Sofia Papagiannaki
                          default=False, help='show metadata until that date')
182 d2d5c360 Sofia Papagiannaki
        parser.add_option('--format', action='store', dest='format',
183 d2d5c360 Sofia Papagiannaki
                          default='%d/%m/%Y', help='format to parse until date')
184 e3fd7f91 Sofia Papagiannaki
        parser.add_option('--version', action='store', dest='version',
185 e3fd7f91 Sofia Papagiannaki
                          default=None, help='show specific version \
186 e3fd7f91 Sofia Papagiannaki
                                  (applies only for objects)')
187 f7ab99df Sofia Papagiannaki
    
188 cfac048c Giorgos Verigakis
    def execute(self, path=''):
189 cfac048c Giorgos Verigakis
        container, sep, object = path.partition('/')
190 d2d5c360 Sofia Papagiannaki
        if self.until:
191 d2d5c360 Sofia Papagiannaki
            t = _time.strptime(self.until, self.format)
192 d2d5c360 Sofia Papagiannaki
            self.until = int(_time.mktime(t))
193 cfac048c Giorgos Verigakis
        if object:
194 0ea1dcc4 Sofia Papagiannaki
            meta = self.client.retrieve_object_metadata(container, object,
195 8fe01d72 Sofia Papagiannaki
                                                        self.restricted,
196 8fe01d72 Sofia Papagiannaki
                                                        self.version)
197 cfac048c Giorgos Verigakis
        elif container:
198 0ea1dcc4 Sofia Papagiannaki
            meta = self.client.retrieve_container_metadata(container,
199 d2d5c360 Sofia Papagiannaki
                                                           self.restricted,
200 d2d5c360 Sofia Papagiannaki
                                                           self.until)
201 cfac048c Giorgos Verigakis
        else:
202 d2d5c360 Sofia Papagiannaki
            meta = self.client.account_metadata(self.restricted, self.until)
203 f07c5a53 Sofia Papagiannaki
        if meta == None:
204 f07c5a53 Sofia Papagiannaki
            print 'Entity does not exist'
205 f07c5a53 Sofia Papagiannaki
        else:
206 f07c5a53 Sofia Papagiannaki
            print_dict(meta, header=None)
207 cfac048c Giorgos Verigakis
208 cfac048c Giorgos Verigakis
@cli_command('create')
209 cfac048c Giorgos Verigakis
class CreateContainer(Command):
210 f07c5a53 Sofia Papagiannaki
    syntax = '<container> [key=val] [...]'
211 cfac048c Giorgos Verigakis
    description = 'create a container'
212 cfac048c Giorgos Verigakis
    
213 f07c5a53 Sofia Papagiannaki
    def execute(self, container, *args):
214 f07c5a53 Sofia Papagiannaki
        headers = {}
215 f07c5a53 Sofia Papagiannaki
        for arg in args:
216 f07c5a53 Sofia Papagiannaki
            key, sep, val = arg.partition('=')
217 f07c5a53 Sofia Papagiannaki
            headers['X_CONTAINER_META_%s' %key.strip().upper()] = val.strip()
218 f07c5a53 Sofia Papagiannaki
        ret = self.client.create_container(container, headers)
219 cfac048c Giorgos Verigakis
        if not ret:
220 cfac048c Giorgos Verigakis
            print 'Container already exists'
221 cfac048c Giorgos Verigakis
222 cfac048c Giorgos Verigakis
@cli_command('delete', 'rm')
223 cfac048c Giorgos Verigakis
class Delete(Command):
224 cfac048c Giorgos Verigakis
    syntax = '<container>[/<object>]'
225 cfac048c Giorgos Verigakis
    description = 'delete a container or an object'
226 cfac048c Giorgos Verigakis
    
227 cfac048c Giorgos Verigakis
    def execute(self, path):
228 cfac048c Giorgos Verigakis
        container, sep, object = path.partition('/')
229 cfac048c Giorgos Verigakis
        if object:
230 cfac048c Giorgos Verigakis
            self.client.delete_object(container, object)
231 cfac048c Giorgos Verigakis
        else:
232 cfac048c Giorgos Verigakis
            self.client.delete_container(container)
233 cfac048c Giorgos Verigakis
234 cfac048c Giorgos Verigakis
@cli_command('get')
235 cfac048c Giorgos Verigakis
class GetObject(Command):
236 cfac048c Giorgos Verigakis
    syntax = '<container>/<object>'
237 cfac048c Giorgos Verigakis
    description = 'get the data of an object'
238 cfac048c Giorgos Verigakis
    
239 f07c5a53 Sofia Papagiannaki
    def add_options(self, parser):
240 f07c5a53 Sofia Papagiannaki
        parser.add_option('-l', action='store_true', dest='detail',
241 f07c5a53 Sofia Papagiannaki
                          default=False, help='show detailed output')
242 f07c5a53 Sofia Papagiannaki
        parser.add_option('--range', action='store', dest='range',
243 f07c5a53 Sofia Papagiannaki
                          default=None, help='show range of data')
244 f07c5a53 Sofia Papagiannaki
        parser.add_option('--if-match', action='store', dest='if-match',
245 f07c5a53 Sofia Papagiannaki
                          default=None, help='show output if ETags match')
246 f07c5a53 Sofia Papagiannaki
        parser.add_option('--if-none-match', action='store',
247 f07c5a53 Sofia Papagiannaki
                          dest='if-none-match', default=None,
248 f07c5a53 Sofia Papagiannaki
                          help='show output if ETags don\'t match')
249 f07c5a53 Sofia Papagiannaki
        parser.add_option('--if-modified-since', action='store', type='str',
250 f07c5a53 Sofia Papagiannaki
                          dest='if-modified-since', default=None,
251 f07c5a53 Sofia Papagiannaki
                          help='show output if modified since then')
252 f07c5a53 Sofia Papagiannaki
        parser.add_option('--if-unmodified-since', action='store', type='str',
253 f07c5a53 Sofia Papagiannaki
                          dest='if-unmodified-since', default=None,
254 f07c5a53 Sofia Papagiannaki
                          help='show output if not modified since then')
255 f07c5a53 Sofia Papagiannaki
        parser.add_option('-f', action='store', type='str',
256 f07c5a53 Sofia Papagiannaki
                          dest='file', default=None,
257 f07c5a53 Sofia Papagiannaki
                          help='save output in file')
258 8fe01d72 Sofia Papagiannaki
        parser.add_option('--version', action='store', type='str',
259 ad71a0ce Sofia Papagiannaki
                          dest='version', default=None,
260 085a31d7 Sofia Papagiannaki
                          help='get the specific \
261 8fe01d72 Sofia Papagiannaki
                               version')
262 085a31d7 Sofia Papagiannaki
        parser.add_option('--versionlist', action='store_true',
263 085a31d7 Sofia Papagiannaki
                          dest='versionlist', default=False,
264 085a31d7 Sofia Papagiannaki
                          help='get the full object version list')
265 f7ab99df Sofia Papagiannaki
    
266 cfac048c Giorgos Verigakis
    def execute(self, path):
267 f07c5a53 Sofia Papagiannaki
        headers = {}
268 f07c5a53 Sofia Papagiannaki
        if self.range:
269 f07c5a53 Sofia Papagiannaki
            headers['RANGE'] = 'bytes=%s' %self.range
270 f07c5a53 Sofia Papagiannaki
        attrs = ['if-match', 'if-none-match', 'if-modified-since',
271 f07c5a53 Sofia Papagiannaki
                 'if-unmodified-since']
272 f07c5a53 Sofia Papagiannaki
        attrs = [a for a in attrs if getattr(self, a)]
273 f07c5a53 Sofia Papagiannaki
        for a in attrs:
274 f07c5a53 Sofia Papagiannaki
            headers[a.replace('-', '_').upper()] = getattr(self, a)
275 cfac048c Giorgos Verigakis
        container, sep, object = path.partition('/')
276 085a31d7 Sofia Papagiannaki
        if self.versionlist:
277 085a31d7 Sofia Papagiannaki
            self.version = 'list'
278 085a31d7 Sofia Papagiannaki
            self.detail = True
279 f07c5a53 Sofia Papagiannaki
        data = self.client.retrieve_object(container, object, self.detail,
280 8fe01d72 Sofia Papagiannaki
                                          headers, self.version)
281 8fe01d72 Sofia Papagiannaki
        f = self.file and open(self.file, 'w') or stdout
282 8fe01d72 Sofia Papagiannaki
        if self.detail:
283 8fe01d72 Sofia Papagiannaki
            data = json.loads(data)
284 085a31d7 Sofia Papagiannaki
            if self.versionlist:
285 8fe01d72 Sofia Papagiannaki
                print_versions(data, f=f)
286 f07c5a53 Sofia Papagiannaki
            else:
287 8fe01d72 Sofia Papagiannaki
                print_dict(data, f=f)
288 f07c5a53 Sofia Papagiannaki
        else:
289 8fe01d72 Sofia Papagiannaki
            f.write(data)
290 8fe01d72 Sofia Papagiannaki
        f.close()
291 cfac048c Giorgos Verigakis
292 f7ab99df Sofia Papagiannaki
@cli_command('mkdir')
293 f7ab99df Sofia Papagiannaki
class PutMarker(Command):
294 f7ab99df Sofia Papagiannaki
    syntax = '<container>/<directory marker>'
295 f7ab99df Sofia Papagiannaki
    description = 'create a directory marker'
296 f7ab99df Sofia Papagiannaki
    
297 f7ab99df Sofia Papagiannaki
    def execute(self, path):
298 f7ab99df Sofia Papagiannaki
        container, sep, object = path.partition('/')
299 f7ab99df Sofia Papagiannaki
        self.client.create_directory_marker(container, object)
300 f7ab99df Sofia Papagiannaki
301 cfac048c Giorgos Verigakis
@cli_command('put')
302 cfac048c Giorgos Verigakis
class PutObject(Command):
303 f07c5a53 Sofia Papagiannaki
    syntax = '<container>/<object> <path> [key=val] [...]'
304 f07c5a53 Sofia Papagiannaki
    description = 'create/override object with path contents or standard input'
305 f7ab99df Sofia Papagiannaki
    
306 f07c5a53 Sofia Papagiannaki
    def add_options(self, parser):
307 f07c5a53 Sofia Papagiannaki
        parser.add_option('--chunked', action='store_true', dest='chunked',
308 f07c5a53 Sofia Papagiannaki
                          default=False, help='set chunked transfer mode')
309 f07c5a53 Sofia Papagiannaki
        parser.add_option('--etag', action='store', dest='etag',
310 f07c5a53 Sofia Papagiannaki
                          default=None, help='check written data')
311 f07c5a53 Sofia Papagiannaki
        parser.add_option('--content-encoding', action='store',
312 f07c5a53 Sofia Papagiannaki
                          dest='content-encoding', default=None,
313 f07c5a53 Sofia Papagiannaki
                          help='provide the object MIME content type')
314 f07c5a53 Sofia Papagiannaki
        parser.add_option('--content-disposition', action='store', type='str',
315 f07c5a53 Sofia Papagiannaki
                          dest='content-disposition', default=None,
316 f07c5a53 Sofia Papagiannaki
                          help='provide the presentation style of the object')
317 961f2fbe Sofia Papagiannaki
        parser.add_option('-S', action='store',
318 961f2fbe Sofia Papagiannaki
                          dest='segment-size', default=False,
319 f07c5a53 Sofia Papagiannaki
                          help='use for large file support')
320 961f2fbe Sofia Papagiannaki
        parser.add_option('--manifest', action='store_true',
321 961f2fbe Sofia Papagiannaki
                          dest='manifest', default=None,
322 961f2fbe Sofia Papagiannaki
                          help='upload a manifestation file')
323 f7ab99df Sofia Papagiannaki
        parser.add_option('--type', action='store',
324 f7ab99df Sofia Papagiannaki
                          dest='content-type', default=False,
325 f7ab99df Sofia Papagiannaki
                          help='create object with specific content type')
326 d2d5c360 Sofia Papagiannaki
        parser.add_option('--touch', action='store_true',
327 e3fd7f91 Sofia Papagiannaki
                          dest='touch', default=False,
328 d2d5c360 Sofia Papagiannaki
                          help='create object with zero data')
329 f7ab99df Sofia Papagiannaki
    
330 d2d5c360 Sofia Papagiannaki
    def execute(self, path, srcpath='-', *args):
331 f07c5a53 Sofia Papagiannaki
        headers = {}
332 f07c5a53 Sofia Papagiannaki
        if self.manifest:
333 f07c5a53 Sofia Papagiannaki
            headers['X_OBJECT_MANIFEST'] = self.manifest
334 f7ab99df Sofia Papagiannaki
        
335 f7ab99df Sofia Papagiannaki
        attrs = ['etag', 'content-encoding', 'content-disposition',
336 f7ab99df Sofia Papagiannaki
                 'content-type']
337 f07c5a53 Sofia Papagiannaki
        attrs = [a for a in attrs if getattr(self, a)]
338 f07c5a53 Sofia Papagiannaki
        for a in attrs:
339 f07c5a53 Sofia Papagiannaki
            headers[a.replace('-', '_').upper()] = getattr(self, a)
340 f07c5a53 Sofia Papagiannaki
        
341 f07c5a53 Sofia Papagiannaki
        #prepare user defined meta
342 f07c5a53 Sofia Papagiannaki
        for arg in args:
343 f07c5a53 Sofia Papagiannaki
            key, sep, val = arg.partition('=')
344 f07c5a53 Sofia Papagiannaki
            headers['X_OBJECT_META_%s' %key.strip().upper()] = val.strip()
345 f07c5a53 Sofia Papagiannaki
        
346 cfac048c Giorgos Verigakis
        container, sep, object = path.partition('/')
347 f07c5a53 Sofia Papagiannaki
        
348 d2d5c360 Sofia Papagiannaki
        f = None
349 d2d5c360 Sofia Papagiannaki
        chunked = False
350 d2d5c360 Sofia Papagiannaki
        if not self.touch:
351 d2d5c360 Sofia Papagiannaki
            f = srcpath != '-' and open(srcpath) or stdin
352 d2d5c360 Sofia Papagiannaki
            chunked = (self.chunked or f == stdin) and True or False
353 f07c5a53 Sofia Papagiannaki
        self.client.create_object(container, object, f, chunked=chunked,
354 f07c5a53 Sofia Papagiannaki
                                  headers=headers)
355 d2d5c360 Sofia Papagiannaki
        if f:
356 d2d5c360 Sofia Papagiannaki
            f.close()
357 cfac048c Giorgos Verigakis
358 cfac048c Giorgos Verigakis
@cli_command('copy', 'cp')
359 cfac048c Giorgos Verigakis
class CopyObject(Command):
360 cfac048c Giorgos Verigakis
    syntax = '<src container>/<src object> [<dst container>/]<dst object>'
361 cfac048c Giorgos Verigakis
    description = 'copies an object to a different location'
362 cfac048c Giorgos Verigakis
    
363 ad71a0ce Sofia Papagiannaki
    def add_options(self, parser):
364 ad71a0ce Sofia Papagiannaki
        parser.add_option('--version', action='store',
365 ad71a0ce Sofia Papagiannaki
                          dest='version', default=False,
366 ad71a0ce Sofia Papagiannaki
                          help='copy specific version')
367 f7ab99df Sofia Papagiannaki
    
368 cfac048c Giorgos Verigakis
    def execute(self, src, dst):
369 cfac048c Giorgos Verigakis
        src_container, sep, src_object = src.partition('/')
370 cfac048c Giorgos Verigakis
        dst_container, sep, dst_object = dst.partition('/')
371 cfac048c Giorgos Verigakis
        if not sep:
372 cfac048c Giorgos Verigakis
            dst_container = src_container
373 cfac048c Giorgos Verigakis
            dst_object = dst
374 ad71a0ce Sofia Papagiannaki
        version = getattr(self, 'version')
375 ad71a0ce Sofia Papagiannaki
        if version:
376 ad71a0ce Sofia Papagiannaki
            headers = {}
377 7e999dec Sofia Papagiannaki
            headers['X_SOURCE_VERSION'] = version
378 f07c5a53 Sofia Papagiannaki
        self.client.copy_object(src_container, src_object, dst_container,
379 7e999dec Sofia Papagiannaki
                                dst_object, headers)
380 cfac048c Giorgos Verigakis
381 cfac048c Giorgos Verigakis
@cli_command('set')
382 3f5b02c7 Sofia Papagiannaki
class SetMeta(Command):
383 3f5b02c7 Sofia Papagiannaki
    syntax = '[<container>[/<object>]] key=val [key=val] [...]'
384 3f5b02c7 Sofia Papagiannaki
    description = 'set metadata'
385 cfac048c Giorgos Verigakis
    
386 cfac048c Giorgos Verigakis
    def execute(self, path, *args):
387 3f5b02c7 Sofia Papagiannaki
        #in case of account fix the args
388 f07c5a53 Sofia Papagiannaki
        if path.find('=') != -1:
389 3f5b02c7 Sofia Papagiannaki
            args = list(args)
390 3f5b02c7 Sofia Papagiannaki
            args.append(path)
391 3f5b02c7 Sofia Papagiannaki
            args = tuple(args)
392 3f5b02c7 Sofia Papagiannaki
            path = ''
393 cfac048c Giorgos Verigakis
        meta = {}
394 cfac048c Giorgos Verigakis
        for arg in args:
395 cfac048c Giorgos Verigakis
            key, sep, val = arg.partition('=')
396 cfac048c Giorgos Verigakis
            meta[key.strip()] = val.strip()
397 3f5b02c7 Sofia Papagiannaki
        container, sep, object = path.partition('/')
398 3f5b02c7 Sofia Papagiannaki
        if object:
399 3f5b02c7 Sofia Papagiannaki
            self.client.update_object_metadata(container, object, **meta)
400 3f5b02c7 Sofia Papagiannaki
        elif container:
401 3f5b02c7 Sofia Papagiannaki
            self.client.update_container_metadata(container, **meta)
402 3f5b02c7 Sofia Papagiannaki
        else:
403 3f5b02c7 Sofia Papagiannaki
            self.client.update_account_metadata(**meta)
404 cfac048c Giorgos Verigakis
405 f07c5a53 Sofia Papagiannaki
@cli_command('update')
406 f07c5a53 Sofia Papagiannaki
class UpdateObject(Command):
407 f07c5a53 Sofia Papagiannaki
    syntax = '<container>/<object> path [key=val] [...]'
408 e3fd7f91 Sofia Papagiannaki
    description = 'update object metadata/data (default mode: append)'
409 f07c5a53 Sofia Papagiannaki
    
410 f07c5a53 Sofia Papagiannaki
    def add_options(self, parser):
411 f07c5a53 Sofia Papagiannaki
        parser.add_option('-a', action='store_true', dest='append',
412 e3fd7f91 Sofia Papagiannaki
                          default=True, help='append data')
413 f07c5a53 Sofia Papagiannaki
        parser.add_option('--start', action='store',
414 f07c5a53 Sofia Papagiannaki
                          dest='start',
415 f07c5a53 Sofia Papagiannaki
                          default=None, help='range of data to be updated')
416 f07c5a53 Sofia Papagiannaki
        parser.add_option('--range', action='store', dest='content-range',
417 f07c5a53 Sofia Papagiannaki
                          default=None, help='range of data to be updated')
418 f07c5a53 Sofia Papagiannaki
        parser.add_option('--chunked', action='store_true', dest='chunked',
419 f07c5a53 Sofia Papagiannaki
                          default=False, help='set chunked transfer mode')
420 f07c5a53 Sofia Papagiannaki
        parser.add_option('--content-encoding', action='store',
421 f07c5a53 Sofia Papagiannaki
                          dest='content-encoding', default=None,
422 f07c5a53 Sofia Papagiannaki
                          help='provide the object MIME content type')
423 f07c5a53 Sofia Papagiannaki
        parser.add_option('--content-disposition', action='store', type='str',
424 f07c5a53 Sofia Papagiannaki
                          dest='content-disposition', default=None,
425 f07c5a53 Sofia Papagiannaki
                          help='provide the presentation style of the object')
426 f07c5a53 Sofia Papagiannaki
        parser.add_option('--manifest', action='store', type='str',
427 f07c5a53 Sofia Papagiannaki
                          dest='manifest', default=None,
428 f07c5a53 Sofia Papagiannaki
                          help='use for large file support')
429 f7ab99df Sofia Papagiannaki
    
430 e3fd7f91 Sofia Papagiannaki
    def execute(self, path, srcpath='-', *args):
431 f07c5a53 Sofia Papagiannaki
        headers = {}
432 f07c5a53 Sofia Papagiannaki
        if self.manifest:
433 f07c5a53 Sofia Papagiannaki
            headers['X_OBJECT_MANIFEST'] = self.manifest
434 f07c5a53 Sofia Papagiannaki
        
435 7e999dec Sofia Papagiannaki
        if getattr(self, 'start'):
436 7e999dec Sofia Papagiannaki
            headers['CONTENT_RANGE'] = 'bytes %s-/*' % getattr(self, 'start')
437 7e999dec Sofia Papagiannaki
        elif self.append:
438 f07c5a53 Sofia Papagiannaki
            headers['CONTENT_RANGE'] = 'bytes */*'
439 f07c5a53 Sofia Papagiannaki
        
440 f07c5a53 Sofia Papagiannaki
        attrs = ['content-encoding', 'content-disposition']
441 f07c5a53 Sofia Papagiannaki
        attrs = [a for a in attrs if getattr(self, a)]
442 f07c5a53 Sofia Papagiannaki
        for a in attrs:
443 f07c5a53 Sofia Papagiannaki
            headers[a.replace('-', '_').upper()] = getattr(self, a)
444 f07c5a53 Sofia Papagiannaki
        
445 f07c5a53 Sofia Papagiannaki
        #prepare user defined meta
446 f07c5a53 Sofia Papagiannaki
        for arg in args:
447 f07c5a53 Sofia Papagiannaki
            key, sep, val = arg.partition('=')
448 f07c5a53 Sofia Papagiannaki
            headers['X_OBJECT_META_%s' %key.strip().upper()] = val.strip()
449 f07c5a53 Sofia Papagiannaki
        
450 f07c5a53 Sofia Papagiannaki
        container, sep, object = path.partition('/')
451 f07c5a53 Sofia Papagiannaki
        
452 f07c5a53 Sofia Papagiannaki
        f = srcpath != '-' and open(srcpath) or stdin
453 f07c5a53 Sofia Papagiannaki
        chunked = (self.chunked or f == stdin) and True or False
454 f07c5a53 Sofia Papagiannaki
        self.client.update_object(container, object, f, chunked=chunked,
455 f07c5a53 Sofia Papagiannaki
                                  headers=headers)
456 f07c5a53 Sofia Papagiannaki
        f.close()
457 f07c5a53 Sofia Papagiannaki
458 f07c5a53 Sofia Papagiannaki
@cli_command('move', 'mv')
459 f07c5a53 Sofia Papagiannaki
class MoveObject(Command):
460 f07c5a53 Sofia Papagiannaki
    syntax = '<src container>/<src object> [<dst container>/]<dst object>'
461 f07c5a53 Sofia Papagiannaki
    description = 'moves an object to a different location'
462 f07c5a53 Sofia Papagiannaki
    
463 f07c5a53 Sofia Papagiannaki
    def execute(self, src, dst):
464 f07c5a53 Sofia Papagiannaki
        src_container, sep, src_object = src.partition('/')
465 f07c5a53 Sofia Papagiannaki
        dst_container, sep, dst_object = dst.partition('/')
466 f07c5a53 Sofia Papagiannaki
        if not sep:
467 f07c5a53 Sofia Papagiannaki
            dst_container = src_container
468 f07c5a53 Sofia Papagiannaki
            dst_object = dst
469 085a31d7 Sofia Papagiannaki
        
470 f07c5a53 Sofia Papagiannaki
        self.client.move_object(src_container, src_object, dst_container,
471 085a31d7 Sofia Papagiannaki
                                dst_object, headers)
472 f07c5a53 Sofia Papagiannaki
473 f7ab99df Sofia Papagiannaki
@cli_command('remove', 'rm')
474 f7ab99df Sofia Papagiannaki
class TrashObject(Command):
475 f7ab99df Sofia Papagiannaki
    syntax = '<container>/<object>'
476 f7ab99df Sofia Papagiannaki
    description = 'trashes an object'
477 f7ab99df Sofia Papagiannaki
    
478 f7ab99df Sofia Papagiannaki
    def execute(self, src):
479 f7ab99df Sofia Papagiannaki
        src_container, sep, src_object = src.partition('/')
480 f7ab99df Sofia Papagiannaki
        
481 f7ab99df Sofia Papagiannaki
        self.client.trash_object(src_container, src_object)
482 f7ab99df Sofia Papagiannaki
483 f7ab99df Sofia Papagiannaki
@cli_command('restore')
484 f7ab99df Sofia Papagiannaki
class TrashObject(Command):
485 f7ab99df Sofia Papagiannaki
    syntax = '<container>/<object>'
486 f7ab99df Sofia Papagiannaki
    description = 'trashes an object'
487 f7ab99df Sofia Papagiannaki
    
488 f7ab99df Sofia Papagiannaki
    def execute(self, src):
489 f7ab99df Sofia Papagiannaki
        src_container, sep, src_object = src.partition('/')
490 f7ab99df Sofia Papagiannaki
        
491 f7ab99df Sofia Papagiannaki
        self.client.restore_object(src_container, src_object)
492 f7ab99df Sofia Papagiannaki
493 f7ab99df Sofia Papagiannaki
@cli_command('unset')
494 f7ab99df Sofia Papagiannaki
class TrashObject(Command):
495 f7ab99df Sofia Papagiannaki
    syntax = '<container>/[<object>] key [key] [...]'
496 f7ab99df Sofia Papagiannaki
    description = 'deletes metadata info'
497 f7ab99df Sofia Papagiannaki
    
498 f7ab99df Sofia Papagiannaki
    def execute(self, path, *args):
499 f7ab99df Sofia Papagiannaki
        #in case of account fix the args
500 961f2fbe Sofia Papagiannaki
        if len(args) == 0:
501 f7ab99df Sofia Papagiannaki
            args = list(args)
502 f7ab99df Sofia Papagiannaki
            args.append(path)
503 f7ab99df Sofia Papagiannaki
            args = tuple(args)
504 f7ab99df Sofia Papagiannaki
            path = ''
505 f7ab99df Sofia Papagiannaki
        meta = []
506 f7ab99df Sofia Papagiannaki
        for key in args:
507 f7ab99df Sofia Papagiannaki
            meta.append(key)
508 f7ab99df Sofia Papagiannaki
        container, sep, object = path.partition('/')
509 f7ab99df Sofia Papagiannaki
        if object:
510 f7ab99df Sofia Papagiannaki
            self.client.delete_object_metadata(container, object, meta)
511 f7ab99df Sofia Papagiannaki
        elif container:
512 f7ab99df Sofia Papagiannaki
            self.client.delete_container_metadata(container, meta)
513 f7ab99df Sofia Papagiannaki
        else:
514 f7ab99df Sofia Papagiannaki
            self.client.delete_account_metadata(meta)
515 f7ab99df Sofia Papagiannaki
516 cfac048c Giorgos Verigakis
def print_usage():
517 cfac048c Giorgos Verigakis
    cmd = Command([])
518 cfac048c Giorgos Verigakis
    parser = cmd.parser
519 cfac048c Giorgos Verigakis
    parser.usage = '%prog <command> [options]'
520 cfac048c Giorgos Verigakis
    parser.print_help()
521 cfac048c Giorgos Verigakis
    
522 cfac048c Giorgos Verigakis
    commands = []
523 cfac048c Giorgos Verigakis
    for cls in set(_cli_commands.values()):
524 cfac048c Giorgos Verigakis
        name = ', '.join(cls.commands)
525 cfac048c Giorgos Verigakis
        description = getattr(cls, 'description', '')
526 cfac048c Giorgos Verigakis
        commands.append('  %s %s' % (name.ljust(12), description))
527 cfac048c Giorgos Verigakis
    print '\nCommands:\n' + '\n'.join(sorted(commands))
528 cfac048c Giorgos Verigakis
529 a4c10cbc Sofia Papagiannaki
def print_dict(d, header='name', f=stdout, detail=True):
530 f07c5a53 Sofia Papagiannaki
    header = header in d and header or 'subdir'
531 f07c5a53 Sofia Papagiannaki
    if header and header in d:
532 f07c5a53 Sofia Papagiannaki
        f.write('%s\n' %d.pop(header))
533 a4c10cbc Sofia Papagiannaki
    if detail:
534 a4c10cbc Sofia Papagiannaki
        patterns = ['^x_(account|container|object)_meta_(\w+)$']
535 a4c10cbc Sofia Papagiannaki
        patterns.append(patterns[0].replace('_', '-'))
536 a4c10cbc Sofia Papagiannaki
        for key, val in sorted(d.items()):
537 a4c10cbc Sofia Papagiannaki
            for p in patterns:
538 a4c10cbc Sofia Papagiannaki
                p = re.compile(p)
539 a4c10cbc Sofia Papagiannaki
                m = p.match(key)
540 a4c10cbc Sofia Papagiannaki
                if m:
541 a4c10cbc Sofia Papagiannaki
                    key = m.group(2)
542 a4c10cbc Sofia Papagiannaki
            f.write('%s: %s\n' % (key.rjust(30), val))
543 f07c5a53 Sofia Papagiannaki
544 a4c10cbc Sofia Papagiannaki
def print_list(l, verbose=False, f=stdout, detail=True):
545 f07c5a53 Sofia Papagiannaki
    for elem in l:
546 f07c5a53 Sofia Papagiannaki
        #if it's empty string continue
547 f07c5a53 Sofia Papagiannaki
        if not elem:
548 f07c5a53 Sofia Papagiannaki
            continue
549 f07c5a53 Sofia Papagiannaki
        if type(elem) == types.DictionaryType:
550 a4c10cbc Sofia Papagiannaki
            print_dict(elem, f=f, detail=detail)
551 f07c5a53 Sofia Papagiannaki
        elif type(elem) == types.StringType:
552 f07c5a53 Sofia Papagiannaki
            if not verbose:
553 f07c5a53 Sofia Papagiannaki
                elem = elem.split('Traceback')[0]
554 f07c5a53 Sofia Papagiannaki
            f.write('%s\n' % elem)
555 f07c5a53 Sofia Papagiannaki
        else:
556 f07c5a53 Sofia Papagiannaki
            f.write('%s\n' % elem)
557 cfac048c Giorgos Verigakis
558 8fe01d72 Sofia Papagiannaki
def print_versions(data, f=stdout):
559 8fe01d72 Sofia Papagiannaki
    if 'versions' not in data:
560 8fe01d72 Sofia Papagiannaki
        f.write('%s\n' %data)
561 8fe01d72 Sofia Papagiannaki
        return
562 8fe01d72 Sofia Papagiannaki
    f.write('versions:\n')
563 8fe01d72 Sofia Papagiannaki
    for id, t in data['versions']:
564 8fe01d72 Sofia Papagiannaki
        f.write('%s @ %s\n' % (str(id).rjust(30), datetime.fromtimestamp(t)))
565 8fe01d72 Sofia Papagiannaki
566 cfac048c Giorgos Verigakis
def main():
567 cfac048c Giorgos Verigakis
    try:
568 cfac048c Giorgos Verigakis
        name = argv[1]
569 cfac048c Giorgos Verigakis
        cls = class_for_cli_command(name)
570 cfac048c Giorgos Verigakis
    except (IndexError, KeyError):
571 cfac048c Giorgos Verigakis
        print_usage()
572 cfac048c Giorgos Verigakis
        exit(1)
573 f07c5a53 Sofia Papagiannaki
    
574 cfac048c Giorgos Verigakis
    cmd = cls(argv[2:])
575 cfac048c Giorgos Verigakis
    
576 e5cd3e33 Sofia Papagiannaki
    try:
577 e5cd3e33 Sofia Papagiannaki
        cmd.execute(*cmd.args)
578 e3fd7f91 Sofia Papagiannaki
    except TypeError, e:
579 e3fd7f91 Sofia Papagiannaki
        print e
580 e5cd3e33 Sofia Papagiannaki
        cmd.parser.usage = '%%prog %s [options] %s' % (name, cmd.syntax)
581 e5cd3e33 Sofia Papagiannaki
        cmd.parser.print_help()
582 e5cd3e33 Sofia Papagiannaki
        exit(1)
583 e5cd3e33 Sofia Papagiannaki
    except Fault, f:
584 e3fd7f91 Sofia Papagiannaki
        print f.status, f.data
585 f7ab99df Sofia Papagiannaki
        status = f.status and '%s ' % f.status or ''
586 f7ab99df Sofia Papagiannaki
        print '%s%s' % (status, f.data)
587 cfac048c Giorgos Verigakis
588 cfac048c Giorgos Verigakis
if __name__ == '__main__':
589 cfac048c Giorgos Verigakis
    main()