Commit e2cc43a4 authored by Kai Willadsen's avatar Kai Willadsen
Browse files

misc: Update path shortening logic for Windows paths (#203)

parent 28a0c466
Pipeline #19577 passed with stages
in 8 minutes and 10 seconds
......@@ -25,6 +25,7 @@ import os
import re
import shutil
import subprocess
from pathlib import PurePath
from gi.repository import Gdk
from gi.repository import GLib
......@@ -293,30 +294,32 @@ def all_same(iterable):
def shorten_names(*names):
"""Remove redunant parts of a list of names (e.g. /tmp/foo{1,2} -> foo{1,2}
"""Remove common parts of a list of paths
For example, `('/tmp/foo1', '/tmp/foo2')` would be summarised as
`('foo1', 'foo2')`. Paths that share a basename are distinguished
by prepending an indicator, e.g., `('/a/b/c', '/a/d/c')` would be
summarised to `['[b] c', '[d] c']`.
# TODO: Update for different path separators and URIs
prefix = os.path.commonprefix(names)
prefixslash = prefix.rfind("/") + 1
names = [n[prefixslash:] for n in names]
paths = [n.split("/") for n in names]
paths = [PurePath(n) for n in names]
# Identify the longest common path among the list of path
common = set(paths[0].parents)
common = common.intersection(*(p.parents for p in paths))
common_parent = sorted(common, key=lambda p: -len([0]
paths = [p.relative_to(common_parent) for p in paths]
basenames = [ for p in paths]
if all_same(basenames):
def firstpart(path: PurePath):
if len( > 1 and[0]:
return "[%s] " %[0]
return ""
return [firstpart(p) + for p in paths]
basenames = [p[-1] for p in paths]
except IndexError:
if all_same(basenames):
def firstpart(alist):
if len(alist) > 1 and alist[0]:
return "[%s] " % alist[0]
return ""
roots = [firstpart(p) for p in paths]
base = basenames[0].strip()
return [r + base for r in roots]
# no common path. empty names get changed to "[None]"
return [name or _("[None]") for name in basenames]
from unittest import mock
import pytest
from meld.misc import all_same, calc_syncpoint, merge_intervals
......@@ -73,3 +75,24 @@ def test_calc_syncpoint(value, page_size, lower, upper, expected):
def test_all_same(lst, expected):
assert all_same(lst) == expected
@pytest.mark.parametrize("os_name, paths, expected", [
('posix', ['/tmp/foo1', '/tmp/foo2'], ['foo1', 'foo2']),
('posix', ['/tmp/foo1', '/tmp/foo2', '/tmp/foo3'], ['foo1', 'foo2', 'foo3']),
('posix', ['/tmp/bar/foo1', '/tmp/woo/foo2'], ['foo1', 'foo2']),
('posix', ['/tmp/bar/foo1', '/tmp/woo/foo1'], ['[bar] foo1', '[woo] foo1']),
('posix', ['/tmp/bar/foo1', '/tmp/woo/foo1', '/tmp/ree/foo1'], ['[bar] foo1', '[woo] foo1', '[ree] foo1']),
('posix', ['/tmp/bar/deep/deep', '/tmp/bar/shallow'], ['deep', 'shallow']),
('posix', ['/tmp/bar/deep/deep/foo1', '/tmp/bar/shallow/foo1'], ['[deep] foo1', '[shallow] foo1']),
# This case doesn't actually make much sense, so it's not that bad
# that our output is... somewhat unclear.
('posix', ['/tmp/bar/subdir/subsub', '/tmp/bar/'], ['subsub', 'bar']),
('nt', ['C:\\Users\\hmm\\bar', 'C:\\Users\\hmm\\foo'], ['bar', 'foo']),
('nt', ['C:\\Users\\bar\\hmm', 'C:\\Users\\foo\\hmm'], ['[bar] hmm', '[foo] hmm']),
def test_shorten_names(os_name, paths, expected):
from meld.misc import shorten_names
with mock.patch('', os_name):
assert shorten_names(*paths) == expected
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment