class ZeitgeistPlugin(PluginClass): plugin_info = { 'name': _('Log events with Zeitgeist'), # T: plugin name 'description': _('Pushes events to the Zeitgeist daemon.'), # T: plugin description 'author': 'Marcel Stimberg', 'help': 'Plugins:Log events with Zeitgeist', } @classmethod def check_dependencies(klass): has_zeitgeist = not ZeitgeistClient is None return has_zeitgeist, [('libzeitgeist', has_zeitgeist, False)] def __init__(self, ui): PluginClass.__init__(self, ui) try: self.zeitgeist_client = ZeitgeistClient() self.zeitgeist_client.register_data_source( 'application://zim.desktop', 'Zim', _('Zim Desktop Wiki'), []) # T: short description of zim except RuntimeError, e: logger.exception( 'Loading zeitgeist client failed, will not log events') self.zeitgeist_client = None
class ZeitgeistPlugin(PluginClass): plugin_info = { 'name': _('Log events with Zeitgeist'), # T: plugin name 'description': _('Pushes events to the Zeitgeist daemon.'), # T: plugin description 'author': 'Marcel Stimberg', 'help': 'Plugins:Log events with Zeitgeist', } @classmethod def check_dependencies(klass): has_zeitgeist = not ZeitgeistClient is None return has_zeitgeist, [('libzeitgeist', has_zeitgeist, False)] def __init__(self, config=None): PluginClass.__init__(self, config) try: self.zeitgeist_client = ZeitgeistClient() self.zeitgeist_client.register_data_source( 'application://zim.desktop', 'Zim', _('Zim Desktop Wiki'), []) # T: short description of zim except RuntimeError as e: logger.exception( 'Loading zeitgeist client failed, will not log events') self.zeitgeist_client = None def create_and_send_event(self, page, event_type): if not self.zeitgeist_client: return if not hasattr(page, 'source') \ or not isinstance(page.source, File): return uri = page.source.uri origin = Gio.File(uri).get_parent().get_uri() text = _('Wiki page: %s') % page.name # T: label for how zim pages show up in the recent files menu, %s is the page name subject = Subject.new_for_values( mimetype='text/x-zim-wiki', uri=uri, origin=origin, interpretation=Interpretation.TEXT_DOCUMENT, manifestation=Manifestation.FILE_DATA_OBJECT, text=text) event = Event.new_for_values(actor='application://zim.desktop', interpretation=event_type, manifestation=Manifestation.USER_ACTIVITY, subjects=[ subject, ]) self.zeitgeist_client.insert_event(event)
class Zeitgeist(EventPlugin): PLUGIN_ID = "zeitgeist" PLUGIN_NAME = _("Event Logging") PLUGIN_DESC = _("Sends song events to the Zeitgeist event logging " "service.") PLUGIN_ICON = Icons.NETWORK_WORKGROUP def enabled(self): self.client = ZeitgeistClient() self.__stopped_by_user = False def disabled(self): del self.client del self.__stopped_by_user def plugin_on_song_started(self, song): if self.__stopped_by_user: manifestation = Manifestation.USER_ACTIVITY else: manifestation = Manifestation.SCHEDULED_ACTIVITY self.__send_event(song, Interpretation.ACCESS_EVENT, manifestation) def plugin_on_song_ended(self, song, stopped): self.__stopped_by_user = stopped if stopped: manifestation = Manifestation.USER_ACTIVITY else: manifestation = Manifestation.SCHEDULED_ACTIVITY self.__send_event(song, Interpretation.LEAVE_EVENT, manifestation) def __send_event(self, song, interpretation, manifestation): if not song: return print_d("event: interpretation=%s, manifestation=%s" % (interpretation.__name__, manifestation.__name__)) subject = Subject.new_for_values( uri=song("~uri"), interpretation=Interpretation.AUDIO, manifestation=Manifestation.FILE_DATA_OBJECT, ) event = Event.new_for_values( timestamp=int(time.time() * 1000), interpretation=interpretation, manifestation=manifestation, actor="application://quodlibet.desktop", subjects=[subject] ) self.client.insert_event(event)
def __init__(self, ui): PluginClass.__init__(self, ui) try: self.zeitgeist_client = ZeitgeistClient() self.zeitgeist_client.register_data_source( 'application://zim.desktop', 'Zim', _('Zim Desktop Wiki'), []) # T: short description of zim except RuntimeError, e: logger.exception( 'Loading zeitgeist client failed, will not log events') self.zeitgeist_client = None
def initialize(self): ''' Inicializes the Zeitgeist client and registers itself as a Zeitgeist data source. ''' self.logger.info('Initialiazing zeitgeist plugin') editor = self.locator.get_service('editor') editor.fileOpened.connect(self._zeitgeist_log_file_open) editor.fileSaved.connect(self._zeitgeist_log_file_modified) #initialize zeitgeist client self.zeitgeist = ZeitgeistClient() self._register_data_source()
def push_to_zeitgeist(commits): ZG = ZeitgeistClient() commits = commits def error_handler(error): print "===> ERROR:", error def ids_reply_handler(ids): global commits print len(commits) if len(commits) > 0: events = format_events(commits[0:100]) commits = commits[100:] time.sleep(0.5) ZG.insert_events(events, ids_reply_handler, error_handler) events = format_events(commits[0:100]) commits = commits[100:] ZG.insert_events(events, ids_reply_handler, error_handler)
def _get_client(self, bus_name, app_uri, app_name, app_description, event_template): client = None try: client = ZeitgeistClient() if hasattr(self.client, "register_data_source"): client.register_data_source( bus_name, app_name or bus_name, app_description or bus_name, event_template or \ [Event.new_for_values(actor=app_uri)]) self.log(logging.DEBUG, 'your client was set') except Exception as e: self.log(logging.ERROR, 'S.O.S: %s', e) raise return client
def __init__(self): """Initialize this instance.""" try: from zeitgeist.client import ZeitgeistClient self.client = ZeitgeistClient() logger.info("Zeitgeist support initialized.") except Exception: logger.exception("Zeitgeist support not started:")
def __init__(self, log=log): self.log = log self._zclient = ZeitgeistClient() self._zdclient = ZeitgeistDBusInterface() self._database = DesktopDatabase(DATABASE_NAME, create=True) self._user = os.environ.get('USERNAME') self._machine = os.uname()
def __init__(self, ui): PluginClass.__init__(self, ui) try: self.zeitgeist_client = ZeitgeistClient() self.zeitgeist_client.register_data_source('application://zim.desktop', 'Zim', _('Zim Desktop Wiki'), []) # T: short description of zim except RuntimeError, e: logger.exception('Loading zeitgeist client failed, will not log events') self.zeitgeist_client = None
def onModLoaded(self): """ The module has been loaded """ self.client = None try: from zeitgeist.client import ZeitgeistClient self.client = ZeitgeistClient() except: logger.info('[%s] Could not create Zeitgeist client\n\n%s' % (MOD_INFO[modules.MODINFO_NAME], traceback.format_exc()))
class CardapioPlugin(CardapioPluginInterface): author = _('Cardapio Team') name = _('Recent documents (simple)') description = _('Search for your most recently used files.') icon = 'document-open-recent' url = '' help_text = '' version = '0.996' plugin_api_version = 1.40 search_delay_type = 'local' default_keyword = 'zgeist' category_count = 1 category_name = _('Recent Documents') category_icon = 'document-open-recent' category_tooltip = _('Files that you have used recently') hide_from_sidebar = False def __init__(self, cardapio_proxy, category): self.c = cardapio_proxy self.loaded = False try: import urllib2, os from zeitgeist.client import ZeitgeistClient from zeitgeist import datamodel except Exception, exception: self.c.write_to_log(self, 'Could not import certain modules', is_error = True) self.c.write_to_log(self, exception, is_error = True) return self.urllib2 = urllib2 self.os = os self.datamodel = datamodel if 'ZeitgeistClient' not in locals(): self.c.write_to_log(self, 'Could not import Zeitgeist', is_error = True) return try: self.zg = ZeitgeistClient() except Exception, exception: self.c.write_to_log(self, 'Could not start Zeitgeist', is_error = True) self.c.write_to_log(self, exception, is_error = True) return
def setUp(self, database_path=None): assert self.daemon is None assert self.client is None self.env = os.environ.copy() self.datapath = tempfile.mkdtemp(prefix="zeitgeist.datapath.") self.env.update({ "ZEITGEIST_DATABASE_PATH": database_path or ":memory:", "ZEITGEIST_DATA_PATH": self.datapath, "XDG_CACHE_HOME": os.path.join(self.datapath, "cache"), }) self.spawn_daemon() # hack to clear the state of the interface ZeitgeistDBusInterface._ZeitgeistDBusInterface__shared_state = {} # Replace the bus connection with a private one for each test case, # so that they don't share signals or other state _set_bus(dbus.SessionBus(private=True)) get_bus().set_exit_on_disconnect(False) self.client = ZeitgeistClient()
class ZeitgeistLogger(object): """A class that logs zeitgeist events.""" client = None def __init__(self): """Initialize this instance.""" try: from zeitgeist.client import ZeitgeistClient self.client = ZeitgeistClient() logger.info("Zeitgeist support initialized.") except Exception: logger.exception("Zeitgeist support not started:") def log(self, event): """Log a zeitgeist event.""" d = Deferred() if self.client: logger.info("Logging Zeitgeist event: %r", event) self.client.insert_event(event, d.callback, d.errback) else: d.callback([]) return d
def onModLoaded(self): """ The module has been loaded """ self.client = None try: from zeitgeist.client import ZeitgeistClient from zeitgeist.datamodel import Event self.client = ZeitgeistClient() if self.client.get_version() >= [0, 3, 2, 999]: self.client.register_data_source("Pogo", "Pogo", "Play your music", [Event.new_for_values(actor="application://pogo.desktop")]) except: logger.info('[%s] Could not create Zeitgeist client\n\n%s' % (MOD_INFO[modules.MODINFO_NAME], traceback.format_exc()))
class ZeitgeistPlugin(PluginClass): plugin_info = { 'name': _('Log events with Zeitgeist'), # T: plugin name 'description': _('Pushes events to the Zeitgeist daemon.'), # T: plugin description 'author': 'Marcel Stimberg', 'help': 'Plugins:Log events with Zeitgeist', } @classmethod def check_dependencies(klass): has_zeitgeist = not ZeitgeistClient is None return has_zeitgeist, [('libzeitgeist', has_zeitgeist, False)] def __init__(self, ui): PluginClass.__init__(self, ui) try: self.zeitgeist_client = ZeitgeistClient() self.zeitgeist_client.register_data_source('application://zim.desktop', 'Zim', _('Zim Desktop Wiki'), []) # T: short description of zim except RuntimeError, e: logger.exception('Loading zeitgeist client failed, will not log events') self.zeitgeist_client = None
def log_install_event(self, desktop_file): """Logs an install event on Zeitgeist""" if not HAVE_MODULE: LOG.warn("No zeitgeist support, impossible to log event") return False if not desktop_file or not len(desktop_file): LOG.warn("Invalid desktop file provided, impossible to log event") return False subject = self.__create_app_subject(desktop_file) subject.text = "Installed with " + self.distro.get_app_name() event = self.__create_user_event() event.interpretation = ZeitgeistDataModel.Interpretation.EVENT_INTERPRETATION.CREATE_EVENT event.append_subject(subject) ZeitgeistClient().insert_event(event) subject.text = "Accessed by " + self.distro.get_app_name() event = self.__create_user_event() event.interpretation = ZeitgeistDataModel.Interpretation.EVENT_INTERPRETATION.ACCESS_EVENT event.append_subject(subject) ZeitgeistClient().insert_event(event) return True
def zclient( self, bus_name='im.pidgin.purple.PurpleInterface', app_uri='application://pidgin.desktop', app_name='Pidgin', app_description="Pidgin is an easy to use and free chat client used by millions. Connect to AIM, MSN, Yahoo, and more chat networks all at once.", event_template=None): if self._client: return self._client try: self._client = ZeitgeistClient() if hasattr(self._client, "register_data_source"): self.client.register_data_source( bus_name, app_name or bus_name, app_description or bus_name, event_template or \ [Event.new_for_values(actor=app_uri)]) except: pass return self._client
class Zeitgeist(modules.ThreadedModule): def __init__(self): """ Constructor """ handlers = { consts.MSG_EVT_APP_QUIT: self.onModUnloaded, consts.MSG_EVT_NEW_TRACK: self.onNewTrack, consts.MSG_EVT_MOD_LOADED: self.onModLoaded, consts.MSG_EVT_APP_STARTED: self.onModLoaded, consts.MSG_EVT_MOD_UNLOADED: self.onModUnloaded, } modules.ThreadedModule.__init__(self, handlers) # --== Message handlers ==-- def onModLoaded(self): """ The module has been loaded """ self.client = None try: from zeitgeist.client import ZeitgeistClient self.client = ZeitgeistClient() except: logger.info('[%s] Could not create Zeitgeist client\n\n%s' % (MOD_INFO[modules.MODINFO_NAME], traceback.format_exc())) def onModUnloaded(self): """ The module has been unloaded """ self.client = None def onNewTrack(self, track): """ Send track information to Zeitgeist """ import mimetypes, os.path from zeitgeist.datamodel import Event, Subject, Interpretation, Manifestation mime, encoding = mimetypes.guess_type(track.getFilePath(), strict=False) subject = Subject.new_for_values( uri = os.path.dirname(track.getURI()), text = track.getTitle() + ' - ' + track.getArtist() + ' - ' + track.getExtendedAlbum(), mimetype = mime, manifestation = unicode(Manifestation.FILE), interpretation = unicode(Interpretation.AUDIO), ) if hasattr(Interpretation, 'ACCESS_EVENT'): eventType = Interpretation.ACCESS_EVENT else: eventType = Interpretation.OPEN_EVENT event = Event.new_for_values( actor = "application://decibel-audio-player.desktop", subjects = [subject,], interpretation = eventType, ) self.client.insert_event(event)
class CardapioPlugin(CardapioPluginInterface): author = _('Cardapio Team') name = _('Recent documents (categorized)') description = _( 'Search for your most recently used files, divided into categories depending on <i>when</i> they were last accessed.' ) icon = 'document-open-recent' url = '' help_text = '' version = '0.996' plugin_api_version = 1.40 search_delay_type = 'local' default_keyword = 'zgeist' category_count = 4 category_name = [ _('Today'), _('This week'), _('This month'), _('All time') ] category_icon = ['document-open-recent'] * 4 category_tooltip = [ _('Files you used today'), _('Files you used this week'), _('Files you used this month'), _('All other files') ] hide_from_sidebar = [False] * 4 def __init__(self, cardapio_proxy, category): # NOTE: Right now Cardapio creates a separate instance for each # category. This is very wasteful! We should instead create a single # instance and pass the category to the search() method instead. self.c = cardapio_proxy self.loaded = False try: import urllib2, os from zeitgeist.client import ZeitgeistClient from zeitgeist import datamodel import time except Exception, exception: self.c.write_to_log(self, 'Could not import certain modules', is_error=True) self.c.write_to_log(self, exception, is_error=True) return self.urllib2 = urllib2 self.os = os self.datamodel = datamodel if 'ZeitgeistClient' not in locals(): self.c.write_to_log(self, 'Could not import Zeitgeist', is_error=True) return try: self.zg = ZeitgeistClient() except Exception, exception: self.c.write_to_log(self, 'Could not start Zeitgeist', is_error=True) self.c.write_to_log(self, exception, is_error=True) return
def get_interface(): global _zg if _zg is None: _zg = ZeitgeistClient() _zg.register_event_subclass(CustomEvent) return _zg
class SoftwareCenterZeitgeist(): """ simple wrapper around zeitgeist """ def __init__(self): try: self.zg_client = ZeitgeistClient() except Exception as e: logging.warn("can not get zeitgeist client: '%s'" % e) self.zg_client = None def get_usage_counter(self, application, callback, timerange=None): """Request the usage count as integer for the given application. When the request is there, "callback" is called. A optional timerange like [time.time(), time.time() - 30*24*60*60] can also be specified """ # helper def _callback(event_ids): callback(len(event_ids)) # no client or empty query -> empty result if not self.zg_client or not application: callback(0) return # the app we are looking for application = "application://"+application.split("/")[-1] # the event_templates e1 = Event.new_for_values( actor=application, interpretation=Interpretation.MODIFY_EVENT.uri) e2 = Event.new_for_values( actor=application, interpretation=Interpretation.CREATE_EVENT.uri) # run it self.zg_client.find_event_ids_for_templates( [e1, e2], _callback, timerange=timerange, num_events=0) def get_popular_mimetypes(self, callback, num=3): """ get the "num" (default to 3) most popular mimetypes based on the last 1000 events that zeitgeist recorded and call "callback" with [(count1, "mime1"), (count2, "mime2"), ...] as arguement """ def _callback(events): # gather mimetypes = {} for event in events: if event.subjects is None: continue mimetype = event.subjects[0].mimetype if not mimetype in mimetypes: mimetypes[mimetype] = 0 mimetypes[mimetype] += 1 # return early if empty results = [] if not mimetypes: callback([]) # convert to result and sort for k, v in mimetypes.items(): results.append([v, k]) results.sort(reverse = True) # tell the client about it callback(results[:num]) # no zeitgeist if not self.zg_client: return # trigger event (actual processing is done in _callback) # FIXME: investigate how result_type MostRecentEvents or # MostRecentSubjects would affect the results self.zg_client.find_events_for_templates( [], _callback, num_events=1000, result_type=ResultType.MostRecentEvents)
def enabled(self): self.client = ZeitgeistClient() self.__stopped_by_user = False
def __init__(self): try: self.zg_client = ZeitgeistClient() except Exception as e: logging.warn("can not get zeitgeist client: '%s'" % e) self.zg_client = None
# You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. import time import rb from gi.repository import GObject, Gio, GLib, Peas from gi.repository import RB from zeitgeist.client import ZeitgeistClient from zeitgeist.datamodel import Event, Subject, Interpretation, Manifestation try: IFACE = ZeitgeistClient() except RuntimeError, e: print "Unable to connect to Zeitgeist, won't send events. Reason: '%s'" % e IFACE = None class ZeitgeistPlugin(GObject.Object, Peas.Activatable): __gtype_name__ = 'ZeitgeistPlugin' object = GObject.property(type=GObject.Object) def __init__(self): GObject.Object.__init__(self) def do_activate(self): print "Loading Zeitgeist plugin..." if IFACE is not None:
class RemoteTestCase(unittest.TestCase): """ Helper class to implement unit tests against a remote Zeitgeist process """ @staticmethod def _get_pid(matching_string): p1 = Popen(["pgrep", "-x", "zeitgeist-daemo"], stdout=PIPE, stderr=PIPE) out = p1.communicate()[0] pid = out.decode().split('\n')[0] p2 = Popen(["ps", "--no-headers", "-fp", pid], stderr=PIPE, stdout=PIPE) pid_line = p2.communicate()[0].decode() return pid_line @staticmethod def _safe_start_subprocess(cmd, env, timeout=1, error_callback=None): """ starts `cmd` in a subprocess and check after `timeout` if everything goes well""" args = {'env': env} if not '--verbose-subprocess' in sys.argv: args['stderr'] = PIPE args['stdout'] = PIPE process = Popen(cmd, **args) # give the process some time to wake up time.sleep(timeout) error = process.poll() if error: cmd = " ".join(cmd) error = "'%s' exits with error %i." % (cmd, error) if error_callback: error += " *** %s" % error_callback(*process.communicate()) raise RuntimeError(error) return process @staticmethod def _safe_start_daemon(env=None, timeout=1): if env is None: env = os.environ.copy() def error_callback(stdout, stderr): stderr = stderr.decode() if "--replace" in stderr: return "%r | %s" % ( stderr, RemoteTestCase._get_pid("./src/zeitgeist-daemon").replace( "\n", "|")) else: return stderr return RemoteTestCase._safe_start_subprocess( ("./src/zeitgeist-daemon", "--no-datahub", "--log-level=DEBUG"), env, timeout, error_callback) def __init__(self, methodName): super(RemoteTestCase, self).__init__(methodName) self.daemon = None self.client = None def spawn_daemon(self): self.daemon = self._safe_start_daemon(env=self.env) def kill_daemon(self, kill_signal=signal.SIGKILL): os.kill(self.daemon.pid, kill_signal) return self.daemon.wait() def setUp(self, database_path=None): assert self.daemon is None assert self.client is None self.env = os.environ.copy() self.datapath = tempfile.mkdtemp(prefix="zeitgeist.datapath.") self.env.update({ "ZEITGEIST_DATABASE_PATH": database_path or ":memory:", "ZEITGEIST_DATA_PATH": self.datapath, "XDG_CACHE_HOME": os.path.join(self.datapath, "cache"), }) self.spawn_daemon() # hack to clear the state of the interface ZeitgeistDBusInterface._ZeitgeistDBusInterface__shared_state = {} # Replace the bus connection with a private one for each test case, # so that they don't share signals or other state _set_bus(dbus.SessionBus(private=True)) get_bus().set_exit_on_disconnect(False) self.client = ZeitgeistClient() def tearDown(self): assert self.daemon is not None assert self.client is not None get_bus().close() self.kill_daemon() if 'ZEITGEIST_TESTS_KEEP_TMP' in os.environ: print('\n\nAll temporary files have been preserved in %s\n' \ % self.datapath) else: shutil.rmtree(self.datapath) def insertEventsAndWait(self, events): """ Insert a set of events and spin a mainloop until the async reply is back and return the result - which should be a list of ids. This method is basically just a hack to invoke an async method in a blocking manner. """ mainloop = self.create_mainloop() result = [] def collect_ids_and_quit(ids): result.extend(ids) mainloop.quit() self.client.insert_events(events, ids_reply_handler=collect_ids_and_quit) mainloop.run() return result def findEventIdsAndWait(self, event_templates, **kwargs): """ Do search based on event_templates and spin a mainloop until the async reply is back and return the result - which should be a list of ids. This method is basically just a hack to invoke an async method in a blocking manner. """ mainloop = self.create_mainloop() result = [] def collect_ids_and_quit(ids): result.extend(ids) mainloop.quit() self.client.find_event_ids_for_templates(event_templates, collect_ids_and_quit, **kwargs) mainloop.run() return result def getEventsAndWait(self, event_ids): """ Request a set of full events and spin a mainloop until the async reply is back and return the result - which should be a list of Events. This method is basically just a hack to invoke an async method in a blocking manner. """ mainloop = self.create_mainloop() result = [] def collect_events_and_quit(events): for event in events: if event: event[0][0] = int(event.id) result.extend(events) mainloop.quit() self.client.get_events(event_ids, collect_events_and_quit) mainloop.run() return result def findEventsForTemplatesAndWait(self, event_templates, **kwargs): """ Execute ZeitgeistClient.find_events_for_templates in a blocking manner. """ mainloop = self.create_mainloop() result = [] def collect_events_and_quit(events): result.extend(events) mainloop.quit() self.client.find_events_for_templates(event_templates, collect_events_and_quit, **kwargs) mainloop.run() return result def findEventsForValuesAndWait(self, *args, **kwargs): """ Execute ZeitgeistClient.find_events_for_value in a blocking manner. """ mainloop = self.create_mainloop() result = [] def collect_events_and_quit(events): result.extend(events) mainloop.quit() self.client.find_events_for_values(collect_events_and_quit, *args, **kwargs) mainloop.run() return result def deleteEventsAndWait(self, event_ids): """ Delete events given by their id and run a loop until the result containing a timetuple describing the interval of changes is returned. This method is basically just a hack to invoke an async method in a blocking manner. """ mainloop = self.create_mainloop() result = [] def collect_timestamp_and_quit(timestamps): result.append(timestamps) mainloop.quit() self.client.delete_events(event_ids, collect_timestamp_and_quit) mainloop.run() return result[0] def findRelatedAndWait(self, subject_uris, num_events, result_type): """ Find related subject uris to given uris and return them. This method is basically just a hack to invoke an async method in a blocking manner. """ mainloop = self.create_mainloop() result = [] def callback(uri_list): result.extend(uri_list) mainloop.quit() self.client.find_related_uris_for_uris(subject_uris, callback, num_events=num_events, result_type=result_type) mainloop.run() return result @staticmethod def create_mainloop(timeout=5): class MainLoopWithFailure(object): """ Remember to wrap callbacks using the asyncTestMethod decorator. """ def __init__(self): self._mainloop = GLib.MainLoop() self.failed = False def __getattr__(self, name): return getattr(self._mainloop, name) def fail(self, message): self.failed = True self.failure_message = message mainloop.quit() def run(self): assert self.failed is False self._mainloop.run() if self.failed: raise AssertionError(self.failure_message) mainloop = MainLoopWithFailure() if timeout is not None: def cb_timeout(): mainloop.fail("Timed out -- " "operations not completed in reasonable time.") return False # stop timeout from being called again # Add an arbitrary timeout so this test won't block if it fails GLib.timeout_add_seconds(timeout, cb_timeout) return mainloop @staticmethod def get_plain_event(ev): """ Ensure that an Event instance is a Plain Old Python Object (popo), without DBus wrappings, etc. """ if not ev: return NULL_EVENT for subject in ev.subjects: if not subject.current_uri: subject.current_uri = subject.uri if not subject.current_origin: subject.current_origin = subject.origin popo = [] popo.append(list(map(str, ev[0]))) popo.append([list(map(str, subj)) for subj in ev[1]]) # We need the check here so that if D-Bus gives us an empty # byte array we don't serialize the text "dbus.Array(...)". popo.append(str(ev[2]) if ev[2] else '') return popo def assertEventsEqual(self, ev1, ev2): ev1 = self.get_plain_event(Event(ev1)) ev2 = self.get_plain_event(Event(ev2)) if ev1 is not NULL_EVENT and ev2 is not NULL_EVENT: if (ev1[0][0] and not ev2[0][0]) or (ev2[0][0] and not ev1[0][0]): ev1[0][0] = ev2[0][0] = "" # delete IDs self.assertEqual(ev1, ev2)
class SoftwareCenterZeitgeist(): """ simple wrapper around zeitgeist """ def __init__(self): try: self.zg_client = ZeitgeistClient() except Exception as e: logging.warn("can not get zeitgeist client: '%s'" % e) self.zg_client = None def get_usage_counter(self, application, callback, timerange=None): """Request the usage count as integer for the given application. When the request is there, "callback" is called. A optional timerange like [time.time(), time.time() - 30*24*60*60] can also be specified """ # helper def _callback(event_ids): callback(len(event_ids)) # no client or empty query -> empty result if not self.zg_client or not application: callback(0) return # the app we are looking for application = "application://" + application.split("/")[-1] # the event_templates e1 = Event.new_for_values( actor=application, interpretation=Interpretation.MODIFY_EVENT.uri) e2 = Event.new_for_values( actor=application, interpretation=Interpretation.CREATE_EVENT.uri) # run it self.zg_client.find_event_ids_for_templates([e1, e2], _callback, timerange=timerange, num_events=0) def get_popular_mimetypes(self, callback, num=3): """ get the "num" (default to 3) most popular mimetypes based on the last 1000 events that zeitgeist recorded and call "callback" with [(count1, "mime1"), (count2, "mime2"), ...] as arguement """ def _callback(events): # gather mimetypes = {} for event in events: if event.subjects is None: continue mimetype = event.subjects[0].mimetype if not mimetype in mimetypes: mimetypes[mimetype] = 0 mimetypes[mimetype] += 1 # return early if empty results = [] if not mimetypes: callback([]) # convert to result and sort for k, v in mimetypes.items(): results.append([v, k]) results.sort(reverse=True) # tell the client about it callback(results[:num]) # no zeitgeist if not self.zg_client: return # trigger event (actual processing is done in _callback) # FIXME: investigate how result_type MostRecentEvents or # MostRecentSubjects would affect the results self.zg_client.find_events_for_templates( [], _callback, num_events=1000, result_type=ResultType.MostRecentEvents)
import os import time import datetime import logging gaj_path = '/home/jendrik/projects/RedNotebook/ref/gnome-activity-journal/' sys.path.insert(0, gaj_path) sys.path.insert(0, os.path.join(gaj_path, 'src')) import gtk import gobject try: import zeitgeist from zeitgeist.client import ZeitgeistClient CLIENT = ZeitgeistClient() if CLIENT.get_version() < [0, 3, 1, 99]: logging.info('Zeitgeist version too old. You need at least 0.3.2') zeitgeist = None else: from zeitgeist.datamodel import Event, Subject, Interpretation, Manifestation, \ ResultType, TimeRange from widgets import Item from common import shade_gdk_color, combine_gdk_color, get_gtk_rgba from daywidgets import DayPartWidget except ImportError, e: logging.info('Zeitgeist not available') zeitgeist = None except RuntimeError, e: logging.error("Unable to connect to Zeitgeist: %s" % e) zeitgeist = None
import os import gtk import gnome.ui import atexit try: from dockmanager.dockmanager import DockManagerItem, DockManagerSink, DOCKITEM_IFACE from zeitgeist.client import ZeitgeistClient from zeitgeist.datamodel import Event, Subject, Interpretation, Manifestation, StorageState from signal import signal, SIGTERM from sys import exit except ImportError, e: exit() try: CLIENT = ZeitgeistClient() version = [int(x) for x in CLIENT.get_version()] MIN_VERSION = [0, 3, 1, 0] if version < MIN_VERSION: print "PLEASE USE ZEITGEIST 0.3.1 or above" exit() except RuntimeError, e: print "Unable to connect to Zeitgeist, won't send events. Reason: '%s'" %e exit() INTERPRETATION = { "http://zeitgeist-project.com/schema/1.0/core#VisitEvent":"OPENED", "http://zeitgeist-project.com/schema/1.0/core#ModifyEvent":"SAVED", "http://zeitgeist-project.com/schema/1.0/core#CreateEvent":"CREATED" }
class RemoteTestCase (unittest.TestCase): """ Helper class to implement unit tests against a remote Zeitgeist process """ @staticmethod def _get_pid(matching_string): p1 = Popen(["ps", "aux"], stdout=PIPE, stderr=PIPE) p2 = Popen(["grep", matching_string], stdin=p1.stdout, stderr=PIPE, stdout=PIPE) return p2.communicate()[0] @staticmethod def _safe_start_subprocess(cmd, env, timeout=1, error_callback=None): """ starts `cmd` in a subprocess and check after `timeout` if everything goes well""" args = { 'env': env } if not '--verbose-subprocess' in sys.argv: args['stderr'] = PIPE args['stdout'] = PIPE process = Popen(cmd, **args) # give the process some time to wake up time.sleep(timeout) error = process.poll() if error: cmd = " ".join(cmd) error = "'%s' exits with error %i." %(cmd, error) if error_callback: error += " *** %s" %error_callback(*process.communicate()) raise RuntimeError(error) return process @staticmethod def _safe_start_daemon(env=None, timeout=1): if env is None: env = os.environ.copy() def error_callback(stdout, stderr): if "--replace" in stderr: return "%r | %s" %(stderr, RemoteTestCase._get_pid( "./src/zeitgeist-daemon").replace("\n", "|")) else: return stderr return RemoteTestCase._safe_start_subprocess( ("./src/zeitgeist-daemon", "--no-datahub", "--log-level=DEBUG"), env, timeout, error_callback) def __init__(self, methodName): super(RemoteTestCase, self).__init__(methodName) self.daemon = None self.client = None def spawn_daemon(self): self.daemon = self._safe_start_daemon(env=self.env) def kill_daemon(self, kill_signal=signal.SIGKILL): os.kill(self.daemon.pid, kill_signal) return self.daemon.wait() def setUp(self, database_path=None): assert self.daemon is None assert self.client is None self.env = os.environ.copy() self.datapath = tempfile.mkdtemp(prefix="zeitgeist.datapath.") self.env.update({ "ZEITGEIST_DATABASE_PATH": database_path or ":memory:", "ZEITGEIST_DATA_PATH": self.datapath, "XDG_CACHE_HOME": os.path.join(self.datapath, "cache"), }) self.spawn_daemon() # hack to clear the state of the interface ZeitgeistDBusInterface._ZeitgeistDBusInterface__shared_state = {} # Replace the bus connection with a private one for each test case, # so that they don't share signals or other state _set_bus(dbus.SessionBus(private=True)) get_bus().set_exit_on_disconnect(False) self.client = ZeitgeistClient() def tearDown(self): assert self.daemon is not None assert self.client is not None get_bus().close() self.kill_daemon() if 'ZEITGEIST_TESTS_KEEP_TMP' in os.environ: print '\n\nAll temporary files have been preserved in %s\n' \ % self.datapath else: shutil.rmtree(self.datapath) def insertEventsAndWait(self, events): """ Insert a set of events and spin a mainloop until the async reply is back and return the result - which should be a list of ids. This method is basically just a hack to invoke an async method in a blocking manner. """ mainloop = self.create_mainloop() result = [] def collect_ids_and_quit(ids): result.extend(ids) mainloop.quit() self.client.insert_events(events, ids_reply_handler=collect_ids_and_quit) mainloop.run() return result def findEventIdsAndWait(self, event_templates, **kwargs): """ Do search based on event_templates and spin a mainloop until the async reply is back and return the result - which should be a list of ids. This method is basically just a hack to invoke an async method in a blocking manner. """ mainloop = self.create_mainloop() result = [] def collect_ids_and_quit(ids): result.extend(ids) mainloop.quit() self.client.find_event_ids_for_templates(event_templates, collect_ids_and_quit, **kwargs) mainloop.run() return result def getEventsAndWait(self, event_ids): """ Request a set of full events and spin a mainloop until the async reply is back and return the result - which should be a list of Events. This method is basically just a hack to invoke an async method in a blocking manner. """ mainloop = self.create_mainloop() result = [] def collect_events_and_quit(events): for event in events: if event: event[0][0] = int(event.id) result.extend(events) mainloop.quit() self.client.get_events(event_ids, collect_events_and_quit) mainloop.run() return result def findEventsForTemplatesAndWait(self, event_templates, **kwargs): """ Execute ZeitgeistClient.find_events_for_templates in a blocking manner. """ mainloop = self.create_mainloop() result = [] def collect_events_and_quit(events): result.extend(events) mainloop.quit() self.client.find_events_for_templates( event_templates, collect_events_and_quit, **kwargs) mainloop.run() return result def findEventsForValuesAndWait(self, *args, **kwargs): """ Execute ZeitgeistClient.find_events_for_value in a blocking manner. """ mainloop = self.create_mainloop() result = [] def collect_events_and_quit(events): result.extend(events) mainloop.quit() self.client.find_events_for_values( collect_events_and_quit, *args, **kwargs) mainloop.run() return result def deleteEventsAndWait(self, event_ids): """ Delete events given by their id and run a loop until the result containing a timetuple describing the interval of changes is returned. This method is basically just a hack to invoke an async method in a blocking manner. """ mainloop = self.create_mainloop() result = [] def collect_timestamp_and_quit(timestamps): result.append(timestamps) mainloop.quit() self.client.delete_events(event_ids, collect_timestamp_and_quit) mainloop.run() return result[0] def findRelatedAndWait(self, subject_uris, num_events, result_type): """ Find related subject uris to given uris and return them. This method is basically just a hack to invoke an async method in a blocking manner. """ mainloop = self.create_mainloop() result = [] def callback(uri_list): result.extend(uri_list) mainloop.quit() self.client.find_related_uris_for_uris(subject_uris, callback, num_events=num_events, result_type=result_type) mainloop.run() return result @staticmethod def create_mainloop(timeout=5): class MainLoopWithFailure(object): """ Remember to wrap callbacks using the asyncTestMethod decorator. """ def __init__(self): self._mainloop = gobject.MainLoop() self.failed = False def __getattr__(self, name): return getattr(self._mainloop, name) def fail(self, message): self.failed = True self.failure_message = message mainloop.quit() def run(self): assert self.failed is False self._mainloop.run() if self.failed: raise AssertionError, self.failure_message mainloop = MainLoopWithFailure() if timeout is not None: def cb_timeout(): mainloop.fail("Timed out -- " "operations not completed in reasonable time.") return False # stop timeout from being called again # Add an arbitrary timeout so this test won't block if it fails gobject.timeout_add_seconds(timeout, cb_timeout) return mainloop @staticmethod def get_plain_event(ev): """ Ensure that an Event instance is a Plain Old Python Object (popo), without DBus wrappings, etc. """ if not ev: return NULL_EVENT for subject in ev.subjects: if not subject.current_uri: subject.current_uri = subject.uri if not subject.current_origin: subject.current_origin = subject.origin popo = [] popo.append(map(unicode, ev[0])) popo.append([map(unicode, subj) for subj in ev[1]]) # We need the check here so that if D-Bus gives us an empty # byte array we don't serialize the text "dbus.Array(...)". popo.append(str(ev[2]) if ev[2] else u'') return popo def assertEventsEqual(self, ev1, ev2): ev1 = self.get_plain_event(Event(ev1)) ev2 = self.get_plain_event(Event(ev2)) if ev1 is not NULL_EVENT and ev2 is not NULL_EVENT: if (ev1[0][0] and not ev2[0][0]) or (ev2[0][0] and not ev1[0][0]): ev1[0][0] = ev2[0][0] = "" # delete IDs self.assertEqual(ev1, ev2)
return getattr(self._extension, name) except TypeError: print _("Could not find extension method \"%s\"") % name if self._restarted: print _("Aborting.") self._show_error() raise SystemExit else: print _("Attempting to restart Zeitgeist...") self._restarted = True CLIENT._iface.Quit() self._extension.reconnect() return self.__getattr__(name) try: CLIENT = ZeitgeistClient() except RuntimeError, e: print "%s: %s" % (_("ERROR"), _("Unable to connect to Zeitgeist:")) print "%s" % e CLIENT = CLIENT_VERSION = CLIENT_EXTENSION = None else: CLIENT_VERSION = CLIENT.get_version() CLIENT_EXTENSION = ClientExtension() STORE = None try: BUS = dbus.SessionBus() except Exception: BUS = None
class Zeitgeist(modules.ThreadedModule): def __init__(self): """ Constructor """ handlers = { consts.MSG_EVT_APP_QUIT: self.onModUnloaded, consts.MSG_EVT_NEW_TRACK: self.onNewTrack, consts.MSG_EVT_MOD_LOADED: self.onModLoaded, consts.MSG_EVT_APP_STARTED: self.onModLoaded, consts.MSG_EVT_MOD_UNLOADED: self.onModUnloaded, } modules.ThreadedModule.__init__(self, handlers) # --== Message handlers ==-- def onModLoaded(self): """ The module has been loaded """ self.client = None try: from zeitgeist.client import ZeitgeistClient from zeitgeist.datamodel import Event self.client = ZeitgeistClient() if self.client.get_version() >= [0, 3, 2, 999]: self.client.register_data_source("Pogo", "Pogo", "Play your music", [Event.new_for_values(actor="application://pogo.desktop")]) except: logger.info('[%s] Could not create Zeitgeist client\n\n%s' % (MOD_INFO[modules.MODINFO_NAME], traceback.format_exc())) def onModUnloaded(self): """ The module has been unloaded """ self.client = None def onNewTrack(self, track): """ Send track information to Zeitgeist """ if self.client is None: return from zeitgeist.datamodel import Interpretation if hasattr(Interpretation, 'ACCESS_EVENT'): event_type = Interpretation.ACCESS_EVENT else: event_type = Interpretation.OPEN_EVENT self.send_to_zeitgeist(track, event_type) def send_to_zeitgeist(self, track, event_type): """ Other players (e.g. Rhythmbox) log the playing of individual files, but we want to log albums. Maybe it would be better to log individual files, but then we would have to distinguish between Manifestation.USER_ACTIVITY and Manifestation.SCHEDULED_ACTIVITY. Another possible addition would be logging Interpretation.LEAVE_EVENT. """ import mimetypes, os.path from zeitgeist.datamodel import Event, Subject, Interpretation, Manifestation mime, encoding = mimetypes.guess_type(track.getFilePath(), strict=False) title = track.getTitle() album = track.getAlbum() artist = track.getArtist() uri = track.getURI() origin = os.path.dirname(uri) # Handle "unknown" tags if 'unknown' in title.lower(): title = track.getBasename() if 'unknown' in album.lower(): album = '' if 'unknown' in artist.lower(): artist = '' subject = Subject.new_for_values( uri = origin, text = ' - '.join([part for part in [artist, album] if part]), mimetype = mime, manifestation = unicode(Manifestation.FILE_DATA_OBJECT), interpretation = unicode(Interpretation.AUDIO), origin = origin, ) event = Event.new_for_values( actor = "application://pogo.desktop", subjects = [subject,], interpretation = unicode(event_type), timestamp = int(time.time() * 1000), ) self.client.insert_event(event)
class ZeitgeistIntegration(plugin.Plugin): ''' Plugin that enables integration with the Zeitgeist Framework. ''' def initialize(self): ''' Inicializes the Zeitgeist client and registers itself as a Zeitgeist data source. ''' self.logger.info('Initialiazing zeitgeist plugin') editor = self.locator.get_service('editor') editor.fileOpened.connect(self._zeitgeist_log_file_open) editor.fileSaved.connect(self._zeitgeist_log_file_modified) #initialize zeitgeist client self.zeitgeist = ZeitgeistClient() self._register_data_source() def finish(self): ''' Deletes the reference to the Zeitgeist client. ''' # remove zeitgeist client del self.zeitgeist self.logger.info('Shutting down zeitgeist plugin') def _register_data_source(self): ''' Registers the plugin as a Zeitgeist data source. ''' unique_id = 'org.ninja.ide' name = 'Ninja IDE' description = 'Very versatile Python IDE' # Describe what sort of events will be inserted templates = [] for interp in (Interpretation.EVENT_INTERPRETATION.ACCESS_EVENT, Interpretation.EVENT_INTERPRETATION.MODIFY_EVENT, Interpretation.EVENT_INTERPRETATION.LEAVE_EVENT, Interpretation.EVENT_INTERPRETATION.CREATE_EVENT): event_template = Event() event_template.interpretation = interp event_template.manifestation = Manifestation.USER_ACTIVITY for subj_interp in (Interpretation.DOCUMENT.TEXT_DOCUMENT. PLAIN_TEXT_DOCUMENT.SOURCE_CODE, Interpretation.DOCUMENT.TEXT_DOCUMENT.PLAIN_TEXT_DOCUMENT): subject_template = Subject() subject_template.interpretation = subj_interp subject_template.manifestation = Manifestation.FILE_DATA_OBJECT event_template.append_subject(subject_template) templates.append(event_template) self.zeitgeist.register_data_source(unique_id, name, description, templates) def _zeitgeist_log_event(self, fileName, interpretation): ''' Registers an event over the file with a given interpretation. ''' fileName = unicode(fileName) self.logger.info('Inserting event for %s' % fileName) subject = Subject.new_for_values( uri='file://%s' % fileName, origin='file://%s' % path.dirname(fileName), text=path.basename(fileName)) event = Event.new_for_values( timestamp=int(time.time() * 1000), interpretation=interpretation, manifestation=Manifestation.USER_ACTIVITY, actor='application://ninja-ide.desktop', subjects=[subject]) def on_id_received(event_ids): self.logger.info( 'Logged %r with event id %d.' % (fileName, event_ids[0])) self.zeitgeist.insert_events([event], on_id_received) def _zeitgeist_log_file_open(self, fileName): ''' Registers an event everytime Ninja IDE opens a file. ''' self._zeitgeist_log_event(unicode(fileName), Interpretation.EVENT_INTERPRETATION.ACCESS_EVENT) def _zeitgeist_log_file_modified(self, fileName): ''' Registers an event everytime Ninja IDE modifies a file. ''' self._zeitgeist_log_event(unicode(fileName), Interpretation.EVENT_INTERPRETATION.MODIFY_EVENT)
# # # http://www.apache.org/licenses/LICENSE-2.0 # # # # Unless required by applicable law or agreed to in writing, software # # distributed under the License is distributed on an "AS IS" BASIS, # # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# # See the License for the specific language governing permissions and # # limitations under the License. # ########################################################################### import datetime, psutil, csv from zeitgeist.client import ZeitgeistClient from zeitgeist.datamodel import * zeitgeist = ZeitgeistClient() b_time = psutil.boot_time() # Only the first time to write the header. #with open('test.csv', 'wb') as csvfile: #writer = csv.writer(csvfile) #writer.writerow(('Boot time', 'Software', 'Time', 'Other Processes')) def intToDate(timestamp): return datetime.datetime.fromtimestamp(timestamp).strftime('%Y-%m-%d %H:%M:%S') def listProcess(): pList = [] for proc in psutil.process_iter(): try: pinfo = proc.as_dict(attrs=['pid', 'name'])
import os import subprocess import sys import time CLIENT = None try: from zeitgeist.client import ZeitgeistClient from zeitgeist.datamodel import Event, Subject, Interpretation, Manifestation except ImportError: pass else: try: CLIENT = ZeitgeistClient() except RuntimeError as e: print("Unable to connect to Zeitgeist, won't send events. Reason: '%s'" % e) def get_repo(): """Get uri of remote repository and its name""" repo = None uri = subprocess.Popen(['git', 'config', '--get', 'remote.origin.url'], stdout=subprocess.PIPE).communicate()[0] if uri: uri = uri.strip().decode(sys.getfilesystemencoding()) if '/' in uri: sep = '/' else:
line = sys.argv[1].strip() prompt_index = line.find(MY_PROMPT) if ( prompt_index > -1 ): args_index = prompt_index + len(MY_PROMPT) prompt = line[:args_index] args = line[args_index:].strip().split(" ") cmd = args[0] # TODO add more commands. For now only command cd triggers event. if(cmd == 'cd'): try: from zeitgeist.client import ZeitgeistClient from zeitgeist.datamodel import Subject, Event, Interpretation, Manifestation zeitgeistclient = ZeitgeistClient() got_zeitgeist = True except (RuntimeError, ImportError, dbus.exceptions.DBusException): got_zeitgeist = False precond = os.getuid() != 0 and os.getenv('DBUS_SESSION_BUS_ADDRESS') != None if got_zeitgeist and precond: uri = 'file:///home/saasbook/typescript.txt' # must exist mimetype = 'text/plain' event_actor = 'app://somefakestring.desktop' event_interp = 'new' event_manif = 'user' subject_interp = 'document' subject_manif = 'file_data_object'