-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Expand file tree
/
Copy pathcontainer_customizer.go
More file actions
140 lines (113 loc) · 4.68 KB
/
container_customizer.go
File metadata and controls
140 lines (113 loc) · 4.68 KB
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
133
134
135
136
137
138
139
140
package frameworks
import (
"fmt"
"github.com/cloudfoundry/java-buildpack/src/java/common"
"os"
"path/filepath"
)
// ContainerCustomizerFramework implements Tomcat configuration customization
// for Spring Boot WAR applications
type ContainerCustomizerFramework struct {
context *common.Context
}
// NewContainerCustomizerFramework creates a new Container Customizer framework instance
func NewContainerCustomizerFramework(ctx *common.Context) *ContainerCustomizerFramework {
return &ContainerCustomizerFramework{context: ctx}
}
// Detect checks if Container Customizer should be included
// Detects Spring Boot WAR files that need Tomcat customization
func (c *ContainerCustomizerFramework) Detect() (string, error) {
buildDir := c.context.Stager.BuildDir()
// Check if this is a Spring Boot WAR application
// Spring Boot WAR apps have WEB-INF and BOOT-INF directories
webInfPath := filepath.Join(buildDir, "WEB-INF")
bootInfPath := filepath.Join(buildDir, "BOOT-INF")
webInfStat, webInfErr := os.Stat(webInfPath)
bootInfStat, bootInfErr := os.Stat(bootInfPath)
// Must have both WEB-INF and BOOT-INF to be a Spring Boot WAR
if webInfErr == nil && webInfStat.IsDir() &&
bootInfErr == nil && bootInfStat.IsDir() {
// Verify Spring Boot by checking for spring-boot-*.jar in lib directories
if c.hasSpringBootJars(buildDir) {
c.context.Log.Debug("Detected Spring Boot WAR application for Container Customizer")
return "Container Customizer", nil
}
}
return "", nil
}
// hasSpringBootJars checks if Spring Boot JARs exist in lib directories
func (c *ContainerCustomizerFramework) hasSpringBootJars(buildDir string) bool {
libDirs := []string{
filepath.Join(buildDir, "WEB-INF", "lib"),
filepath.Join(buildDir, "BOOT-INF", "lib"),
}
for _, libDir := range libDirs {
if _, err := os.Stat(libDir); err != nil {
continue
}
entries, err := os.ReadDir(libDir)
if err != nil {
continue
}
for _, entry := range entries {
if entry.IsDir() {
continue
}
name := entry.Name()
// Look for spring-boot-*.jar files
if filepath.Ext(name) == ".jar" && contains(name, "spring-boot-") {
return true
}
}
}
return false
}
// Supply installs the Container Customizer library
func (c *ContainerCustomizerFramework) Supply() error {
c.context.Log.Debug("Installing Container Customizer")
// Get container-customizer dependency from manifest
dep, err := c.context.Manifest.DefaultVersion("container-customizer")
if err != nil {
return fmt.Errorf("unable to determine Container Customizer version: %w", err)
}
// Install Container Customizer JAR to deps directory
customizerDir := filepath.Join(c.context.Stager.DepDir(), "container_customizer")
if err := c.context.Installer.InstallDependency(dep, customizerDir); err != nil {
return fmt.Errorf("failed to install Container Customizer: %w", err)
}
c.context.Log.Debug("Installed Container Customizer version %s", dep.Version)
return nil
}
// Finalize adds the Container Customizer JAR to the classpath
// The Container Customizer library provides hooks for external Tomcat configuration
func (c *ContainerCustomizerFramework) Finalize() error {
// Find the installed Container Customizer JAR
customizerDir := filepath.Join(c.context.Stager.DepDir(), "container_customizer")
jarPattern := filepath.Join(customizerDir, "container-customizer-*.jar")
matches, err := filepath.Glob(jarPattern)
if err != nil || len(matches) == 0 {
c.context.Log.Warning("Container Customizer JAR not found, skipping classpath configuration")
return nil
}
// Get buildpack index for multi-buildpack support
depsIdx := c.context.Stager.DepsIdx()
// Convert staging path to runtime path for CLASSPATH
// Staging: /tmp/staging/deps/<idx>/container_customizer/container-customizer-2.0.0.jar
// Runtime: $DEPS_DIR/<idx>/container_customizer/container-customizer-2.0.0.jar
relPath := filepath.Base(matches[0])
runtimePath := fmt.Sprintf("$DEPS_DIR/%s/container_customizer/%s", depsIdx, relPath)
// Write profile.d script to add Container Customizer JAR to classpath
// This ensures it's available to the embedded Tomcat at startup
profileScript := fmt.Sprintf(`# Container Customizer Framework
export CLASSPATH="%s:${CLASSPATH:-}"
`, runtimePath)
if err := c.context.Stager.WriteProfileD("container_customizer.sh", profileScript); err != nil {
return fmt.Errorf("failed to write container_customizer.sh profile.d script: %w", err)
}
c.context.Log.Info("Configured Container Customizer for embedded Tomcat customization")
c.context.Log.Debug("Container Customizer JAR will be added to classpath at runtime: %s", runtimePath)
return nil
}
func (c *ContainerCustomizerFramework) DependencyIdentifier() string {
return "container-customizer"
}