-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathbuild.go
132 lines (108 loc) · 3.96 KB
/
build.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package pipenvinstall
import (
"os"
"path/filepath"
"time"
"github.com/paketo-buildpacks/packit/v2"
"github.com/paketo-buildpacks/packit/v2/chronos"
"github.com/paketo-buildpacks/packit/v2/draft"
"github.com/paketo-buildpacks/packit/v2/fs"
"github.com/paketo-buildpacks/packit/v2/sbom"
"github.com/paketo-buildpacks/packit/v2/scribe"
)
//go:generate faux --interface InstallProcess --output fakes/install_process.go
//go:generate faux --interface SitePackagesProcess --output fakes/site_packages_process.go
//go:generate faux --interface VenvDirLocator --output fakes/venv_dir_locator.go
//go:generate faux --interface SBOMGenerator --output fakes/sbom_generator.go
// SitePackagesProcess defines the interface for determining the site-packages path.
type SitePackagesProcess interface {
Execute(layerPath string) (sitePackagesPath string, err error)
}
// InstallProcess defines the interface for installing the pipenv dependencies.
type InstallProcess interface {
Execute(workingDir string, targetLayer, cacheLayer packit.Layer) error
}
// VenvDirLocator defines the interface for locating the virtual environment
// directory under a given path
type VenvDirLocator interface {
LocateVenvDir(path string) (venvDir string, err error)
}
type SBOMGenerator interface {
Generate(dir string) (sbom.SBOM, error)
}
// Build will return a packit.BuildFunc that will be invoked during the build
// phase of the buildpack lifecycle.
//
// Build will install the pipenv dependencies by using the Pipfile to a
// packages layer. It also makes use of a cache layer to reuse the pipenv
// cache.
func Build(
installProcess InstallProcess,
siteProcess SitePackagesProcess,
venvDirLocator VenvDirLocator,
sbomGenerator SBOMGenerator,
clock chronos.Clock,
logger scribe.Emitter,
) packit.BuildFunc {
return func(context packit.BuildContext) (packit.BuildResult, error) {
logger.Title("%s %s", context.BuildpackInfo.Name, context.BuildpackInfo.Version)
packagesLayer, err := context.Layers.Get(PackagesLayerName)
if err != nil {
return packit.BuildResult{}, err
}
cacheLayer, err := context.Layers.Get(CacheLayerName)
if err != nil {
return packit.BuildResult{}, err
}
planner := draft.NewPlanner()
packagesLayer.Launch, packagesLayer.Build = planner.MergeLayerTypes(SitePackages, context.Plan.Entries)
packagesLayer.Cache = packagesLayer.Launch || packagesLayer.Build
cacheLayer.Cache = true
logger.Process("Executing build process")
duration, err := clock.Measure(func() error {
return installProcess.Execute(context.WorkingDir, packagesLayer, cacheLayer)
})
if err != nil {
return packit.BuildResult{}, err
}
logger.Action("Completed in %s", duration.Round(time.Millisecond))
logger.Break()
venvDir, err := venvDirLocator.LocateVenvDir(packagesLayer.Path)
if err != nil {
return packit.BuildResult{}, err
}
sitePackagesPath, err := siteProcess.Execute(packagesLayer.Path)
if err != nil {
return packit.BuildResult{}, err
}
logger.GeneratingSBOM(packagesLayer.Path)
var sbomContent sbom.SBOM
duration, err = clock.Measure(func() error {
sbomContent, err = sbomGenerator.Generate(context.WorkingDir)
return err
})
if err != nil {
return packit.BuildResult{}, err
}
logger.Action("Completed in %s", duration.Round(time.Millisecond))
logger.Break()
logger.FormattingSBOM(context.BuildpackInfo.SBOMFormats...)
packagesLayer.SBOM, err = sbomContent.InFormats(context.BuildpackInfo.SBOMFormats...)
if err != nil {
return packit.BuildResult{}, err
}
packagesLayer.SharedEnv.Prepend("PATH", filepath.Join(venvDir, "bin"), ":")
packagesLayer.SharedEnv.Prepend("PYTHONPATH", sitePackagesPath, string(os.PathListSeparator))
logger.EnvironmentVariables(packagesLayer)
layers := []packit.Layer{packagesLayer}
if _, err := os.Stat(cacheLayer.Path); err == nil {
if !fs.IsEmptyDir(cacheLayer.Path) {
layers = append(layers, cacheLayer)
}
}
result := packit.BuildResult{
Layers: layers,
}
return result, nil
}
}