Statistics
| Branch: | Tag: | Revision:

root / tools / store @ 3f5b02c7

History | View | Annotate | Download (9.1 kB)

1
#!/usr/bin/env python
2

    
3
from getpass import getuser
4
from optparse import OptionParser
5
from os.path import basename
6
from sys import argv, exit, stdin
7
from pithos.lib.client import Client, Fault
8

    
9
import json
10
import logging
11

    
12
DEFAULT_HOST = '127.0.0.1:8000'
13
DEFAULT_API = 'v1'
14

    
15
_cli_commands = {}
16

    
17
def cli_command(*args):
18
    def decorator(cls):
19
        cls.commands = args
20
        for name in args:
21
            _cli_commands[name] = cls
22
        return cls
23
    return decorator
24

    
25
def class_for_cli_command(name):
26
    return _cli_commands[name]
27

    
28
def print_dict(d, header='name'):
29
    if header:
30
        print d.pop(header)
31
    for key, val in sorted(d.items()):
32
        print '%s: %s' % (key.rjust(15), val)
33

    
34

    
35
class Command(object):
36
    def __init__(self, argv):
37
        parser = OptionParser()
38
        parser.add_option('--host', dest='host', metavar='HOST', default=DEFAULT_HOST,
39
                            help='use server HOST')
40
        parser.add_option('--user', dest='user', metavar='USERNAME', default=getuser(),
41
                            help='use account USERNAME')
42
        parser.add_option('--api', dest='api', metavar='API', default=DEFAULT_API,
43
                            help='use api API')
44
        parser.add_option('-v', action='store_true', dest='verbose', default=False,
45
                            help='use verbose output')
46
        parser.add_option('-d', action='store_true', dest='debug', default=False,
47
                            help='use debug output')
48
        self.add_options(parser)
49
        options, args = parser.parse_args(argv)
50
        
51
        # Add options to self
52
        for opt in parser.option_list:
53
            key = opt.dest
54
            if key:
55
                val = getattr(options, key)
56
                setattr(self, key, val)
57
        
58
        self.client = Client(self.host, self.user, self.api, self.verbose, self.debug)
59
        
60
        self.parser = parser
61
        self.args = args
62
    
63
    def add_options(self, parser):
64
        pass
65

    
66
    def execute(self, *args):
67
        pass
68

    
69

    
70
@cli_command('list', 'ls')
71
class List(Command):
72
    syntax = '[container]'
73
    description = 'list containers or objects'
74
    
75
    def add_options(self, parser):
76
        parser.add_option('-l', action='store_true', dest='detail',
77
                          default=False, help='show detailed output')
78
        parser.add_option('-n', action='store', type='int', dest='limit',
79
                          default=1000, help='show limited output')
80
        parser.add_option('--marker', action='store', type='str',
81
                          dest='marker', default=None,
82
                          help='show output greater then marker')
83
        parser.add_option('--prefix', action='store', type='str',
84
                          dest='prefix', default=None,
85
                          help='show output starting with prefix')
86
        parser.add_option('--delimiter', action='store', type='str',
87
                          dest='delimiter', default=None,
88
                          help='show output up to the delimiter')
89
        parser.add_option('--path', action='store', type='str',
90
                          dest='path', default=None,
91
                          help='show output starting with prefix up to /')
92
        parser.add_option('--meta', action='store', type='str',
93
                          dest='meta', default=None,
94
                          help='show output having the specified meta keys')
95
        parser.add_option('--if-modified-since', action='store', type='str',
96
                          dest='if_modified_since', default=None,
97
                          help='show output if modified since then')
98
        parser.add_option('--if-unmodified-since', action='store', type='str',
99
                          dest='if_unmodified_since', default=None,
100
                          help='show output if not modified since then')
101
        
102
    def execute(self, container=None):
103
        if container:
104
            self.list_objects(container)
105
        else:
106
            self.list_containers()
107
    
108
    def list_containers(self):
109
        l = self.client.list_containers(self.detail, self.limit, self.marker,
110
                                        self.if_modified_since,
111
                                        self.if_unmodified_since)
112
        if self.detail:
113
            for container in l:
114
                print_dict(container)
115
                print
116
        else:
117
            if self.verbose:
118
                print l
119
            else:
120
                print l.split('Traceback')[0]
121

    
122
    def list_objects(self, container):
123
        l = self.client.list_objects(container, self.detail, self.limit,
124
                                        self.marker, self.prefix,
125
                                        self.delimiter, self.path,
126
                                        self.meta,
127
                                        self.if_modified_since,
128
                                        self.if_unmodified_since)
129
        if self.detail:
130
            for obj in l:
131
                print_dict(obj)
132
                print
133
        else:
134
            if self.verbose:
135
                print l
136
            else:
137
                print l.split('Traceback')[0]
138

    
139
@cli_command('meta')
140
class Meta(Command):
141
    syntax = '[<container>[/<object>]]'
142
    description = 'get the metadata of an account, a container or an object'
143

    
144
    def execute(self, path=''):
145
        container, sep, object = path.partition('/')
146
        if object:
147
            meta = self.client.retrieve_object_metadata(container, object)
148
        elif container:
149
            meta = self.client.retrieve_container_metadata(container)
150
        else:
151
            meta = self.client.account_metadata()
152
        print_dict(meta, header=None)
153

    
154

    
155
@cli_command('create')
156
class CreateContainer(Command):
157
    syntax = '<container>'
158
    description = 'create a container'
159
    
160
    def execute(self, container):
161
        ret = self.client.create_container(container)
162
        if not ret:
163
            print 'Container already exists'
164

    
165

    
166
@cli_command('delete', 'rm')
167
class Delete(Command):
168
    syntax = '<container>[/<object>]'
169
    description = 'delete a container or an object'
170
    
171
    def execute(self, path):
172
        container, sep, object = path.partition('/')
173
        if object:
174
            self.client.delete_object(container, object)
175
        else:
176
            self.client.delete_container(container)
177

    
178

    
179
@cli_command('get')
180
class GetObject(Command):
181
    syntax = '<container>/<object>'
182
    description = 'get the data of an object'
183
    
184
    def execute(self, path):
185
        container, sep, object = path.partition('/')
186
        print self.client.retrieve_object(container, object)
187

    
188

    
189
@cli_command('put')
190
class PutObject(Command):
191
    syntax = '<container>/<object> <path>'
192
    description = 'create or update an object with contents of path'
193

    
194
    def execute(self, path, srcpath):
195
        container, sep, object = path.partition('/')
196
        f = open(srcpath) if srcpath != '-' else stdin
197
        data = f.read()
198
        self.client.create_object(container, object, data)
199
        f.close()
200

    
201

    
202
@cli_command('copy', 'cp')
203
class CopyObject(Command):
204
    syntax = '<src container>/<src object> [<dst container>/]<dst object>'
205
    description = 'copies an object to a different location'
206
    
207
    def execute(self, src, dst):
208
        src_container, sep, src_object = src.partition('/')
209
        dst_container, sep, dst_object = dst.partition('/')
210
        if not sep:
211
            dst_container = src_container
212
            dst_object = dst
213
        self.client.copy_object(src_container, src_object, dst_container, dst_object)
214

    
215
@cli_command('set')
216
class SetMeta(Command):
217
    syntax = '[<container>[/<object>]] key=val [key=val] [...]'
218
    description = 'set metadata'
219
    
220
    def execute(self, path, *args):
221
        #in case of account fix the args
222
        print path
223
        if path.find('='):
224
            args = list(args)
225
            args.append(path)
226
            args = tuple(args)
227
            path = ''
228
        meta = {}
229
        for arg in args:
230
            key, sep, val = arg.partition('=')
231
            meta[key.strip()] = val.strip()
232
        container, sep, object = path.partition('/')
233
        if object:
234
            self.client.update_object_metadata(container, object, **meta)
235
        elif container:
236
            self.client.update_container_metadata(container, **meta)
237
        else:
238
            self.client.update_account_metadata(**meta)
239

    
240
def print_usage():
241
    cmd = Command([])
242
    parser = cmd.parser
243
    parser.usage = '%prog <command> [options]'
244
    parser.print_help()
245
    
246
    commands = []
247
    for cls in set(_cli_commands.values()):
248
        name = ', '.join(cls.commands)
249
        description = getattr(cls, 'description', '')
250
        commands.append('  %s %s' % (name.ljust(12), description))
251
    print '\nCommands:\n' + '\n'.join(sorted(commands))
252

    
253

    
254

    
255
def main():
256
    try:
257
        name = argv[1]
258
        cls = class_for_cli_command(name)
259
    except (IndexError, KeyError):
260
        print_usage()
261
        exit(1)
262

    
263
    cmd = cls(argv[2:])
264
    
265
    try:
266
        cmd.execute(*cmd.args)
267
    except TypeError:
268
        cmd.parser.usage = '%%prog %s [options] %s' % (name, cmd.syntax)
269
        cmd.parser.print_help()
270
        exit(1)
271
    except Fault, f:
272
        print f.data
273

    
274

    
275
if __name__ == '__main__':
276
    main()