Merge lp:~zeitgeist/zeitgeist/remove-datahub into lp:zeitgeist/0.1
- remove-datahub
- Merge into 0.8-python
Status: | Merged |
---|---|
Merged at revision: | 1617 |
Proposed branch: | lp:~zeitgeist/zeitgeist/remove-datahub |
Merge into: | lp:zeitgeist/0.1 |
Diff against target: |
1349 lines (+25/-1166) 14 files modified
Makefile.am (+3/-13) _zeitgeist/Makefile.am (+1/-1) _zeitgeist/loggers/Makefile.am (+0/-9) _zeitgeist/loggers/datasources/Makefile.am (+0/-6) _zeitgeist/loggers/datasources/_recentmanager.py (+0/-146) _zeitgeist/loggers/datasources/recent.py (+0/-371) _zeitgeist/loggers/iso_strptime.py (+0/-86) _zeitgeist/loggers/zeitgeist_base.py (+0/-91) _zeitgeist/loggers/zeitgeist_setup_service.py (+0/-243) configure.ac (+0/-2) po/POTFILES.in (+0/-4) test/loggers-datasources-recent-test.py (+0/-49) zeitgeist-daemon.py (+21/-10) zeitgeist-datahub.py (+0/-135) |
To merge this branch: | bzr merge lp:~zeitgeist/zeitgeist/remove-datahub |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Markus Korn | Approve | ||
Review via email: mp+38339@code.launchpad.net |
Commit message
Description of the change
initial fix for bzr bug #655164
removed zeitgeist-
Markus Korn (thekorn) wrote : | # |
Seif Lotfy (seif) wrote : | # |
Hey Markus,
Sorry about that. I ran the make check and forgot to run the proper dameon. Very sorry. The fix is up. Cheers
Seif
- 1618. By Seif Lotfy
-
fix stupid mistake in zeitgeist-daemon.py
- 1619. By Markus Korn
-
Some modification to how the datahub is invoked iwthin the daemon:
- OSError means that there is no datahub found in $PATH
- we tell the user which datahub binary is executed (this makes debugging
in dev environments easier)
- we are not translating debugging output
Markus Korn (thekorn) wrote : | # |
Seif, that's looking much better ;)
I could not find you on irc, so I did a few changes to zeitgeist-daemon.py which came into my mind while reading the code, please contact me if you think they don't make sense...
Markus Korn (thekorn) wrote : | # |
All tests are running fine, zeitgeist-daemon is looking good, and it seems to me that you managed to remove everything related to the old datahub, Good work.
Preview Diff
1 | === modified file 'Makefile.am' |
2 | --- Makefile.am 2010-09-03 10:16:51 +0000 |
3 | +++ Makefile.am 2010-10-14 09:46:58 +0000 |
4 | @@ -6,8 +6,7 @@ |
5 | intltool-update.in |
6 | |
7 | bin_SCRIPTS = \ |
8 | - zeitgeist-daemon \ |
9 | - zeitgeist-datahub |
10 | + zeitgeist-daemon |
11 | |
12 | EXTRA_DIST = \ |
13 | $(bin_SCRIPTS) \ |
14 | @@ -16,7 +15,6 @@ |
15 | COPYRIGHT \ |
16 | NEWS \ |
17 | zeitgeist-daemon.py \ |
18 | - zeitgeist-datahub.py \ |
19 | zeitgeist-daemon.pc.in |
20 | |
21 | DISTCLEANFILES = \ |
22 | @@ -25,8 +23,7 @@ |
23 | intltool-update |
24 | |
25 | CLEANFILES = \ |
26 | - zeitgeist-daemon \ |
27 | - zeitgeist-datahub |
28 | + zeitgeist-daemon |
29 | |
30 | pkgconfigdir = $(libdir)/pkgconfig |
31 | pkgconfig_DATA = zeitgeist-daemon.pc |
32 | @@ -34,19 +31,12 @@ |
33 | zeitgeist-daemon: zeitgeist-daemon.py |
34 | sed \ |
35 | -e "s!\/usr\/bin\/env python!$(PYTHON)!" \ |
36 | - -e "s!zeitgeist-datahub\.py!zeitgeist-datahub!" \ |
37 | < $< > $@ |
38 | chmod +x zeitgeist-daemon |
39 | zeitgeist-daemon: Makefile |
40 | |
41 | -zeitgeist-datahub: zeitgeist-datahub.py |
42 | - sed \ |
43 | - -e "s!\/usr\/bin\/env python!$(PYTHON)!" \ |
44 | - < $< > $@ |
45 | - chmod +x zeitgeist-datahub |
46 | -zeitgeist-datahub: Makefile |
47 | |
48 | -all-local: zeitgeist-daemon zeitgeist-datahub |
49 | +all-local: zeitgeist-daemon |
50 | |
51 | # Generate ChangeLog |
52 | dist-hook: |
53 | |
54 | === modified file '_zeitgeist/Makefile.am' |
55 | --- _zeitgeist/Makefile.am 2010-06-22 19:53:09 +0000 |
56 | +++ _zeitgeist/Makefile.am 2010-10-14 09:46:58 +0000 |
57 | @@ -1,4 +1,4 @@ |
58 | -SUBDIRS = engine loggers |
59 | +SUBDIRS = engine |
60 | |
61 | appdir = $(datadir)/zeitgeist/_zeitgeist/ |
62 | |
63 | |
64 | === removed directory '_zeitgeist/loggers' |
65 | === removed file '_zeitgeist/loggers/Makefile.am' |
66 | --- _zeitgeist/loggers/Makefile.am 2010-06-17 20:43:34 +0000 |
67 | +++ _zeitgeist/loggers/Makefile.am 1970-01-01 00:00:00 +0000 |
68 | @@ -1,9 +0,0 @@ |
69 | -SUBDIRS = datasources |
70 | - |
71 | -appdir = $(datadir)/zeitgeist/_zeitgeist/loggers/ |
72 | - |
73 | -app_PYTHON = \ |
74 | - __init__.py \ |
75 | - iso_strptime.py \ |
76 | - zeitgeist_setup_service.py \ |
77 | - zeitgeist_base.py |
78 | |
79 | === removed file '_zeitgeist/loggers/__init__.py' |
80 | === removed directory '_zeitgeist/loggers/datasources' |
81 | === removed file '_zeitgeist/loggers/datasources/Makefile.am' |
82 | --- _zeitgeist/loggers/datasources/Makefile.am 2010-06-17 20:43:34 +0000 |
83 | +++ _zeitgeist/loggers/datasources/Makefile.am 1970-01-01 00:00:00 +0000 |
84 | @@ -1,6 +0,0 @@ |
85 | -appdir = $(datadir)/zeitgeist/_zeitgeist/loggers/datasources |
86 | - |
87 | -app_PYTHON = \ |
88 | - __init__.py \ |
89 | - _recentmanager.py \ |
90 | - recent.py |
91 | |
92 | === removed file '_zeitgeist/loggers/datasources/__init__.py' |
93 | === removed file '_zeitgeist/loggers/datasources/_recentmanager.py' |
94 | --- _zeitgeist/loggers/datasources/_recentmanager.py 2010-01-16 18:21:11 +0000 |
95 | +++ _zeitgeist/loggers/datasources/_recentmanager.py 1970-01-01 00:00:00 +0000 |
96 | @@ -1,146 +0,0 @@ |
97 | -# -.- coding: utf-8 -.- |
98 | - |
99 | -# Zeitgeist |
100 | -# |
101 | -# Copyright © 2009 Markus Korn <thekorn@gmx.de> |
102 | -# Copyright © 2009 Siegfried-Angel Gevatter Pujals <rainct@ubuntu.com> |
103 | -# |
104 | -# This program is free software: you can redistribute it and/or modify |
105 | -# it under the terms of the GNU Lesser General Public License as published by |
106 | -# the Free Software Foundation, either version 3 of the License, or |
107 | -# (at your option) any later version. |
108 | -# |
109 | -# This program is distributed in the hope that it will be useful, |
110 | -# but WITHOUT ANY WARRANTY; without even the implied warranty of |
111 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
112 | -# GNU Lesser General Public License for more details. |
113 | -# |
114 | -# You should have received a copy of the GNU Lesser General Public License |
115 | -# along with this program. If not, see <http://www.gnu.org/licenses/>. |
116 | - |
117 | -import urllib |
118 | -import gobject |
119 | -import gio |
120 | -import os.path |
121 | -import time |
122 | -import logging |
123 | -from xml.dom.minidom import parse as minidom_parse |
124 | - |
125 | -from _zeitgeist.loggers.iso_strptime import iso_strptime |
126 | - |
127 | -DST = bool(time.mktime(time.gmtime(0))) |
128 | -log = logging.getLogger("zeitgeist.logger._recentmanager") |
129 | - |
130 | -class FileInfo(object): |
131 | - |
132 | - @staticmethod |
133 | - def convert_timestring(time_str): |
134 | - # My observation is that all times in self.RECENTFILE are in UTC (I might be wrong here) |
135 | - # so we need to parse the time string into a timestamp |
136 | - # and correct the result by the timezone difference |
137 | - try: |
138 | - timetuple = time.strptime(time_str, "%Y-%m-%dT%H:%M:%SZ") |
139 | - except ValueError: |
140 | - timetuple = iso_strptime(time_str.rstrip("Z")).timetuple() |
141 | - result = int(time.mktime(timetuple)) |
142 | - if DST: |
143 | - result -= time.altzone |
144 | - return result |
145 | - |
146 | - def __init__(self, node): |
147 | - self._uri = node.getAttribute("href") |
148 | - self._path = "/%s" % self._uri.split("///", 1)[-1] |
149 | - self._added = self.convert_timestring(node.getAttribute("added")) |
150 | - self._modified = self.convert_timestring(node.getAttribute("modified")) |
151 | - self._visited = self.convert_timestring(node.getAttribute("visited")) |
152 | - |
153 | - mimetype = node.getElementsByTagNameNS( |
154 | - "http://www.freedesktop.org/standards/shared-mime-info", |
155 | - "mime-type") |
156 | - if not mimetype: |
157 | - raise ValueError, "Could not find mimetype for item: %s" % self._uri |
158 | - self._mimetype = mimetype[-1].getAttribute("type") |
159 | - |
160 | - applications = node.getElementsByTagNameNS( |
161 | - "http://www.freedesktop.org/standards/desktop-bookmarks", |
162 | - "applications") |
163 | - assert applications |
164 | - application = applications[0].getElementsByTagNameNS( |
165 | - "http://www.freedesktop.org/standards/desktop-bookmarks", |
166 | - "application") |
167 | - if not application: |
168 | - raise ValueError, "Could not find application for item: %s" % self._uri |
169 | - self._application = application[-1].getAttribute("exec").strip("'") |
170 | - |
171 | - def get_mime_type(self): |
172 | - return self._mimetype |
173 | - |
174 | - def get_visited(self): |
175 | - return self._visited |
176 | - |
177 | - def get_added(self): |
178 | - return self._added |
179 | - |
180 | - def get_modified(self): |
181 | - return self._modified |
182 | - |
183 | - def get_uri_display(self): |
184 | - return self._path |
185 | - |
186 | - def get_uri(self): |
187 | - return self._uri |
188 | - |
189 | - def get_display_name(self): |
190 | - return unicode(os.path.basename(urllib.unquote(str(self._path)))) |
191 | - |
192 | - def exists(self): |
193 | - if not self._uri.startswith("file:///"): |
194 | - return True # Don't check online resources |
195 | - return gio.File(self._path).get_path() is not None |
196 | - |
197 | - def get_private_hint(self): |
198 | - return False # FIXME: How to get this? |
199 | - |
200 | - def last_application(self): |
201 | - # Not necessary, our get_application_info always returns the info of |
202 | - # the last application |
203 | - return "" |
204 | - |
205 | - def get_application_info(self, app): |
206 | - return (self._application, None, None) |
207 | - |
208 | -class RecentManager(gobject.GObject): |
209 | - |
210 | - RECENTFILE = os.path.expanduser("~/.recently-used.xbel") |
211 | - |
212 | - def __init__(self): |
213 | - super(RecentManager, self).__init__() |
214 | - if not os.path.exists(self.RECENTFILE): |
215 | - raise OSError("Can't use alternative RecentManager, '%s' not found" % self.RECENTFILE) |
216 | - |
217 | - self._fetching_items = None |
218 | - file_object = gio.File(self.RECENTFILE) |
219 | - self.file_monitor = file_object.monitor_file() |
220 | - self.file_monitor.set_rate_limit(1600) # for to high rates RecentManager |
221 | - # gets hickup, not sure what's optimal here |
222 | - self.file_monitor.connect("changed", self._content_changed) |
223 | - |
224 | - def _content_changed(self, monitor, fileobj, _, event): |
225 | - # Only emit the signal if we aren't already parsing RECENTFILE |
226 | - if not self._fetching_items: |
227 | - self.emit("changed") |
228 | - |
229 | - def get_items(self): |
230 | - self._fetching_items = True |
231 | - xml = minidom_parse(self.RECENTFILE) |
232 | - for bookmark in xml.getElementsByTagName("bookmark"): |
233 | - yield FileInfo(bookmark) |
234 | - self._fetching_items = False |
235 | - |
236 | - def set_limit(self, limit): |
237 | - pass |
238 | - |
239 | -gobject.type_register(RecentManager) |
240 | - |
241 | -gobject.signal_new("changed", RecentManager, |
242 | - gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()) |
243 | |
244 | === removed file '_zeitgeist/loggers/datasources/recent.py' |
245 | --- _zeitgeist/loggers/datasources/recent.py 2010-09-25 13:19:51 +0000 |
246 | +++ _zeitgeist/loggers/datasources/recent.py 1970-01-01 00:00:00 +0000 |
247 | @@ -1,371 +0,0 @@ |
248 | -# -.- coding: utf-8 -.- |
249 | - |
250 | -# Zeitgeist |
251 | -# |
252 | -# Copyright © 2009 Alex Graveley <alex.graveley@beatniksoftewarel.com> |
253 | -# Copyright © 2009 Markus Korn <thekorn@gmx.de> |
254 | -# Copyright © 2009 Natan Yellin <aantny@gmail.com> |
255 | -# Copyright © 2009 Seif Lotfy <seif@lotfy.com> |
256 | -# Copyright © 2009 Shane Fagan <shanepatrickfagan@yahoo.ie> |
257 | -# Copyright © 2009-2010 Siegfried-Angel Gevatter Pujals <rainct@ubuntu.com> |
258 | -# |
259 | -# This program is free software: you can redistribute it and/or modify |
260 | -# it under the terms of the GNU Lesser General Public License as published by |
261 | -# the Free Software Foundation, either version 3 of the License, or |
262 | -# (at your option) any later version. |
263 | -# |
264 | -# This program is distributed in the hope that it will be useful, |
265 | -# but WITHOUT ANY WARRANTY; without even the implied warranty of |
266 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
267 | -# GNU Lesser General Public License for more details. |
268 | -# |
269 | -# You should have received a copy of the GNU Lesser General Public License |
270 | -# along with this program. If not, see <http://www.gnu.org/licenses/>. |
271 | - |
272 | -from __future__ import with_statement |
273 | -import os |
274 | -import re |
275 | -import fnmatch |
276 | -import urllib |
277 | -import time |
278 | -import logging |
279 | -from xdg import BaseDirectory |
280 | - |
281 | -from zeitgeist import _config |
282 | -from zeitgeist.datamodel import Event, Subject, Interpretation, Manifestation, \ |
283 | - DataSource, get_timestamp_for_now |
284 | -from _zeitgeist.loggers.zeitgeist_base import DataProvider |
285 | - |
286 | -log = logging.getLogger("zeitgeist.logger.datasources.recent") |
287 | - |
288 | -try: |
289 | - import gtk |
290 | - if gtk.pygtk_version >= (2, 15, 2): |
291 | - recent_manager = gtk.recent_manager_get_default |
292 | - else: |
293 | - from _recentmanager import RecentManager |
294 | - recent_manager = RecentManager |
295 | -except ImportError: |
296 | - log.exception(_("Could not import GTK; data source disabled.")) |
297 | - enabled = False |
298 | -else: |
299 | - enabled = True |
300 | - |
301 | -class SimpleMatch(object): |
302 | - """ Wrapper around fnmatch.fnmatch which allows to define mimetype |
303 | - patterns by using shell-style wildcards. |
304 | - """ |
305 | - |
306 | - def __init__(self, pattern): |
307 | - self.__pattern = pattern |
308 | - |
309 | - def match(self, text): |
310 | - return fnmatch.fnmatch(text, self.__pattern) |
311 | - |
312 | - def __repr__(self): |
313 | - return "%s(%r)" %(self.__class__.__name__, self.__pattern) |
314 | - |
315 | -DOCUMENT_MIMETYPES = [ |
316 | - # Covers: |
317 | - # vnd.corel-draw |
318 | - # vnd.ms-powerpoint |
319 | - # vnd.ms-excel |
320 | - # vnd.oasis.opendocument.* |
321 | - # vnd.stardivision.* |
322 | - # vnd.sun.xml.* |
323 | - SimpleMatch(u"application/vnd.*"), |
324 | - # Covers: x-applix-word, x-applix-spreadsheet, x-applix-presents |
325 | - SimpleMatch(u"application/x-applix-*"), |
326 | - # Covers: x-kword, x-kspread, x-kpresenter, x-killustrator |
327 | - re.compile(u"application/x-k(word|spread|presenter|illustrator)"), |
328 | - u"application/ms-powerpoint", |
329 | - u"application/msword", |
330 | - u"application/pdf", |
331 | - u"application/postscript", |
332 | - u"application/ps", |
333 | - u"application/rtf", |
334 | - u"application/x-abiword", |
335 | - u"application/x-gnucash", |
336 | - u"application/x-gnumeric", |
337 | - SimpleMatch(u"application/x-java*"), |
338 | - SimpleMatch(u"*/x-tex"), |
339 | - SimpleMatch(u"*/x-latex"), |
340 | - SimpleMatch(u"*/x-dvi"), |
341 | - u"text/plain" |
342 | -] |
343 | - |
344 | -IMAGE_MIMETYPES = [ |
345 | - # Covers: |
346 | - # vnd.corel-draw |
347 | - u"application/vnd.corel-draw", |
348 | - # Covers: x-kword, x-kspread, x-kpresenter, x-killustrator |
349 | - re.compile(u"application/x-k(word|spread|presenter|illustrator)"), |
350 | - SimpleMatch(u"image/*"), |
351 | -] |
352 | - |
353 | -AUDIO_MIMETYPES = [ |
354 | - SimpleMatch(u"audio/*"), |
355 | - u"application/ogg" |
356 | -] |
357 | - |
358 | -VIDEO_MIMETYPES = [ |
359 | - SimpleMatch(u"video/*"), |
360 | - u"application/ogg" |
361 | -] |
362 | - |
363 | -DEVELOPMENT_MIMETYPES = [ |
364 | - u"application/ecmascript", |
365 | - u"application/javascript", |
366 | - u"application/x-csh", |
367 | - u"application/x-designer", |
368 | - u"application/x-desktop", |
369 | - u"application/x-dia-diagram", |
370 | - u"application/x-fluid", |
371 | - u"application/x-glade", |
372 | - u"application/xhtml+xml", |
373 | - u"application/x-java-archive", |
374 | - u"application/x-m4", |
375 | - u"application/xml", |
376 | - u"application/x-object", |
377 | - u"application/x-perl", |
378 | - u"application/x-php", |
379 | - u"application/x-ruby", |
380 | - u"application/x-shellscript", |
381 | - u"application/x-sql", |
382 | - u"text/css", |
383 | - u"text/html", |
384 | - u"text/x-c", |
385 | - u"text/x-c++", |
386 | - u"text/x-chdr", |
387 | - u"text/x-copying", |
388 | - u"text/x-credits", |
389 | - u"text/x-csharp", |
390 | - u"text/x-c++src", |
391 | - u"text/x-csrc", |
392 | - u"text/x-dsrc", |
393 | - u"text/x-eiffel", |
394 | - u"text/x-gettext-translation", |
395 | - u"text/x-gettext-translation-template", |
396 | - u"text/x-haskell", |
397 | - u"text/x-idl", |
398 | - u"text/x-java", |
399 | - u"text/x-lisp", |
400 | - u"text/x-lua", |
401 | - u"text/x-makefile", |
402 | - u"text/x-objcsrc", |
403 | - u"text/x-ocaml", |
404 | - u"text/x-pascal", |
405 | - u"text/x-patch", |
406 | - u"text/x-python", |
407 | - u"text/x-sql", |
408 | - u"text/x-tcl", |
409 | - u"text/x-troff", |
410 | - u"text/x-vala", |
411 | - u"text/x-vhdl", |
412 | -] |
413 | - |
414 | -ALL_MIMETYPES = DOCUMENT_MIMETYPES + IMAGE_MIMETYPES + AUDIO_MIMETYPES + \ |
415 | - VIDEO_MIMETYPES + DEVELOPMENT_MIMETYPES |
416 | - |
417 | -class MimeTypeSet(set): |
418 | - """ Set which allows to match against a string or an object with a |
419 | - match() method. |
420 | - """ |
421 | - |
422 | - def __init__(self, *items): |
423 | - super(MimeTypeSet, self).__init__() |
424 | - self.__pattern = set() |
425 | - for item in items: |
426 | - if isinstance(item, (str, unicode)): |
427 | - self.add(item) |
428 | - elif hasattr(item, "match"): |
429 | - self.__pattern.add(item) |
430 | - else: |
431 | - raise ValueError("Bad mimetype '%s'" %item) |
432 | - |
433 | - def __contains__(self, mimetype): |
434 | - result = super(MimeTypeSet, self).__contains__(mimetype) |
435 | - if not result: |
436 | - for pattern in self.__pattern: |
437 | - if pattern.match(mimetype): |
438 | - return True |
439 | - return result |
440 | - |
441 | - def __len__(self): |
442 | - return super(MimeTypeSet, self).__len__() + len(self.__pattern) |
443 | - |
444 | - def __repr__(self): |
445 | - items = ", ".join(sorted(map(repr, self | self.__pattern))) |
446 | - return "%s(%s)" %(self.__class__.__name__, items) |
447 | - |
448 | - |
449 | -class RecentlyUsedManagerGtk(DataProvider): |
450 | - |
451 | - FILTERS = { |
452 | - # dict of name as key and the matching mimetypes as value |
453 | - # if the value is None this filter matches all mimetypes |
454 | - "DOCUMENT": MimeTypeSet(*DOCUMENT_MIMETYPES), |
455 | - "IMAGE": MimeTypeSet(*IMAGE_MIMETYPES), |
456 | - "AUDIO": MimeTypeSet(*AUDIO_MIMETYPES), |
457 | - "VIDEO": MimeTypeSet(*VIDEO_MIMETYPES), |
458 | - "SOURCE_CODE": MimeTypeSet(*DEVELOPMENT_MIMETYPES), |
459 | - } |
460 | - |
461 | - def __init__(self, client): |
462 | - DataProvider.__init__(self, |
463 | - unique_id="com.zeitgeist-project,datahub,recent", |
464 | - name="Recently Used Documents", |
465 | - description="Logs events from GtkRecentlyUsed", |
466 | - event_templates=[Event.new_for_values(interpretation=i) for i in ( |
467 | - Interpretation.CREATE_EVENT, |
468 | - Interpretation.ACCESS_EVENT, |
469 | - Interpretation.MODIFY_EVENT |
470 | - )], |
471 | - client=client) |
472 | - self._load_data_sources_registry() |
473 | - self.recent_manager = recent_manager() |
474 | - self.recent_manager.set_limit(-1) |
475 | - self.recent_manager.connect("changed", lambda m: self.emit("reload")) |
476 | - self.config.connect("configured", lambda m: self.emit("reload")) |
477 | - |
478 | - def _load_data_sources_registry(self): |
479 | - self._ignore_apps = {} |
480 | - def _data_source_registered(datasource): |
481 | - for tmpl in datasource[DataSource.EventTemplates]: |
482 | - actor = tmpl[0][Event.Actor] |
483 | - if actor: |
484 | - if not actor in self._ignore_apps: |
485 | - self._ignore_apps[actor] = set() |
486 | - interp = tmpl[0][Event.Interpretation] |
487 | - if interp: |
488 | - self._ignore_apps[actor].add(interp) |
489 | - for datasource in self._registry.GetDataSources(): |
490 | - _data_source_registered(datasource) |
491 | - self._registry.connect("DataSourceRegistered", _data_source_registered) |
492 | - |
493 | - @staticmethod |
494 | - def _desktop_file_matches_app(filename, application, mimetype): |
495 | - """ Checks whether the given .desktop file represents the indicated |
496 | - application. |
497 | - |
498 | - If a mimetype is also given, only .desktop files listing it as |
499 | - supported will be considered. This is needed to differentiate |
500 | - between the different OpenOffice.org components, for instance. |
501 | - """ |
502 | - |
503 | - try: |
504 | - with open(filename) as desktopfile: |
505 | - _exec = False |
506 | - _mime = False |
507 | - for line in desktopfile: |
508 | - if line.startswith("Exec=") and \ |
509 | - line.split("=", 1)[-1].strip().split()[0] == application: |
510 | - if mimetype is None or _mime: |
511 | - return True |
512 | - else: |
513 | - _exec = True |
514 | - elif line.startswith("MimeType=") and mimetype in \ |
515 | - line.split("=", 1)[-1].split(";"): |
516 | - if _exec: |
517 | - return True |
518 | - else: |
519 | - _mime = True |
520 | - |
521 | - except IOError: |
522 | - pass # file may be a broken symlink (LP: #523761) |
523 | - except Exception, e: |
524 | - log.warning('Corrupt .desktop file: %s', filename) |
525 | - |
526 | - return False |
527 | - |
528 | - @staticmethod |
529 | - def _find_desktop_file_for_application(application, mimetype): |
530 | - """ Searches for a .desktop file for the given application in |
531 | - $XDG_DATADIRS and returns the path to the found file. If no file |
532 | - is found, returns None. |
533 | - """ |
534 | - desktopfiles = \ |
535 | - list(BaseDirectory.load_data_paths("applications", "%s.desktop" % application)) |
536 | - if desktopfiles: |
537 | - return unicode(desktopfiles[0]) |
538 | - else: |
539 | - is_match = RecentlyUsedManagerGtk._desktop_file_matches_app # local stuff is accessed faster |
540 | - for path in BaseDirectory.load_data_paths("applications"): |
541 | - for filename in (name for name in os.listdir(path) if name.endswith(".desktop")): |
542 | - fullname = os.path.join(path, filename) |
543 | - if (is_match(fullname, application, mimetype)): |
544 | - return unicode(fullname) |
545 | - |
546 | - return None |
547 | - |
548 | - def _get_interpretation_for_mimetype(self, mimetype): |
549 | - matching_filter = None |
550 | - for filter_name, mimetypes in self.FILTERS.iteritems(): |
551 | - if mimetype and mimetype in mimetypes: |
552 | - matching_filter = filter_name |
553 | - break |
554 | - if matching_filter: |
555 | - return getattr(Interpretation, matching_filter).uri |
556 | - return "" |
557 | - |
558 | - def _get_items(self): |
559 | - # We save the start timestamp to avoid race conditions |
560 | - last_seen = get_timestamp_for_now() |
561 | - |
562 | - events = [] |
563 | - |
564 | - for (num, info) in enumerate(self.recent_manager.get_items()): |
565 | - uri = info.get_uri() |
566 | - if info.exists() and not info.get_private_hint() and not uri.startswith("file:///tmp/"): |
567 | - last_application = info.last_application().strip() |
568 | - application = info.get_application_info(last_application)[0].split()[0] |
569 | - mimetype = unicode(info.get_mime_type()) |
570 | - if application in ("ooffice", "soffice"): |
571 | - # Special case OpenOffice.org *sigh* |
572 | - desktopfile = self._find_desktop_file_for_application("ooffice", mimetype) |
573 | - else: |
574 | - desktopfile = self._find_desktop_file_for_application(application, None) |
575 | - if not desktopfile: |
576 | - continue |
577 | - actor = u"application://%s" % os.path.basename(desktopfile) |
578 | - |
579 | - subject = Subject.new_for_values( |
580 | - uri = unicode(uri), |
581 | - interpretation = self._get_interpretation_for_mimetype( |
582 | - unicode(info.get_mime_type())), |
583 | - manifestation = Manifestation.FILE_DATA_OBJECT.uri, |
584 | - text = info.get_display_name(), |
585 | - mimetype = mimetype, |
586 | - origin = uri.rpartition("/")[0] |
587 | - ) |
588 | - |
589 | - times = set() |
590 | - for meth, interp in ( |
591 | - (info.get_added, Interpretation.CREATE_EVENT.uri), |
592 | - (info.get_visited, Interpretation.ACCESS_EVENT.uri), |
593 | - (info.get_modified, Interpretation.MODIFY_EVENT.uri) |
594 | - ): |
595 | - if actor not in self._ignore_apps or \ |
596 | - (self._ignore_apps[actor] and |
597 | - interp not in self._ignore_apps[actor]): |
598 | - times.add((meth() * 1000, interp)) |
599 | - |
600 | - is_new = False |
601 | - for timestamp, use in times: |
602 | - if timestamp <= self._last_seen: |
603 | - continue |
604 | - is_new = True |
605 | - events.append(Event.new_for_values( |
606 | - timestamp = timestamp, |
607 | - interpretation = use, |
608 | - manifestation = Manifestation.USER_ACTIVITY.uri, |
609 | - actor = actor, |
610 | - subjects = [subject] |
611 | - )) |
612 | - if num % 50 == 0: |
613 | - self._process_gobject_events() |
614 | - self._last_seen = last_seen |
615 | - return events |
616 | - |
617 | -if enabled: |
618 | - __datasource__ = RecentlyUsedManagerGtk |
619 | |
620 | === removed file '_zeitgeist/loggers/iso_strptime.py' |
621 | --- _zeitgeist/loggers/iso_strptime.py 2009-07-20 17:10:41 +0000 |
622 | +++ _zeitgeist/loggers/iso_strptime.py 1970-01-01 00:00:00 +0000 |
623 | @@ -1,86 +0,0 @@ |
624 | -# -.- coding: utf-8 -.- |
625 | - |
626 | -# This file is part of wadllib. |
627 | -# |
628 | -# Copyright © 2009 Canonical Ltd. |
629 | -# |
630 | -# wadllib is free software: you can redistribute it and/or modify it under the |
631 | -# terms of the GNU Lesser General Public License as published by the Free |
632 | -# Software Foundation, version 3 of the License. |
633 | -# |
634 | -# wadllib is distributed in the hope that it will be useful, but WITHOUT ANY |
635 | -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
636 | -# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
637 | -# details. |
638 | -# |
639 | -# You should have received a copy of the GNU Lesser General Public License |
640 | -# along with wadllib. If not, see <http://www.gnu.org/licenses/>. |
641 | - |
642 | -""" |
643 | -Parser for ISO 8601 time strings |
644 | -================================ |
645 | - |
646 | ->>> d = iso_strptime("2008-01-07T05:30:30.345323+03:00") |
647 | ->>> d |
648 | -datetime.datetime(2008, 1, 7, 5, 30, 30, 345323, tzinfo=TimeZone(10800)) |
649 | ->>> d.timetuple() |
650 | -(2008, 1, 7, 5, 30, 30, 0, 7, 0) |
651 | ->>> d.utctimetuple() |
652 | -(2008, 1, 7, 2, 30, 30, 0, 7, 0) |
653 | ->>> iso_strptime("2008-01-07T05:30:30.345323-03:00") |
654 | -datetime.datetime(2008, 1, 7, 5, 30, 30, 345323, tzinfo=TimeZone(-10800)) |
655 | ->>> iso_strptime("2008-01-07T05:30:30.345323") |
656 | -datetime.datetime(2008, 1, 7, 5, 30, 30, 345323) |
657 | ->>> iso_strptime("2008-01-07T05:30:30") |
658 | -datetime.datetime(2008, 1, 7, 5, 30, 30) |
659 | ->>> iso_strptime("2008-01-07T05:30:30+02:00") |
660 | -datetime.datetime(2008, 1, 7, 5, 30, 30, tzinfo=TimeZone(7200)) |
661 | -""" |
662 | - |
663 | -import re |
664 | -import datetime |
665 | - |
666 | -RE_TIME = re.compile(r"""^ |
667 | - # pattern matching date |
668 | - (?P<year>\d{4})\-(?P<month>\d{2})\-(?P<day>\d{2}) |
669 | - # separator |
670 | - T |
671 | - # pattern matching time |
672 | - (?P<hour>\d{2})\:(?P<minutes>\d{2})\:(?P<seconds>\d{2}) |
673 | - # pattern matching optional microseconds |
674 | - (\.(?P<microseconds>\d{6})\d*)? |
675 | - # pattern matching optional timezone offset |
676 | - (?P<tz_offset>[\-\+]\d{2}\:\d{2})? |
677 | - $""", re.VERBOSE) |
678 | - |
679 | -class TimeZone(datetime.tzinfo): |
680 | - |
681 | - def __init__(self, tz_string): |
682 | - hours, minutes = tz_string.lstrip("-+").split(":") |
683 | - self.stdoffset = datetime.timedelta(hours=int(hours), |
684 | - minutes=int(minutes)) |
685 | - if tz_string.startswith("-"): |
686 | - self.stdoffset *= -1 |
687 | - |
688 | - def __repr__(self): |
689 | - return "TimeZone(%s)" % ( |
690 | - self.stdoffset.days*24*60*60 + self.stdoffset.seconds) |
691 | - |
692 | - def utcoffset(self, dt): |
693 | - return self.stdoffset |
694 | - |
695 | - def dst(self, dt): |
696 | - return datetime.timedelta(0) |
697 | - |
698 | -def iso_strptime(time_str): |
699 | - x = RE_TIME.match(time_str) |
700 | - if not x: |
701 | - raise ValueError("unable to parse time '%s'" %time_str) |
702 | - d = datetime.datetime(int(x.group("year")), int(x.group("month")), |
703 | - int(x.group("day")), int(x.group("hour")), int(x.group("minutes")), |
704 | - int(x.group("seconds"))) |
705 | - if x.group("microseconds"): |
706 | - d = d.replace(microsecond=int(x.group("microseconds"))) |
707 | - if x.group("tz_offset"): |
708 | - d = d.replace(tzinfo=TimeZone(x.group("tz_offset"))) |
709 | - return d |
710 | |
711 | === removed file '_zeitgeist/loggers/zeitgeist_base.py' |
712 | --- _zeitgeist/loggers/zeitgeist_base.py 2010-04-22 18:28:40 +0000 |
713 | +++ _zeitgeist/loggers/zeitgeist_base.py 1970-01-01 00:00:00 +0000 |
714 | @@ -1,91 +0,0 @@ |
715 | -# -.- coding: utf-8 -.- |
716 | - |
717 | -# Zeitgeist |
718 | -# |
719 | -# Copyright © 2009 Seif Lotfy <seif@lotfy.com> |
720 | -# Copyright © 2009-2010 Siegfried-Angel Gevatter Pujals <rainct@ubuntu.com> |
721 | -# Copyright © 2009 Natan Yellin <aantny@gmail.com> |
722 | -# Copyright © 2009 Alex Graveley <alex@beatniksoftware.com> |
723 | -# Copyright © 2009 Markus Korn <thekorn@gmx.de> |
724 | -# |
725 | -# This program is free software: you can redistribute it and/or modify |
726 | -# it under the terms of the GNU Lesser General Public License as published by |
727 | -# the Free Software Foundation, either version 3 of the License, or |
728 | -# (at your option) any later version. |
729 | -# |
730 | -# This program is distributed in the hope that it will be useful, |
731 | -# but WITHOUT ANY WARRANTY; without even the implied warranty of |
732 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
733 | -# GNU Lesser General Public License for more details. |
734 | -# |
735 | -# You should have received a copy of the GNU Lesser General Public License |
736 | -# along with this program. If not, see <http://www.gnu.org/licenses/>. |
737 | - |
738 | -from threading import Thread |
739 | -import gobject |
740 | -import logging |
741 | - |
742 | -from zeitgeist.datamodel import DataSource |
743 | -from _zeitgeist.loggers.zeitgeist_setup_service import _Configuration, DefaultConfiguration |
744 | - |
745 | -class DataProvider(gobject.GObject, Thread): |
746 | - |
747 | - __gsignals__ = { |
748 | - "reload" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), |
749 | - } |
750 | - |
751 | - def __init__(self, unique_id, name, description="", event_templates=[], |
752 | - client=None, config=None): |
753 | - |
754 | - # Initialize superclasses |
755 | - Thread.__init__(self) |
756 | - gobject.GObject.__init__(self) |
757 | - |
758 | - self._name = name |
759 | - self._client = client |
760 | - self._ctx = gobject.main_context_default() |
761 | - |
762 | - if client: |
763 | - self._registry = self._client.get_extension("DataSourceRegistry", |
764 | - "data_source_registry") |
765 | - try: |
766 | - self._last_seen = [ds[DataSource.LastSeen] for ds in \ |
767 | - self._registry.GetDataSources() if \ |
768 | - ds[DataSource.UniqueId] == unique_id][0] - 1800000 |
769 | - # We substract 30 minutes to make sure no events get missed. |
770 | - except IndexError: |
771 | - self._last_seen = 0 |
772 | - self._enabled = self._registry.RegisterDataSource(unique_id, name, |
773 | - description, event_templates) |
774 | - |
775 | - if not config: |
776 | - self.config = DefaultConfiguration(self._name) |
777 | - else: |
778 | - if not isinstance(config, _Configuration): |
779 | - raise TypeError |
780 | - self.config = config |
781 | - |
782 | - def get_name(self): |
783 | - return self._name |
784 | - |
785 | - def get_items(self): |
786 | - if not self._enabled: |
787 | - return [] |
788 | - # FIXME: We need to figure out what to do with this configuration stuff |
789 | - # Maybe merge it into the DataSource registry so that everyone |
790 | - # can benefit from it, or just throw it out. |
791 | - if not self.config.isConfigured() or not self.config.enabled: |
792 | - logging.warning("'%s' isn't enabled or configured." % \ |
793 | - self.config.get_internal_name()) |
794 | - return [] |
795 | - return self._get_items() |
796 | - |
797 | - def _get_items(self): |
798 | - """ Subclasses should override this to return data. """ |
799 | - raise NotImplementedError |
800 | - |
801 | - def _process_gobject_events(self): |
802 | - """ Check for pending gobject events. This should be called in some |
803 | - meaningful place in _get_items on long running updates. """ |
804 | - while self._ctx.pending(): |
805 | - self._ctx.iteration() |
806 | |
807 | === removed file '_zeitgeist/loggers/zeitgeist_setup_service.py' |
808 | --- _zeitgeist/loggers/zeitgeist_setup_service.py 2009-09-04 15:13:13 +0000 |
809 | +++ _zeitgeist/loggers/zeitgeist_setup_service.py 1970-01-01 00:00:00 +0000 |
810 | @@ -1,243 +0,0 @@ |
811 | -# -.- coding: utf-8 -.- |
812 | - |
813 | -# Zeitgeist |
814 | -# |
815 | -# Copyright © 2009 Markus Korn <thekorn@gmx.de> |
816 | -# |
817 | -# This program is free software: you can redistribute it and/or modify |
818 | -# it under the terms of the GNU Lesser General Public License as published by |
819 | -# the Free Software Foundation, either version 3 of the License, or |
820 | -# (at your option) any later version. |
821 | -# |
822 | -# This program is distributed in the hope that it will be useful, |
823 | -# but WITHOUT ANY WARRANTY; without even the implied warranty of |
824 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
825 | -# GNU Lesser General Public License for more details. |
826 | -# |
827 | -# You should have received a copy of the GNU Lesser General Public License |
828 | -# along with this program. If not, see <http://www.gnu.org/licenses/>. |
829 | - |
830 | -import dbus |
831 | -import dbus.service |
832 | -import gobject |
833 | -import gconf |
834 | -import glib |
835 | -import dbus.mainloop.glib |
836 | -from ConfigParser import SafeConfigParser |
837 | -from xdg import BaseDirectory |
838 | -from StringIO import StringIO |
839 | - |
840 | -dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) |
841 | - |
842 | -class DataProviderService(dbus.service.Object): |
843 | - |
844 | - def __init__(self, datasources, mainloop=None): |
845 | - bus_name = dbus.service.BusName("org.gnome.zeitgeist.datahub", dbus.SessionBus()) |
846 | - dbus.service.Object.__init__(self, bus_name, "/org/gnome/zeitgeist/datahub") |
847 | - self._mainloop = mainloop |
848 | - self.__datasources = datasources |
849 | - |
850 | - @dbus.service.method("org.gnome.zeitgeist.DataHub", |
851 | - out_signature="as") |
852 | - def GetDataProviders(self): |
853 | - return [i.config.get_internal_name() for i in self.__datasources if i.config.has_dbus_service()] |
854 | - |
855 | - def needs_setup(self): |
856 | - return not self.__configuration.isConfigured() |
857 | - |
858 | - |
859 | -class SetupService(dbus.service.Object): |
860 | - |
861 | - def __init__(self, datasource, root_config, mainloop=None): |
862 | - bus_name = dbus.service.BusName("org.gnome.zeitgeist.datahub", dbus.SessionBus()) |
863 | - dbus.service.Object.__init__(self, |
864 | - bus_name, "/org/gnome/zeitgeist/datahub/dataprovider/%s" %datasource) |
865 | - self._mainloop = mainloop |
866 | - self.__configuration = root_config |
867 | - if not isinstance(self.__configuration, _Configuration): |
868 | - raise TypeError |
869 | - self.__setup_is_running = None |
870 | - |
871 | - @dbus.service.method("org.gnome.zeitgeist.DataHub", |
872 | - in_signature="iss") |
873 | - def SetConfiguration(self, token, option, value): |
874 | - if token != self.__setup_is_running: |
875 | - raise RuntimeError("wrong client") |
876 | - self.__configuration.set_attribute(option, value) |
877 | - |
878 | - @dbus.service.signal("org.gnome.zeitgeist.DataHub") |
879 | - def NeedsSetup(self): |
880 | - pass |
881 | - |
882 | - @dbus.service.method("org.gnome.zeitgeist.DataHub", |
883 | - in_signature="i", out_signature="b") |
884 | - def RequestSetupRun(self, token): |
885 | - if self.__setup_is_running is None: |
886 | - self.__setup_is_running = token |
887 | - return True |
888 | - else: |
889 | - raise False |
890 | - |
891 | - @dbus.service.method("org.gnome.zeitgeist.DataHub", |
892 | - out_signature="a(sb)") |
893 | - def GetOptions(self, token): |
894 | - if token != self.__setup_is_running: |
895 | - raise RuntimeError("wrong client") |
896 | - return self.__configuration.get_options() |
897 | - |
898 | - def needs_setup(self): |
899 | - return not self.__configuration.isConfigured() |
900 | - |
901 | - |
902 | -class _Configuration(gobject.GObject): |
903 | - |
904 | - @staticmethod |
905 | - def like_bool(value): |
906 | - if isinstance(value, bool): |
907 | - return value |
908 | - elif value.lower() in ("true", "1", "on"): |
909 | - return True |
910 | - elif value.lower() in ("false", "0", "off"): |
911 | - return False |
912 | - else: |
913 | - raise ValueError |
914 | - |
915 | - def __init__(self, internal_name, use_dbus=True, mainloop=None): |
916 | - gobject.GObject.__init__(self) |
917 | - self.__required = set() |
918 | - self.__items = dict() |
919 | - self.__internal_name = internal_name.replace(" ", "_").lower() |
920 | - if use_dbus: |
921 | - self.__dbus_service = SetupService(self.__internal_name, self, mainloop) |
922 | - else: |
923 | - self.__dbus_service = None |
924 | - |
925 | - def has_dbus_service(self): |
926 | - return self.__dbus_service is not None |
927 | - |
928 | - def get_internal_name(self): |
929 | - return self.__internal_name |
930 | - |
931 | - def add_option(self, name, to_type=str, to_string=str, default=None, |
932 | - required=True, secret=False): |
933 | - if name in self.__items: |
934 | - raise ValueError |
935 | - if required: |
936 | - self.__required.add(name) |
937 | - if to_type is None: |
938 | - to_type = lambda x: x |
939 | - self.__items[name] = (to_type(default), (to_type, to_string), secret) |
940 | - |
941 | - def __getattr__(self, name): |
942 | - if not self.isConfigured(): |
943 | - raise RuntimeError |
944 | - return self.__items[name][0] |
945 | - |
946 | - def get_as_string(self, name): |
947 | - if not self.isConfigured(): |
948 | - raise RuntimeError |
949 | - try: |
950 | - value, (_, to_string), _ = self.__items[name] |
951 | - except KeyError: |
952 | - raise AttributeError |
953 | - return str(to_string(value)) |
954 | - |
955 | - def set_attribute(self, name, value, check_configured=True): |
956 | - if name not in self.__items: |
957 | - raise ValueError |
958 | - _, (to_type, to_string), secret = self.__items[name] |
959 | - self.__items[name] = (to_type(value), (to_type, to_string), secret) |
960 | - if name in self.__required: |
961 | - self.remove_requirement(name) |
962 | - if check_configured and self.isConfigured(): |
963 | - glib.idle_add(self.emit, "configured") |
964 | - |
965 | - def remove_requirement(self, name): |
966 | - self.__required.remove(name) |
967 | - |
968 | - def add_requirement(self, name): |
969 | - if not name in self.__items: |
970 | - raise ValueError |
971 | - self.__required.add(name) |
972 | - |
973 | - def isConfigured(self): |
974 | - return not self.__required |
975 | - |
976 | - def read_config(self, filename, section): |
977 | - config = SafeConfigParser() |
978 | - config.readfp(open(filename)) |
979 | - if config.has_section(section): |
980 | - for name, value in config.items(section): |
981 | - self.set_attribute(name, value) |
982 | - |
983 | - def dump_config(self, config=None): |
984 | - section = self.get_internal_name() |
985 | - if config is None: |
986 | - config = SafeConfigParser() |
987 | - try: |
988 | - config.add_section(section) |
989 | - except ConfigParser.DuplicateSectionError: |
990 | - pass |
991 | - for key, value in self.__items.iteritems(): |
992 | - value, _, secret = value |
993 | - if not secret: |
994 | - config.set(section, key, str(value)) |
995 | - f = StringIO() |
996 | - config.write(f) |
997 | - return f.getvalue() |
998 | - |
999 | - def get_requirements(self): |
1000 | - return self.__required |
1001 | - |
1002 | - def get_options(self): |
1003 | - return [(str(key), key in self.__required) for key in self.__items] |
1004 | - |
1005 | - |
1006 | -gobject.signal_new("configured", _Configuration, |
1007 | - gobject.SIGNAL_RUN_LAST, |
1008 | - gobject.TYPE_NONE, |
1009 | - tuple()) |
1010 | - |
1011 | - |
1012 | -class DefaultConfiguration(_Configuration): |
1013 | - |
1014 | - CONFIGFILE = BaseDirectory.load_first_config("zeitgeist", "dataprovider.conf") |
1015 | - DEFAULTS = [ |
1016 | - ("enabled", _Configuration.like_bool, str, True, False), |
1017 | - ] |
1018 | - |
1019 | - def __init__(self, dataprovider): |
1020 | - super(DefaultConfiguration, self).__init__(dataprovider) |
1021 | - for default in self.DEFAULTS: |
1022 | - self.add_option(*default) |
1023 | - if self.CONFIGFILE: |
1024 | - self.read_config(self.CONFIGFILE, self.get_internal_name()) |
1025 | - |
1026 | - def save_config(self): |
1027 | - if self.CONFIGFILE: |
1028 | - config = SafeConfigParser() |
1029 | - config.readfp(open(self.CONFIGFILE)) |
1030 | - self.dump_config(config) |
1031 | - f = StringIO() |
1032 | - config.write(f) |
1033 | - configfile = open(self.CONFIGFILE, "w") |
1034 | - try: |
1035 | - config.write(configfile) |
1036 | - finally: |
1037 | - configfile.close() |
1038 | - |
1039 | -if __name__ == "__main__": |
1040 | - |
1041 | - # TODO: Move this to test/. |
1042 | - |
1043 | - def test(config): |
1044 | - for option, required in config.get_options(): |
1045 | - print option, getattr(config, option) |
1046 | - |
1047 | - dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) |
1048 | - mainloop = gobject.MainLoop() |
1049 | - |
1050 | - config = _Configuration("test", True, mainloop) |
1051 | - config.add_option("enabled", _Configuration.like_bool, default=False) |
1052 | - config.connect("configured", test) |
1053 | - mainloop.run() |
1054 | |
1055 | === modified file 'configure.ac' |
1056 | --- configure.ac 2010-09-26 18:16:01 +0000 |
1057 | +++ configure.ac 2010-10-14 09:46:58 +0000 |
1058 | @@ -26,8 +26,6 @@ |
1059 | zeitgeist-daemon.pc |
1060 | zeitgeist/Makefile |
1061 | _zeitgeist/Makefile |
1062 | - _zeitgeist/loggers/Makefile |
1063 | - _zeitgeist/loggers/datasources/Makefile |
1064 | _zeitgeist/engine/Makefile |
1065 | _zeitgeist/engine/extensions/Makefile |
1066 | _zeitgeist/engine/upgrades/Makefile |
1067 | |
1068 | === modified file 'po/POTFILES.in' |
1069 | --- po/POTFILES.in 2009-11-27 20:32:54 +0000 |
1070 | +++ po/POTFILES.in 2010-10-14 09:46:58 +0000 |
1071 | @@ -1,8 +1,4 @@ |
1072 | zeitgeist-daemon.py |
1073 | -zeitgeist-datahub.py |
1074 | zeitgeist/datamodel.py |
1075 | _zeitgeist/singleton.py |
1076 | -_zeitgeist/loggers/zeitgeist_base.py |
1077 | -_zeitgeist/loggers/zeitgeist_setup_service.py |
1078 | -_zeitgeist/loggers/datasources/recent.py |
1079 | _zeitgeist/engine/remote.py |
1080 | |
1081 | === removed file 'test/loggers-datasources-recent-test.py' |
1082 | --- test/loggers-datasources-recent-test.py 2010-09-21 09:17:41 +0000 |
1083 | +++ test/loggers-datasources-recent-test.py 1970-01-01 00:00:00 +0000 |
1084 | @@ -1,49 +0,0 @@ |
1085 | -#!/usr/bin/python |
1086 | - |
1087 | -# Update python path to use local zeitgeist module |
1088 | -import sys |
1089 | -import os |
1090 | -import re |
1091 | -import unittest |
1092 | - |
1093 | -sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) |
1094 | - |
1095 | -SimpleMatch = None |
1096 | -MimeTypeSet = None |
1097 | - |
1098 | -class BaseTestCase(unittest.TestCase): |
1099 | - |
1100 | - def setUp(self): |
1101 | - global SimpleMatch |
1102 | - global MimeTypeSet |
1103 | - if None in (SimpleMatch, MimeTypeSet): |
1104 | - from _zeitgeist.loggers.datasources.recent import SimpleMatch as _SM, MimeTypeSet as _MTS |
1105 | - SimpleMatch = _SM |
1106 | - MimeTypeSet = _MTS |
1107 | - |
1108 | -class SimpleMatchTest(BaseTestCase): |
1109 | - |
1110 | - def testmatch(self): |
1111 | - self.assertTrue(SimpleMatch("boo/*").match("boo/bar")) |
1112 | - self.assertTrue(SimpleMatch("boo/bar.*").match("boo/bar.foo")) |
1113 | - self.assertFalse(SimpleMatch("boo/bar.*").match("boo/barfoo")) |
1114 | - |
1115 | -class MimeTypeSetTest(BaseTestCase): |
1116 | - |
1117 | - def testinit(self): |
1118 | - self.assertEquals(repr(MimeTypeSet("boo", "bar", "foo")), "MimeTypeSet('bar', 'boo', 'foo')") |
1119 | - self.assertEquals(repr(MimeTypeSet("boo", "foo", "foo")), "MimeTypeSet('boo', 'foo')") |
1120 | - m = MimeTypeSet("boo", SimpleMatch("bar/*"), re.compile("test.*")) |
1121 | - self.assertEquals(len(m), 3) |
1122 | - self.assertRaises(ValueError, MimeTypeSet, 1) |
1123 | - |
1124 | - def testcontains(self): |
1125 | - m = MimeTypeSet("boo", SimpleMatch("bar/*"), re.compile("test.*")) |
1126 | - self.assertTrue("boo" in m) |
1127 | - self.assertTrue("bar/boo" in m) |
1128 | - self.assertTrue("testboo" in m) |
1129 | - self.assertFalse("boobar" in m) |
1130 | - self.assertFalse("bar" in m) |
1131 | - |
1132 | -if __name__ == '__main__': |
1133 | - unittest.main() |
1134 | |
1135 | === modified file 'zeitgeist-daemon.py' |
1136 | --- zeitgeist-daemon.py 2010-09-15 12:56:45 +0000 |
1137 | +++ zeitgeist-daemon.py 2010-10-14 09:46:58 +0000 |
1138 | @@ -21,13 +21,13 @@ |
1139 | import sys |
1140 | import os |
1141 | import gobject |
1142 | -import subprocess |
1143 | import dbus.mainloop.glib |
1144 | import gettext |
1145 | import logging |
1146 | import optparse |
1147 | import signal |
1148 | from copy import copy |
1149 | +from subprocess import Popen, PIPE |
1150 | |
1151 | # Make sure we can find the private _zeitgeist namespace |
1152 | from zeitgeist import _config |
1153 | @@ -39,6 +39,7 @@ |
1154 | sys.path.insert(0, constants.USER_EXTENSION_PATH) |
1155 | |
1156 | gettext.install("zeitgeist", _config.localedir, unicode=1) |
1157 | +DATAHUB = "zeitgeist-datahub" |
1158 | |
1159 | def check_loglevel(option, opt, value): |
1160 | value = value.upper() |
1161 | @@ -46,6 +47,11 @@ |
1162 | return value |
1163 | raise optparse.OptionValueError( |
1164 | "option %s: invalid value: %s" % (opt, value)) |
1165 | + |
1166 | +def which(executable): |
1167 | + p = Popen(["which", str(executable)], stderr=PIPE, stdout=PIPE) |
1168 | + p.wait() |
1169 | + return p.stdout.read().strip() or None |
1170 | |
1171 | class Options(optparse.Option): |
1172 | |
1173 | @@ -100,16 +106,21 @@ |
1174 | logging.error(unicode(e)) |
1175 | sys.exit(1) |
1176 | |
1177 | -passive_loggers = os.path.join(_config.bindir, "zeitgeist-datahub.py") |
1178 | if _config.options.start_datahub: |
1179 | - if os.path.isfile(passive_loggers): |
1180 | - devnull = open(os.devnull, 'w') |
1181 | - subprocess.Popen(passive_loggers, stdin=devnull, stdout=devnull, |
1182 | - stderr=devnull) |
1183 | - del devnull |
1184 | + # hide all output of the datahub for now, |
1185 | + # in the future we might want to be more verbose here to make |
1186 | + # debugging easier in case sth. goes wrong with the datahub |
1187 | + devnull = open(os.devnull, "w") |
1188 | + try: |
1189 | + # we assume to find the datahub somewhere in PATH |
1190 | + p = Popen(DATAHUB, stdin=devnull, stdout=devnull, stderr=devnull) |
1191 | + except OSError: |
1192 | + logging.warning("Unable to start the datahub, no binary found") |
1193 | else: |
1194 | - logging.warning( |
1195 | - _("File \"%s\" not found, not starting datahub") % passive_loggers) |
1196 | + # TODO: delayed check if the datahub is still running after some time |
1197 | + # and not failed because of some error |
1198 | + # tell the user which datahub we are running |
1199 | + logging.debug("Running datahub (%s) with PID=%i" %(which(DATAHUB), p.pid)) |
1200 | |
1201 | def handle_sighup(signum, frame): |
1202 | """We are using the SIGHUP signal to shutdown zeitgeist in a clean way""" |
1203 | @@ -117,5 +128,5 @@ |
1204 | interface.Quit() |
1205 | signal.signal(signal.SIGHUP, handle_sighup) |
1206 | |
1207 | -logging.info(_(u"Starting Zeitgeist service...")) |
1208 | +logging.info("Starting Zeitgeist service...") |
1209 | mainloop.run() |
1210 | |
1211 | === removed file 'zeitgeist-datahub.py' |
1212 | --- zeitgeist-datahub.py 2010-01-21 14:57:23 +0000 |
1213 | +++ zeitgeist-datahub.py 1970-01-01 00:00:00 +0000 |
1214 | @@ -1,135 +0,0 @@ |
1215 | -#! /usr/bin/env python |
1216 | -# -.- coding: utf-8 -.- |
1217 | - |
1218 | -# Zeitgeist |
1219 | -# |
1220 | -# Copyright © 2009 Siegfried-Angel Gevatter Pujals <rainct@ubuntu.com> |
1221 | -# |
1222 | -# This program is free software: you can redistribute it and/or modify |
1223 | -# it under the terms of the GNU Lesser General Public License as published by |
1224 | -# the Free Software Foundation, either version 3 of the License, or |
1225 | -# (at your option) any later version. |
1226 | -# |
1227 | -# This program is distributed in the hope that it will be useful, |
1228 | -# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1229 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1230 | -# GNU Lesser General Public License for more details. |
1231 | -# |
1232 | -# You should have received a copy of the GNU Lesser General Public License |
1233 | -# along with this program. If not, see <http://www.gnu.org/licenses/>. |
1234 | - |
1235 | -import sys |
1236 | -import os |
1237 | -import glob |
1238 | -import gettext |
1239 | -import logging |
1240 | -import gobject |
1241 | -import dbus.exceptions |
1242 | - |
1243 | -from zeitgeist import _config |
1244 | -_config.setup_path() |
1245 | - |
1246 | -from zeitgeist.client import ZeitgeistDBusInterface |
1247 | -from _zeitgeist.loggers.zeitgeist_setup_service import DataProviderService |
1248 | - |
1249 | -gettext.install("zeitgeist", _config.localedir, unicode=1) |
1250 | -logging.basicConfig(level=logging.DEBUG) |
1251 | - |
1252 | -sys.path.insert(0, _config.datasourcedir) |
1253 | - |
1254 | -class DataHub(gobject.GObject): |
1255 | - |
1256 | - __gsignals__ = { |
1257 | - "reload" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), |
1258 | - } |
1259 | - |
1260 | - def __init__(self): |
1261 | - |
1262 | - gobject.GObject.__init__(self) |
1263 | - |
1264 | - self._client = ZeitgeistDBusInterface() |
1265 | - self._client.connect_exit(self._daemon_exit) |
1266 | - |
1267 | - # Load the data sources |
1268 | - self._sources = [] |
1269 | - for datasource_file in glob.glob(_config.datasourcedir + '/*.py'): |
1270 | - if not datasource_file.startswith('_'): |
1271 | - self._load_datasource_file(os.path.basename(datasource_file)) |
1272 | - |
1273 | - # Start by fetch new items from all sources |
1274 | - self._sources_queue = list(self._sources) |
1275 | - if not self._sources_queue: |
1276 | - logging.warning(_("No passive loggers found, bye.")) |
1277 | - sys.exit(1) # Mainloop doesn't exist yet, exit directly |
1278 | - self._db_update_in_progress = True |
1279 | - gobject.idle_add(self._update_db_async) |
1280 | - |
1281 | - for source in self._sources: |
1282 | - source.connect("reload", self._update_db_with_source) |
1283 | - |
1284 | - self._mainloop = gobject.MainLoop() |
1285 | - self.dbus_service = DataProviderService(self._sources, None) |
1286 | - self._mainloop.run() |
1287 | - |
1288 | - def _daemon_exit(self): |
1289 | - self._mainloop.quit() |
1290 | - |
1291 | - def _load_datasource_file(self, datasource_file): |
1292 | - |
1293 | - try: |
1294 | - datasource_object = __import__(datasource_file[:-3]) |
1295 | - except ImportError, err: |
1296 | - logging.exception(_("Could not load file: %s" % datasource_file)) |
1297 | - return False |
1298 | - |
1299 | - if hasattr(datasource_object, "__datasource__"): |
1300 | - objs = datasource_object.__datasource__ |
1301 | - for obj in objs if hasattr(objs, "__iter__") else (objs,): |
1302 | - self._sources.append(obj(self._client)) |
1303 | - |
1304 | - def _update_db_with_source(self, source): |
1305 | - """ |
1306 | - Add new items into the database. This funcion should not be |
1307 | - called directly, but instead activated through the "reload" |
1308 | - signal. |
1309 | - """ |
1310 | - |
1311 | - if not source in self._sources_queue: |
1312 | - self._sources_queue.append(source) |
1313 | - if not self._db_update_in_progress: |
1314 | - self._db_update_in_progress = True |
1315 | - gobject.idle_add(self._update_db_async) |
1316 | - |
1317 | - def _update_db_async(self): |
1318 | - |
1319 | - logging.debug(_("Updating database with new %s items") % \ |
1320 | - self._sources_queue[0].get_name()) |
1321 | - |
1322 | - events = self._sources_queue[0].get_items() |
1323 | - if events: |
1324 | - self._insert_events(self._sources_queue[0].get_name(), events) |
1325 | - |
1326 | - del self._sources_queue[0] |
1327 | - |
1328 | - if len(self._sources_queue) == 0: |
1329 | - self._db_update_in_progress = False |
1330 | - return False # Return False to stop this callback |
1331 | - |
1332 | - # Otherwise, if there are more items in the queue return True so |
1333 | - # that GTK+ will continue to call this function in idle CPU time |
1334 | - return True |
1335 | - |
1336 | - def _insert_events(self, source_name, events): |
1337 | - try: |
1338 | - self._client.InsertEvents(events) |
1339 | - except dbus.exceptions.DBusException, error: |
1340 | - error = error.get_dbus_name() |
1341 | - if error == "org.freedesktop.DBus.Error.ServiceUnknown": |
1342 | - logging.warning( |
1343 | - _("Lost connection to zeitgeist-daemon, terminating.")) |
1344 | - self._daemon_exit() |
1345 | - else: |
1346 | - logging.exception(_("Error logging item from \"%s\": %s" % \ |
1347 | - (source_name, error))) |
1348 | - |
1349 | -datahub = DataHub() |
Hi Seif, daemon" and a close look to zeitgeist-daemon.py will show you at least two *very* obvious errors.
thanks for working on this. But why are you proposing branch to be merged into lp:zeitgeist although they are obviously not working. A simple "./zeitgeist-
I personally don't find it motivating being ask for a review of a branch which obviously has not been tested by the author </rant>