1
1
package phpdist
2
2
3
3
import (
4
+ "os"
4
5
"path/filepath"
6
+ "strings"
5
7
"time"
6
8
7
9
"github.com/Masterminds/semver"
8
- "github.com/paketo-buildpacks/packit"
9
- "github.com/paketo-buildpacks/packit/chronos"
10
- "github.com/paketo-buildpacks/packit/postal"
10
+ "github.com/paketo-buildpacks/packit/v2"
11
+ "github.com/paketo-buildpacks/packit/v2/chronos"
12
+ "github.com/paketo-buildpacks/packit/v2/postal"
13
+ "github.com/paketo-buildpacks/packit/v2/scribe"
11
14
)
12
15
16
+ //go:generate faux --interface FileManager --output fakes/file_manager.go
17
+
18
+ // FileManager defines the interface for manipulating files in the PHP installation
19
+ // in the build container.
20
+ type FileManager interface {
21
+ FindExtensions (layerRoot string ) (string , error )
22
+ WriteConfig (layerRoot , cnbPath string , data PhpIniConfig ) (defaultConfig string , buildpackConfig string , err error )
23
+ }
24
+
13
25
//go:generate faux --interface EntryResolver --output fakes/entry_resolver.go
26
+
27
+ // EntryResolver defines the interface for picking the most relevant entry from
28
+ // the Buildpack Plan entries.
14
29
type EntryResolver interface {
15
- Resolve ([]packit.BuildpackPlanEntry ) packit.BuildpackPlanEntry
30
+ Resolve (name string , entries []packit.BuildpackPlanEntry , priorities []interface {}) (packit.BuildpackPlanEntry , []packit.BuildpackPlanEntry )
31
+ MergeLayerTypes (name string , entries []packit.BuildpackPlanEntry ) (launch , build bool )
16
32
}
17
33
18
34
//go:generate faux --interface DependencyManager --output fakes/dependency_manager.go
35
+
36
+ // DependencyManager defines the interface for picking the best matching
37
+ // dependency, installing it, and generating a BOM.
19
38
type DependencyManager interface {
20
39
Resolve (path , id , version , stack string ) (postal.Dependency , error )
21
- Install (dependency postal.Dependency , cnbPath , layerPath string ) error
40
+ Deliver (dependency postal.Dependency , cnbPath , layerPath , platformPath string ) error
41
+ GenerateBillOfMaterials (dependencies ... postal.Dependency ) []packit.BOMEntry
22
42
}
23
43
24
44
//go:generate faux --interface EnvironmentConfiguration --output fakes/environment_configuration.go
25
- type EnvironmentConfiguration interface {
26
- Configure (layer packit.Layer ) error
27
- }
28
45
29
- //go:generate faux --interface BuildPlanRefinery --output fakes/build_plan_refinery.go
30
- type BuildPlanRefinery interface {
31
- BillOfMaterials (dependency postal.Dependency ) packit.BuildpackPlan
46
+ // EnvironmentConfiguration defines the interface for setting build- and launch-time
47
+ // environment variables on the layer.
48
+ type EnvironmentConfiguration interface {
49
+ Configure (layer packit.Layer , extensionsDir , defaultIni string , scanDirs []string ) error
32
50
}
33
51
34
- func Build (entries EntryResolver ,
52
+ // Build will return a packit.BuildFunc that will be invoked during the build
53
+ // phase of the buildpack lifecycle.
54
+ //
55
+ // Build will find the right php dependency to install, install it in a layer,
56
+ // and generate a Bill-of-Materials. On rebuilds, it reuses the cached
57
+ // dependency if the SHA256 of the requested version matches the SHA256 of the
58
+ // cached version. Build also sets up a default php.ini configuration.
59
+ func Build (entryResolver EntryResolver ,
35
60
dependencies DependencyManager ,
61
+ files FileManager ,
36
62
environment EnvironmentConfiguration ,
37
- planRefinery BuildPlanRefinery ,
38
- logger LogEmitter ,
63
+ logger scribe.Emitter ,
39
64
clock chronos.Clock ) packit.BuildFunc {
40
65
return func (context packit.BuildContext ) (packit.BuildResult , error ) {
41
66
var err error
42
67
43
- logger .Title (context .BuildpackInfo )
68
+ logger .Title ("%s %s" , context .BuildpackInfo . Name , context . BuildpackInfo . Version )
44
69
logger .Process ("Resolving PHP version" )
45
70
46
- entry := entries .Resolve (context .Plan .Entries )
71
+ entry , entries := entryResolver .Resolve (PHPDependency , context .Plan .Entries , EntryPriorities )
72
+ logger .Candidates (entries )
47
73
48
74
version , _ := entry .Metadata ["version" ].(string )
49
75
dependency , err := dependencies .Resolve (filepath .Join (context .CNBPath , "buildpack.toml" ), entry .Name , version , context .Stack )
@@ -52,7 +78,7 @@ func Build(entries EntryResolver,
52
78
return packit.BuildResult {}, err
53
79
}
54
80
55
- logger .SelectedDependency (entry , dependency . Version )
81
+ logger .SelectedDependency (entry , dependency , clock . Now () )
56
82
57
83
source , _ := entry .Metadata ["version-source" ].(string )
58
84
if source == "buildpack.yml" {
@@ -62,28 +88,51 @@ func Build(entries EntryResolver,
62
88
logger .Break ()
63
89
}
64
90
65
- phpLayer , err := context .Layers .Get ("php" )
91
+ logger .Debug .Process ("Getting the layer associated with PHP:" )
92
+ phpLayer , err := context .Layers .Get (PHPDependency )
66
93
if err != nil {
67
94
return packit.BuildResult {}, err
68
95
}
96
+ logger .Debug .Subprocess (phpLayer .Path )
97
+ logger .Debug .Break ()
69
98
70
- bom := planRefinery .BillOfMaterials (postal.Dependency {
71
- ID : dependency .ID ,
72
- Name : dependency .Name ,
73
- SHA256 : dependency .SHA256 ,
74
- Stacks : dependency .Stacks ,
75
- URI : dependency .URI ,
76
- Version : dependency .Version ,
77
- })
99
+ logger .Debug .Process ("Generating the SBOM" )
100
+ logger .Debug .Break ()
101
+ bom := dependencies .GenerateBillOfMaterials (dependency )
102
+ launch , build := entryResolver .MergeLayerTypes (PHPDependency , context .Plan .Entries )
103
+
104
+ phpLayer .Launch , phpLayer .Build , phpLayer .Cache = launch , build , build
105
+
106
+ var buildMetadata packit.BuildMetadata
107
+ if build {
108
+ buildMetadata .BOM = bom
109
+ }
110
+
111
+ var launchMetadata packit.LaunchMetadata
112
+ if launch {
113
+ launchMetadata .BOM = bom
114
+ }
78
115
79
116
cachedSHA , ok := phpLayer .Metadata [DepKey ].(string )
80
117
if ok && cachedSHA == dependency .SHA256 {
81
118
logger .Process ("Reusing cached layer %s" , phpLayer .Path )
119
+ logger .Debug .Subprocess ("SHA256 of cached PHP dependency matches SHA256 of resolved dependency" )
82
120
logger .Break ()
83
121
122
+ if phpLayer .Build {
123
+ logger .Debug .Process ("PHP layer will be available to other buildpacks during build" )
124
+ }
125
+ if phpLayer .Launch {
126
+ logger .Debug .Process ("PHP layer will be available at runtime" )
127
+ }
128
+ if phpLayer .Cache {
129
+ logger .Debug .Process ("PHP layer will be cached" )
130
+ }
131
+
84
132
return packit.BuildResult {
85
- Plan : bom ,
86
133
Layers : []packit.Layer {phpLayer },
134
+ Build : buildMetadata ,
135
+ Launch : launchMetadata ,
87
136
}, nil
88
137
}
89
138
@@ -94,9 +143,7 @@ func Build(entries EntryResolver,
94
143
return packit.BuildResult {}, err
95
144
}
96
145
97
- phpLayer .Launch = entry .Metadata ["launch" ] == true
98
- phpLayer .Build = entry .Metadata ["build" ] == true
99
- phpLayer .Cache = entry .Metadata ["build" ] == true
146
+ phpLayer .Launch , phpLayer .Build , phpLayer .Cache = launch , build , build
100
147
101
148
phpLayer .Metadata = map [string ]interface {}{
102
149
DepKey : dependency .SHA256 ,
@@ -105,7 +152,9 @@ func Build(entries EntryResolver,
105
152
106
153
logger .Subprocess ("Installing PHP %s" , dependency .Version )
107
154
duration , err := clock .Measure (func () error {
108
- return dependencies .Install (dependency , context .CNBPath , phpLayer .Path )
155
+ logger .Debug .Subprocess ("Installation path: %s" , phpLayer .Path )
156
+ logger .Debug .Subprocess ("Dependency URI: %s" , dependency .URI )
157
+ return dependencies .Deliver (dependency , context .CNBPath , phpLayer .Path , context .Platform .Path )
109
158
})
110
159
if err != nil {
111
160
return packit.BuildResult {}, err
@@ -114,14 +163,60 @@ func Build(entries EntryResolver,
114
163
logger .Action ("Completed in %s" , duration .Round (time .Millisecond ))
115
164
logger .Break ()
116
165
117
- err = environment .Configure (phpLayer )
166
+ logger .Debug .Subprocess ("Finding PHP extensions directory" )
167
+ extensionsDir , err := files .FindExtensions (phpLayer .Path )
168
+ if err != nil {
169
+ return packit.BuildResult {}, err
170
+ }
171
+ logger .Debug .Break ()
172
+
173
+ libDir := "lib"
174
+ if userLibDir := os .Getenv ("BP_PHP_LIB_DIR" ); userLibDir != "" {
175
+ libDir = userLibDir
176
+ logger .Debug .Subprocess ("$BP_PHP_LIB_DIR = %s" , libDir )
177
+ logger .Debug .Break ()
178
+ }
179
+
180
+ logger .Subprocess ("Generating default PHP configuration" )
181
+ defaultConfig , buildpackConfig , err := files .WriteConfig (phpLayer .Path , context .CNBPath , PhpIniConfig {
182
+ IncludePath : strings .Join ([]string {
183
+ filepath .Join (phpLayer .Path , "lib" , "php" ),
184
+ filepath .Join (context .WorkingDir , libDir ),
185
+ }, string (os .PathListSeparator )),
186
+ ExtensionDir : extensionsDir ,
187
+ // TODO: figure out where extensions and zendextensions arrays come from
188
+ // Do we even need to load extensions in the default INI file? Maybe better to simply require that folks add additional INI files?
189
+ })
190
+ if err != nil {
191
+ return packit.BuildResult {}, err
192
+ }
193
+ logger .Debug .Action ("Generated %s and %s" , defaultConfig , buildpackConfig )
194
+ logger .Break ()
195
+
196
+ err = environment .Configure (phpLayer , extensionsDir , defaultConfig , []string {
197
+ filepath .Dir (defaultConfig ),
198
+ filepath .Dir (buildpackConfig ),
199
+ filepath .Join (context .WorkingDir , "php.ini.d" ),
200
+ })
118
201
if err != nil {
119
202
return packit.BuildResult {}, err
120
203
}
204
+ logger .EnvironmentVariables (phpLayer )
205
+
206
+ if phpLayer .Build {
207
+ logger .Debug .Process ("PHP layer will be available to other buildpacks during build" )
208
+ }
209
+ if phpLayer .Launch {
210
+ logger .Debug .Process ("PHP layer will be available at runtime" )
211
+ }
212
+ if phpLayer .Cache {
213
+ logger .Debug .Process ("PHP layer will be cached" )
214
+ }
121
215
122
216
return packit.BuildResult {
123
- Plan : bom ,
124
217
Layers : []packit.Layer {phpLayer },
218
+ Build : buildMetadata ,
219
+ Launch : launchMetadata ,
125
220
}, nil
126
221
}
127
222
}
0 commit comments