def is_valid(self):
     if isabs(self._program):
         returnval = exists(self._program)
     else:
         returnval = is_program_in_path(self._program)
     if not returnval:
         LOGGER.debug("%s does not exist", self._program)
     return returnval
Esempio n. 2
0
 def is_valid(self):
     if isabs(self._program):
         returnval = exists(self._program)
     else:
         returnval = is_program_in_path(self._program)
     if not returnval:
         LOGGER.debug("%s does not exist", self._program)
     return returnval
Esempio n. 3
0
    def query_path_programs(self, query, desktop_progs):
        """
        @param query: Query string
        @param desktop_progs: Names of binaries from .desktop files
        """
        args = query.split(" ")
        program = args[0]
        priority = self.get_priority()

        if len(args) == 1:
            results = []
            for pathdir in PATH:
                try:
                    pathstat = stat(pathdir)
                    pathmtime = pathstat.st_mtime
                except OSError:
                    continue

                indexpair = self._path_indexers.get(pathdir, None)
                if indexpair is not None:
                    indexer, updatetime = indexpair
                else:
                    indexer, updatetime = deskbar.core.Indexer.Indexer(), -1
                if pathmtime > updatetime:
                    self._scan_path(pathdir, indexer)
                    self._path_indexers[pathdir] = (indexer, time.time())
                for match in indexer.look_up(program):
                    if match.get_hash() in desktop_progs:
                        continue
                    match.set_priority(priority +
                                       get_priority_for_name(query, program))
                    results.append(match)

            return results
        else:
            # We have arguments, execute the command as typed in by the user
            if not (program in desktop_progs) and is_program_in_path(program):
                match = PathProgramMatch(program, query)
                match.set_priority(self.get_priority() + EXACT_MATCH_PRIO)
                return [match]
            else:
                return []
Esempio n. 4
0
    def query_path_programs(self, query, desktop_progs):
        """
        @param query: Query string
        @param desktop_progs: Names of binaries from .desktop files
        """
        args = query.split(" ")     
        program = args[0]
        priority = self.get_priority()

        if len(args) == 1:
            results = []
            for pathdir in PATH:
                try:
                    pathstat = stat(pathdir)
                    pathmtime = pathstat.st_mtime
                except OSError:
                    continue

                indexpair = self._path_indexers.get(pathdir, None)
                if indexpair is not None:
                    indexer, updatetime = indexpair
                else:
                    indexer, updatetime = deskbar.core.Indexer.Indexer(), -1
                if pathmtime > updatetime:
                    self._scan_path(pathdir, indexer)
                    self._path_indexers[pathdir] = (indexer, time.time())
                for match in indexer.look_up(program):
                    if match.get_hash() in desktop_progs:
                        continue
                    match.set_priority(priority + get_priority_for_name(query, program))
                    results.append(match)

            return results
        else:
            # We have arguments, execute the command as typed in by the user
            if not (program in desktop_progs) and is_program_in_path(program):
                match = PathProgramMatch(program, query)
                match.set_priority (self.get_priority() + EXACT_MATCH_PRIO)
                return [match]
            else:
                return []
Esempio n. 5
0
class BeagleLiveHandler(deskbar.interfaces.Module):

    INFOS = {
        'icon':
        load_icon("system-search"),
        "name":
        _("Beagle Live"),
        "description":
        _("Search all of your documents (using Beagle), as you type"),
        'version':
        VERSION,
    }

    def __init__(self):
        deskbar.interfaces.Module.__init__(self)
        self.__counter_lock = threading.Lock()
        self.__beagle_lock = threading.Lock()
        self.__snippet_lock = threading.Lock()
        self.__finished_lock = threading.Lock()

        self.__snippet_request = {}  # Maps beagle.Hit to beagle.SnippetRequest

        # We have to store instances for each query term
        self._counter = {}  # Count hits for each hit type
        self._at_max = {
        }  # Whether we have reached the maximum for a particular hit type before
        self._beagle_query = {}
        self.__hits_added_id = {}
        self.__hits_finished_id = {}
        self.__finished = {
        }  # Whether we got all matches from beagle for query

    def initialize(self):
        self.beagle = beagle.Client()

    def stop(self):
        self.beagle = None

    def query(self, qstring):
        self.__counter_lock.acquire()
        self._counter[qstring] = {}
        self._at_max[qstring] = {}
        self.__counter_lock.release()

        self.__finished_lock.acquire()
        self.__finished[qstring] = False
        self.__finished_lock.release()

        try:
            self.__beagle_lock.acquire()

            beagle_query = beagle.Query()
            self.__hits_added_id[qstring] = beagle_query.connect(
                "hits-added", self._on_hits_added, qstring)
            self.__hits_finished_id[qstring] = beagle_query.connect(
                "finished", self._on_finished, qstring)
            beagle_query.add_text(qstring)

            self._beagle_query[qstring] = beagle_query

            LOGGER.debug("Sending beagle query (%r) for '%s'",
                         self._beagle_query[qstring], qstring)
            try:
                self.beagle.send_request_async(self._beagle_query[qstring])
            except GError, e:
                LOGGER.exception(e)
                self._cleanup_query(qstring)
        finally:
            self.__beagle_lock.release()

    def _on_hits_added(self, query, response, qstring):
        for hit in response.get_hits():
            if hit.get_type() not in TYPES:
                LOGGER.info("Beagle live seen an unknown type: %s",
                            str(hit.get_type()))
                continue

            beagle_type = self._get_beagle_type(hit)
            if beagle_type == None:
                continue

            if beagle_type.get_has_snippet():
                self._get_snippet(query, hit, qstring, beagle_type)
            else:
                self._create_match(hit, beagle_type, qstring)

    def _on_finished(self, query, response, qstring):
        LOGGER.debug("Beagle query (%r) for '%s' finished with response %r",
                     query, qstring, response)
        self.__finished_lock.acquire()
        self.__finished[qstring] = True
        self.__finished_lock.release()

    def _on_snippet_received(self, request, response, hit, qstring,
                             beagle_type):
        snippet = response.get_snippet()
        if snippet == None:
            snippet_text = None
        else:
            # Remove trailing whitespaces and escape '%'
            snippet_text = snippet.strip().replace("%", "%%")

        self._create_match(hit, beagle_type, qstring, snippet_text)

    def _on_snippet_closed(self, request, hit, qstring):
        self._cleanup_snippet(hit)

        self.__snippet_lock.acquire()
        n_snippets = len(self.__snippet_request)
        self.__snippet_lock.release()

        self.__finished_lock.acquire()
        finished = self.__finished[qstring]
        self.__finished_lock.release()

        # FIXME: This only works when at least one
        # result has a snippet, otherwise we
        # miss cleaning up
        if finished and n_snippets == 0:
            self._cleanup_query(qstring)
            self._cleanup_counter(qstring)

    def _cleanup_counter(self, qstring):
        self.__counter_lock.acquire()
        if qstring in self._counter:
            del self._counter[qstring]
            del self._at_max[qstring]
        self.__counter_lock.release()

    def _cleanup_snippet(self, hit):
        LOGGER.debug("Cleaning up hit %r", hit)
        self.__snippet_lock.acquire()
        del self.__snippet_request[hit]
        self.__snippet_lock.release()
        hit.unref()

    def _cleanup_query(self, qstring):
        LOGGER.debug("Cleaning up query for '%s'", qstring)
        # Remove counter for query
        self.__beagle_lock.acquire()
        # Disconnect signals, otherwise we receive late matches
        # when beagle found the query term in a newly indexed file
        beagle_query = self._beagle_query[qstring]
        beagle_query.disconnect(self.__hits_added_id[qstring])
        beagle_query.disconnect(self.__hits_finished_id[qstring])
        del self._beagle_query[qstring]
        del self.__hits_added_id[qstring]
        del self.__hits_finished_id[qstring]
        self.__beagle_lock.release()

        self.__finished_lock.acquire()
        del self.__finished[qstring]
        self.__finished_lock.release()

    def _get_snippet(self, query, hit, qstring, beagle_type):
        LOGGER.debug("Retrieving snippet for hit %r", hit)

        snippet_request = beagle.SnippetRequest()
        snippet_request.set_query(query)
        snippet_request.set_hit(hit)
        hit.ref()
        snippet_request.connect('response', self._on_snippet_received, hit,
                                qstring, beagle_type)
        snippet_request.connect('closed', self._on_snippet_closed, hit,
                                qstring)

        self.__snippet_lock.acquire()
        self.__snippet_request[hit] = snippet_request
        self.__snippet_lock.release()

        try:
            self.__beagle_lock.acquire()
            try:
                self.beagle.send_request_async(snippet_request)
            except GError, e:
                LOGGER.exception(e)
                self._cleanup_snippet(hit)
        finally:
            self.__beagle_lock.release()

    def _get_beagle_type(self, hit):
        """
        Returns the appropriate L{BeagleType}
        for the given hit
        
        @type hit: beagle.Hit
        @return: L{BeagleType} instance
        """
        hit_type = hit.get_type()
        snippet = None

        if hit_type in TYPES:
            beagle_type = TYPES[hit_type]
        else:
            LOGGER.warning("Unknown beagle match type found: %s",
                           result["type"])
            return None

        # Directories are Files in beagle context
        if hit_type == "File":
            filetype = hit.get_properties("beagle:FileType")
            if filetype != None \
                and filetype[0] in BEAGLE_FILE_TYPE_TO_TYPES_MAP:
                beagle_type = TYPES[BEAGLE_FILE_TYPE_TO_TYPES_MAP[filetype[0]]]

        return beagle_type

    def _create_match(self, hit, beagle_type, qstring, snippet=None):
        # Get category
        cat_type = beagle_type.get_category()

        result = {
            "uri": hit.get_uri(),
            "type": beagle_type,
            "snippet": snippet,
        }

        self.__counter_lock.acquire()
        # Create new counter for query and type
        if not cat_type in self._counter[qstring]:
            self._counter[qstring][cat_type] = 0
        # Increase counter
        self._counter[qstring][cat_type] += 1

        if self._counter[qstring][cat_type] > MAX_RESULTS:
            if cat_type in self._at_max[qstring]:
                # We already reached the maximum before
                self.__counter_lock.release()
                return
            else:
                # We reach the maximum for the first time
                self._at_max[qstring][cat_type] = True
                self._emit_query_ready(qstring, [
                    BeagleSearchMatch(qstring, cat_type,
                                      beagle_type.get_hit_type())
                ])
            self.__counter_lock.release()
            return
        self.__counter_lock.release()

        self._get_properties(hit, result)
        self._escape_pango_markup(result, qstring)

        self._emit_query_ready(qstring, [
            BeagleLiveMatch(
                result, category=cat_type, priority=self.get_priority())
        ])

    def _get_properties(self, hit, result):
        beagle_type = result["type"]

        name = None
        for prop in beagle_type.get_name_properties():
            try:
                name = hit.get_properties(
                    prop
                )[0]  # get_property_one() would be cleaner, but this works around bug #330053
            except:
                pass

            if name != None:
                result["name"] = name
                break

        if name == None:
            #translators: This is used for unknown values returned by beagle
            #translators: for example unknown email sender, or unknown note title
            result["name"] = _("?")

        for prop, keys in beagle_type.get_extra_properties().items():
            val = None
            for key in keys:
                try:
                    val = hit.get_properties(
                        key
                    )[0]  # get_property_one() would be cleaner, but this works around bug #330053
                except:
                    pass

                if val != None:
                    result[prop] = val
                    break

            if val == None:
                #translators: This is used for unknown values returned by beagle
                #translators: for example unknown email sender, or unknown note title
                result[prop] = _("?")

    def _escape_pango_markup(self, result, qstring):
        """
        Escape everything for display through pango markup, except filenames.
        Filenames are escaped in escaped_uri or escaped_identifier
        """
        for key, val in result.items():
            if key == "uri" or key == "identifier":
                result["escaped_" + key] = cgi.escape(val)
            elif key == "snippet":
                # Add the snippet, in escaped form if available
                if result["snippet"] != None and result["snippet"] != "":
                    tmp = re.sub(r"<.*?>", "", result["snippet"])
                    tmp = re.sub(r"</.*?>", "", tmp)
                    result["snippet"] = cgi.escape(tmp)

                    # FIXME: re.escape too much, we only want to escape special regex chars
                    # we should provide a convenient method for _all_ modules
                    result["snippet"] = re.sub(
                        re.escape(qstring),
                        "<span weight='bold'>" + qstring + "</span>",
                        result["snippet"], re.IGNORECASE)
                else:
                    result["snippet"] = ""
            elif isinstance(result[key], str):
                result[key] = cgi.escape(val)

    @staticmethod
    def has_requirements():
        # Check if we have python bindings for beagle
        try:
            import beagle
        except Exception, e:
            BeagleLiveHandler.INSTRUCTIONS = _(
                "Could not load beagle, libbeagle has been compiled without python bindings."
            )
            return False

        # Check if beagled is running
        if not beagle.beagle_util_daemon_is_running():
            if is_program_in_path("beagled"):
                BeagleLiveHandler.INSTRUCTIONS = _(
                    "Beagle daemon is not running.")
                return False
            else:
                BeagleLiveHandler.INSTRUCTIONS = _(
                    "Beagled could not be found in your $PATH.")
                return False
        else:
            return True