From d39ec59e58f483cb333acfe54f19419b29055af4 Mon Sep 17 00:00:00 2001 From: Pascal Zimmermann Date: Tue, 10 Mar 2026 21:03:19 +0100 Subject: [PATCH] feat: Add flit-core support Signed-off-by: Pascal Zimmermann --- CONTRIBUTING.md | 2 +- README.md | 16 +++++++++++++++- src/python/supply/supply.go | 14 +++++++++++--- src/python/supply/supply_test.go | 26 ++++++++++++++++++-------- 4 files changed, 45 insertions(+), 13 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c6cf6d375..c7116b9a2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,7 +4,7 @@ All pull request authors must have a Contributor License Agreement (CLA) on-file with us. Please sign the Contributor License Agreements for Cloud Foundry ([Individual or Corporate](https://www.cloudfoundry.org/community/cla/)) via the EasyCLA application when you submit your first Pull Request. -When sending signed CLA please provide your github username in case of individual CLA or the list of github usernames that can make pull requests on behalf of your organization. +When sending signed CLA please provide your Github username in case of individual CLA or the list of Github usernames that can make pull requests on behalf of your organization. If you are confident that you're covered under a Corporate CLA, please make sure you've publicized your membership in the appropriate Github Org, per these instructions. diff --git a/README.md b/README.md index 897a55aba..eda068e0b 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,20 @@ This buildpack supports running Django and Flask apps. Official buildpack documentation can be found at [python buildpack docs](http://docs.cloudfoundry.org/buildpacks/python/index.html). +## Adding new dependencies + +If you want to add a new dependency to the buildpack, please add it to the [config.yml](https://github.com/cloudfoundry/buildpacks-ci/blob/5a63d13df09f83d5dff7c71d0a12c3e2dc798d39/pipelines/dependency-builds/config.yml#L272) file. For example, if you want to add a new version of Python, add an entry like the following: + +```yaml +python: + lines: + - line: 3.14.X + deprecation_date: 2030-10-07 + link: https://peps.python.org/pep-0745/ +``` + +The new dependency will be automatically added to the buildpack [manifest.yml](manifest.yml) file. + ### Building the Buildpack To build this buildpack, run the following commands from the buildpack's directory: @@ -24,7 +38,7 @@ To build this buildpack, run the following commands from the buildpack's directo 1. Install buildpack-packager ```bash - go install github.com/cloudfoundry/libbuildpack/packager/buildpack-packager + go install github.com/cloudfoundry/libbuildpack/packager/buildpack-packager@latest ``` 1. Build the buildpack diff --git a/src/python/supply/supply.go b/src/python/supply/supply.go index b36a48fd9..f9bef58f8 100644 --- a/src/python/supply/supply.go +++ b/src/python/supply/supply.go @@ -743,15 +743,23 @@ func (s *Supplier) RunPipVendored() error { // dependencies - wheel and setuptools. These are packaged by the dependency // pipeline within the "pip" dependency. func (s *Supplier) InstallCommonBuildDependencies() error { - var commonDeps = []string{"wheel", "setuptools"} tempPath := filepath.Join("/tmp", "common_build_deps") if err := s.Installer.InstallOnlyVersion("pip", tempPath); err != nil { return err } + if err := s.Installer.InstallOnlyVersion("flit-core", tempPath); err != nil { + return err + } + + s.Log.Info("Installing build-time dependency flit-core (bootstrap)") + args := []string{tempPath, "--no-build-isolation"} + if err := s.runPipInstall(args...); err != nil { + return fmt.Errorf("could not bootstrap-install flit-core: %v", err) + } - for _, dep := range commonDeps { + for _, dep := range []string{"wheel", "setuptools"} { s.Log.Info("Installing build-time dependency %s", dep) - args := []string{dep, "--no-index", "--upgrade-strategy=only-if-needed", fmt.Sprintf("--find-links=%s", tempPath)} + args := []string{dep, "--no-index", "--no-build-isolation", "--upgrade-strategy=only-if-needed", fmt.Sprintf("--find-links=%s", tempPath)} if err := s.runPipInstall(args...); err != nil { return fmt.Errorf("could not install build-time dependency %s: %v", dep, err) } diff --git a/src/python/supply/supply_test.go b/src/python/supply/supply_test.go index b7947dc30..366268d5a 100644 --- a/src/python/supply/supply_test.go +++ b/src/python/supply/supply_test.go @@ -633,22 +633,32 @@ MarkupSafe==2.0.1 Describe("InstallCommonBuildDependencies", func() { Context("successful installation", func() { - It("runs command to install wheel and setuptools", func() { + It("bootstraps flit-core, wheel and setuptools", func() { mockInstaller.EXPECT().InstallOnlyVersion("pip", "/tmp/common_build_deps") - mockCommand.EXPECT().Execute(buildDir, gomock.Any(), gomock.Any(), "python", "-m", "pip", "install", "wheel", "--no-index", "--upgrade-strategy=only-if-needed", "--find-links=/tmp/common_build_deps") - mockCommand.EXPECT().Execute(buildDir, gomock.Any(), gomock.Any(), "python", "-m", "pip", "install", "setuptools", "--no-index", "--upgrade-strategy=only-if-needed", "--find-links=/tmp/common_build_deps") + mockInstaller.EXPECT().InstallOnlyVersion("flit-core", "/tmp/common_build_deps") + mockCommand.EXPECT().Execute(buildDir, gomock.Any(), gomock.Any(), "python", "-m", "pip", "install", "/tmp/common_build_deps", "--no-build-isolation") + mockCommand.EXPECT().Execute(buildDir, gomock.Any(), gomock.Any(), "python", "-m", "pip", "install", "wheel", "--no-index", "--no-build-isolation", "--upgrade-strategy=only-if-needed", "--find-links=/tmp/common_build_deps") + mockCommand.EXPECT().Execute(buildDir, gomock.Any(), gomock.Any(), "python", "-m", "pip", "install", "setuptools", "--no-index", "--no-build-isolation", "--upgrade-strategy=only-if-needed", "--find-links=/tmp/common_build_deps") Expect(supplier.InstallCommonBuildDependencies()).To(Succeed()) }) }) - Context("installation fails", func() { - BeforeEach(func() { - mockCommand.EXPECT().Execute(buildDir, gomock.Any(), gomock.Any(), "python", "-m", "pip", "install", "wheel", "--no-index", "--upgrade-strategy=only-if-needed", "--find-links=/tmp/common_build_deps").Return(fmt.Errorf("some-pip-error")) - }) + Context("flit-core bootstrap fails", func() { + It("returns a useful error message", func() { + mockInstaller.EXPECT().InstallOnlyVersion("pip", "/tmp/common_build_deps") + mockInstaller.EXPECT().InstallOnlyVersion("flit-core", "/tmp/common_build_deps") + mockCommand.EXPECT().Execute(buildDir, gomock.Any(), gomock.Any(), "python", "-m", "pip", "install", "/tmp/common_build_deps", "--no-build-isolation").Return(fmt.Errorf("bootstrap-error")) + Expect(supplier.InstallCommonBuildDependencies()).To(MatchError("could not bootstrap-install flit-core: bootstrap-error")) + }) + }) + Context("wheel installation fails", func() { It("returns a useful error message", func() { - mockInstaller.EXPECT().InstallOnlyVersion(gomock.Any(), gomock.Any()).Times(1) + mockInstaller.EXPECT().InstallOnlyVersion("pip", "/tmp/common_build_deps") + mockInstaller.EXPECT().InstallOnlyVersion("flit-core", "/tmp/common_build_deps") + mockCommand.EXPECT().Execute(buildDir, gomock.Any(), gomock.Any(), "python", "-m", "pip", "install", "/tmp/common_build_deps", "--no-build-isolation") + mockCommand.EXPECT().Execute(buildDir, gomock.Any(), gomock.Any(), "python", "-m", "pip", "install", "wheel", "--no-index", "--no-build-isolation", "--upgrade-strategy=only-if-needed", "--find-links=/tmp/common_build_deps").Return(fmt.Errorf("some-pip-error")) Expect(supplier.InstallCommonBuildDependencies()).To(MatchError("could not install build-time dependency wheel: some-pip-error")) }) })