diff options
author | Sascha Silbe <sascha@silbe.org> | 2010-01-11 19:42:16 (GMT) |
---|---|---|
committer | Sascha Silbe <sascha@silbe.org> | 2010-01-11 19:42:16 (GMT) |
commit | 34d07f91c26e583f8975c23bbc87ab090418c32f (patch) | |
tree | 5b67688a9fdd87a97a295d730c032d8f6de0a73d | |
parent | ce2baf9c4218aab997b20d38e3c6e6e23be2d45a (diff) | |
parent | 86fc4060f9db84725be89577a625ffecebb78263 (diff) |
Merge commit 'refs/top-bases/t/testsuite' into t/testsuite
-rw-r--r-- | NEWS | 6 | ||||
-rwxr-xr-x | bin/copy-from-journal | 131 | ||||
-rwxr-xr-x | bin/copy-to-journal | 8 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | src/carquinyol/filestore.py | 19 | ||||
-rw-r--r-- | src/carquinyol/indexstore.py | 27 |
6 files changed, 105 insertions, 88 deletions
@@ -1,3 +1,9 @@ +v0.87.2 2009-12-21 +* copy-to-journal dbus error #573 +* file descriptor leak in filestore.retrieve() #1550 +* range queries use lexical comparison, not numerical #1342 +* add and use type information for Xapian value-stored properties #1437 + v0.87.1 2009-12-01 * Make reading version file more robust (sayamindu) #1562 * Use gobject_timeout_add_seconds to make power usage more efficient (sayamindu) #1567 diff --git a/bin/copy-from-journal b/bin/copy-from-journal index 457e9ff..7a10bfd 100755 --- a/bin/copy-from-journal +++ b/bin/copy-from-journal @@ -8,6 +8,7 @@ import sys import os import shutil import optparse +import dbus if os.path.exists("/tmp/olpc-session-bus"): os.environ["DBUS_SESSION_BUS_ADDRESS"] = "unix:path=/tmp/olpc-session-bus" @@ -46,67 +47,75 @@ if __name__ == "__main__": parser.print_help() exit(0) - dsentry = None - - # Get object directly if we were given an explicit object ID. - if options.object_id is not None: - dsentry = datastore.get(options.object_id) - - # Compose the query based on the options provided. - if dsentry is None: - query = {} - - if options.query is not None: - query['query'] = options.query - - # We only want a single file at a time; limit the number of objects - # returned to two, as anything more than one means the criteria were - # not limited enough. - objects, count = datastore.find(query, limit=RETURN_LIMIT, sorting='-mtime') - print '%r' % query - if count > 1: - print 'WARNING: %d objects found; retrieving most recent.' % (count) - for i in xrange(1, RETURN_LIMIT): - objects[i].destroy() - - if count > 0: - dsentry = objects[0] - - # If neither an explicit object ID nor a query gave us data, fail. - if dsentry is None: - print 'ERROR: unable to determine journal object to copy.' - parser.print_help() - exit(0) - - # Print metadata if that is what the user asked for. - if options.show_meta: - print 'Metadata:' - for key, val in dsentry.metadata.get_dictionary().iteritems(): - if key != 'preview': - print '%20s -> %s' % (key, val) - - # If no file is associated with this object, we can't save it out. - if dsentry.get_file_path() == "": - print 'ERROR: no file associated with object, just metadata.' + try: + dsentry = None + + # Get object directly if we were given an explicit object ID. + if options.object_id is not None: + dsentry = datastore.get(options.object_id) + + # Compose the query based on the options provided. + if dsentry is None: + query = {} + + if options.query is not None: + query['query'] = options.query + + # We only want a single file at a time; limit the number of objects + # returned to two, as anything more than one means the criteria were + # not limited enough. + objects, count = datastore.find(query, limit=RETURN_LIMIT, sorting='-mtime') + if count > 1: + print 'WARNING: %d objects found; retrieving most recent.' % (count) + for i in xrange(1, RETURN_LIMIT): + objects[i].destroy() + + if count > 0: + dsentry = objects[0] + + # If neither an explicit object ID nor a query gave us data, fail. + if dsentry is None: + print 'ERROR: unable to determine journal object to copy.' + parser.print_help() + exit(0) + + # Print metadata if that is what the user asked for. + if options.show_meta: + print 'Metadata:' + for key, val in dsentry.metadata.get_dictionary().iteritems(): + if key != 'preview': + print '%20s -> %s' % (key, val) + + # If no file is associated with this object, we can't save it out. + if dsentry.get_file_path() == "": + print 'ERROR: no file associated with object, just metadata.' + dsentry.destroy() + exit(0) + + outname = args[0] + outroot, outext = os.path.splitext(outname) + + # Do our best to determine the output file extension, based on Sugar's + # MIME-type-to-extension mappings. + if outext == "": + mimetype = dsentry.metadata['mime_type'] + outext = sugar.mime.get_primary_extension(mimetype) + if outext == None: + outext = "dsobject" + outext = '.' + outext + + # Lastly, actually copy the file out of the datastore and onto the + # filesystem. + shutil.copyfile(dsentry.get_file_path(), outroot + outext) + print '%s -> %s' % (dsentry.get_file_path(), outroot + outext) + + # Cleanup. dsentry.destroy() - exit(0) - - outname = args[0] - outroot, outext = os.path.splitext(outname) - - # Do our best to determine the output file extension, based on Sugar's - # MIME-type-to-extension mappings. - if outext == "": - mimetype = dsentry.metadata['mime_type'] - outext = sugar.mime.get_primary_extension(mimetype) - if outext == None: - outext = "dsobject" - outext = '.' + outext - # Lastly, actually copy the file out of the datastore and onto the - # filesystem. - shutil.copyfile(dsentry.get_file_path(), outroot + outext) - print '%s -> %s' % (dsentry.get_file_path(), outroot + outext) + except dbus.DBusException: + print 'ERROR: Unable to connect to the datastore.\n'\ + 'Check that you are running in the same environment as the '\ + 'datastore service.' - # Cleanup. - dsentry.destroy() + except Exception, e: + print 'ERROR: %s' % (e) diff --git a/bin/copy-to-journal b/bin/copy-to-journal index cf2cf20..d6ae6f3 100755 --- a/bin/copy-to-journal +++ b/bin/copy-to-journal @@ -11,6 +11,7 @@ import sys import os import optparse from gettext import gettext as _ +import dbus if os.path.exists("/tmp/olpc-session-bus"): os.environ["DBUS_SESSION_BUS_ADDRESS"] = "unix:path=/tmp/olpc-session-bus" @@ -88,5 +89,10 @@ if __name__ == "__main__": entry.destroy() + except dbus.DBusException: + print 'ERROR: Unable to connect to the datastore.\n'\ + 'Check that you are running in the same environment as the '\ + 'datastore service.' + except Exception, e: - print 'Error: %s' % (e) + print 'ERROR: %s' % (e) diff --git a/configure.ac b/configure.ac index c5eab2f..0a482fd 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([sugar-datastore],[0.87.1],[],[sugar-datastore]) +AC_INIT([sugar-datastore],[0.87.2],[],[sugar-datastore]) AC_PREREQ([2.59]) diff --git a/src/carquinyol/filestore.py b/src/carquinyol/filestore.py index 5a90a8e..9724397 100644 --- a/src/carquinyol/filestore.py +++ b/src/carquinyol/filestore.py @@ -110,21 +110,10 @@ class FileStore(object): elif extension: extension = '.' + extension - destination_path = os.path.join(destination_dir, uid + extension) - - attempt = 1 - while os.path.exists(destination_path): - if attempt > 10: - fd_, destination_path = tempfile.mkstemp(prefix=uid, - suffix=extension, - dir=destination_dir) - del fd_ - os.unlink(destination_path) - break - else: - file_name = '%s_%s%s' % (uid, attempt, extension) - destination_path = os.path.join(destination_dir, file_name) - attempt += 1 + fd, destination_path = tempfile.mkstemp(prefix=uid + '_', + suffix=extension, dir=destination_dir) + os.close(fd) + os.unlink(destination_path) # Try to hard link from the original file to the targetpath. This can # fail if the file is in a different filesystem. Do a symlink instead. diff --git a/src/carquinyol/indexstore.py b/src/carquinyol/indexstore.py index d390872..4dfd620 100644 --- a/src/carquinyol/indexstore.py +++ b/src/carquinyol/indexstore.py @@ -56,14 +56,15 @@ _QUERY_TERM_MAP = { } _QUERY_VALUE_MAP = { - 'timestamp': _VALUE_TIMESTAMP, + 'timestamp': {'number': _VALUE_TIMESTAMP, 'type': float}, } class TermGenerator (xapian.TermGenerator): def index_document(self, document, properties): - document.add_value(_VALUE_TIMESTAMP, str(properties['timestamp'])) + document.add_value(_VALUE_TIMESTAMP, + xapian.sortable_serialise(float(properties['timestamp']))) document.add_value(_VALUE_TITLE, properties.get('title', '').strip()) self.set_document(document) @@ -132,33 +133,39 @@ class QueryParser (xapian.QueryParser): else: return Query(_PREFIX_NONE + str(value)) - def _parse_query_value_range(self, name, value, value_no): + def _parse_query_value_range(self, name, info, value): if len(value) != 2: raise TypeError( 'Only tuples of size 2 have a defined meaning. ' 'Did you mean to pass a list instead?') start, end = value - return Query(Query.OP_VALUE_RANGE, value_no, str(start), str(end)) + return Query(Query.OP_VALUE_RANGE, info['number'], + self._convert_value(info, start), self._convert_value(info, end)) - def _parse_query_value(self, name, value_no, value): + def _convert_value(self, info, value): + if info['type'] in (float, int, long): + return xapian.sortable_serialise(info['type'](value)) + + return str(info['type'](value)) + + def _parse_query_value(self, name, info, value): if isinstance(value, list): - subqueries = [self._parse_query_value(name, value_no, word) + subqueries = [self._parse_query_value(name, info, word) for word in value] return Query(Query.OP_OR, subqueries) elif isinstance(value, tuple): - return self._parse_query_value_range(name, value, value_no) + return self._parse_query_value_range(name, info, value) elif isinstance(value, dict): # compatibility option for timestamp: {'start': 0, 'end': 1} start = value.get('start', 0) end = value.get('end', sys.maxint) - return self._parse_query_value_range(name, (start, end), value_no) + return self._parse_query_value_range(name, info, (start, end)) else: - return Query(Query.OP_VALUE_RANGE, - _QUERY_VALUE_MAP[name], str(value), str(value)) + return self._parse_query_value_range(name, info, (value, value)) def _parse_query_xapian(self, query_str): try: |