Merge pull request #1836 from jtratner/fix-env-calculation-with-hashes

Fix env calculation with hashes
This commit is contained in:
Tzu-ping Chung
2018-03-23 16:06:13 +08:00
committed by GitHub
4 changed files with 75 additions and 22 deletions
+17
View File
@@ -38,6 +38,23 @@ If you'd like a specific package to be installed with a specific package index,
Very fancy.
☤ Injecting credentials into Pipfiles via environment variables
-----------------------------------------------------------------
Pipenv will expand environment variables (if defined) in your Pipfile. Quite
useful if you need to authenticate to a private PyPI::
[[source]]
url = "https://$USERNAME:${PASSWORD}@mypypi.example.com/simple"
verify_ssl = true
name = "pypi"
Luckily - pipenv will hash your Pipfile *before* expanding environment
variables (and, helpfully, will substitute the environment variables again when
you install from the lock file - so no need to commit any secrets! Woo!)
☤ Specifying Basically Anything
-------------------------------
+9 -22
View File
@@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
import contextlib
import codecs
import logging
import os
import sys
@@ -1312,20 +1311,14 @@ def do_init(
)
# Write out the lockfile if it doesn't exist, but not if the Pipfile is being ignored
if (project.lockfile_exists and not ignore_pipfile) and not skip_lock:
# Open the lockfile.
with codecs.open(project.lockfile_location, 'r') as f:
lockfile = simplejson.load(f)
# Update the lockfile if it is out-of-date.
p = pipfile.load(project.pipfile_location)
# Check that the hash of the Lockfile matches the lockfile's hash.
if not lockfile['_meta'].get('hash', {}).get('sha256') == p.hash:
old_hash = lockfile['_meta'].get('hash', {}).get('sha256')[-6:]
new_hash = p.hash[-6:]
old_hash = project.get_lockfile_hash()
new_hash = project.calculate_pipfile_hash()
if new_hash != old_hash:
if deploy:
click.echo(
crayons.red(
'Your Pipfile.lock ({0}) is out of date. Expected: ({1}).'.format(
old_hash, new_hash
old_hash[-6:], new_hash[-6:]
)
)
)
@@ -1338,7 +1331,7 @@ def do_init(
click.echo(
crayons.red(
u'Pipfile.lock ({0}) out of date, updating to ({1})…'.format(
old_hash, new_hash
old_hash[-6:], new_hash[-6:]
),
bold=True,
),
@@ -1655,19 +1648,13 @@ def ensure_lockfile(keep_outdated=False):
keep_outdated = project.settings.get('keep_outdated')
# Write out the lockfile if it doesn't exist, but not if the Pipfile is being ignored
if project.lockfile_exists:
# Open the lockfile.
with codecs.open(project.lockfile_location, 'r') as f:
lockfile = simplejson.load(f)
# Update the lockfile if it is out-of-date.
p = pipfile.load(project.pipfile_location)
# Check that the hash of the Lockfile matches the lockfile's hash.
if not lockfile['_meta'].get('hash', {}).get('sha256') == p.hash:
old_hash = lockfile['_meta'].get('hash', {}).get('sha256')[-6:]
new_hash = p.hash[-6:]
old_hash = project.get_lockfile_hash()
new_hash = project.calculate_pipfile_hash()
if new_hash != old_hash:
click.echo(
crayons.red(
u'Pipfile.lock ({0}) out of date, updating to ({1})…'.format(
old_hash, new_hash
old_hash[-6:], new_hash[-6:]
),
bold=True,
),
+14
View File
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
import codecs
import json
import os
import re
@@ -640,3 +641,16 @@ class Project(object):
def recase_pipfile(self):
self.write_toml(recase_file(self._pipfile))
def get_lockfile_hash(self):
if not os.path.exists(self.lockfile_location):
return
# Open the lockfile.
with codecs.open(self.lockfile_location, 'r') as f:
lockfile = json.load(f)
return lockfile['_meta'].get('hash', {}).get('sha256')
def calculate_pipfile_hash(self):
# Update the lockfile if it is out-of-date.
p = pipfile.load(self.pipfile_location, inject_env=False)
return p.hash
+35
View File
@@ -12,6 +12,7 @@ from pipenv.utils import (
)
from pipenv.vendor import toml
from pipenv.vendor import delegator
from pipenv.patched import pipfile
from pipenv.project import Project
from pipenv.vendor.six import PY2
if PY2:
@@ -1118,3 +1119,37 @@ requests = "==2.14.0"
with PipenvInstance(pypi=pypi) as p:
c = p.pipenv('clean')
assert c.return_code == 0
@pytest.mark.install
def test_environment_variable_value_does_not_change_hash(self, pypi, monkeypatch):
with PipenvInstance(chdir=True, pypi=pypi) as p:
with open(p.pipfile_path, 'w') as f:
f.write("""
[[source]]
url = 'https://${PYPI_USERNAME}:${PYPI_PASSWORD}@pypi.python.org/simple'
verify_ssl = true
name = 'pypi'
[requires]
python_version = '2.7'
[packages]
flask = "==0.12.2"
""")
monkeypatch.setitem(os.environ, 'PYPI_USERNAME', 'whatever')
monkeypatch.setitem(os.environ, 'PYPI_PASSWORD', 'pass')
assert Project().get_lockfile_hash() is None
c = p.pipenv('install')
lock_hash = Project().get_lockfile_hash()
assert lock_hash is not None
assert lock_hash == Project().calculate_pipfile_hash()
# sanity check on pytest
assert 'PYPI_USERNAME' not in str(pipfile.load(p.pipfile_path))
assert c.return_code == 0
assert Project().get_lockfile_hash() == Project.calculate_pipfile_hash()
monkeypatch.setitem(os.environ, 'PYPI_PASSWORD', 'pass2')
assert Project().get_lockfile_hash() == Project.calculate_pipfile_hash()
with open(p.pipfile_path, 'a') as f:
f.write('requests = "==2.14.0"\n')
assert Project().get_lockfile_hash() != Project.calculate_pipfile_hash()