Author: Antonio Cuni <anto.c...@gmail.com> Branch: app_main-refactor Changeset: r55509:203459fe802c Date: 2012-06-08 16:11 +0200 http://bitbucket.org/pypy/pypy/changeset/203459fe802c/
Log: copy the logic to find the stdlib from app_main into sys.initpath, and make it rpython. Also, add tests for it, which is always good :-) diff --git a/pypy/module/sys/__init__.py b/pypy/module/sys/__init__.py --- a/pypy/module/sys/__init__.py +++ b/pypy/module/sys/__init__.py @@ -44,7 +44,7 @@ 'warnoptions' : 'state.get(space).w_warnoptions', 'builtin_module_names' : 'space.w_None', 'pypy_getudir' : 'state.pypy_getudir', # not translated - 'pypy_initial_path' : 'initpath.pypy_initial_path', + 'pypy_find_stdlib' : 'initpath.pypy_find_stdlib', 'pypy_find_executable' : 'initpath.pypy_find_executable', '_getframe' : 'vm._getframe', diff --git a/pypy/module/sys/initpath.py b/pypy/module/sys/initpath.py --- a/pypy/module/sys/initpath.py +++ b/pypy/module/sys/initpath.py @@ -9,11 +9,16 @@ from pypy.rlib import rpath from pypy.rlib.objectmodel import we_are_translated from pypy.interpreter.gateway import unwrap_spec +from pypy.module.sys.state import get_state platform = sys.platform IS_WINDOWS = sys.platform == 'win32' def find_executable(executable): + """ + Return the absolute path of the executable, by looking into PATH and the + current directory. If it cannot be found, return ''. + """ if we_are_translated() and IS_WINDOWS and not executable.lower().endswith('.exe'): executable += '.exe' if os.sep in executable or (IS_WINDOWS and ':' in executable): @@ -35,15 +40,57 @@ return executable +def readlink_maybe(filename): + if hasattr(os, 'readlink'): + return os.readlink(filename) + raise NotImplementedError + +def resolvedirof(filename): + try: + filename = rpath.rabspath(filename) + except OSError: + pass + dirname = rpath.rabspath(os.path.join(filename, '..')) + if os.path.islink(filename): + try: + link = readlink_maybe(filename) + except OSError: + pass + else: + return resolvedirof(os.path.join(dirname, link)) + return dirname + +def find_stdlib(state, executable): + """ + Find and compute the stdlib path, starting from the directory where + ``executable`` is and going one level up until we find it. Return a tuple + (path, prefix), where ``prefix`` is the root directory which contains the + stdlib. + If it cannot be found, return (None, None). + """ + search = executable + while True: + dirname = resolvedirof(search) + if dirname == search: + return None, None # not found :-( + newpath = compute_stdlib_path_maybe(state, dirname) + if newpath is not None: + return newpath, dirname + search = dirname # walk to the parent directory + + def checkdir(path): st = os.stat(path) if not stat.S_ISDIR(st[0]): raise OSError(errno.ENOTDIR, path) - - def compute_stdlib_path(state, prefix): + """ + Compute the paths for the stdlib rooted at ``prefix``. ``prefix`` must at + least contain a directory called ``lib-python/X.Y`` and another one called + ``lib_pypy``. If they cannot be found, it raises OSError. + """ from pypy.module.sys.version import CPYTHON_VERSION dirname = '%d.%d' % (CPYTHON_VERSION[0], CPYTHON_VERSION[1]) @@ -77,23 +124,28 @@ # return importlist +def compute_stdlib_path_maybe(state, prefix): + """ + Return the stdlib path rooted at ``prefix``, or None if it cannot be + found. + """ + try: + return compute_stdlib_path(state, prefix) + except OSError: + return None @unwrap_spec(executable='str0') def pypy_find_executable(space, executable): return space.wrap(find_executable(executable)) - @unwrap_spec(srcdir='str0') -def pypy_initial_path(space, srcdir): - try: - path = compute_stdlib_path(get(space), srcdir) - except OSError: +def pypy_find_stdlib(space, executable): + path, prefix = find_stdlib(get_state(space), executable) + if path is None: return space.w_None else: space.setitem(space.sys.w_dict, space.wrap('prefix'), - space.wrap(srcdir)) + space.wrap(prefix)) space.setitem(space.sys.w_dict, space.wrap('exec_prefix'), - space.wrap(srcdir)) + space.wrap(prefix)) return space.newlist([space.wrap(p) for p in path]) - - diff --git a/pypy/module/sys/state.py b/pypy/module/sys/state.py --- a/pypy/module/sys/state.py +++ b/pypy/module/sys/state.py @@ -3,7 +3,6 @@ """ import os import pypy -from pypy.module.sys.initpath import compute_stdlib_path # ____________________________________________________________ # @@ -18,7 +17,8 @@ self.w_argv = space.newlist([]) self.setinitialpath(space) - def setinitialpath(self, space): + def setinitialpath(self, space): + from pypy.module.sys.initpath import compute_stdlib_path # Initialize the default path pypydir = os.path.dirname(os.path.abspath(pypy.__file__)) srcdir = os.path.dirname(pypydir) @@ -26,7 +26,7 @@ self.w_path = space.newlist([space.wrap(p) for p in path]) -def get(space): +def get_state(space): return space.fromcache(State) class IOState: diff --git a/pypy/module/sys/test/test_initpath.py b/pypy/module/sys/test/test_initpath.py --- a/pypy/module/sys/test/test_initpath.py +++ b/pypy/module/sys/test/test_initpath.py @@ -1,6 +1,6 @@ import py import os.path -from pypy.module.sys.initpath import compute_stdlib_path, find_executable +from pypy.module.sys.initpath import compute_stdlib_path, find_executable, find_stdlib from pypy.module.sys.version import PYPY_VERSION, CPYTHON_VERSION def build_hierarchy(prefix): @@ -9,8 +9,25 @@ b = prefix.join('lib-python', dirname).ensure(dir=1) return a, b +def test_find_stdlib(tmpdir): + bin_dir = tmpdir.join('bin').ensure(dir=True) + pypy = bin_dir.join('pypy').ensure(file=True) + build_hierarchy(tmpdir) + path, prefix = find_stdlib(None, str(pypy)) + assert prefix == tmpdir -def test_stdlib_in_prefix(tmpdir): +@py.test.mark.skipif('not hasattr(os, "symlink")') +def test_find_stdlib_follow_symlink(tmpdir): + pypydir = tmpdir.join('opt', 'pypy-xxx') + pypy = pypydir.join('bin', 'pypy').ensure(file=True) + build_hierarchy(pypydir) + pypy_sym = tmpdir.join('pypy_sym') + os.symlink(str(pypy), str(pypy_sym)) + path, prefix = find_stdlib(None, str(pypy_sym)) + assert prefix == pypydir + + +def test_compute_stdlib_path(tmpdir): dirs = build_hierarchy(tmpdir) path = compute_stdlib_path(None, str(tmpdir)) # we get at least 'dirs', and maybe more (e.g. plat-linux2) diff --git a/pypy/rlib/rpath.py b/pypy/rlib/rpath.py --- a/pypy/rlib/rpath.py +++ b/pypy/rlib/rpath.py @@ -18,4 +18,3 @@ return path else: raise ImportError('Unsupported os: %s' % os.name) - _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit