Repository: pypa/pip

Issue:
pip version check file doesn't honor cache-dir
- Pip version: 7.1.0
- Python version: 2.7.6
- Operating System: Fedora 22

My pip config looks like:

```
[dev@machine ~] $ cat ~/.config/pip/pip.conf 
[global]
cache-dir=/ssd/dev/.pip/cache
```

Whenever I try to install any package, it caches the wheels in the `cache-dir` as specified above. However, the pip-version check is performed and the file `selfcheck.json` and it's lock file is placed in the directory: `$HOME/.cache/pip/` , which should have been inside the `cache-dir` as specified above.

I get around this problem by specifying the following in the pip config (but it's not a very good solution):

```
disable-pip-version-check=true
```



Discussion:
I'm at PyCon sprints, researching this before making changes.


I was able to recreate this issue using the latest pip (10.0.1)

Looking in the code, I found that in `pip._internal.utils.outdated` there are two classes that write out the _selfcheck.json_ file.

For users not in virtual environmnets
	`pip._internal.utils.outdated.GlobalSelfCheckState` puts _selfcheck.json_ in the directory specified in USER_CACHE_DIR
For users in virtual environments
	`pip._internal.utils.outdated.VirtualenvSelfCheckState` puts _pip-selfcheck.json_ in the directory specified in sys.prefix

I am not certain if we would want to change this for both scenarios or just for users not in virtual environments.

From looking at the code, it looks like the change would be as follows:

`pip._internal.utils.outdated.pip_version_check` has access to to the configured cache directory in `options.cache_dir`
 To fix the problem, this value could be passed through as an argument into  `pip._internal.utils.outdated.load_selfcheck_state` and from there into `pip._internal.utils.outdated.GlobalSelfCheckState.__init__`
 And possibly into `pip._internal.utils.outdated.VirtualenvSelfCheckState.__init_`


Hey @tomfbiz! Are you on IRC?
Quick look suggests we can kill the virtual env file completely, and just use the per user cache file for all environments, and then plumb the cache-dir file through appropriately. 

Does that answer your question?
Noting here that we (mostly @dstufft, @tomfbiz :P) had a discussion on IRC and we're likely simply removing the virtualenv specific file.

Resolving patch:
diff --git a/src/pip/_internal/utils/outdated.py b/src/pip/_internal/utils/outdated.py
--- a/src/pip/_internal/utils/outdated.py
+++ b/src/pip/_internal/utils/outdated.py
@@ -11,7 +11,6 @@
 
 from pip._internal.compat import WINDOWS
 from pip._internal.index import PackageFinder
-from pip._internal.locations import USER_CACHE_DIR, running_under_virtualenv
 from pip._internal.utils.filesystem import check_path_owner
 from pip._internal.utils.misc import ensure_dir, get_installed_version
 
@@ -21,34 +20,9 @@
 logger = logging.getLogger(__name__)
 
 
-class VirtualenvSelfCheckState(object):
-    def __init__(self):
-        self.statefile_path = os.path.join(sys.prefix, "pip-selfcheck.json")
-
-        # Load the existing state
-        try:
-            with open(self.statefile_path) as statefile:
-                self.state = json.load(statefile)
-        except (IOError, ValueError):
-            self.state = {}
-
-    def save(self, pypi_version, current_time):
-        # Attempt to write out our version check file
-        with open(self.statefile_path, "w") as statefile:
-            json.dump(
-                {
-                    "last_check": current_time.strftime(SELFCHECK_DATE_FMT),
-                    "pypi_version": pypi_version,
-                },
-                statefile,
-                sort_keys=True,
-                separators=(",", ":")
-            )
-
-
-class GlobalSelfCheckState(object):
-    def __init__(self):
-        self.statefile_path = os.path.join(USER_CACHE_DIR, "selfcheck.json")
+class SelfCheckState(object):
+    def __init__(self, cache_dir):
+        self.statefile_path = os.path.join(cache_dir, "selfcheck.json")
 
         # Load the existing state
         try:
@@ -84,13 +58,6 @@ def save(self, pypi_version, current_time):
                           separators=(",", ":"))
 
 
-def load_selfcheck_statefile():
-    if running_under_virtualenv():
-        return VirtualenvSelfCheckState()
-    else:
-        return GlobalSelfCheckState()
-
-
 def pip_version_check(session, options):
     """Check for an update for pip.
 
@@ -106,7 +73,7 @@ def pip_version_check(session, options):
     pypi_version = None
 
     try:
-        state = load_selfcheck_statefile()
+        state = SelfCheckState(cache_dir=options.cache_dir)
 
         current_time = datetime.datetime.utcnow()
         # Determine if we need to refresh the state


Test patch:
diff --git a/tests/unit/test_unit_outdated.py b/tests/unit/test_unit_outdated.py
--- a/tests/unit/test_unit_outdated.py
+++ b/tests/unit/test_unit_outdated.py
@@ -3,6 +3,7 @@
 import sys
 from contextlib import contextmanager
 
+
 import freezegun
 import pretend
 import pytest
@@ -37,6 +38,7 @@ def _options():
     return pretend.stub(
         find_links=False, extra_index_urls=[], index_url='default_url',
         pre=False, trusted_hosts=False, process_dependency_links=False,
+        cache_dir='',
     )
 
 
@@ -72,16 +74,17 @@ def test_pip_version_check(monkeypatch, stored_time, installed_ver, new_ver,
         save=pretend.call_recorder(lambda v, t: None),
     )
     monkeypatch.setattr(
-        outdated, 'load_selfcheck_statefile', lambda: fake_state
+        outdated, 'SelfCheckState', lambda **kw: fake_state
     )
 
     with freezegun.freeze_time(
-            "1970-01-09 10:00:00",
-            ignore=[
-                "six.moves",
-                "pip._vendor.six.moves",
-                "pip._vendor.requests.packages.urllib3.packages.six.moves",
-            ]):
+        "1970-01-09 10:00:00",
+        ignore=[
+            "six.moves",
+            "pip._vendor.six.moves",
+            "pip._vendor.requests.packages.urllib3.packages.six.moves",
+        ]
+    ):
         latest_pypi_version = outdated.pip_version_check(None, _options())
 
     # See we return None if not installed_version
@@ -105,41 +108,7 @@ def test_pip_version_check(monkeypatch, stored_time, installed_ver, new_ver,
         assert len(outdated.logger.warning.calls) == 0
 
 
-def test_virtualenv_state(monkeypatch):
-    CONTENT = '{"last_check": "1970-01-02T11:00:00Z", "pypi_version": "1.0"}'
-    fake_file = pretend.stub(
-        read=pretend.call_recorder(lambda: CONTENT),
-        write=pretend.call_recorder(lambda s: None),
-    )
-
-    @pretend.call_recorder
-    @contextmanager
-    def fake_open(filename, mode='r'):
-        yield fake_file
-
-    monkeypatch.setattr(outdated, 'open', fake_open, raising=False)
-
-    monkeypatch.setattr(outdated, 'running_under_virtualenv',
-                        pretend.call_recorder(lambda: True))
-
-    monkeypatch.setattr(sys, 'prefix', 'virtually_env')
-
-    state = outdated.load_selfcheck_statefile()
-    state.save('2.0', datetime.datetime.utcnow())
-
-    assert len(outdated.running_under_virtualenv.calls) == 1
-
-    expected_path = os.path.join('virtually_env', 'pip-selfcheck.json')
-    assert fake_open.calls == [
-        pretend.call(expected_path),
-        pretend.call(expected_path, 'w'),
-    ]
-
-    # json.dumps will call this a number of times
-    assert len(fake_file.write.calls)
-
-
-def test_global_state(monkeypatch, tmpdir):
+def test_self_check_state(monkeypatch, tmpdir):
     CONTENT = '''{"pip_prefix": {"last_check": "1970-01-02T11:00:00Z",
         "pypi_version": "1.0"}}'''
     fake_file = pretend.stub(
@@ -164,18 +133,12 @@ def fake_lock(filename):
     monkeypatch.setattr(lockfile, 'LockFile', fake_lock)
     monkeypatch.setattr(os.path, "exists", lambda p: True)
 
-    monkeypatch.setattr(outdated, 'running_under_virtualenv',
-                        pretend.call_recorder(lambda: False))
-
     cache_dir = tmpdir / 'cache_dir'
-    monkeypatch.setattr(outdated, 'USER_CACHE_DIR', cache_dir)
     monkeypatch.setattr(sys, 'prefix', tmpdir / 'pip_prefix')
 
-    state = outdated.load_selfcheck_statefile()
+    state = outdated.SelfCheckState(cache_dir=cache_dir)
     state.save('2.0', datetime.datetime.utcnow())
 
-    assert len(outdated.running_under_virtualenv.calls) == 1
-
     expected_path = cache_dir / 'selfcheck.json'
     assert fake_lock.calls == [pretend.call(expected_path)]