We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Fail legacy install if .egg-info directory was not created
**What's the problem this feature will solve?**

Currently on the legacy install code path ([here](https://github.com/pypa/pip/blob/e0239735a3d8a504e00133090dde2210b6564a38/src/pip/_internal/req/req_install.py#L997-L1004)) if execution of `setup.py install ...` didn't result in an `.egg-info` directory being created we trace a warning and continue.

This is bad because we will have installed an uninstallable package and the only penalty is a small warning which is very easy to miss.

**Describe the solution you'd like**

Instead of tracing a warning we should throw an exception.

This prevents additional packages from being installed and possibly hiding the warning from users.

**Alternative Solutions**

Continue tracing the warning as before.

**Additional context**

* [this support query](https://kite.trade/forum/discussion/4335/could-not-find-egg-info-directory-in-install-record-for-kiteconnect) for [this package](https://github.com/zerodhatech/pykiteconnect/blob/7af60a776fbfafb6c30cfbd8d4f6c192618c5af5/setup.py#L48) which does an egg install in its setup.py regardless of setuptools version.
* [this query](https://stackoverflow.com/questions/26091641/what-does-a-could-not-find-egg-info-directory-in-install-record-from-pip-mean) which implicates having an older version of setuptools

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/pip/_internal/operations/install/legacy.py`
Content:
```
1 """Legacy installation process, i.e. `setup.py install`.
2 """
3 
4 import logging
5 import os
6 import sys
7 from distutils.util import change_root
8 
9 from pip._internal.utils.deprecation import deprecated
10 from pip._internal.utils.logging import indent_log
11 from pip._internal.utils.misc import ensure_dir
12 from pip._internal.utils.setuptools_build import make_setuptools_install_args
13 from pip._internal.utils.subprocess import runner_with_spinner_message
14 from pip._internal.utils.temp_dir import TempDirectory
15 from pip._internal.utils.typing import MYPY_CHECK_RUNNING
16 
17 if MYPY_CHECK_RUNNING:
18     from typing import List, Optional, Sequence
19 
20     from pip._internal.build_env import BuildEnvironment
21     from pip._internal.models.scheme import Scheme
22 
23 
24 logger = logging.getLogger(__name__)
25 
26 
27 class LegacyInstallFailure(Exception):
28     def __init__(self):
29         # type: () -> None
30         self.parent = sys.exc_info()
31 
32 
33 def install(
34     install_options,  # type: List[str]
35     global_options,  # type: Sequence[str]
36     root,  # type: Optional[str]
37     home,  # type: Optional[str]
38     prefix,  # type: Optional[str]
39     use_user_site,  # type: bool
40     pycompile,  # type: bool
41     scheme,  # type: Scheme
42     setup_py_path,  # type: str
43     isolated,  # type: bool
44     req_name,  # type: str
45     build_env,  # type: BuildEnvironment
46     unpacked_source_directory,  # type: str
47     req_description,  # type: str
48 ):
49     # type: (...) -> bool
50 
51     header_dir = scheme.headers
52 
53     with TempDirectory(kind="record") as temp_dir:
54         try:
55             record_filename = os.path.join(temp_dir.path, 'install-record.txt')
56             install_args = make_setuptools_install_args(
57                 setup_py_path,
58                 global_options=global_options,
59                 install_options=install_options,
60                 record_filename=record_filename,
61                 root=root,
62                 prefix=prefix,
63                 header_dir=header_dir,
64                 home=home,
65                 use_user_site=use_user_site,
66                 no_user_config=isolated,
67                 pycompile=pycompile,
68             )
69 
70             runner = runner_with_spinner_message(
71                 "Running setup.py install for {}".format(req_name)
72             )
73             with indent_log(), build_env:
74                 runner(
75                     cmd=install_args,
76                     cwd=unpacked_source_directory,
77                 )
78 
79             if not os.path.exists(record_filename):
80                 logger.debug('Record file %s not found', record_filename)
81                 # Signal to the caller that we didn't install the new package
82                 return False
83 
84         except Exception:
85             # Signal to the caller that we didn't install the new package
86             raise LegacyInstallFailure
87 
88         # At this point, we have successfully installed the requirement.
89 
90         # We intentionally do not use any encoding to read the file because
91         # setuptools writes the file using distutils.file_util.write_file,
92         # which does not specify an encoding.
93         with open(record_filename) as f:
94             record_lines = f.read().splitlines()
95 
96     def prepend_root(path):
97         # type: (str) -> str
98         if root is None or not os.path.isabs(path):
99             return path
100         else:
101             return change_root(root, path)
102 
103     for line in record_lines:
104         directory = os.path.dirname(line)
105         if directory.endswith('.egg-info'):
106             egg_info_dir = prepend_root(directory)
107             break
108     else:
109         deprecated(
110             reason=(
111                 "{} did not indicate that it installed an "
112                 ".egg-info directory. Only setup.py projects "
113                 "generating .egg-info directories are supported."
114             ).format(req_description),
115             replacement=(
116                 "for maintainers: updating the setup.py of {0}. "
117                 "For users: contact the maintainers of {0} to let "
118                 "them know to update their setup.py.".format(
119                     req_name
120                 )
121             ),
122             gone_in="20.2",
123             issue=6998,
124         )
125         # FIXME: put the record somewhere
126         return True
127 
128     new_lines = []
129     for line in record_lines:
130         filename = line.strip()
131         if os.path.isdir(filename):
132             filename += os.path.sep
133         new_lines.append(
134             os.path.relpath(prepend_root(filename), egg_info_dir)
135         )
136     new_lines.sort()
137     ensure_dir(egg_info_dir)
138     inst_files_path = os.path.join(egg_info_dir, 'installed-files.txt')
139     with open(inst_files_path, 'w') as f:
140         f.write('\n'.join(new_lines) + '\n')
141 
142     return True
143
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/pip/_internal/operations/install/legacy.py b/src/pip/_internal/operations/install/legacy.py
--- a/src/pip/_internal/operations/install/legacy.py
+++ b/src/pip/_internal/operations/install/legacy.py
@@ -6,7 +6,7 @@
 import sys
 from distutils.util import change_root
 
-from pip._internal.utils.deprecation import deprecated
+from pip._internal.exceptions import InstallationError
 from pip._internal.utils.logging import indent_log
 from pip._internal.utils.misc import ensure_dir
 from pip._internal.utils.setuptools_build import make_setuptools_install_args
@@ -106,24 +106,12 @@
             egg_info_dir = prepend_root(directory)
             break
     else:
-        deprecated(
-            reason=(
-                "{} did not indicate that it installed an "
-                ".egg-info directory. Only setup.py projects "
-                "generating .egg-info directories are supported."
-            ).format(req_description),
-            replacement=(
-                "for maintainers: updating the setup.py of {0}. "
-                "For users: contact the maintainers of {0} to let "
-                "them know to update their setup.py.".format(
-                    req_name
-                )
-            ),
-            gone_in="20.2",
-            issue=6998,
-        )
-        # FIXME: put the record somewhere
-        return True
+        message = (
+            "{} did not indicate that it installed an "
+            ".egg-info directory. Only setup.py projects "
+            "generating .egg-info directories are supported."
+        ).format(req_description)
+        raise InstallationError(message)
 
     new_lines = []
     for line in record_lines:

{"golden_diff": "diff --git a/src/pip/_internal/operations/install/legacy.py b/src/pip/_internal/operations/install/legacy.py\n--- a/src/pip/_internal/operations/install/legacy.py\n+++ b/src/pip/_internal/operations/install/legacy.py\n@@ -6,7 +6,7 @@\n import sys\n from distutils.util import change_root\n \n-from pip._internal.utils.deprecation import deprecated\n+from pip._internal.exceptions import InstallationError\n from pip._internal.utils.logging import indent_log\n from pip._internal.utils.misc import ensure_dir\n from pip._internal.utils.setuptools_build import make_setuptools_install_args\n@@ -106,24 +106,12 @@\n             egg_info_dir = prepend_root(directory)\n             break\n     else:\n-        deprecated(\n-            reason=(\n-                \"{} did not indicate that it installed an \"\n-                \".egg-info directory. Only setup.py projects \"\n-                \"generating .egg-info directories are supported.\"\n-            ).format(req_description),\n-            replacement=(\n-                \"for maintainers: updating the setup.py of {0}. \"\n-                \"For users: contact the maintainers of {0} to let \"\n-                \"them know to update their setup.py.\".format(\n-                    req_name\n-                )\n-            ),\n-            gone_in=\"20.2\",\n-            issue=6998,\n-        )\n-        # FIXME: put the record somewhere\n-        return True\n+        message = (\n+            \"{} did not indicate that it installed an \"\n+            \".egg-info directory. Only setup.py projects \"\n+            \"generating .egg-info directories are supported.\"\n+        ).format(req_description)\n+        raise InstallationError(message)\n \n     new_lines = []\n     for line in record_lines:\n", "issue": "Fail legacy install if .egg-info directory was not created\n**What's the problem this feature will solve?**\r\n\r\nCurrently on the legacy install code path ([here](https://github.com/pypa/pip/blob/e0239735a3d8a504e00133090dde2210b6564a38/src/pip/_internal/req/req_install.py#L997-L1004)) if execution of `setup.py install ...` didn't result in an `.egg-info` directory being created we trace a warning and continue.\r\n\r\nThis is bad because we will have installed an uninstallable package and the only penalty is a small warning which is very easy to miss.\r\n\r\n**Describe the solution you'd like**\r\n\r\nInstead of tracing a warning we should throw an exception.\r\n\r\nThis prevents additional packages from being installed and possibly hiding the warning from users.\r\n\r\n**Alternative Solutions**\r\n\r\nContinue tracing the warning as before.\r\n\r\n**Additional context**\r\n\r\n* [this support query](https://kite.trade/forum/discussion/4335/could-not-find-egg-info-directory-in-install-record-for-kiteconnect) for [this package](https://github.com/zerodhatech/pykiteconnect/blob/7af60a776fbfafb6c30cfbd8d4f6c192618c5af5/setup.py#L48) which does an egg install in its setup.py regardless of setuptools version.\r\n* [this query](https://stackoverflow.com/questions/26091641/what-does-a-could-not-find-egg-info-directory-in-install-record-from-pip-mean) which implicates having an older version of setuptools\n", "before_files": [{"content": "\"\"\"Legacy installation process, i.e. `setup.py install`.\n\"\"\"\n\nimport logging\nimport os\nimport sys\nfrom distutils.util import change_root\n\nfrom pip._internal.utils.deprecation import deprecated\nfrom pip._internal.utils.logging import indent_log\nfrom pip._internal.utils.misc import ensure_dir\nfrom pip._internal.utils.setuptools_build import make_setuptools_install_args\nfrom pip._internal.utils.subprocess import runner_with_spinner_message\nfrom pip._internal.utils.temp_dir import TempDirectory\nfrom pip._internal.utils.typing import MYPY_CHECK_RUNNING\n\nif MYPY_CHECK_RUNNING:\n    from typing import List, Optional, Sequence\n\n    from pip._internal.build_env import BuildEnvironment\n    from pip._internal.models.scheme import Scheme\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass LegacyInstallFailure(Exception):\n    def __init__(self):\n        # type: () -> None\n        self.parent = sys.exc_info()\n\n\ndef install(\n    install_options,  # type: List[str]\n    global_options,  # type: Sequence[str]\n    root,  # type: Optional[str]\n    home,  # type: Optional[str]\n    prefix,  # type: Optional[str]\n    use_user_site,  # type: bool\n    pycompile,  # type: bool\n    scheme,  # type: Scheme\n    setup_py_path,  # type: str\n    isolated,  # type: bool\n    req_name,  # type: str\n    build_env,  # type: BuildEnvironment\n    unpacked_source_directory,  # type: str\n    req_description,  # type: str\n):\n    # type: (...) -> bool\n\n    header_dir = scheme.headers\n\n    with TempDirectory(kind=\"record\") as temp_dir:\n        try:\n            record_filename = os.path.join(temp_dir.path, 'install-record.txt')\n            install_args = make_setuptools_install_args(\n                setup_py_path,\n                global_options=global_options,\n                install_options=install_options,\n                record_filename=record_filename,\n                root=root,\n                prefix=prefix,\n                header_dir=header_dir,\n                home=home,\n                use_user_site=use_user_site,\n                no_user_config=isolated,\n                pycompile=pycompile,\n            )\n\n            runner = runner_with_spinner_message(\n                \"Running setup.py install for {}\".format(req_name)\n            )\n            with indent_log(), build_env:\n                runner(\n                    cmd=install_args,\n                    cwd=unpacked_source_directory,\n                )\n\n            if not os.path.exists(record_filename):\n                logger.debug('Record file %s not found', record_filename)\n                # Signal to the caller that we didn't install the new package\n                return False\n\n        except Exception:\n            # Signal to the caller that we didn't install the new package\n            raise LegacyInstallFailure\n\n        # At this point, we have successfully installed the requirement.\n\n        # We intentionally do not use any encoding to read the file because\n        # setuptools writes the file using distutils.file_util.write_file,\n        # which does not specify an encoding.\n        with open(record_filename) as f:\n            record_lines = f.read().splitlines()\n\n    def prepend_root(path):\n        # type: (str) -> str\n        if root is None or not os.path.isabs(path):\n            return path\n        else:\n            return change_root(root, path)\n\n    for line in record_lines:\n        directory = os.path.dirname(line)\n        if directory.endswith('.egg-info'):\n            egg_info_dir = prepend_root(directory)\n            break\n    else:\n        deprecated(\n            reason=(\n                \"{} did not indicate that it installed an \"\n                \".egg-info directory. Only setup.py projects \"\n                \"generating .egg-info directories are supported.\"\n            ).format(req_description),\n            replacement=(\n                \"for maintainers: updating the setup.py of {0}. \"\n                \"For users: contact the maintainers of {0} to let \"\n                \"them know to update their setup.py.\".format(\n                    req_name\n                )\n            ),\n            gone_in=\"20.2\",\n            issue=6998,\n        )\n        # FIXME: put the record somewhere\n        return True\n\n    new_lines = []\n    for line in record_lines:\n        filename = line.strip()\n        if os.path.isdir(filename):\n            filename += os.path.sep\n        new_lines.append(\n            os.path.relpath(prepend_root(filename), egg_info_dir)\n        )\n    new_lines.sort()\n    ensure_dir(egg_info_dir)\n    inst_files_path = os.path.join(egg_info_dir, 'installed-files.txt')\n    with open(inst_files_path, 'w') as f:\n        f.write('\\n'.join(new_lines) + '\\n')\n\n    return True\n", "path": "src/pip/_internal/operations/install/legacy.py"}], "after_files": [{"content": "\"\"\"Legacy installation process, i.e. `setup.py install`.\n\"\"\"\n\nimport logging\nimport os\nimport sys\nfrom distutils.util import change_root\n\nfrom pip._internal.exceptions import InstallationError\nfrom pip._internal.utils.logging import indent_log\nfrom pip._internal.utils.misc import ensure_dir\nfrom pip._internal.utils.setuptools_build import make_setuptools_install_args\nfrom pip._internal.utils.subprocess import runner_with_spinner_message\nfrom pip._internal.utils.temp_dir import TempDirectory\nfrom pip._internal.utils.typing import MYPY_CHECK_RUNNING\n\nif MYPY_CHECK_RUNNING:\n    from typing import List, Optional, Sequence\n\n    from pip._internal.build_env import BuildEnvironment\n    from pip._internal.models.scheme import Scheme\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass LegacyInstallFailure(Exception):\n    def __init__(self):\n        # type: () -> None\n        self.parent = sys.exc_info()\n\n\ndef install(\n    install_options,  # type: List[str]\n    global_options,  # type: Sequence[str]\n    root,  # type: Optional[str]\n    home,  # type: Optional[str]\n    prefix,  # type: Optional[str]\n    use_user_site,  # type: bool\n    pycompile,  # type: bool\n    scheme,  # type: Scheme\n    setup_py_path,  # type: str\n    isolated,  # type: bool\n    req_name,  # type: str\n    build_env,  # type: BuildEnvironment\n    unpacked_source_directory,  # type: str\n    req_description,  # type: str\n):\n    # type: (...) -> bool\n\n    header_dir = scheme.headers\n\n    with TempDirectory(kind=\"record\") as temp_dir:\n        try:\n            record_filename = os.path.join(temp_dir.path, 'install-record.txt')\n            install_args = make_setuptools_install_args(\n                setup_py_path,\n                global_options=global_options,\n                install_options=install_options,\n                record_filename=record_filename,\n                root=root,\n                prefix=prefix,\n                header_dir=header_dir,\n                home=home,\n                use_user_site=use_user_site,\n                no_user_config=isolated,\n                pycompile=pycompile,\n            )\n\n            runner = runner_with_spinner_message(\n                \"Running setup.py install for {}\".format(req_name)\n            )\n            with indent_log(), build_env:\n                runner(\n                    cmd=install_args,\n                    cwd=unpacked_source_directory,\n                )\n\n            if not os.path.exists(record_filename):\n                logger.debug('Record file %s not found', record_filename)\n                # Signal to the caller that we didn't install the new package\n                return False\n\n        except Exception:\n            # Signal to the caller that we didn't install the new package\n            raise LegacyInstallFailure\n\n        # At this point, we have successfully installed the requirement.\n\n        # We intentionally do not use any encoding to read the file because\n        # setuptools writes the file using distutils.file_util.write_file,\n        # which does not specify an encoding.\n        with open(record_filename) as f:\n            record_lines = f.read().splitlines()\n\n    def prepend_root(path):\n        # type: (str) -> str\n        if root is None or not os.path.isabs(path):\n            return path\n        else:\n            return change_root(root, path)\n\n    for line in record_lines:\n        directory = os.path.dirname(line)\n        if directory.endswith('.egg-info'):\n            egg_info_dir = prepend_root(directory)\n            break\n    else:\n        message = (\n            \"{} did not indicate that it installed an \"\n            \".egg-info directory. Only setup.py projects \"\n            \"generating .egg-info directories are supported.\"\n        ).format(req_description)\n        raise InstallationError(message)\n\n    new_lines = []\n    for line in record_lines:\n        filename = line.strip()\n        if os.path.isdir(filename):\n            filename += os.path.sep\n        new_lines.append(\n            os.path.relpath(prepend_root(filename), egg_info_dir)\n        )\n    new_lines.sort()\n    ensure_dir(egg_info_dir)\n    inst_files_path = os.path.join(egg_info_dir, 'installed-files.txt')\n    with open(inst_files_path, 'w') as f:\n        f.write('\\n'.join(new_lines) + '\\n')\n\n    return True\n", "path": "src/pip/_internal/operations/install/legacy.py"}]}