From 97ac451a805ce085e8f7db722d53ac337e6d2e49 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz <me@kennethreitz.org> Date: Tue, 6 Mar 2018 15:44:50 -0500 Subject: [PATCH] Pipenv uninstall, and other improvements (#650) --- CHANGELOG.md | 6 +++ bin/compile | 21 ++++------ bin/steps/pip-uninstall | 21 ++++++---- bin/steps/pipenv | 89 +++++++++++++++++++++++++++-------------- vendor/pip-pop/pip-diff | 1 + vendor/pipenv-to-pip | 26 ++++++++++++ 6 files changed, 114 insertions(+), 50 deletions(-) mode change 100644 => 100755 bin/steps/pipenv create mode 100755 vendor/pipenv-to-pip diff --git a/CHANGELOG.md b/CHANGELOG.md index 76c085f2..676f8d59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Python Buildpack Changelog +# 126 + +Skip installs if Pipfile.lock hasn't changed, and uninstall stale dependencies with Pipenv. + +- No longer warn if there is no `Procfile`. + # 125 Set `PYTHONPATH` during collectstatic runs, other updates. diff --git a/bin/compile b/bin/compile index 39592548..8d7db16f 100755 --- a/bin/compile +++ b/bin/compile @@ -100,12 +100,6 @@ export PKG_CONFIG_PATH=/app/.heroku/vendor/lib/pkg-config:/app/.heroku/python/li # Switch to the repo's context. cd "$BUILD_DIR" -# Warn for lack of Procfile. -if [[ ! -f Procfile ]]; then - puts-warn 'Warning: Your application is missing a Procfile. This file tells Heroku how to run your application.' - puts-warn 'Learn more: https://devcenter.heroku.com/articles/procfile' -fi - # Prepare the cache. mkdir -p "$CACHE_DIR" @@ -166,7 +160,14 @@ mtime "python.install.time" "${start}" # Pipenv support. # shellcheck source=bin/steps/pipenv -source "$BIN_DIR/steps/pipenv" +sub_env "$BIN_DIR/steps/pipenv" + +# Uninstall removed dependencies with Pip. +let start=$(nowms) +# shellcheck source=bin/steps/pip-uninstall +source "$BIN_DIR/steps/pip-uninstall" +mtime "pip.uninstall.time" "${start}" + # If no requirements.txt file given, assume `setup.py develop` is intended. if [ ! -f requirements.txt ] && [ ! -f Pipfile ]; then @@ -197,12 +198,6 @@ sub_env "$BIN_DIR/steps/geo-libs" # shellcheck source=bin/steps/gdal source "$BIN_DIR/steps/gdal" -# Uninstall removed dependencies with Pip. -let start=$(nowms) -# shellcheck source=bin/steps/pip-uninstall -source "$BIN_DIR/steps/pip-uninstall" -mtime "pip.uninstall.time" "${start}" - # Install dependencies with Pip (where the magic happens). let start=$(nowms) # shellcheck source=bin/steps/pip-install diff --git a/bin/steps/pip-uninstall b/bin/steps/pip-uninstall index 6cf469f1..9ec05394 100755 --- a/bin/steps/pip-uninstall +++ b/bin/steps/pip-uninstall @@ -2,19 +2,24 @@ set +e # Install dependencies with Pip. +# shellcheck source=bin/utils +source $BIN_DIR/utils -if [[ -f .heroku/python/requirements-declared.txt ]]; then +if [ ! "$SKIP_PIP_INSTALL" ]; then - cp .heroku/python/requirements-declared.txt requirements-declared.txt + if [[ -f .heroku/python/requirements-declared.txt ]]; then - pip-diff --stale requirements-declared.txt requirements.txt --exclude setuptools pip wheel > .heroku/python/requirements-stale.txt + cp .heroku/python/requirements-declared.txt requirements-declared.txt - rm -fr requirements-declared.txt + pip-diff --stale requirements-declared.txt requirements.txt --exclude setuptools pip wheel > .heroku/python/requirements-stale.txt - if [[ -s .heroku/python/requirements-stale.txt ]]; then - puts-step "Uninstalling stale dependencies" - /app/.heroku/python/bin/pip uninstall -r .heroku/python/requirements-stale.txt -y --exists-action=w | cleanup | indent + rm -fr requirements-declared.txt + + if [[ -s .heroku/python/requirements-stale.txt ]]; then + puts-step "Uninstalling stale dependencies" + /app/.heroku/python/bin/pip uninstall -r .heroku/python/requirements-stale.txt -y --exists-action=w | cleanup | indent + fi fi -fi +fi set -e diff --git a/bin/steps/pipenv b/bin/steps/pipenv old mode 100644 new mode 100755 index 37af5620..a61301ee --- a/bin/steps/pipenv +++ b/bin/steps/pipenv @@ -5,41 +5,72 @@ # shellcheck source=bin/utils source $BIN_DIR/utils -# Pipenv support (Generate requriements.txt with pipenv). -if [[ -f Pipfile ]]; then - if [[ ! -f requirements.txt ]]; then - puts-step "Installing requirements with latest Pipenv…" - - # Measure that we're using Pipenv. - mcount "tool.pipenv" - - # Set PIP_EXTRA_INDEX_URL - if [[ -r $ENV_DIR/PIP_EXTRA_INDEX_URL ]]; then - PIP_EXTRA_INDEX_URL="$(cat "$ENV_DIR/PIP_EXTRA_INDEX_URL")" - export PIP_EXTRA_INDEX_URL - fi - # Install pipenv. - /app/.heroku/python/bin/pip install pipenv --upgrade &> /dev/null +if [[ -f Pipfile.lock ]]; then + if [[ -f .heroku/python/Pipfile.lock.sha256 ]]; then + if [[ $(openssl dgst -sha256 Pipfile.lock) == $(cat .heroku/python/Pipfile.lock.sha256) ]]; then + if [[ ! "$PIPENV_ALWAYS_INSTALL" ]]; then + echo "Skipping installation, as Pipfile.lock hasn't changed since last deploy." | indent + echo "To disable this functionality, run the following command:" + echo "" + echo " $ heroku config:set PIPENV_ALWAYS_INSTALL=1" | indent - # Install the dependencies. - if [[ ! -f Pipfile.lock ]]; then - /app/.heroku/python/bin/pipenv install --system --skip-lock 2>&1 | indent - else - /app/.heroku/python/bin/pipenv install --system --deploy 2>&1 | indent + SKIP_PIPENV_INSTALL=1 + fi fi + fi +fi - # Install the test dependencies, for CI. - if [ "$INSTALL_TEST" ]; then - puts-step "Installing test dependencies…" - /app/.heroku/python/bin/pipenv install --dev --system --deploy 2>&1 | cleanup | indent - fi - # Skip pip install, later. - export SKIP_PIP_INSTALL=1 +if [ ! "$SKIP_PIPENV_INSTALL" ]; then + + # Pipenv support (Generate requriements.txt with pipenv). + if [[ -f Pipfile ]]; then + if [[ ! -f requirements.txt ]]; then + puts-step "Installing requirements with latest Pipenv…" + + # Measure that we're using Pipenv. + mcount "tool.pipenv" + + # Set PIP_EXTRA_INDEX_URL + if [[ -r $ENV_DIR/PIP_EXTRA_INDEX_URL ]]; then + PIP_EXTRA_INDEX_URL="$(cat "$ENV_DIR/PIP_EXTRA_INDEX_URL")" + export PIP_EXTRA_INDEX_URL + fi - # Pip freeze, for compatibility. - /app/.heroku/python/bin/pip freeze > requirements.txt + # if [[ -f .heroku/python/requirements-declared.txt ]]; then + # cp .heroku/python/requirements-declared.txt requirements.txt + # fi + # Install pipenv. + /app/.heroku/python/bin/pip install pipenv --upgrade &> /dev/null + + # Install the dependencies. + if [[ ! -f Pipfile.lock ]]; then + /app/.heroku/python/bin/pipenv install --system --skip-lock 2>&1 | indent + else + pipenv-to-pip Pipfile.lock > requirements.txt + "$BIN_DIR/steps/pip-uninstall" + cp requirements.txt .heroku/python/requirements-declared.txt + openssl dgst -sha256 Pipfile.lock > .heroku/python/Pipfile.lock.sha256 + + /app/.heroku/python/bin/pipenv install --system --deploy 2>&1 | indent + fi + + # Install the test dependencies, for CI. + if [ "$INSTALL_TEST" ]; then + puts-step "Installing test dependencies…" + /app/.heroku/python/bin/pipenv install --dev --system --deploy 2>&1 | cleanup | indent + fi + + # Skip pip install, later. + export SKIP_PIP_INSTALL=1 + + # Pip freeze, for compatibility. + pip freeze > requirements.txt + fi fi +else + pipenv-to-pip Pipfile.lock > requirements.txt + export SKIP_PIP_INSTALL=1 fi diff --git a/vendor/pip-pop/pip-diff b/vendor/pip-pop/pip-diff index 1081f3d2..2bb1877c 100755 --- a/vendor/pip-pop/pip-diff +++ b/vendor/pip-pop/pip-diff @@ -41,6 +41,7 @@ class Requirements(object): 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 + requirement.req.name = requirement.req.name.lower() self.requirements.append(requirement.req) diff --git a/vendor/pipenv-to-pip b/vendor/pipenv-to-pip new file mode 100755 index 00000000..95732486 --- /dev/null +++ b/vendor/pipenv-to-pip @@ -0,0 +1,26 @@ +#!/usr/bin/env python + +import json +import sys + + +def main(): + INFILE = sys.argv[1] + + with open(INFILE, 'rb') as f: + lockfile = json.load(f) + + packages = [] + for package in lockfile.get('default', {}): + try: + packages.append('{0}{1}'.format(package, lockfile['default'][package]['version'])) + except KeyError: + pass + + print('\n'.join(packages)) + + +try: + main() +except Exception: + pass -- GitLab