⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dirdiff.py

📁 LINUX下的文件比较工具
💻 PY
📖 第 1 页 / 共 3 页
字号:
    def set_locations(self, locations):        self.set_num_panes(len(locations))        locations = [os.path.abspath(l or ".") for l in locations]        self.model.clear()        for pane, loc in enumerate(locations):            self.fileentry[pane].set_filename(loc)        child = self.model.add_entries(None, locations)        self._update_item_state(child)        self.recompute_label()        self.scheduler.remove_all_tasks()        self.recursively_update( (0,) )    def recursively_update( self, path ):        """Recursively update from tree path 'path'.        """        it = self.model.get_iter( path )        child = self.model.iter_children( it )        while child:            self.model.remove(child)            child = self.model.iter_children( it )        self._update_item_state(it)        self.scheduler.add_task( self._search_recursively_iter( path ).next )    def _search_recursively_iter(self, rootpath):        self.filter_hide_current.set_sensitive(False)        yield _("[%s] Scanning %s") % (self.label_text, "")        prefixlen = 1 + len( self.model.value_path( self.model.get_iter(rootpath), 0 ) )        symlinks_followed = {} # only follow symlinks once        todo = [ rootpath ]        while len(todo):            todo.sort() # depth first            path = todo.pop(0)            it = self.model.get_iter( path )            roots = self.model.value_paths( it )            yield _("[%s] Scanning %s") % (self.label_text, roots[0][prefixlen:])            differences = [0]            if not self.button_ignore_case.get_active():                class accum(object):                    def __init__(self, parent, roots):                        self.items = []                        self.n = parent.num_panes                    def add(self, pane, items):                        self.items.extend(items)                    def get(self):                        self.items.sort()                        def repeat(s, n):                            for i in xrange(n):                                yield s                        return [ tuple(repeat(i,self.n)) for i in  uniq(self.items) ]            else:                canonicalize = lambda x : x.lower()                class accum(object):                    def __init__(self, parent, roots):                        self.items = {} # map canonical names to realnames                        self.bad = []                        self.parent = parent                        self.roots = roots                        self.default = [None] * self.parent.num_panes                    def add(self, pane, items):                        for i in items:                            ci = canonicalize(i)                            try:                                assert self.items[ ci ][pane] == None                            except KeyError:                                self.items[ ci ] = self.default[:]                                self.items[ ci ][pane] = i                            except AssertionError:                                self.bad.append( _("'%s' hidden by '%s'") %                                    ( os.path.join(self.roots[pane], i), self.items[ ci ][pane]) )                            else:                                self.items[ ci ][pane] = i                    def get(self):                        if len(self.bad):                            misc.run_dialog(_("You are running a case insensitive comparison on"                                " a case sensitive filesystem. Some files are not visible:\n%s")                                % "\n".join( self.bad ), self.parent )                        keys = self.items.keys()                        keys.sort()                        def fixup(key, tuples): # replace None with a usable label                            def first_nonempty(seq):                                for s in seq:                                    if s: return s                            return tuple([ t or first_nonempty(tuples) or k for t in tuples ])                        return [ fixup(k, self.items[k]) for k in keys ]            accumdirs = accum(self, roots)            accumfiles = accum(self, roots)            for pane, root in enumerate(roots):                if os.path.isdir( root ):                    try:                        entries = os.listdir( root )                    except OSError, err:                        self.model.add_error( it, err.strerror, pane )                        differences = [1]                    else:                        for f in self.name_filters:                            entries = filter(f.filter, entries)                        files = []                        dirs = []                        for e in entries:                            s = os.lstat( join(root,e) )                            if stat.S_ISLNK(s.st_mode):                                if not self.prefs.ignore_symlinks:                                    key = (s.st_dev, s.st_ino)                                    if symlinks_followed.get( key, 0 ) == 0:                                        symlinks_followed[key] = 1                                        try:                                            s = os.stat( join(root,e) )                                        except OSError, err:                                            print "ignoring dangling symlink", e                                            pass                                        else:                                            if stat.S_ISREG(s.st_mode):                                                files.append(e)                                            elif stat.S_ISDIR(s.st_mode):                                                dirs.append(e)                            elif stat.S_ISREG(s.st_mode):                                files.append(e)                            elif stat.S_ISDIR(s.st_mode):                                dirs.append(e)                        accumfiles.add( pane, files )                        accumdirs.add( pane, dirs )            alldirs = accumdirs.get()            allfiles = self._filter_on_state( roots, accumfiles.get() )            # then directories and files            if len(alldirs) + len(allfiles) != 0:                def add_entry(names):                    child = self.model.add_entries( it, [join(r,n) for r,n in zip(roots, names) ] )                    differences[0] |= self._update_item_state(child)                    return child                map(lambda x : todo.append( self.model.get_path(add_entry(x))), alldirs )                map(add_entry, allfiles)            else: # directory is empty, add a placeholder                self.model.add_empty(it)            if differences[0]:                start = path[:]                while len(start) and not self.treeview[0].row_expanded(start):                    start = start[:-1]                level = len(start)                while level < len(path):                    level += 1                    self.treeview[0].expand_row( path[:level], 0)        yield _("[%s] Done") % self.label_text        self.filter_hide_current.set_sensitive(True)    def launch_comparison(self, it, pane, force=1):        """Launch comparison at 'it'.            If it is a file we launch a diff.           If it is a folder we recursively open diffs for each non equal file.        """        paths = filter(os.path.exists, self.model.value_paths(it))        self.emit("create-diff", paths)    def launch_comparisons_on_selected(self):        """Launch comparisons on all selected elements.        """        pane = self._get_focused_pane()        if pane != None:            selected = self._get_selected_paths(pane)            get_iter = self.model.get_iter            for s in selected:                self.launch_comparison( get_iter(s), pane )    def copy_selected(self, direction):        assert direction in (-1,1)        src_pane = self._get_focused_pane()        if src_pane != None:            dst_pane = src_pane + direction            assert dst_pane >= 0 and dst_pane < self.num_panes            paths = self._get_selected_paths(src_pane)            paths.reverse()            model = self.model            for path in paths: #filter(lambda x: x.name!=None, sel):                it = model.get_iter(path)                name = model.value_path(it, src_pane)                if name == None:                    continue                src = model.value_path(it, src_pane)                dst = model.value_path(it, dst_pane)                try:                    if os.path.isfile(src):                        dstdir = os.path.dirname( dst )                        if not os.path.exists( dstdir ):                            os.makedirs( dstdir )                        shutil.copy2( src, dstdir )                        self.file_created( path, dst_pane)                    elif os.path.isdir(src):                        if os.path.exists(dst):                            if misc.run_dialog( _("'%s' exists.\nOverwrite?") % os.path.basename(dst),                                    parent = self,                                    buttonstype = gtk.BUTTONS_OK_CANCEL) != gtk.RESPONSE_OK:                                continue                        misc.copytree(src, dst)                        self.recursively_update( path )                except (OSError,IOError), e:                    misc.run_dialog(_("Error copying '%s' to '%s'\n\n%s.") % (src, dst,e), self)    def delete_selected(self):        """Delete all selected files/folders recursively.        """        # reverse so paths dont get changed        pane = self._get_focused_pane()        if pane != None:            paths = self._get_selected_paths(pane)            paths.reverse()            for path in paths:                it = self.model.get_iter(path)                name = self.model.value_path(it, pane)                try:                    if os.path.isfile(name):                        os.remove(name)                        self.file_deleted( path, pane)                    elif os.path.isdir(name):                        if misc.run_dialog(_("'%s' is a directory.\nRemove recusively?") % os.path.basename(name),                                parent = self,                                buttonstype=gtk.BUTTONS_OK_CANCEL) == gtk.RESPONSE_OK:                            shutil.rmtree(name)                            self.recursively_update( path )                        self.file_deleted( path, pane)                except OSError, e:                    misc.run_dialog(_("Error removing %s\n\n%s.") % (name,e), parent = self)    def on_treeview_cursor_changed(self, *args):        pane = self._get_focused_pane()        if pane == None: return        paths = self._get_selected_paths(pane)        if len(paths) > 0:            def rwx(mode):                return "".join( [ ((mode& (1<<i)) and "xwr"[i%3] or "-") for i in range(8,-1,-1) ] )            def nice(deltat):                times = (                    (60, lambda n: ngettext("%i second","%i seconds",n)),                    (60, lambda n: ngettext("%i minute","%i minutes",n)),                    (24, lambda n: ngettext("%i hour","%i hours",n)),                    ( 7, lambda n: ngettext("%i day","%i days",n)),                    ( 4, lambda n: ngettext("%i week","%i weeks",n)),                    (12, lambda n: ngettext("%i month","%i months",n)),                    (100,lambda n: ngettext("%i year","%i years",n)) )                for units, msg in times:                    if abs(int(deltat)) < 5 * units:                        return msg(int(deltat)) % int(deltat)                    deltat /= units            fname = self.model.value_path( self.model.get_iter(paths[0]), pane )            try:                stat = os.stat(fname)            except OSError:                self.emit("status-changed", "" )            else:                self.emit("status-changed", "%s : %s" % (rwx(stat.st_mode), nice(time.time() - stat.st_mtime) ) )    def on_switch_event(self):        if self.treeview_focussed:            self.scheduler.add_task( self.treeview_focussed.grab_focus )            self.scheduler.add_task( self.on_treeview_cursor_changed )    def on_treeview_key_press_event(self, view, event):        pane = self.treeview.index(view)        tree = None        if gtk.keysyms.Right == event.keyval:            if pane+1 < self.num_panes:                tree = self.treeview[pane+1]        elif gtk.keysyms.Left == event.keyval:            if pane-1 >= 0:                tree = self.treeview[pane-1]        if tree != None:            paths = self._get_selected_paths(pane)            view.get_selection().unselect_all()            tree.grab_focus()            tree.get_selection().unselect_all()            if len(paths):                tree.set_cursor(paths[0])                for p in paths:                    tree.get_selection().select_path(p)            tree.emit("cursor-changed")        return event.keyval in (gtk.keysyms.Left, gtk.keysyms.Right) #handled    def on_treeview_row_activated(self, view, path, column):        it = self.model.get_iter(path)        files = []        for i in range(self.num_panes):            fname = self.model.value_path( it, i )            if os.path.exists(fname):                files.append(fname)            else:                files.append(None)        if files.count(None) != self.num_panes:            # Its possible to have file 'foo' in one pane and dir 'foo' in another.            # We want to do the right thing depending on the one clicked.            clicked_pane = [ t.get_column(0) for t in self.treeview ].index(column)            while files[clicked_pane] == None: # clicked on missing entry?                clicked_pane = (clicked_pane+1) % self.num_panes            if os.path.isfile( files[clicked_pane] ):                self.emit("create-diff", filter(os.path.isfile, _not_none(files) ))            else:                if view.row_expanded(path):                    view.collapse_row(path)                else:                    view.expand_row(path,0)    def on_treeview_row_expanded(self, view, it, path):        self._do_to_others(view, self.treeview, "expand_row", (path,0) )        self._update_diffmaps()    def on_treeview_row_collapsed(self, view, me, path):        self._do_to_others(view, self.treeview, "collapse_row", (path,) )        self._update_diffmaps()    def on_treeview_focus_in_event(self, tree, event):        self.treeview_focussed = tree        pane = self.treeview.index(tree)        if pane > 0:            self.button_copy_left.set_sensitive(1)        if pane+1 < self.num_panes:            self.button_copy_right.set_sensitive(1)        self.button_delete.set_sensitive(1)    def on_treeview_focus_out_event(self, tree, event):        self.button_copy_left.set_sensitive(0)        self.button_copy_right.set_sensitive(0)        self.button_delete.set_sensitive(0)        #        # Toolbar handlers        #    def on_button_diff_clicked(self, button):        self.launch_comparisons_on_selected()    def on_button_copy_left_clicked(self, button):        self.copy_selected(-1)    def on_button_copy_right_clicked(self, button):        self.copy_selected(1)    def on_button_delete_clicked(self, button):        self.delete_selected()    def on_button_edit_clicked(self, button):        pane = self._get_focused_pane()        if pane != None:            m = self.model

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -