Revision 25c3841c tools/store

b/tools/store
37 37
from optparse import OptionParser
38 38
from os import environ
39 39
from sys import argv, exit, stdin, stdout
40
from pithos.lib.client import Client, Fault
40
from pithos.lib.client import Pithos_Client, Fault
41 41
from datetime import datetime
42 42

  
43 43
import json
......
47 47
import time as _time
48 48
import os
49 49

  
50
DEFAULT_HOST = 'pithos.dev.grnet.gr'
51
#DEFAULT_HOST = '127.0.0.1:8000'
52
#DEFAULT_API = 'v1'
50
#DEFAULT_HOST = 'pithos.dev.grnet.gr'
51
DEFAULT_HOST = '127.0.0.1:8000'
52
DEFAULT_API = 'v1'
53 53

  
54 54
_cli_commands = {}
55 55

  
......
70 70
    def __init__(self, name, argv):
71 71
        parser = OptionParser('%%prog %s [options] %s' % (name, self.syntax))
72 72
        parser.add_option('--host', dest='host', metavar='HOST',
73
                          default=DEFAULT_HOST, help='use server HOST')
73
                          default=_get_server(), help='use server HOST')
74 74
        parser.add_option('--user', dest='user', metavar='USERNAME',
75 75
                          default=_get_user(),
76 76
                          help='use account USERNAME')
......
93 93
                val = getattr(options, key)
94 94
                setattr(self, key, val)
95 95
        
96
        self.client = Client(self.host, self.token, self.user, self.api, self.verbose,
96
        self.client = Pithos_Client(self.host, self.token, self.user, self.api, self.verbose,
97 97
                             self.debug)
98 98
        
99 99
        self.parser = parser
100 100
        self.args = args
101
        
101
    
102
    def _build_args(self, attrs):
103
        args = {}
104
        for a in [a for a in attrs if getattr(self, a)]:
105
            args[a] = getattr(self, a)
106
        return args
107

  
102 108
    def add_options(self, parser):
103 109
        pass
104 110
    
......
114 120
        parser.add_option('-l', action='store_true', dest='detail',
115 121
                          default=False, help='show detailed output')
116 122
        parser.add_option('-n', action='store', type='int', dest='limit',
117
                          default=1000, help='show limited output')
123
                          default=10000, help='show limited output')
118 124
        parser.add_option('--marker', action='store', type='str',
119 125
                          dest='marker', default=None,
120 126
                          help='show output greater then marker')
......
148 154
            self.list_containers()
149 155
    
150 156
    def list_containers(self):
151
        params = {'limit':self.limit, 'marker':self.marker}
152
        headers = {'IF_MODIFIED_SINCE':self.if_modified_since,
153
                   'IF_UNMODIFIED_SINCE':self.if_unmodified_since}
157
        attrs = ['detail', 'limit', 'marker', 'if_modified_since',
158
                 'if_unmodified_since']
159
        args = self._build_args(attrs)
154 160
        
155 161
        if self.until:
156 162
            t = _time.strptime(self.until, self.format)
157
            params['until'] = int(_time.mktime(t))
163
            args['until'] = int(_time.mktime(t))
158 164
        
159
        l = self.client.list_containers(self.detail, params, headers)
165
        l = self.client.list_containers(**args)
160 166
        print_list(l)
161 167
    
162 168
    def list_objects(self, container):
163 169
        #prepate params
164 170
        params = {}
165
        attrs = ['limit', 'marker', 'prefix', 'delimiter', 'path', 'meta']
166
        for a in [a for a in attrs if getattr(self, a)]:
167
            params[a] = getattr(self, a)
171
        attrs = ['detail', 'limit', 'marker', 'prefix', 'delimiter', 'path',
172
                 'meta', 'if_modified_since', 'if_unmodified_since']
173
        args = self._build_args(attrs)
168 174
        
169 175
        if self.until:
170 176
            t = _time.strptime(self.until, self.format)
171
            params['until'] = int(_time.mktime(t))
177
            args['until'] = int(_time.mktime(t))
172 178
        
173
        headers = {'IF_MODIFIED_SINCE':self.if_modified_since,
174
                   'IF_UNMODIFIED_SINCE':self.if_unmodified_since}
175 179
        container, sep, object = container.partition('/')
176 180
        if object:
177 181
            return
......
179 183
        detail = 'json'
180 184
        #if request with meta quering disable trash filtering
181 185
        show_trashed = True if self.meta else False
182
        l = self.client.list_objects(container, detail, headers,
183
                                     include_trashed = show_trashed, **params)
186
        l = self.client.list_objects(container, **args)
184 187
        print_list(l, detail=self.detail)
185 188

  
186 189
@cli_command('meta')
......
201 204
    
202 205
    def execute(self, path=''):
203 206
        container, sep, object = path.partition('/')
207
        args = {'restricted':self.restricted}
204 208
        if self.until:
205 209
            t = _time.strptime(self.until, self.format)
206
            self.until = int(_time.mktime(t))
210
            args['until'] = int(_time.mktime(t))
211
            
207 212
        if object:
208 213
            meta = self.client.retrieve_object_metadata(container, object,
209 214
                                                        self.restricted,
210 215
                                                        self.version)
211 216
        elif container:
212
            meta = self.client.retrieve_container_metadata(container,
213
                                                           self.restricted,
214
                                                           self.until)
217
            meta = self.client.retrieve_container_metadata(container, **args)
215 218
        else:
216
            meta = self.client.account_metadata(self.restricted, self.until)
219
            meta = self.client.retrieve_account_metadata(**args)
217 220
        if meta == None:
218 221
            print 'Entity does not exist'
219 222
        else:
......
225 228
    description = 'create a container'
226 229
    
227 230
    def execute(self, container, *args):
228
        headers = {}
229 231
        meta = {}
230 232
        for arg in args:
231 233
            key, sep, val = arg.partition('=')
232 234
            meta[key] = val
233
        ret = self.client.create_container(container, headers, **meta)
235
        ret = self.client.create_container(container, **meta)
234 236
        if not ret:
235 237
            print 'Container already exists'
236 238

  
......
239 241
    syntax = '<container>[/<object>]'
240 242
    description = 'delete a container or an object'
241 243
    
244
    def add_options(self, parser):
245
        parser.add_option('--until', action='store', dest='until',
246
                          default=False, help='remove history until that date')
247
        parser.add_option('--format', action='store', dest='format',
248
                          default='%d/%m/%Y', help='format to parse until date')
249
    
242 250
    def execute(self, path):
243 251
        container, sep, object = path.partition('/')
252
        if self.until:
253
            t = _time.strptime(self.until, self.format)
254
            until = int(_time.mktime(t))
255
        
244 256
        if object:
245
            self.client.delete_object(container, object)
257
            self.client.delete_object(container, object, until)
246 258
        else:
247
            self.client.delete_container(container)
259
            self.client.delete_container(container, until)
248 260

  
249 261
@cli_command('get')
250 262
class GetObject(Command):
......
256 268
                          default=False, help='show detailed output')
257 269
        parser.add_option('--range', action='store', dest='range',
258 270
                          default=None, help='show range of data')
259
        parser.add_option('--if-range', action='store', dest='if-range',
271
        parser.add_option('--if-range', action='store', dest='if_range',
260 272
                          default=None, help='show range of data')
261
        parser.add_option('--if-match', action='store', dest='if-match',
273
        parser.add_option('--if-match', action='store', dest='if_match',
262 274
                          default=None, help='show output if ETags match')
263 275
        parser.add_option('--if-none-match', action='store',
264
                          dest='if-none-match', default=None,
276
                          dest='if_none_match', default=None,
265 277
                          help='show output if ETags don\'t match')
266 278
        parser.add_option('--if-modified-since', action='store', type='str',
267
                          dest='if-modified-since', default=None,
279
                          dest='if_modified_since', default=None,
268 280
                          help='show output if modified since then')
269 281
        parser.add_option('--if-unmodified-since', action='store', type='str',
270
                          dest='if-unmodified-since', default=None,
282
                          dest='if_unmodified_since', default=None,
271 283
                          help='show output if not modified since then')
272 284
        parser.add_option('-o', action='store', type='str',
273 285
                          dest='file', default=None,
......
281 293
                          help='get the full object version list')
282 294
    
283 295
    def execute(self, path):
284
        headers = {}
296
        attrs = ['detail', 'if_match', 'if_none_match', 'if_modified_since',
297
                 'if_unmodified_since']
298
        args = self._build_args(attrs)
299
        
285 300
        if self.range:
286
            headers['RANGE'] = 'bytes=%s' %self.range
287
        if getattr(self, 'if-range'):
288
            headers['IF_RANGE'] = 'If-Range:%s' % getattr(self, 'if-range')
289
        attrs = ['if-match', 'if-none-match', 'if-modified-since',
290
                 'if-unmodified-since']
291
        attrs = [a for a in attrs if getattr(self, a)]
292
        for a in attrs:
293
            headers[a.replace('-', '_').upper()] = getattr(self, a)
301
            args['range'] = 'bytes=%s' %self.range
302
        if getattr(self, 'if_range'):
303
            args['if-range'] = 'If-Range:%s' % getattr(self, 'if_range')
304
        
294 305
        container, sep, object = path.partition('/')
306
        data = None
295 307
        if self.versionlist:
296
            self.version = 'list'
297
            self.detail = True
298
        data = self.client.retrieve_object(container, object, self.detail,
299
                                          headers, self.version)
308
            if 'detail' in args.keys():
309
                args.pop('detail')
310
            data = self.client.retrieve_object_versionlist(container, object, **args)
311
        elif self.version:
312
            data = self.client.retrieve_object_version(container, object,
313
                                                       self.version, **args)
314
        else:
315
            data = self.client.retrieve_object(container, object, **args)    
316
        
300 317
        f = self.file and open(self.file, 'w') or stdout
301 318
        if self.detail:
302 319
            data = json.loads(data)
......
330 347
        parser.add_option('--etag', action='store', dest='etag',
331 348
                          default=None, help='check written data')
332 349
        parser.add_option('--content-encoding', action='store',
333
                          dest='content-encoding', default=None,
350
                          dest='content_encoding', default=None,
334 351
                          help='provide the object MIME content type')
335 352
        parser.add_option('--content-disposition', action='store', type='str',
336
                          dest='content-disposition', default=None,
353
                          dest='content_disposition', default=None,
337 354
                          help='provide the presentation style of the object')
338
        parser.add_option('-S', action='store',
339
                          dest='segment-size', default=False,
340
                          help='use for large file support')
355
        #parser.add_option('-S', action='store',
356
        #                  dest='segment_size', default=False,
357
        #                  help='use for large file support')
341 358
        parser.add_option('--manifest', action='store_true',
342
                          dest='manifest', default=None,
359
                          dest='x_object_manifest', default=None,
343 360
                          help='upload a manifestation file')
344
        parser.add_option('--type', action='store',
345
                          dest='content-type', default=False,
361
        parser.add_option('--content-type', action='store',
362
                          dest='content_type', default=None,
346 363
                          help='create object with specific content type')
347 364
        parser.add_option('--sharing', action='store',
348
                          dest='sharing', default=None,
365
                          dest='x_object_sharing', default=None,
349 366
                          help='define sharing object policy')
350 367
        parser.add_option('-f', action='store',
351 368
                          dest='srcpath', default=None,
352 369
                          help='file descriptor to read from (pass - for standard input)')
353
        parser.add_option('--public', action='store',
354
                          dest='public', default=None,
370
        parser.add_option('--public', action='store_true',
371
                          dest='x_object_public', default=False,
355 372
                          help='make object publicly accessible (\'True\'/\'False\')')
356 373
    
357 374
    def execute(self, path, *args):
......
364 381
            key, sep, val = arg.partition('=')
365 382
            meta[key] = val
366 383
        
367
        headers = {}
368
        manifest = getattr(self, 'manifest')
369
        if manifest:
370
            # if it's manifestation file
371
            # send zero-byte data with X-Object-Manifest header
372
            self.touch = True
373
            headers['X_OBJECT_MANIFEST'] = manifest
374
        if self.sharing:
375
            headers['X_OBJECT_SHARING'] = self.sharing
376
        
377
        attrs = ['etag', 'content-encoding', 'content-disposition',
378
                 'content-type']
379
        attrs = [a for a in attrs if getattr(self, a)]
380
        for a in attrs:
381
            headers[a.replace('-', '_').upper()] = getattr(self, a)
384
        attrs = ['etag', 'content_encoding', 'content_disposition',
385
                 'content_type', 'x_object_sharing', 'x_object_public']
386
        args = self._build_args(attrs)
382 387
        
383 388
        container, sep, object = path.partition('/')
384 389
        
......
388 393
        
389 394
        if self.use_hashes and not f:
390 395
            raise Fault('Illegal option combination')
391
        if self.public not in ['True', 'False', None]:
392
            raise Fault('Not acceptable value for public')
393
        public = eval(self.public) if self.public else None
394
        self.client.create_object(container, object, f, chunked=self.chunked,
395
                                  headers=headers, use_hashes=self.use_hashes,
396
                                  public=public, **meta)
396
        
397
        if self.chunked:
398
            self.client.create_object_using_chunks(container, object, f,
399
                                                    meta=meta, **args)
400
        elif self.use_hashes:
401
            format = 'json' if detail else 'text'
402
            self.client.create_object_by_hashmap(container, object, f, format,
403
                                 meta=meta, **args)
404
        elif self.x_object_manifest:
405
            self.client.create_manifestation(container, object, self.x_object_manifest)
406
        else:
407
            data = f.read() if f else None
408
            self.client.create_object(container, object, data, meta=meta, **args)
397 409
        if f:
398 410
            f.close()
399 411

  
......
469 481
        parser.add_option('--chunked', action='store_true', dest='chunked',
470 482
                          default=False, help='set chunked transfer mode')
471 483
        parser.add_option('--content-encoding', action='store',
472
                          dest='content-encoding', default=None,
484
                          dest='content_encoding', default=None,
473 485
                          help='provide the object MIME content type')
474 486
        parser.add_option('--content-disposition', action='store', type='str',
475
                          dest='content-disposition', default=None,
487
                          dest='content_disposition', default=None,
476 488
                          help='provide the presentation style of the object')
477 489
        parser.add_option('--manifest', action='store', type='str',
478
                          dest='manifest', default=None,
490
                          dest='x_object_manifest', default=None,
479 491
                          help='use for large file support')        
480 492
        parser.add_option('--sharing', action='store',
481
                          dest='sharing', default=None,
493
                          dest='x_object_sharing', default=None,
482 494
                          help='define sharing object policy')
483 495
        parser.add_option('--nosharing', action='store_true',
484 496
                          dest='no_sharing', default=None,
......
487 499
                          dest='srcpath', default=None,
488 500
                          help='file descriptor to read from: pass - for standard input')
489 501
        parser.add_option('--public', action='store',
490
                          dest='public', default=None,
502
                          dest='x_object_public', default=False,
491 503
                          help='publish/unpublish object (\'True\'/\'False\')')
492 504
    
493 505
    def execute(self, path, *args):
494 506
        if path.find('=') != -1:
495 507
            raise Fault('Missing path argument')
496 508
        
497
        headers = {}
498
        if self.manifest:
499
            headers['X_OBJECT_MANIFEST'] = self.manifest
500
        if self.sharing:
501
            headers['X_OBJECT_SHARING'] = self.sharing
502
        if self.no_sharing:
503
            headers['X_OBJECT_SHARING'] = ''
504
        
505
        attrs = ['content-encoding', 'content-disposition']
506
        attrs = [a for a in attrs if getattr(self, a)]
507
        for a in attrs:
508
            headers[a.replace('-', '_').upper()] = getattr(self, a)
509
        
510 509
        #prepare user defined meta
511 510
        meta = {}
512 511
        for arg in args:
513 512
            key, sep, val = arg.partition('=')
514 513
            meta[key] = val
515 514
        
515
        if self.no_sharing:
516
            self.x_object_sharing = ''
517
        
518
        attrs = ['content_encoding', 'content_disposition', 'x_object_sharing',
519
                 'x_object_public']
520
        args = self._build_args(attrs)
521
        
516 522
        container, sep, object = path.partition('/')
517 523
        
518 524
        f = None
519
        chunked = False
520 525
        if self.srcpath:
521
            f = self.srcpath != '-' and open(self.srcpath) or stdin
522
        if f:
523
            chunked = True if (self.chunked or f == stdin) else False
524
        if self.public not in ['True', 'False', None]:
525
            raise Fault('Not acceptable value for public')
526
        public = eval(self.public) if self.public else None
527
        self.client.update_object(container, object, f, chunked=chunked,
528
                                  headers=headers, offset=self.offset,
529
                                  public=public, **meta)
526
            f = open(self.srcpath) if self.srcpath != '-' else stdin
527
        
528
        if self.chunked:
529
            self.client.update_object_using_chunks(container, object, f,
530
                                                    meta=meta, **args)
531
        else:
532
            data = f.read() if f else None
533
            self.client.update_object(container, object, data, meta=meta, **args)
530 534
        if f:
531 535
            f.close()
532 536

  
......
680 684
        patterns = ['^x_(account|container|object)_meta_(\w+)$']
681 685
        patterns.append(patterns[0].replace('_', '-'))
682 686
        for key, val in sorted(d.items()):
683
            for p in patterns:
684
                p = re.compile(p)
685
                m = p.match(key)
686
                if m:
687
                    key = m.group(2)
688 687
            f.write('%s: %s\n' % (key.rjust(30), val))
689 688

  
690 689
def print_list(l, verbose=False, f=stdout, detail=True):
......
720 719
            return os.environ['PITHOS_AUTH']
721 720
        except KeyError:
722 721
            return '0000'
723
    
722

  
723
def _get_server():
724
    try:
725
        return os.environ['PITHOS_SERVER']
726
    except KeyError:
727
        return DEFAULT_HOST
724 728

  
725 729
def main():
726 730
    try:
......
732 736
    
733 737
    cmd = cls(name, argv[2:])
734 738
    
739
    #cmd.execute(*cmd.args)
735 740
    try:
736 741
        cmd.execute(*cmd.args)
737 742
    except TypeError, e:

Also available in: Unified diff