[meld] Rework case insensitivity handling in DirDiff comparison
- From: Kai Willadsen <kaiw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [meld] Rework case insensitivity handling in DirDiff comparison
- Date: Sat, 5 Feb 2011 22:55:14 +0000 (UTC)
commit b70b16de42ee99e46c8601438f834017930b525b
Author: Kai Willadsen <kai willadsen gmail com>
Date: Tue Jan 11 06:20:35 2011 +1000
Rework case insensitivity handling in DirDiff comparison
This commit moves handling of case insensitivity into a single
top-level class in the dirdiff module, and simplifies the handling of
shadowed filenames. In addition, we now show only one error dialogue
for a single comparison, rather than one per subdirectory with
shadowing filenames.
meld/dirdiff.py | 111 +++++++++++++++++++++++++++----------------------------
1 files changed, 55 insertions(+), 56 deletions(-)
---
diff --git a/meld/dirdiff.py b/meld/dirdiff.py
index 4ac757e..1233874 100644
--- a/meld/dirdiff.py
+++ b/meld/dirdiff.py
@@ -15,6 +15,7 @@
### along with this program; if not, write to the Free Software
### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+import collections
import errno
import paths
from ui import gnomeglade
@@ -181,6 +182,33 @@ class TypeFilter(object):
self.active = active
self.filter = filter
+
+class CanonicalListing(object):
+ """Multi-pane lists with canonicalised matching and error detection"""
+
+ def __init__(self, n, canonicalize=None):
+ self.items = collections.defaultdict(lambda: [None] * n)
+ self.errors = []
+ if canonicalize is not None:
+ self.canonicalize = canonicalize
+ self.add = self.add_canon
+
+ def add(self, pane, item):
+ self.items[item][pane] = item
+
+ def add_canon(self, pane, item):
+ ci = self.canonicalize(item)
+ if self.items[ci][pane] is None:
+ self.items[ci][pane] = item
+ else:
+ self.errors.append((pane, item, self.items[ci][pane]))
+
+ def get(self):
+ first = lambda seq: next(s for s in seq if s)
+ filled = lambda seq: tuple([s or first(seq) for s in seq])
+ return sorted([filled(v) for v in self.items.itervalues()])
+
+
################################################################################
#
# DirDiff
@@ -415,6 +443,8 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
symlinks_followed = set()
todo = [ rootpath ]
expanded = set()
+
+ shadowed_entries = []
while len(todo):
todo.sort() # depth first
path = todo.pop(0)
@@ -422,53 +452,13 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
roots = self.model.value_paths( it )
yield _("[%s] Scanning %s") % (self.label_text, roots[0][prefixlen:])
differences = False
- if not self.actiongroup.get_action("IgnoreCase").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):
- return [(i,) * self.n for i in sorted(set(self.items))]
- else:
+
+ canonicalize = None
+ if self.actiongroup.get_action("IgnoreCase").get_active():
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] is 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(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) for t in tuples])
- return [fixup(self.items[k]) for k in keys]
-
- accumdirs = accum(self, roots)
- accumfiles = accum(self, roots)
+ dirs = CanonicalListing(self.num_panes, canonicalize)
+ files = CanonicalListing(self.num_panes, canonicalize)
+
for pane, root in enumerate(roots):
if not os.path.isdir(root):
continue
@@ -483,8 +473,6 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
for f in self.name_filters:
entries = filter(f.filter, entries)
- files = []
- dirs = []
for e in entries:
try:
s = os.lstat(os.path.join(root, e))
@@ -504,9 +492,9 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
try:
s = os.stat(os.path.join(root, e))
if stat.S_ISREG(s.st_mode):
- files.append(e)
+ files.add(pane, e)
elif stat.S_ISDIR(s.st_mode):
- dirs.append(e)
+ dirs.add(pane, e)
except OSError, err:
if err.errno == errno.ENOENT:
error_string = e + ": Dangling symlink"
@@ -515,17 +503,18 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
self.model.add_error(it, error_string, pane)
differences = True
elif stat.S_ISREG(s.st_mode):
- files.append(e)
+ files.add(pane, e)
elif stat.S_ISDIR(s.st_mode):
- dirs.append(e)
+ dirs.add(pane, e)
else:
# FIXME: Unhandled stat type
pass
- accumfiles.add(pane, files)
- accumdirs.add(pane, dirs)
- alldirs = accumdirs.get()
- allfiles = self._filter_on_state( roots, accumfiles.get() )
+ for pane, f1, f2 in dirs.errors + files.errors:
+ shadowed_entries.append((roots[pane], f1, f2))
+
+ alldirs = dirs.get()
+ allfiles = self._filter_on_state(roots, files.get())
# then directories and files
if len(alldirs) + len(allfiles) != 0:
@@ -542,6 +531,16 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
self.model.add_empty(it)
if differences:
expanded.add(path)
+
+ if shadowed_entries:
+ formatted_entries = []
+ for root, f1, f2 in shadowed_entries:
+ paths = [os.path.join(root, f) for f in (f1, f2)]
+ formatted_entries.append("'%s' hidden by '%s'" % (paths[0], paths[1]))
+ misc.run_dialog(_("You are running a case insensitive comparison on"
+ " a case sensitive filesystem. Some files are not visible:\n%s")
+ % "\n".join(formatted_entries), self)
+
for path in sorted(expanded):
self.treeview[0].expand_to_path(path)
yield _("[%s] Done") % self.label_text
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]