From 9b185f99d505b701dc09b173e834a67d9c306a82 Mon Sep 17 00:00:00 2001 From: David Lord Date: Tue, 30 May 2017 08:05:33 -0700 Subject: [PATCH] use pkg_resources to check for distributions (#395) more accurate than parsing requirements.txt fixes #359 --- CHANGELOG.md | 9 +++++++ bin/steps/collectstatic | 2 +- bin/steps/cryptography | 2 +- bin/steps/gdal | 2 +- bin/steps/pylibmc | 2 +- bin/steps/setuptools | 2 +- vendor/pip-pop/pip-grep | 57 ++++++++--------------------------------- 7 files changed, 25 insertions(+), 51 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dae77f5b..9a701a735 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Python Buildpack Changelog +# 104 + +unreleased + +- Use `pkg_resources` to check if a distribution is installed instead of + parsing `requirements.txt`. ([#395][395]) + +[395]: https://github.com/heroku/heroku-buildpack-python/pull/395 + ## 103 Bug fixes and improvements. diff --git a/bin/steps/collectstatic b/bin/steps/collectstatic index 6e36c7aab..20bbb85f5 100755 --- a/bin/steps/collectstatic +++ b/bin/steps/collectstatic @@ -20,7 +20,7 @@ MANAGE_FILE=${MANAGE_FILE:-fakepath} [ -f .heroku/collectstatic_disabled ] && DISABLE_COLLECTSTATIC=1 # Ensure that Django is explicitly specified in requirements.txt -pip-grep -s requirements.txt django Django && DJANGO_INSTALLED=1 +pip-grep -s Django && DJANGO_INSTALLED=1 if [ ! "$DISABLE_COLLECTSTATIC" ] && [ -f "$MANAGE_FILE" ] && [ "$DJANGO_INSTALLED" ]; then diff --git a/bin/steps/cryptography b/bin/steps/cryptography index 8a507999d..dd4ea32f9 100755 --- a/bin/steps/cryptography +++ b/bin/steps/cryptography @@ -18,7 +18,7 @@ PKG_CONFIG_PATH="/app/.heroku/vendor/lib/pkgconfig:$PKG_CONFIG_PATH" source $BIN_DIR/utils # If a package using cffi exists within requirements, use vendored libffi. -if (pip-grep -s requirements.txt argon2-cffi bcrypt cffi cryptography django[argon2] Django[argon2] django[bcrypt] Django[bcrypt] PyNaCl pyOpenSSL PyOpenSSL requests[security] misaka &> /dev/null) then +if (pip-grep -s argon2-cffi bcrypt cffi cryptography PyNaCl pyOpenSSL PyOpenSSL misaka &> /dev/null) then if [ ! -d ".heroku/vendor/lib/libffi-3.1" ]; then echo "-----> Noticed cffi. Bootstrapping libffi." diff --git a/bin/steps/gdal b/bin/steps/gdal index 50a09ac33..82892b007 100755 --- a/bin/steps/gdal +++ b/bin/steps/gdal @@ -18,7 +18,7 @@ PKG_CONFIG_PATH="/app/.heroku/vendor/lib/pkgconfig:$PKG_CONFIG_PATH" source $BIN_DIR/utils # If GDAL exists within requirements, use vendored gdal. -if (pip-grep -s requirements.txt GDAL gdal pygdal &> /dev/null) then +if (pip-grep -s GDAL pygdal &> /dev/null) then if [ ! -f ".heroku/vendor/bin/gdalserver" ]; then echo "-----> Noticed GDAL. Bootstrapping gdal." diff --git a/bin/steps/pylibmc b/bin/steps/pylibmc index f574e5350..d5cc78571 100755 --- a/bin/steps/pylibmc +++ b/bin/steps/pylibmc @@ -17,7 +17,7 @@ source $BIN_DIR/utils # If pylibmc exists within requirements, use vendored libmemcached. -if (pip-grep -s requirements.txt pylibmc &> /dev/null) then +if (pip-grep -s pylibmc &> /dev/null) then if [ ! -d ".heroku/vendor/lib/sasl2" ]; then echo "-----> Noticed pylibmc. Bootstrapping libmemcached." diff --git a/bin/steps/setuptools b/bin/steps/setuptools index 870cfd4a5..66a861738 100755 --- a/bin/steps/setuptools +++ b/bin/steps/setuptools @@ -3,7 +3,7 @@ # Syntax sugar. source $BIN_DIR/utils -if (pip-grep -s requirements.txt setuptools distribute &> /dev/null) then +if (pip-grep -s setuptools distribute &> /dev/null) then puts-warn 'The package setuptools/distribute is listed in requirements.txt.' puts-warn 'Please remove to ensure expected behavior. ' diff --git a/vendor/pip-pop/pip-grep b/vendor/pip-pop/pip-grep index 9e3371d0c..8b90a4936 100755 --- a/vendor/pip-pop/pip-grep +++ b/vendor/pip-pop/pip-grep @@ -2,58 +2,26 @@ # -*- coding: utf-8 -*- """Usage: - pip-grep [-s] ... + pip-grep [-s] ... Options: -h --help Show this screen. """ -import os from docopt import docopt -from pip.req import parse_requirements -from pip.index import PackageFinder -from pip._vendor.requests import session +from pkg_resources import DistributionNotFound, get_distribution -requests = session() +def has_any_distribution(names, silent=False): + for name in names: + try: + get_distribution(name) + except DistributionNotFound: + continue -class Requirements(object): - def __init__(self, reqfile=None): - super(Requirements, self).__init__() - self.path = reqfile - self.requirements = [] - - if reqfile: - self.load(reqfile) - - def __repr__(self): - return ''.format(self.path) - - def load(self, reqfile): - if not os.path.exists(reqfile): - raise ValueError('The given requirements file does not exist.') - - finder = PackageFinder([], [], session=requests) - for requirement in parse_requirements(reqfile, finder=finder, session=requests): - if requirement.req: - if not getattr(requirement.req, 'name', None): - # Prior to pip 8.1.2 the attribute `name` did not exist. - requirement.req.name = requirement.req.project_name - self.requirements.append(requirement.req) - - -def grep(reqfile, packages, silent=False): - try: - r = Requirements(reqfile) - except ValueError: if not silent: - print('There was a problem loading the given requirement file.') - exit(os.EX_NOINPUT) + print('Package {name} found!'.format(name=name)) - for req in r.requirements: - if req.name in packages: - if not silent: - print('Package {} found!'.format(req.name)) - exit(0) + exit(0) if not silent: print('Not found.') @@ -63,10 +31,7 @@ def grep(reqfile, packages, silent=False): def main(): args = docopt(__doc__, version='pip-grep') - - kwargs = {'reqfile': args[''], 'packages': args[''], 'silent': args['-s']} - - grep(**kwargs) + has_any_distribution(names=args[''], silent=args['-s']) if __name__ == '__main__':