coredata: Use our own implementation of commonpath

os.path.commonpath was added in Python 3.5, so just write our own for
now. pathlib was added in Python 3.4, so this should be ok. We need to
use that instead of doing str.split() etc because Windows path handling
has a lot of exceptions and pathlib handles all that for us.

Also adds a unit test for this.
pull/1342/head
Nirbheek Chauhan 8 years ago
parent 66fbcde96e
commit bb491735a9
  1. 5
      mesonbuild/coredata.py
  2. 25
      mesonbuild/mesonlib.py
  3. 17
      run_unittests.py

@ -13,7 +13,8 @@
# limitations under the License. # limitations under the License.
import pickle, os, uuid import pickle, os, uuid
from .mesonlib import MesonException, default_libdir, default_libexecdir, default_prefix from .mesonlib import MesonException, commonpath
from .mesonlib import default_libdir, default_libexecdir, default_prefix
version = '0.38.0.dev1' version = '0.38.0.dev1'
backendlist = ['ninja', 'vs2010', 'vs2015', 'xcode'] backendlist = ['ninja', 'vs2010', 'vs2015', 'xcode']
@ -158,7 +159,7 @@ class CoreData:
if option.endswith('dir') and os.path.isabs(value) and \ if option.endswith('dir') and os.path.isabs(value) and \
option not in builtin_dir_noprefix_options: option not in builtin_dir_noprefix_options:
# Value must be a subdir of the prefix # Value must be a subdir of the prefix
if os.path.commonpath([value, prefix]) != prefix: if commonpath([value, prefix]) != prefix:
m = 'The value of the {!r} option is {!r} which must be a ' \ m = 'The value of the {!r} option is {!r} which must be a ' \
'subdir of the prefix {!r}.\nNote that if you pass a ' \ 'subdir of the prefix {!r}.\nNote that if you pass a ' \
'relative path, it is assumed to be a subdir of prefix.' 'relative path, it is assumed to be a subdir of prefix.'

@ -496,3 +496,28 @@ def Popen_safe(args, write=None, stderr=subprocess.PIPE, **kwargs):
stderr=stderr, **kwargs) stderr=stderr, **kwargs)
o, e = p.communicate(write) o, e = p.communicate(write)
return p, o, e return p, o, e
def commonpath(paths):
'''
For use on Python 3.4 where os.path.commonpath is not available.
We currently use it everywhere so this receives enough testing.
'''
# XXX: Replace me with os.path.commonpath when we start requiring Python 3.5
import pathlib
if not paths:
raise ValueError('arg is an empty sequence')
common = pathlib.PurePath(paths[0])
for path in paths[1:]:
new = []
path = pathlib.PurePath(path)
for c, p in zip(common.parts, path.parts):
if c != p:
break
new.append(c)
# Don't convert '' into '.'
if not new:
common = ''
break
new = os.path.join(*new)
common = pathlib.PurePath(new)
return str(common)

@ -153,6 +153,23 @@ class InternalTests(unittest.TestCase):
a = ['-Ldir', '-Lbah'] + a a = ['-Ldir', '-Lbah'] + a
self.assertEqual(a, ['-Ibar', '-Ifoo', '-Ibaz', '-I..', '-I.', '-Ldir', '-Lbah', '-Werror', '-O3', '-O2', '-Wall']) self.assertEqual(a, ['-Ibar', '-Ifoo', '-Ibaz', '-I..', '-I.', '-Ldir', '-Lbah', '-Werror', '-O3', '-O2', '-Wall'])
def test_commonpath(self):
from os.path import sep
commonpath = mesonbuild.mesonlib.commonpath
self.assertRaises(ValueError, commonpath, [])
self.assertEqual(commonpath(['/usr', '/usr']), sep + 'usr')
self.assertEqual(commonpath(['/usr', '/usr/']), sep + 'usr')
self.assertEqual(commonpath(['/usr', '/usr/bin']), sep + 'usr')
self.assertEqual(commonpath(['/usr/', '/usr/bin']), sep + 'usr')
self.assertEqual(commonpath(['/usr/./', '/usr/bin']), sep + 'usr')
self.assertEqual(commonpath(['/usr/bin', '/usr/bin']), sep + 'usr' + sep + 'bin')
self.assertEqual(commonpath(['/usr//bin', '/usr/bin']), sep + 'usr' + sep + 'bin')
self.assertEqual(commonpath(['/usr/./bin', '/usr/bin']), sep + 'usr' + sep + 'bin')
self.assertEqual(commonpath(['/usr/local', '/usr/lib']), sep + 'usr')
self.assertEqual(commonpath(['/usr', '/bin']), sep)
self.assertEqual(commonpath(['/usr', 'bin']), '')
self.assertEqual(commonpath(['blam', 'bin']), '')
class LinuxlikeTests(unittest.TestCase): class LinuxlikeTests(unittest.TestCase):
def setUp(self): def setUp(self):

Loading…
Cancel
Save