Statistics
| Branch: | Tag: | Revision:

root / tools / store @ f7ab99df

History | View | Annotate | Download (21.9 kB)

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