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

Side by Side Diff: third_party/gsutil/boto/sdb/domain.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,2007 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
22 """
23 Represents an SDB Domain
24 """
25 from boto.sdb.queryresultset import SelectResultSet
26
27 class Domain:
28
29 def __init__(self, connection=None, name=None):
30 self.connection = connection
31 self.name = name
32 self._metadata = None
33
34 def __repr__(self):
35 return 'Domain:%s' % self.name
36
37 def __iter__(self):
38 return iter(self.select("SELECT * FROM `%s`" % self.name))
39
40 def startElement(self, name, attrs, connection):
41 return None
42
43 def endElement(self, name, value, connection):
44 if name == 'DomainName':
45 self.name = value
46 else:
47 setattr(self, name, value)
48
49 def get_metadata(self):
50 if not self._metadata:
51 self._metadata = self.connection.domain_metadata(self)
52 return self._metadata
53
54 def put_attributes(self, item_name, attributes,
55 replace=True, expected_value=None):
56 """
57 Store attributes for a given item.
58
59 :type item_name: string
60 :param item_name: The name of the item whose attributes are being stored .
61
62 :type attribute_names: dict or dict-like object
63 :param attribute_names: The name/value pairs to store as attributes
64
65 :type expected_value: list
66 :param expected_value: If supplied, this is a list or tuple consisting
67 of a single attribute name and expected value. The list can be
68 of the form:
69
70 * ['name', 'value']
71
72 In which case the call will first verify that the attribute
73 "name" of this item has a value of "value". If it does, the delete
74 will proceed, otherwise a ConditionalCheckFailed error will be
75 returned. The list can also be of the form:
76
77 * ['name', True|False]
78
79 which will simply check for the existence (True) or non-existence
80 (False) of the attribute.
81
82 :type replace: bool
83 :param replace: Whether the attribute values passed in will replace
84 existing values or will be added as addition values.
85 Defaults to True.
86
87 :rtype: bool
88 :return: True if successful
89 """
90 return self.connection.put_attributes(self, item_name, attributes,
91 replace, expected_value)
92
93 def batch_put_attributes(self, items, replace=True):
94 """
95 Store attributes for multiple items.
96
97 :type items: dict or dict-like object
98 :param items: A dictionary-like object. The keys of the dictionary are
99 the item names and the values are themselves dictionaries
100 of attribute names/values, exactly the same as the
101 attribute_names parameter of the scalar put_attributes
102 call.
103
104 :type replace: bool
105 :param replace: Whether the attribute values passed in will replace
106 existing values or will be added as addition values.
107 Defaults to True.
108
109 :rtype: bool
110 :return: True if successful
111 """
112 return self.connection.batch_put_attributes(self, items, replace)
113
114 def get_attributes(self, item_name, attribute_name=None,
115 consistent_read=False, item=None):
116 """
117 Retrieve attributes for a given item.
118
119 :type item_name: string
120 :param item_name: The name of the item whose attributes are being retrie ved.
121
122 :type attribute_names: string or list of strings
123 :param attribute_names: An attribute name or list of attribute names. T his
124 parameter is optional. If not supplied, all att ributes
125 will be retrieved for the item.
126
127 :rtype: :class:`boto.sdb.item.Item`
128 :return: An Item mapping type containing the requested attribute name/va lues
129 """
130 return self.connection.get_attributes(self, item_name, attribute_name,
131 consistent_read, item)
132
133 def delete_attributes(self, item_name, attributes=None,
134 expected_values=None):
135 """
136 Delete attributes from a given item.
137
138 :type item_name: string
139 :param item_name: The name of the item whose attributes are being delete d.
140
141 :type attributes: dict, list or :class:`boto.sdb.item.Item`
142 :param attributes: Either a list containing attribute names which will c ause
143 all values associated with that attribute name to be deleted or
144 a dict or Item containing the attribute names and key s and list
145 of values to delete as the value. If no value is sup plied,
146 all attribute name/values for the item will be delete d.
147
148 :type expected_value: list
149 :param expected_value: If supplied, this is a list or tuple consisting
150 of a single attribute name and expected value. The list can be of
151 the form:
152
153 * ['name', 'value']
154
155 In which case the call will first verify that the attribute "name"
156 of this item has a value of "value". If it does, the delete
157 will proceed, otherwise a ConditionalCheckFailed error will be
158 returned. The list can also be of the form:
159
160 * ['name', True|False]
161
162 which will simply check for the existence (True) or
163 non-existence (False) of the attribute.
164
165 :rtype: bool
166 :return: True if successful
167 """
168 return self.connection.delete_attributes(self, item_name, attributes,
169 expected_values)
170
171 def batch_delete_attributes(self, items):
172 """
173 Delete multiple items in this domain.
174
175 :type items: dict or dict-like object
176 :param items: A dictionary-like object. The keys of the dictionary are
177 the item names and the values are either:
178
179 * dictionaries of attribute names/values, exactly the
180 same as the attribute_names parameter of the scalar
181 put_attributes call. The attribute name/value pairs
182 will only be deleted if they match the name/value
183 pairs passed in.
184 * None which means that all attributes associated
185 with the item should be deleted.
186
187 :rtype: bool
188 :return: True if successful
189 """
190 return self.connection.batch_delete_attributes(self, items)
191
192 def select(self, query='', next_token=None, consistent_read=False, max_items =None):
193 """
194 Returns a set of Attributes for item names within domain_name that match the query.
195 The query must be expressed in using the SELECT style syntax rather than the
196 original SimpleDB query language.
197
198 :type query: string
199 :param query: The SimpleDB query to be performed.
200
201 :rtype: iter
202 :return: An iterator containing the results. This is actually a generat or
203 function that will iterate across all search results, not just the
204 first page.
205 """
206 return SelectResultSet(self, query, max_items=max_items, next_token=next _token,
207 consistent_read=consistent_read)
208
209 def get_item(self, item_name, consistent_read=False):
210 """
211 Retrieves an item from the domain, along with all of its attributes.
212
213 :param string item_name: The name of the item to retrieve.
214 :rtype: :class:`boto.sdb.item.Item` or ``None``
215 :keyword bool consistent_read: When set to true, ensures that the most
216 recent data is returned.
217 :return: The requested item, or ``None`` if there was no match found
218 """
219 item = self.get_attributes(item_name, consistent_read=consistent_read)
220 if item:
221 item.domain = self
222 return item
223 else:
224 return None
225
226 def new_item(self, item_name):
227 return self.connection.item_cls(self, item_name)
228
229 def delete_item(self, item):
230 self.delete_attributes(item.name)
231
232 def to_xml(self, f=None):
233 """Get this domain as an XML DOM Document
234 :param f: Optional File to dump directly to
235 :type f: File or Stream
236
237 :return: File object where the XML has been dumped to
238 :rtype: file
239 """
240 if not f:
241 from tempfile import TemporaryFile
242 f = TemporaryFile()
243 print >> f, '<?xml version="1.0" encoding="UTF-8"?>'
244 print >> f, '<Domain id="%s">' % self.name
245 for item in self:
246 print >> f, '\t<Item id="%s">' % item.name
247 for k in item:
248 print >> f, '\t\t<attribute id="%s">' % k
249 values = item[k]
250 if not isinstance(values, list):
251 values = [values]
252 for value in values:
253 print >> f, '\t\t\t<value><![CDATA[',
254 if isinstance(value, unicode):
255 value = value.encode('utf-8', 'replace')
256 else:
257 value = unicode(value, errors='replace').encode('utf-8', 'replace')
258 f.write(value)
259 print >> f, ']]></value>'
260 print >> f, '\t\t</attribute>'
261 print >> f, '\t</Item>'
262 print >> f, '</Domain>'
263 f.flush()
264 f.seek(0)
265 return f
266
267
268 def from_xml(self, doc):
269 """Load this domain based on an XML document"""
270 import xml.sax
271 handler = DomainDumpParser(self)
272 xml.sax.parse(doc, handler)
273 return handler
274
275 def delete(self):
276 """
277 Delete this domain, and all items under it
278 """
279 return self.connection.delete_domain(self)
280
281
282 class DomainMetaData:
283
284 def __init__(self, domain=None):
285 self.domain = domain
286 self.item_count = None
287 self.item_names_size = None
288 self.attr_name_count = None
289 self.attr_names_size = None
290 self.attr_value_count = None
291 self.attr_values_size = None
292
293 def startElement(self, name, attrs, connection):
294 return None
295
296 def endElement(self, name, value, connection):
297 if name == 'ItemCount':
298 self.item_count = int(value)
299 elif name == 'ItemNamesSizeBytes':
300 self.item_names_size = int(value)
301 elif name == 'AttributeNameCount':
302 self.attr_name_count = int(value)
303 elif name == 'AttributeNamesSizeBytes':
304 self.attr_names_size = int(value)
305 elif name == 'AttributeValueCount':
306 self.attr_value_count = int(value)
307 elif name == 'AttributeValuesSizeBytes':
308 self.attr_values_size = int(value)
309 elif name == 'Timestamp':
310 self.timestamp = value
311 else:
312 setattr(self, name, value)
313
314 import sys
315 from xml.sax.handler import ContentHandler
316 class DomainDumpParser(ContentHandler):
317 """
318 SAX parser for a domain that has been dumped
319 """
320
321 def __init__(self, domain):
322 self.uploader = UploaderThread(domain)
323 self.item_id = None
324 self.attrs = {}
325 self.attribute = None
326 self.value = ""
327 self.domain = domain
328
329 def startElement(self, name, attrs):
330 if name == "Item":
331 self.item_id = attrs['id']
332 self.attrs = {}
333 elif name == "attribute":
334 self.attribute = attrs['id']
335 elif name == "value":
336 self.value = ""
337
338 def characters(self, ch):
339 self.value += ch
340
341 def endElement(self, name):
342 if name == "value":
343 if self.value and self.attribute:
344 value = self.value.strip()
345 attr_name = self.attribute.strip()
346 if attr_name in self.attrs:
347 self.attrs[attr_name].append(value)
348 else:
349 self.attrs[attr_name] = [value]
350 elif name == "Item":
351 self.uploader.items[self.item_id] = self.attrs
352 # Every 20 items we spawn off the uploader
353 if len(self.uploader.items) >= 20:
354 self.uploader.start()
355 self.uploader = UploaderThread(self.domain)
356 elif name == "Domain":
357 # If we're done, spawn off our last Uploader Thread
358 self.uploader.start()
359
360 from threading import Thread
361 class UploaderThread(Thread):
362 """Uploader Thread"""
363
364 def __init__(self, domain):
365 self.db = domain
366 self.items = {}
367 Thread.__init__(self)
368
369 def run(self):
370 try:
371 self.db.batch_put_attributes(self.items)
372 except:
373 print "Exception using batch put, trying regular put instead"
374 for item_name in self.items:
375 self.db.put_attributes(item_name, self.items[item_name])
376 print ".",
377 sys.stdout.flush()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698