diff --git a/CHANGELOG.md b/CHANGELOG.md index ec93530..0acdbb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- User-provided environment variables are now propagated to subprocesses such as `pip install`. ([#65](https://github.com/heroku/buildpacks-python/pull/65)) - Updated pip from 23.1.2 to 23.2. ([#67](https://github.com/heroku/buildpacks-python/pull/67)) - Updated setuptools from 67.8.0 to 68.0.0. ([#51](https://github.com/heroku/buildpacks-python/pull/51)) diff --git a/buildpack.toml b/buildpack.toml index 961ebdd..e8ac309 100644 --- a/buildpack.toml +++ b/buildpack.toml @@ -7,7 +7,6 @@ name = "Python" homepage = "https://github.com/heroku/buildpacks-python" description = "Heroku's official Python Cloud Native Buildpack." keywords = ["python", "heroku"] -clear-env = true [[buildpack.licenses]] type = "BSD-3-Clause" diff --git a/src/layers/python.rs b/src/layers/python.rs index 8b75d66..8656628 100644 --- a/src/layers/python.rs +++ b/src/layers/python.rs @@ -321,6 +321,8 @@ fn generate_layer_env(layer_path: &Path, python_version: &PythonVersion) -> Laye // However, the uWSGI package uses the wrong `sysconfig` APIs so tries to reference the old // compile location, unless we override that by setting `PYTHONHOME`: // https://github.com/unbit/uwsgi/issues/2525 + // In addition, some legacy apps have `PYTHONHOME` set to an invalid value, so if we did not + // set it explicitly here, Python would fail to run both during the build and at runtime. .chainable_insert( Scope::All, ModificationBehavior::Override, diff --git a/src/main.rs b/src/main.rs index 6a2b637..b058417 100644 --- a/src/main.rs +++ b/src/main.rs @@ -66,10 +66,10 @@ impl Buildpack for PythonBuildpack { let packaging_tool_versions = PackagingToolVersions::default(); // We inherit the current process's env vars, since we want `PATH` and `HOME` from the OS - // to be set, so that later commands can find tools like Git in the stack image. We exclude - // user-provided env vars (by setting `clear-env` to true in `buildpack.toml`) to prevent an - // app's env vars from breaking internal buildpack commands. Any buildpack steps that need - // user-provided env vars must explicitly retrieve them via `context.platform.env`. + // to be set (so that later commands can find tools like Git in the stack image), along + // with previous-buildpack or user-provided env vars (so that features like env vars in + // in requirements files work). We protect against broken user-provided env vars by + // making sure that buildpack env vars take precedence in layers envs and command usage. let mut command_env = Env::from_current(); // Create the layer containing the Python runtime, and the packages `pip`, `setuptools` and `wheel`. diff --git a/tests/fixtures/pip_editable_git_compiled/requirements.txt b/tests/fixtures/pip_editable_git_compiled/requirements.txt index a6710b5..a9b27b0 100644 --- a/tests/fixtures/pip_editable_git_compiled/requirements.txt +++ b/tests/fixtures/pip_editable_git_compiled/requirements.txt @@ -4,5 +4,8 @@ # # A C-based package is used instead of a pure Python package, in order to test that the # Python headers can be found in the `include/pythonX.Y/` directory of the Python layer. +# +# The URL to the package is specified via env var, to test that user-provided env vars +# are propagated to pip for use by its env var interpolation feature. --e git+https://github.com/pypa/wheel@0.40.0#egg=extension.dist&subdirectory=tests/testdata/extension.dist +-e git+${WHEEL_PACKAGE_URL}@0.40.0#egg=extension.dist&subdirectory=tests/testdata/extension.dist diff --git a/tests/integration/pip.rs b/tests/integration/pip.rs index e7aa13c..0a14caf 100644 --- a/tests/integration/pip.rs +++ b/tests/integration/pip.rs @@ -156,6 +156,7 @@ fn pip_cache_invalidation_and_metadata_compatibility() { } // This tests that: +// - Requirements file env var interpolation works (ie: user-provided env vars have been propagated to pip). // - Git from the stack image can be found (ie: the system PATH has been correctly propagated to pip). // - The editable mode repository clone is saved into the dependencies layer not the app dir. // - Compiling a source distribution package (as opposed to a pre-built wheel) works. @@ -164,7 +165,8 @@ fn pip_cache_invalidation_and_metadata_compatibility() { #[ignore = "integration test"] fn pip_editable_git_compiled() { TestRunner::default().build( - BuildConfig::new(builder(), "tests/fixtures/pip_editable_git_compiled"), + BuildConfig::new(builder(), "tests/fixtures/pip_editable_git_compiled") + .env("WHEEL_PACKAGE_URL", "https://github.com/pypa/wheel"), |context| { assert_contains!( context.pack_stdout, diff --git a/tests/integration/python_version.rs b/tests/integration/python_version.rs index dbc1e3e..cb872db 100644 --- a/tests/integration/python_version.rs +++ b/tests/integration/python_version.rs @@ -76,9 +76,17 @@ fn builds_with_python_version(fixture_path: &str, python_version: &str) { } = PackagingToolVersions::default(); let mut config = BuildConfig::new(builder(), fixture_path); - // Checks that potentially broken user-provided env vars are not being passed unfiltered to - // subprocesses we launch (such as `pip install`), thanks to `clear-env` in `buildpack.toml`. - config.env("PYTHONHOME", "/invalid-path"); + // Checks that potentially broken user-provided env vars don't take precedence over those + // set by this buildpack and break running Python. These are based on the env vars that + // used to be set by `bin/release` by very old versions of the classic Python buildpack: + // https://github.com/heroku/heroku-buildpack-python/blob/27abdfe7d7ad104dabceb45641415251e965671c/bin/release#L11-L18 + config.envs([ + ("LD_LIBRARY_PATH", "/invalid-path"), + ("LIBRARY_PATH", "/invalid-path"), + ("PATH", "/invalid-path"), + ("PYTHONHOME", "/invalid-path"), + ("PYTHONPATH", "/invalid-path"), + ]); TestRunner::default().build(config, |context| { assert_empty!(context.pack_stderr);