PIPInstallRequirements installs dependencies from the given requirements files in a virtual env. It will install the files in order in which they are specified, so that dependencies specified in later requirements files can override later ones. This function is responsible for installing requiremen
(ctx *gcp.Context, l *libcnb.Layer, reqs ...string)
| 216 | // accidentally override some builtin stdlib modules, e.g. typing, enum, etc., and cause both |
| 217 | // build-time and run-time failures. |
| 218 | func PIPInstallRequirements(ctx *gcp.Context, l *libcnb.Layer, reqs ...string) error { |
| 219 | if cap := ctx.Capability(PipInstallerCapability); cap != nil { |
| 220 | i, ok := cap.(pipInstaller) |
| 221 | if !ok { |
| 222 | return gcp.InternalErrorf("capability %q does not implement pipInstaller interface", PipInstallerCapability) |
| 223 | } |
| 224 | return i.Install(ctx, l, reqs...) |
| 225 | } |
| 226 | |
| 227 | shouldInstall, err := prepareDependenciesLayer(ctx, l, "pip", reqs...) |
| 228 | if err != nil { |
| 229 | return err |
| 230 | } |
| 231 | if !shouldInstall { |
| 232 | ctx.Logf("Application dependencies are up to date, skipping installation.") |
| 233 | return nil |
| 234 | } |
| 235 | |
| 236 | ctx.Logf("Installing application dependencies.") |
| 237 | if err := ar.GeneratePythonConfig(ctx); err != nil { |
| 238 | return fmt.Errorf("generating Artifact Registry credentials: %w", err) |
| 239 | } |
| 240 | |
| 241 | // History of the logic below: |
| 242 | // |
| 243 | // pip install --target has several subtle issues: |
| 244 | // We cannot use --upgrade: https://github.com/pypa/pip/issues/8799. |
| 245 | // We also cannot _not_ use --upgrade, see the requirements_bin_conflict acceptance test. |
| 246 | // |
| 247 | // Instead, we use Python per-user site-packages (https://www.python.org/dev/peps/pep-0370/) |
| 248 | // where we can and virtualenv where we cannot. |
| 249 | // |
| 250 | // Each requirements file is installed separately to allow the requirements.txt files |
| 251 | // to specify conflicting dependencies (e.g. functions-framework pins package A at 1.2.0 but |
| 252 | // the user's requirements.txt file pins A at 1.4.0. The user should be able to override |
| 253 | // the functions-framework-pinned package). |
| 254 | |
| 255 | // HACK: For backwards compatibility with Python 3.7 and 3.8 on App Engine and Cloud Functions. |
| 256 | virtualEnv := requiresVirtualEnv() |
| 257 | if virtualEnv { |
| 258 | // --without-pip and --system-site-packages allow us to use `pip` and other packages from the |
| 259 | // build image and avoid reinstalling them, saving about 10MB. |
| 260 | // TODO(b/140775593): Use virtualenv pip after FTL is no longer used and remove from build image. |
| 261 | if _, err := ctx.Exec([]string{"python3", "-m", "venv", "--without-pip", "--system-site-packages", l.Path}); err != nil { |
| 262 | return err |
| 263 | } |
| 264 | if err := copySharedLibs(ctx, l); err != nil { |
| 265 | return err |
| 266 | } |
| 267 | |
| 268 | // The VIRTUAL_ENV variable is usually set by the virtual environment's activate script. |
| 269 | l.SharedEnvironment.Override("VIRTUAL_ENV", l.Path) |
| 270 | // Use the virtual environment python3 for all subsequent commands in this buildpack, for |
| 271 | // subsequent buildpacks, l.Path/bin will be added by lifecycle. |
| 272 | if err := ctx.Setenv("PATH", filepath.Join(l.Path, "bin")+string(os.PathListSeparator)+os.Getenv("PATH")); err != nil { |
| 273 | return err |
| 274 | } |
| 275 | if err := ctx.Setenv("VIRTUAL_ENV", l.Path); err != nil { |
no test coverage detected