Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Silbe <sascha@silbe.org>2010-01-11 19:42:16 (GMT)
committer Sascha Silbe <sascha@silbe.org>2010-01-11 19:42:16 (GMT)
commit34d07f91c26e583f8975c23bbc87ab090418c32f (patch)
tree5b67688a9fdd87a97a295d730c032d8f6de0a73d
parentce2baf9c4218aab997b20d38e3c6e6e23be2d45a (diff)
parent86fc4060f9db84725be89577a625ffecebb78263 (diff)
Merge commit 'refs/top-bases/t/testsuite' into t/testsuite
-rw-r--r--NEWS6
-rwxr-xr-xbin/copy-from-journal131
-rwxr-xr-xbin/copy-to-journal8
-rw-r--r--configure.ac2
-rw-r--r--src/carquinyol/filestore.py19
-rw-r--r--src/carquinyol/indexstore.py27
6 files changed, 105 insertions, 88 deletions
diff --git a/NEWS b/NEWS
index 7a280dc..7afc9d0 100644
--- a/NEWS
+++ b/NEWS
@@ -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: