Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(295)

Side by Side Diff: third_party/gsutil/boto/sdb/db/manager/xmlmanager.py

Issue 12042069: Scripts to download files from google storage based on sha1 sums (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: Removed gsutil/tests and gsutil/docs Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # Copyright (c) 2006-2008 Mitch Garnaat http://garnaat.org/
2 #
3 # Permission is hereby granted, free of charge, to any person obtaining a
4 # copy of this software and associated documentation files (the
5 # "Software"), to deal in the Software without restriction, including
6 # without limitation the rights to use, copy, modify, merge, publish, dis-
7 # tribute, sublicense, and/or sell copies of the Software, and to permit
8 # persons to whom the Software is furnished to do so, subject to the fol-
9 # lowing conditions:
10 #
11 # The above copyright notice and this permission notice shall be included
12 # in all copies or substantial portions of the Software.
13 #
14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
16 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
17 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 # IN THE SOFTWARE.
21 import boto
22 from boto.utils import find_class, Password
23 from boto.sdb.db.key import Key
24 from boto.sdb.db.model import Model
25 from datetime import datetime
26 from xml.dom.minidom import getDOMImplementation, parse, parseString, Node
27
28 ISO8601 = '%Y-%m-%dT%H:%M:%SZ'
29
30 class XMLConverter:
31 """
32 Responsible for converting base Python types to format compatible with under lying
33 database. For SimpleDB, that means everything needs to be converted to a st ring
34 when stored in SimpleDB and from a string when retrieved.
35
36 To convert a value, pass it to the encode or decode method. The encode meth od
37 will take a Python native value and convert to DB format. The decode method will
38 take a DB format value and convert it to Python native format. To find the appropriate
39 method to call, the generic encode/decode methods will look for the type-spe cific
40 method by searching for a method called "encode_<type name>" or "decode_<typ e name>".
41 """
42 def __init__(self, manager):
43 self.manager = manager
44 self.type_map = { bool : (self.encode_bool, self.decode_bool),
45 int : (self.encode_int, self.decode_int),
46 long : (self.encode_long, self.decode_long),
47 Model : (self.encode_reference, self.decode_reference) ,
48 Key : (self.encode_reference, self.decode_reference),
49 Password : (self.encode_password, self.decode_password ),
50 datetime : (self.encode_datetime, self.decode_datetime )}
51
52 def get_text_value(self, parent_node):
53 value = ''
54 for node in parent_node.childNodes:
55 if node.nodeType == node.TEXT_NODE:
56 value += node.data
57 return value
58
59 def encode(self, item_type, value):
60 if item_type in self.type_map:
61 encode = self.type_map[item_type][0]
62 return encode(value)
63 return value
64
65 def decode(self, item_type, value):
66 if item_type in self.type_map:
67 decode = self.type_map[item_type][1]
68 return decode(value)
69 else:
70 value = self.get_text_value(value)
71 return value
72
73 def encode_prop(self, prop, value):
74 if isinstance(value, list):
75 if hasattr(prop, 'item_type'):
76 new_value = []
77 for v in value:
78 item_type = getattr(prop, "item_type")
79 if Model in item_type.mro():
80 item_type = Model
81 new_value.append(self.encode(item_type, v))
82 return new_value
83 else:
84 return value
85 else:
86 return self.encode(prop.data_type, value)
87
88 def decode_prop(self, prop, value):
89 if prop.data_type == list:
90 if hasattr(prop, 'item_type'):
91 item_type = getattr(prop, "item_type")
92 if Model in item_type.mro():
93 item_type = Model
94 values = []
95 for item_node in value.getElementsByTagName('item'):
96 value = self.decode(item_type, item_node)
97 values.append(value)
98 return values
99 else:
100 return self.get_text_value(value)
101 else:
102 return self.decode(prop.data_type, value)
103
104 def encode_int(self, value):
105 value = int(value)
106 return '%d' % value
107
108 def decode_int(self, value):
109 value = self.get_text_value(value)
110 if value:
111 value = int(value)
112 else:
113 value = None
114 return value
115
116 def encode_long(self, value):
117 value = long(value)
118 return '%d' % value
119
120 def decode_long(self, value):
121 value = self.get_text_value(value)
122 return long(value)
123
124 def encode_bool(self, value):
125 if value == True:
126 return 'true'
127 else:
128 return 'false'
129
130 def decode_bool(self, value):
131 value = self.get_text_value(value)
132 if value.lower() == 'true':
133 return True
134 else:
135 return False
136
137 def encode_datetime(self, value):
138 return value.strftime(ISO8601)
139
140 def decode_datetime(self, value):
141 value = self.get_text_value(value)
142 try:
143 return datetime.strptime(value, ISO8601)
144 except:
145 return None
146
147 def encode_reference(self, value):
148 if isinstance(value, str) or isinstance(value, unicode):
149 return value
150 if value == None:
151 return ''
152 else:
153 val_node = self.manager.doc.createElement("object")
154 val_node.setAttribute('id', value.id)
155 val_node.setAttribute('class', '%s.%s' % (value.__class__.__module__ , value.__class__.__name__))
156 return val_node
157
158 def decode_reference(self, value):
159 if not value:
160 return None
161 try:
162 value = value.childNodes[0]
163 class_name = value.getAttribute("class")
164 id = value.getAttribute("id")
165 cls = find_class(class_name)
166 return cls.get_by_ids(id)
167 except:
168 return None
169
170 def encode_password(self, value):
171 if value and len(value) > 0:
172 return str(value)
173 else:
174 return None
175
176 def decode_password(self, value):
177 value = self.get_text_value(value)
178 return Password(value)
179
180
181 class XMLManager(object):
182
183 def __init__(self, cls, db_name, db_user, db_passwd,
184 db_host, db_port, db_table, ddl_dir, enable_ssl):
185 self.cls = cls
186 if not db_name:
187 db_name = cls.__name__.lower()
188 self.db_name = db_name
189 self.db_user = db_user
190 self.db_passwd = db_passwd
191 self.db_host = db_host
192 self.db_port = db_port
193 self.db_table = db_table
194 self.ddl_dir = ddl_dir
195 self.s3 = None
196 self.converter = XMLConverter(self)
197 self.impl = getDOMImplementation()
198 self.doc = self.impl.createDocument(None, 'objects', None)
199
200 self.connection = None
201 self.enable_ssl = enable_ssl
202 self.auth_header = None
203 if self.db_user:
204 import base64
205 base64string = base64.encodestring('%s:%s' % (self.db_user, self.db_ passwd))[:-1]
206 authheader = "Basic %s" % base64string
207 self.auth_header = authheader
208
209 def _connect(self):
210 if self.db_host:
211 if self.enable_ssl:
212 from httplib import HTTPSConnection as Connection
213 else:
214 from httplib import HTTPConnection as Connection
215
216 self.connection = Connection(self.db_host, self.db_port)
217
218 def _make_request(self, method, url, post_data=None, body=None):
219 """
220 Make a request on this connection
221 """
222 if not self.connection:
223 self._connect()
224 try:
225 self.connection.close()
226 except:
227 pass
228 self.connection.connect()
229 headers = {}
230 if self.auth_header:
231 headers["Authorization"] = self.auth_header
232 self.connection.request(method, url, body, headers)
233 resp = self.connection.getresponse()
234 return resp
235
236 def new_doc(self):
237 return self.impl.createDocument(None, 'objects', None)
238
239 def _object_lister(self, cls, doc):
240 for obj_node in doc.getElementsByTagName('object'):
241 if not cls:
242 class_name = obj_node.getAttribute('class')
243 cls = find_class(class_name)
244 id = obj_node.getAttribute('id')
245 obj = cls(id)
246 for prop_node in obj_node.getElementsByTagName('property'):
247 prop_name = prop_node.getAttribute('name')
248 prop = obj.find_property(prop_name)
249 if prop:
250 if hasattr(prop, 'item_type'):
251 value = self.get_list(prop_node, prop.item_type)
252 else:
253 value = self.decode_value(prop, prop_node)
254 value = prop.make_value_from_datastore(value)
255 setattr(obj, prop.name, value)
256 yield obj
257
258 def reset(self):
259 self._connect()
260
261 def get_doc(self):
262 return self.doc
263
264 def encode_value(self, prop, value):
265 return self.converter.encode_prop(prop, value)
266
267 def decode_value(self, prop, value):
268 return self.converter.decode_prop(prop, value)
269
270 def get_s3_connection(self):
271 if not self.s3:
272 self.s3 = boto.connect_s3(self.aws_access_key_id, self.aws_secret_ac cess_key)
273 return self.s3
274
275 def get_list(self, prop_node, item_type):
276 values = []
277 try:
278 items_node = prop_node.getElementsByTagName('items')[0]
279 except:
280 return []
281 for item_node in items_node.getElementsByTagName('item'):
282 value = self.converter.decode(item_type, item_node)
283 values.append(value)
284 return values
285
286 def get_object_from_doc(self, cls, id, doc):
287 obj_node = doc.getElementsByTagName('object')[0]
288 if not cls:
289 class_name = obj_node.getAttribute('class')
290 cls = find_class(class_name)
291 if not id:
292 id = obj_node.getAttribute('id')
293 obj = cls(id)
294 for prop_node in obj_node.getElementsByTagName('property'):
295 prop_name = prop_node.getAttribute('name')
296 prop = obj.find_property(prop_name)
297 value = self.decode_value(prop, prop_node)
298 value = prop.make_value_from_datastore(value)
299 if value != None:
300 try:
301 setattr(obj, prop.name, value)
302 except:
303 pass
304 return obj
305
306 def get_props_from_doc(self, cls, id, doc):
307 """
308 Pull out the properties from this document
309 Returns the class, the properties in a hash, and the id if provided as a tuple
310 :return: (cls, props, id)
311 """
312 obj_node = doc.getElementsByTagName('object')[0]
313 if not cls:
314 class_name = obj_node.getAttribute('class')
315 cls = find_class(class_name)
316 if not id:
317 id = obj_node.getAttribute('id')
318 props = {}
319 for prop_node in obj_node.getElementsByTagName('property'):
320 prop_name = prop_node.getAttribute('name')
321 prop = cls.find_property(prop_name)
322 value = self.decode_value(prop, prop_node)
323 value = prop.make_value_from_datastore(value)
324 if value != None:
325 props[prop.name] = value
326 return (cls, props, id)
327
328
329 def get_object(self, cls, id):
330 if not self.connection:
331 self._connect()
332
333 if not self.connection:
334 raise NotImplementedError("Can't query without a database connection ")
335 url = "/%s/%s" % (self.db_name, id)
336 resp = self._make_request('GET', url)
337 if resp.status == 200:
338 doc = parse(resp)
339 else:
340 raise Exception("Error: %s" % resp.status)
341 return self.get_object_from_doc(cls, id, doc)
342
343 def query(self, cls, filters, limit=None, order_by=None):
344 if not self.connection:
345 self._connect()
346
347 if not self.connection:
348 raise NotImplementedError("Can't query without a database connection ")
349
350 from urllib import urlencode
351
352 query = str(self._build_query(cls, filters, limit, order_by))
353 if query:
354 url = "/%s?%s" % (self.db_name, urlencode({"query": query}))
355 else:
356 url = "/%s" % self.db_name
357 resp = self._make_request('GET', url)
358 if resp.status == 200:
359 doc = parse(resp)
360 else:
361 raise Exception("Error: %s" % resp.status)
362 return self._object_lister(cls, doc)
363
364 def _build_query(self, cls, filters, limit, order_by):
365 import types
366 if len(filters) > 4:
367 raise Exception('Too many filters, max is 4')
368 parts = []
369 properties = cls.properties(hidden=False)
370 for filter, value in filters:
371 name, op = filter.strip().split()
372 found = False
373 for property in properties:
374 if property.name == name:
375 found = True
376 if types.TypeType(value) == types.ListType:
377 filter_parts = []
378 for val in value:
379 val = self.encode_value(property, val)
380 filter_parts.append("'%s' %s '%s'" % (name, op, val) )
381 parts.append("[%s]" % " OR ".join(filter_parts))
382 else:
383 value = self.encode_value(property, value)
384 parts.append("['%s' %s '%s']" % (name, op, value))
385 if not found:
386 raise Exception('%s is not a valid field' % name)
387 if order_by:
388 if order_by.startswith("-"):
389 key = order_by[1:]
390 type = "desc"
391 else:
392 key = order_by
393 type = "asc"
394 parts.append("['%s' starts-with ''] sort '%s' %s" % (key, key, type) )
395 return ' intersection '.join(parts)
396
397 def query_gql(self, query_string, *args, **kwds):
398 raise NotImplementedError("GQL queries not supported in XML")
399
400 def save_list(self, doc, items, prop_node):
401 items_node = doc.createElement('items')
402 prop_node.appendChild(items_node)
403 for item in items:
404 item_node = doc.createElement('item')
405 items_node.appendChild(item_node)
406 if isinstance(item, Node):
407 item_node.appendChild(item)
408 else:
409 text_node = doc.createTextNode(item)
410 item_node.appendChild(text_node)
411
412 def save_object(self, obj, expected_value=None):
413 """
414 Marshal the object and do a PUT
415 """
416 doc = self.marshal_object(obj)
417 if obj.id:
418 url = "/%s/%s" % (self.db_name, obj.id)
419 else:
420 url = "/%s" % (self.db_name)
421 resp = self._make_request("PUT", url, body=doc.toxml())
422 new_obj = self.get_object_from_doc(obj.__class__, None, parse(resp))
423 obj.id = new_obj.id
424 for prop in obj.properties():
425 try:
426 propname = prop.name
427 except AttributeError:
428 propname = None
429 if propname:
430 value = getattr(new_obj, prop.name)
431 if value:
432 setattr(obj, prop.name, value)
433 return obj
434
435
436 def marshal_object(self, obj, doc=None):
437 if not doc:
438 doc = self.new_doc()
439 if not doc:
440 doc = self.doc
441 obj_node = doc.createElement('object')
442
443 if obj.id:
444 obj_node.setAttribute('id', obj.id)
445
446 obj_node.setAttribute('class', '%s.%s' % (obj.__class__.__module__,
447 obj.__class__.__name__))
448 root = doc.documentElement
449 root.appendChild(obj_node)
450 for property in obj.properties(hidden=False):
451 prop_node = doc.createElement('property')
452 prop_node.setAttribute('name', property.name)
453 prop_node.setAttribute('type', property.type_name)
454 value = property.get_value_for_datastore(obj)
455 if value is not None:
456 value = self.encode_value(property, value)
457 if isinstance(value, list):
458 self.save_list(doc, value, prop_node)
459 elif isinstance(value, Node):
460 prop_node.appendChild(value)
461 else:
462 text_node = doc.createTextNode(unicode(value).encode("ascii" , "ignore"))
463 prop_node.appendChild(text_node)
464 obj_node.appendChild(prop_node)
465
466 return doc
467
468 def unmarshal_object(self, fp, cls=None, id=None):
469 if isinstance(fp, str) or isinstance(fp, unicode):
470 doc = parseString(fp)
471 else:
472 doc = parse(fp)
473 return self.get_object_from_doc(cls, id, doc)
474
475 def unmarshal_props(self, fp, cls=None, id=None):
476 """
477 Same as unmarshalling an object, except it returns
478 from "get_props_from_doc"
479 """
480 if isinstance(fp, str) or isinstance(fp, unicode):
481 doc = parseString(fp)
482 else:
483 doc = parse(fp)
484 return self.get_props_from_doc(cls, id, doc)
485
486 def delete_object(self, obj):
487 url = "/%s/%s" % (self.db_name, obj.id)
488 return self._make_request("DELETE", url)
489
490 def set_key_value(self, obj, name, value):
491 self.domain.put_attributes(obj.id, {name : value}, replace=True)
492
493 def delete_key_value(self, obj, name):
494 self.domain.delete_attributes(obj.id, name)
495
496 def get_key_value(self, obj, name):
497 a = self.domain.get_attributes(obj.id, name)
498 if name in a:
499 return a[name]
500 else:
501 return None
502
503 def get_raw_item(self, obj):
504 return self.domain.get_item(obj.id)
505
506 def set_property(self, prop, obj, name, value):
507 pass
508
509 def get_property(self, prop, obj, name):
510 pass
511
512 def load_object(self, obj):
513 if not obj._loaded:
514 obj = obj.get_by_id(obj.id)
515 obj._loaded = True
516 return obj
517
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698