diff options
Diffstat (limited to 'src/fringlib/fringwalker.py')
-rw-r--r-- | src/fringlib/fringwalker.py | 290 |
1 files changed, 191 insertions, 99 deletions
diff --git a/src/fringlib/fringwalker.py b/src/fringlib/fringwalker.py index bb6195b..a341955 100644 --- a/src/fringlib/fringwalker.py +++ b/src/fringlib/fringwalker.py @@ -1,147 +1,239 @@ -import os, os.path, stat, sys, time +import os, os.path, stat, sys +import threading +import posixpath # instead of os.path for gnomevfs operations +import time + import gobject, gtk -from threading import Thread +from gnomevfs import * -class sum_list: - def __init__(self, l, name = None): +try: import fringtools +except: print 'Error: Could not find "fringtools" extension module' - self.the_sum = 0 - self.data = list(l) - self.name = name +WALKER_CLASSIC = 0 +WALKER_GNOMEVFS = 1 +WALKER_CPP = 2 - for fn, i in self.data: +def print_tree( treearray, tab=0 ): + """ An utility function to print out a tree array """ - if isinstance(i, sum_list): - self.the_sum += i.the_sum - else: - self.the_sum += i + fn, data, size = treearray + print " "*tab,"%s (%i)"%(fn,size) + if not data: return + if tab > 1: return + for e in data: + print_tree(e,tab+1) - def __str__(self): - return self.name+": "+str(self.data) - def sort(self): +def treearray_cmp_fn( a, b ): + """ a and b are tuples describing a directory tree. Compare first by directory + status, then by size, and finally by name. """ - def cmp_fn(a, b): - a_dir = isinstance(a[1], sum_list) - b_dir = isinstance(b[1], sum_list) + a_dir = a[1] != None + b_dir = b[1] != None - if a_dir and not b_dir: - return 1 - elif b_dir and not a_dir: - return -1 - elif a_dir: - return cmp(a[1].the_sum, b[1].the_sum) - else: - return cmp(a[1], b[1]) + if a_dir and not b_dir: + return 1 + elif b_dir and not a_dir: + return -1 + elif a_dir and b_dir: + return cmp(a[2], b[2]) # compare sizes + else: + return cmp(a[0], b[0]) # compare names - self.data.sort(cmp_fn) class FringWalker( gobject.GObject ): + """ Manages requests for walking directories + + Directory entries are represented by tuples of the following form: + (name, contents, size) + + name: the file name of the directory + contents: a list of entries within the entry. If None, the entry is not a directory + size: the size of the entry. + """ __gsignals__ = { 'list-changed': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), 'finished': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), + 'manually-stopped': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, () ), 'progress': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT,gobject.TYPE_INT)), } def __init__(self): gobject.GObject.__init__(self) self.thread = None - self.stopsignal = False self.showhidden = False - def walk(self,path): - self.thread = Thread(None,self._parse,None,(path,)) - self.stopsignal = False - print "start thread (%s)"%path + def walk(self,uri,method=WALKER_GNOMEVFS): + self.stop() + self.thread = WalkThread(self,uri,self.showhidden,method) self.thread.start() def stop(self): - if self.thread is None: - return - - if not self.thread.isAlive(): + if self.thread: + self.emit("manually-stopped") + self.thread.stopsignal = True self.thread = None - return - - self.stopsignal = True - print "stopping thread:" - #self.thread.join() - print "ok" - - def _parse(self,path): - """ Parse the root directory """ - def progress_fn(c, l, r): - # emit signals + def _progress_fn(self, walkthread, c, l, r): + # only emit if called from the current request + if walkthread == self.thread: gtk.gdk.threads_enter() self.emit("progress", c, l) self.emit("list-changed", r) gtk.gdk.threads_leave() - - r = self._build_tree(path, progress_fn) - gtk.gdk.threads_enter() - self.emit("finished", r) - gtk.gdk.threads_leave() + def _finished_fn(self, walkthread, r): + if walkthread == self.thread: + gtk.gdk.threads_enter() + self.emit("finished", r) + gtk.gdk.threads_leave() + self.thread = None - print "finished walking", path - def _build_tree(self, path, progress_fn = None): - """ Parse directories recursively """ - - ret = [] - tmp_dirs = [] - +class WalkThread( threading.Thread ): + """ A separate class for the thread. """ + + + def __init__(self, master, uri, showhidden, method=WALKER_CLASSIC): + """ Parameters: A FringWalker instance, a string with the path and a bool """ + threading.Thread.__init__(self) + self.stopsignal = False + self.master = master + self.uri = URI(uri) + self.showhidden = showhidden + self.method = method + + def __uri_tail(self, uri): + """ Return the tail (the filename) of a gnomevfs uri """ + f = format_uri_for_display(str(uri)) + f = posixpath.split( f )[-1] + return f + + def build_tree_python(self, path): + l = [] + total = 0 + for fn in os.listdir(path): + if self.stopsignal: return (None,None,0) + if not self.showhidden and fn[0] == ".": continue + try: p = os.path.join(path, fn) + except: continue + s = os.lstat(p) + if stat.S_ISDIR(s.st_mode): + sub = self.build_tree_python(p) + l.append( sub ) + total += sub[2] + elif stat.S_ISREG(s.st_mode): + l.append( (fn, None, s.st_size) ) + total += s.st_size + return (os.path.split(path)[-1], l, total) + + + + def build_tree_gnomevfs(self, uri): + + try: h = DirectoryHandle(uri) + except InvalidURIError: + print uri,"is not a valid uri, skipped" + return (str(uri), None, 0) + except NotFoundError: + print uri,"not found, skipped" + return (str(uri), None, 0) + + l = [] + total = 0 + d = h.next() try: - # walk files in directory - for fn in os.listdir(path): + while True: + if self.stopsignal: return (None,None,0) + d = h.next() + if not self.showhidden and d.name[0] == ".": continue - if self.stopsignal: - return sum_list([]) + if d.type == 2: # directory + sub = self.build_tree_gnomevfs(uri.append_path(d.name)) + l.append( sub ) + total += sub[2] + else: + l.append( (d.name, None, d.size) ) + total += d.size - if not self.showhidden and fn[0] == '.': - continue + except StopIteration: pass + return (self.__uri_tail(uri), l, total) - try: - p = os.path.join(path, fn) - s = os.lstat(p) - except: - continue - if stat.S_ISDIR(s.st_mode): - tmp_dirs.append(fn); - elif stat.S_ISREG(s.st_mode): - ret.append((fn, s.st_size)) - except OSError: - pass + def run(self): + """ Parse the root directory """ + # write some debug information + starttime = time.time() + print "start walking",self.uri, + if self.method == WALKER_CPP: print "(using c++ extension)" + elif self.method == WALKER_GNOMEVFS: print "(using python and gnomevfs)" + else: print "(using classic python)" + + # scan root directory first (using gnomevfs) + try: h = DirectoryHandle(self.uri) + except InvalidURIError: + print uri,"is not a valid uri, skipped" + return (str(self.uri), None, 0) + except NotFoundError: + print uri,"not found, skipped" + return (str(self.uri), None, 0) + + subdirectories = [] + l = [] + total = 0 + d = h.next() try: - c = 0 - - for fn in tmp_dirs: - c += 1 - - if self.stopsignal: - return sum_list([]) - - try: - p = os.path.join(path, fn) - except: - continue + while True: + if self.stopsignal: return + d = h.next() + if not self.showhidden and d.name[0] == ".": continue + + if d.type == 2: # directory + subdirectories.append( d.name ); + else: + l.append( (d.name, None, d.size) ) + total += d.size + except StopIteration: pass + + # emit an intermediate version to fill up the screen while waiting + self.master._progress_fn(self, + 0, len(subdirectories), + (self.__uri_tail(self.uri), l, total)) + + # now walk the subdirectories with the faster extension function + c = 0 + + for directory in subdirectories: + c += 1 + + if self.method == WALKER_CPP: + path = get_local_path_from_uri(str(self.uri))+os.sep+directory + sub = fringtools.build_tree(path, self.showhidden) + elif self.method == WALKER_GNOMEVFS: + uri = self.uri + sub = self.build_tree_gnomevfs(uri.append_path(directory)) + else: + path = get_local_path_from_uri(str(self.uri))+os.sep+directory + sub = self.build_tree_python(path) - ret.append((fn, self._build_tree(p))) + if self.stopsignal: return - if not (progress_fn is None): - r = sum_list(ret, os.path.split(path)[-1]) - r.sort() - progress_fn(c, len(tmp_dirs), r) - - except OSError: - pass + total += sub[2] + l.append( (directory,sub[1],sub[2]) ); - r = sum_list(ret, os.path.split(path)[-1]) - r.sort() + l.sort(treearray_cmp_fn) - return r + # emit an intermediate version after each directory + self.master._progress_fn(self, + c, len(subdirectories), + (self.__uri_tail(self.uri), l, total)) + + + l.sort(treearray_cmp_fn) + # emit final signal + self.master._finished_fn(self,(self.__uri_tail(self.uri), l, total)) + print "finished walking",self.uri,"(time=%s)"%round(time.time()-starttime,2) + |