Repository: pypa/virtualenv

Issue:
Incorrect (broken) virtualenv layout with pypy3.8's new layout
**Issue**

PyPy3.8 (currently 7.3.6rc1) supports a new install layout that resembles CPython more. That is, `sys.prefix` no longer needs being isolated, and site-packages are found in `$prefix/lib/pypy3.8/site-packages`. However, virtualenv tries to symlink everything from `/usr/lib` including the `pypy3.8` directory. As a result, the user can't write to the site-packages directory in the venv.

I haven't tried running it as root but I can imagine it doing major mess if it virtualenv doesn't take any precautions from writing into system directories.

**Environment**

Provide at least:
- OS: Gentoo Linux
- ``pip list`` of the host python where ``virtualenv`` is installed: [pip-list.txt](https://github.com/pypa/virtualenv/files/7167321/pip-list.txt)


**Output of the virtual environment creation**

Make sure to run the creation with `-vvv --with-traceback`:

Full output: [output.txt](https://github.com/pypa/virtualenv/files/7167331/output.txt)

tail:
```
1048 create virtualenv import hook file /tmp/z/lib/pypy3.8/site-packages/_virtualenv.pth [DEBUG api:95]
Traceback (most recent call last):
  File "/usr/lib/pypy3.8/runpy.py", line 198, in _run_module_as_main
    "__main__", mod_spec)
  File "/usr/lib/pypy3.8/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "/usr/lib/pypy3.8/site-packages/virtualenv/__main__.py", line 80, in <module>
    run_with_catch()  # pragma: no cov
  File "/usr/lib/pypy3.8/site-packages/virtualenv/__main__.py", line 65, in run_with_catch
    run(args, options, env)
  File "/usr/lib/pypy3.8/site-packages/virtualenv/__main__.py", line 18, in run
    session = cli_run(args, options, env)
  File "/usr/lib/pypy3.8/site-packages/virtualenv/run/__init__.py", line 32, in cli_run
    of_session.run()
  File "/usr/lib/pypy3.8/site-packages/virtualenv/run/session.py", line 46, in run
    self._create()
  File "/usr/lib/pypy3.8/site-packages/virtualenv/run/session.py", line 53, in _create
    self.creator.run()
  File "/usr/lib/pypy3.8/site-packages/virtualenv/create/creator.py", line 171, in run
    self.create()
  File "/usr/lib/pypy3.8/site-packages/virtualenv/create/via_global_ref/builtin/via_global_self_do.py", line 101, in create
    super(ViaGlobalRefVirtualenvBuiltin, self).create()
  File "/usr/lib/pypy3.8/site-packages/virtualenv/create/via_global_ref/api.py", line 89, in create
    self.install_patch()
  File "/usr/lib/pypy3.8/site-packages/virtualenv/create/via_global_ref/api.py", line 96, in install_patch
    pth.write_text("import _virtualenv")
  File "/usr/lib/pypy3.8/pathlib.py", line 1255, in write_text
    with self.open(mode='w', encoding=encoding, errors=errors) as f:
  File "/usr/lib/pypy3.8/pathlib.py", line 1223, in open
    opener=self._opener)
  File "/usr/lib/pypy3.8/pathlib.py", line 1078, in _opener
    return self._accessor.open(self, flags, mode)
PermissionError: [Errno 13] Permission denied: PosixPath('/tmp/z/lib/pypy3.8/site-packages/_virtualenv.pth')
```


Discussion:
Turns out there's a similar (yet somewhat opposite) problem in pypy's built-in `venv` module: https://foss.heptapod.net/pypy/pypy/-/issues/3553. Maybe it's better to wait for a fix there, in case something relevant changes.
Can confirm major mess ensues when the system site packages dir is not owned by root :sob: 
Is this related?
I found that trying to change a seeded module does not seem to work. I [opened an issue on PyPy](https://foss.heptapod.net/pypy/pypy/-/issues/3567) where creating a virtualenv in `/tmp/venv_pypy38`, and then trying to update setuptools with `pypy --upgrade 'setuptools<49.2.0'` does not succeed (it cannot uninstall the seeded version):
```
Collecting setuptools<49.2.0
  Using cached setuptools-49.1.3-py3-none-any.whl (789 kB)
Installing collected packages: setuptools
  Attempting uninstall: setuptools
    Found existing installation: setuptools 58.1.0
    Not uninstalling setuptools at /home/matti/oss/pypy3.8-HEAD/lib/pypy3.8/site-packages, outside environment /tmp/venv_pypy38
    Can't uninstall 'setuptools'. No files were found to uninstall.
Successfully installed setuptools-58.1.0

```

Resolving patch:
diff --git a/src/virtualenv/create/via_global_ref/builtin/pypy/pypy3.py b/src/virtualenv/create/via_global_ref/builtin/pypy/pypy3.py
--- a/src/virtualenv/create/via_global_ref/builtin/pypy/pypy3.py
+++ b/src/virtualenv/create/via_global_ref/builtin/pypy/pypy3.py
@@ -28,7 +28,7 @@ class PyPy3Posix(PyPy3, PosixSupports):
     @property
     def stdlib(self):
         """PyPy3 respects sysconfig only for the host python, virtual envs is instead lib/pythonx.y/site-packages"""
-        return self.dest / "lib" / "python{}".format(self.interpreter.version_release_str) / "site-packages"
+        return self.dest / "lib" / "pypy{}".format(self.interpreter.version_release_str) / "site-packages"
 
     @classmethod
     def _shared_libs(cls):
@@ -41,9 +41,19 @@ def to_lib(self, src):
     def sources(cls, interpreter):
         for src in super(PyPy3Posix, cls).sources(interpreter):
             yield src
+        # Also copy/symlink anything under prefix/lib, which, for "portable"
+        # PyPy builds, includes the tk,tcl runtime and a number of shared
+        # objects. In distro-specific builds or on conda this should be empty
+        # (on PyPy3.8+ it will, like on CPython, hold the stdlib).
         host_lib = Path(interpreter.system_prefix) / "lib"
+        stdlib = Path(interpreter.system_stdlib)
         if host_lib.exists() and host_lib.is_dir():
             for path in host_lib.iterdir():
+                if stdlib == path:
+                    # For PyPy3.8+ the stdlib lives in lib/pypy3.8
+                    # We need to avoid creating a symlink to it since that
+                    # will defeat the purpose of a virtualenv
+                    continue
                 yield PathRefToDest(path, dest=cls.to_lib)
 
 


Test patch: