Skip to content

Commit 45fad82

Browse files
authored
feat: improved pyproject.toml handling (#59)
* refactor: move BuildPlanMetadata in common * feat: initial implementation of pyproject.toml improved handling This initial implementation returns a basic plan which matches what is generated by each supported backend. * refactor: use original detection when applicable * refactor: improve no backend handling Originally, poetry is selected when no backend is present in the pyproject.toml file however, it can also be the case with uv projects. Therefore check for the presence of a uv.lock file and adjust the detection accordingly. * refactor: remove detection for poetry and uv in main detect It is done through PyProjectHandler.
1 parent a933905 commit 45fad82

39 files changed

+522
-195
lines changed

detect.go

Lines changed: 19 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66
package pythonpackagers
77

88
import (
9+
"path/filepath"
10+
911
"github.com/paketo-buildpacks/packit/v2"
12+
"github.com/paketo-buildpacks/packit/v2/fs"
1013
"github.com/paketo-buildpacks/packit/v2/scribe"
1114

1215
conda "github.com/paketo-buildpacks/python-packagers/pkg/packagers/conda"
1316
pipinstall "github.com/paketo-buildpacks/python-packagers/pkg/packagers/pip"
1417
pipenvinstall "github.com/paketo-buildpacks/python-packagers/pkg/packagers/pipenv"
15-
poetryinstall "github.com/paketo-buildpacks/python-packagers/pkg/packagers/poetry"
16-
uvinstall "github.com/paketo-buildpacks/python-packagers/pkg/packagers/uv"
1718
)
1819

1920
// Detect will return a packit.DetectFunc that will be invoked during the
@@ -23,11 +24,26 @@ import (
2324
// it will pass detection.
2425
func Detect(logger scribe.Emitter) packit.DetectFunc {
2526
return func(context packit.DetectContext) (packit.DetectResult, error) {
27+
logger.Title("Checking for pyproject.toml")
28+
pyprojectPath := filepath.Join(context.WorkingDir, "pyproject.toml")
29+
found, err := fs.Exists(pyprojectPath)
30+
if err != nil {
31+
return packit.DetectResult{}, err
32+
}
33+
if found {
34+
parser := NewPyProjectHandler()
35+
installer, err := parser.GetInstaller(context.WorkingDir)
36+
if err != nil {
37+
return packit.DetectResult{}, err
38+
}
39+
logger.Detail("Doing detection for: %s", installer)
40+
return parser.Detect(installer, context)
41+
}
42+
2643
logger.Title("Checking for pip")
2744
pipResult, err := pipinstall.Detect()(context)
2845

2946
if err == nil {
30-
// plans = append(plans, pipResult.Plan)
3147
return packit.DetectResult{
3248
Plan: pipResult.Plan,
3349
}, nil
@@ -39,7 +55,6 @@ func Detect(logger scribe.Emitter) packit.DetectFunc {
3955
condaResult, err := conda.Detect()(context)
4056

4157
if err == nil {
42-
// plans = append(plans, condaResult.Plan)
4358
return packit.DetectResult{
4459
Plan: condaResult.Plan,
4560
}, nil
@@ -54,38 +69,13 @@ func Detect(logger scribe.Emitter) packit.DetectFunc {
5469
)(context)
5570

5671
if err == nil {
57-
// plans = append(plans, pipenvResult.Plan)
5872
return packit.DetectResult{
5973
Plan: pipenvResult.Plan,
6074
}, nil
6175
} else {
6276
logger.Detail("%s", err)
6377
}
6478

65-
logger.Title("Checking for uv")
66-
uvResult, err := uvinstall.Detect()(context)
67-
68-
if err == nil {
69-
// plans = append(plans, uvResult.Plan)
70-
return packit.DetectResult{
71-
Plan: uvResult.Plan,
72-
}, nil
73-
} else {
74-
logger.Detail("%s", err)
75-
}
76-
77-
logger.Title("Checking for poetry")
78-
poetryResult, err := poetryinstall.Detect()(context)
79-
80-
if err == nil {
81-
// plans = append(plans, poetryResult.Plan)
82-
return packit.DetectResult{
83-
Plan: poetryResult.Plan,
84-
}, nil
85-
} else {
86-
logger.Detail("%s", err)
87-
}
88-
8979
return packit.DetectResult{}, packit.Fail.WithMessage("No python packager manager related files found")
9080
}
9181
}

detect_test.go

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/paketo-buildpacks/packit/v2"
1515
"github.com/paketo-buildpacks/packit/v2/scribe"
1616
pythonpackagers "github.com/paketo-buildpacks/python-packagers"
17+
common "github.com/paketo-buildpacks/python-packagers/pkg/packagers/common"
1718
conda "github.com/paketo-buildpacks/python-packagers/pkg/packagers/conda"
1819
pip "github.com/paketo-buildpacks/python-packagers/pkg/packagers/pip"
1920
pipenv "github.com/paketo-buildpacks/python-packagers/pkg/packagers/pipenv"
@@ -71,8 +72,8 @@ func testDetect(t *testing.T, context spec.G, it spec.S) {
7172
Requires: []packit.BuildPlanRequirement{
7273
{
7374
Name: conda.CondaPlanEntry,
74-
Metadata: map[string]interface{}{
75-
"build": true,
75+
Metadata: common.BuildPlanMetadata{
76+
Build: true,
7677
},
7778
},
7879
},
@@ -101,8 +102,8 @@ func testDetect(t *testing.T, context spec.G, it spec.S) {
101102
Requires: []packit.BuildPlanRequirement{
102103
{
103104
Name: conda.CondaPlanEntry,
104-
Metadata: map[string]interface{}{
105-
"build": true,
105+
Metadata: common.BuildPlanMetadata{
106+
Build: true,
106107
},
107108
},
108109
},
@@ -133,19 +134,19 @@ func testDetect(t *testing.T, context spec.G, it spec.S) {
133134
Requires: []packit.BuildPlanRequirement{
134135
{
135136
Name: pip.CPython,
136-
Metadata: pip.BuildPlanMetadata{
137+
Metadata: common.BuildPlanMetadata{
137138
Build: true,
138139
},
139140
},
140141
{
141142
Name: pip.Pip,
142-
Metadata: pip.BuildPlanMetadata{
143+
Metadata: common.BuildPlanMetadata{
143144
Build: true,
144145
},
145146
},
146147
{
147148
Name: pip.Manager,
148-
Metadata: pip.BuildPlanMetadata{
149+
Metadata: common.BuildPlanMetadata{
149150
Build: true,
150151
},
151152
},
@@ -177,19 +178,19 @@ func testDetect(t *testing.T, context spec.G, it spec.S) {
177178
Requires: []packit.BuildPlanRequirement{
178179
{
179180
Name: pipenv.CPython,
180-
Metadata: pipenv.BuildPlanMetadata{
181+
Metadata: common.BuildPlanMetadata{
181182
Build: true,
182183
},
183184
},
184185
{
185186
Name: pipenv.Pipenv,
186-
Metadata: pipenv.BuildPlanMetadata{
187+
Metadata: common.BuildPlanMetadata{
187188
Build: true,
188189
},
189190
},
190191
{
191192
Name: pipenv.Manager,
192-
Metadata: pipenv.BuildPlanMetadata{
193+
Metadata: common.BuildPlanMetadata{
193194
Build: true,
194195
},
195196
},
@@ -218,13 +219,13 @@ func testDetect(t *testing.T, context spec.G, it spec.S) {
218219
Requires: []packit.BuildPlanRequirement{
219220
{
220221
Name: poetry.CPython,
221-
Metadata: poetry.BuildPlanMetadata{
222+
Metadata: common.BuildPlanMetadata{
222223
Build: true,
223224
},
224225
},
225226
{
226227
Name: poetry.Poetry,
227-
Metadata: poetry.BuildPlanMetadata{
228+
Metadata: common.BuildPlanMetadata{
228229
Build: true,
229230
},
230231
},
@@ -233,10 +234,11 @@ func testDetect(t *testing.T, context spec.G, it spec.S) {
233234
})
234235
})
235236

236-
context("When only a uv.lock file is present", func() {
237+
context("When a uv.lock file is present", func() {
237238
it.Before(func() {
238239
Expect(os.RemoveAll(filepath.Join(workingDir, "x.py"))).To(Succeed())
239240
Expect(os.WriteFile(filepath.Join(workingDir, "uv.lock"), []byte{}, os.ModePerm)).To(Succeed())
241+
Expect(os.WriteFile(filepath.Join(workingDir, "pyproject.toml"), []byte{}, os.ModePerm)).To(Succeed())
240242
})
241243

242244
it("passes detection", func() {
@@ -253,8 +255,8 @@ func testDetect(t *testing.T, context spec.G, it spec.S) {
253255
Requires: []packit.BuildPlanRequirement{
254256
{
255257
Name: uv.UvPlanEntry,
256-
Metadata: map[string]interface{}{
257-
"build": true,
258+
Metadata: common.BuildPlanMetadata{
259+
Build: true,
258260
},
259261
},
260262
},
@@ -264,8 +266,13 @@ func testDetect(t *testing.T, context spec.G, it spec.S) {
264266

265267
context("When a uv.lock and pyproject.toml file is present", func() {
266268
it.Before(func() {
269+
content := []byte(`
270+
[build-system]
271+
requires = ["uv_build>=0.10.0,<0.11.0"]
272+
build-backend = "uv_build"
273+
`)
267274
Expect(os.RemoveAll(filepath.Join(workingDir, "x.py"))).To(Succeed())
268-
Expect(os.WriteFile(filepath.Join(workingDir, "pyproject.toml"), []byte{}, os.ModePerm)).To(Succeed())
275+
Expect(os.WriteFile(filepath.Join(workingDir, "pyproject.toml"), content, os.ModePerm)).To(Succeed())
269276
Expect(os.WriteFile(filepath.Join(workingDir, "uv.lock"), []byte{}, os.ModePerm)).To(Succeed())
270277
})
271278

@@ -283,8 +290,8 @@ func testDetect(t *testing.T, context spec.G, it spec.S) {
283290
Requires: []packit.BuildPlanRequirement{
284291
{
285292
Name: uv.UvPlanEntry,
286-
Metadata: map[string]interface{}{
287-
"build": true,
293+
Metadata: common.BuildPlanMetadata{
294+
Build: true,
288295
},
289296
},
290297
},

init_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414

1515
func TestUnitPythonPackagers(t *testing.T) {
1616
suite := spec.New("python-packagers", spec.Report(report.Terminal{}), spec.Sequential())
17+
suite("PyProjectHandler", testPyProjectHandler)
1718
suite("Detect", testDetect)
1819
suite("Build", testBuild)
1920
suite.Run(t)

pkg/packagers/common/common.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,19 @@ func (f Generator) Generate(dir string) (sbom.SBOM, error) {
2121
return sbom.Generate(dir)
2222
}
2323

24+
// BuildPlanMetadata is the buildpack-specific data included in build plan
25+
// requirements.
26+
type BuildPlanMetadata struct {
27+
// Build denotes the dependency is needed at build-time.
28+
Build bool `toml:"build"`
29+
// Launch denotes the dependency is needed at run-time.
30+
Launch bool `toml:"launch"`
31+
// Version denotes the version to request.
32+
Version string `toml:"version"`
33+
// VersionSource denotes the source of version request.
34+
VersionSource string `toml:"version-source"`
35+
}
36+
2437
// CommonBuildParameters are the parameters shared
2538
// by all packager build function implementation
2639
type CommonBuildParameters struct {

pkg/packagers/conda/build_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@ import (
1515
"github.com/paketo-buildpacks/packit/v2/chronos"
1616
"github.com/paketo-buildpacks/packit/v2/sbom"
1717
"github.com/paketo-buildpacks/packit/v2/scribe"
18+
"github.com/sclevine/spec"
19+
1820
pythonpackagers "github.com/paketo-buildpacks/python-packagers/pkg/packagers/common"
1921
condaenvupdate "github.com/paketo-buildpacks/python-packagers/pkg/packagers/conda"
2022
"github.com/paketo-buildpacks/python-packagers/pkg/packagers/conda/fakes"
21-
"github.com/sclevine/spec"
2223

2324
. "github.com/onsi/gomega"
2425
)

pkg/packagers/conda/conda_runner_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ import (
1515

1616
"github.com/paketo-buildpacks/packit/v2/pexec"
1717
"github.com/paketo-buildpacks/packit/v2/scribe"
18+
"github.com/sclevine/spec"
19+
1820
condaenvupdate "github.com/paketo-buildpacks/python-packagers/pkg/packagers/conda"
1921
"github.com/paketo-buildpacks/python-packagers/pkg/packagers/conda/fakes"
20-
"github.com/sclevine/spec"
2122

2223
. "github.com/onsi/gomega"
2324
. "github.com/paketo-buildpacks/occam/matchers"

pkg/packagers/conda/detect.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import (
99

1010
"github.com/paketo-buildpacks/packit/v2"
1111
"github.com/paketo-buildpacks/packit/v2/fs"
12+
13+
common "github.com/paketo-buildpacks/python-packagers/pkg/packagers/common"
1214
)
1315

1416
// Detect returns a packit.DetectFunc that will be invoked during the
@@ -40,8 +42,8 @@ func Detect() packit.DetectFunc {
4042
Requires: []packit.BuildPlanRequirement{
4143
{
4244
Name: CondaPlanEntry,
43-
Metadata: map[string]interface{}{
44-
"build": true,
45+
Metadata: common.BuildPlanMetadata{
46+
Build: true,
4547
},
4648
},
4749
},

pkg/packagers/conda/detect_test.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ import (
1010
"testing"
1111

1212
"github.com/paketo-buildpacks/packit/v2"
13-
condaenvupdate "github.com/paketo-buildpacks/python-packagers/pkg/packagers/conda"
1413
"github.com/sclevine/spec"
1514

1615
. "github.com/onsi/gomega"
16+
17+
common "github.com/paketo-buildpacks/python-packagers/pkg/packagers/common"
18+
condaenvupdate "github.com/paketo-buildpacks/python-packagers/pkg/packagers/conda"
1719
)
1820

1921
func testDetect(t *testing.T, context spec.G, it spec.S) {
@@ -56,8 +58,8 @@ func testDetect(t *testing.T, context spec.G, it spec.S) {
5658
Requires: []packit.BuildPlanRequirement{
5759
{
5860
Name: "conda",
59-
Metadata: map[string]interface{}{
60-
"build": true,
61+
Metadata: common.BuildPlanMetadata{
62+
Build: true,
6163
},
6264
},
6365
},
@@ -85,8 +87,8 @@ func testDetect(t *testing.T, context spec.G, it spec.S) {
8587
Requires: []packit.BuildPlanRequirement{
8688
{
8789
Name: "conda",
88-
Metadata: map[string]interface{}{
89-
"build": true,
90+
Metadata: common.BuildPlanMetadata{
91+
Build: true,
9092
},
9193
},
9294
},

pkg/packagers/pip/build_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@ import (
1515
"github.com/paketo-buildpacks/packit/v2/chronos"
1616
"github.com/paketo-buildpacks/packit/v2/sbom"
1717
"github.com/paketo-buildpacks/packit/v2/scribe"
18+
"github.com/sclevine/spec"
19+
1820
pythonpackagers "github.com/paketo-buildpacks/python-packagers/pkg/packagers/common"
1921
pipinstall "github.com/paketo-buildpacks/python-packagers/pkg/packagers/pip"
2022
"github.com/paketo-buildpacks/python-packagers/pkg/packagers/pip/fakes"
21-
"github.com/sclevine/spec"
2223

2324
. "github.com/onsi/gomega"
2425
)

pkg/packagers/pip/detect.go

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,9 @@ import (
1111

1212
"github.com/paketo-buildpacks/packit/v2"
1313
"github.com/paketo-buildpacks/packit/v2/fs"
14-
)
1514

16-
// BuildPlanMetadata is the buildpack specific data included in build plan
17-
// requirements.
18-
type BuildPlanMetadata struct {
19-
// Build denotes the dependency is needed at build-time.
20-
Build bool `toml:"build"`
21-
}
15+
common "github.com/paketo-buildpacks/python-packagers/pkg/packagers/common"
16+
)
2217

2318
// Detect will return a packit.DetectFunc that will be invoked during the
2419
// detect phase of the buildpack lifecycle.
@@ -63,19 +58,19 @@ func Detect() packit.DetectFunc {
6358
Requires: []packit.BuildPlanRequirement{
6459
{
6560
Name: CPython,
66-
Metadata: BuildPlanMetadata{
61+
Metadata: common.BuildPlanMetadata{
6762
Build: true,
6863
},
6964
},
7065
{
7166
Name: Pip,
72-
Metadata: BuildPlanMetadata{
67+
Metadata: common.BuildPlanMetadata{
7368
Build: true,
7469
},
7570
},
7671
{
7772
Name: Manager,
78-
Metadata: BuildPlanMetadata{
73+
Metadata: common.BuildPlanMetadata{
7974
Build: true,
8075
},
8176
},

0 commit comments

Comments
 (0)