@@ -24,65 +24,97 @@ func NewDistZipContainer(ctx *common.Context) *DistZipContainer {
2424
2525// Detect checks if this is a Dist ZIP application
2626func (d * DistZipContainer ) Detect () (string , error ) {
27+ matches , err := d .findDistZipMatches ()
28+ if err != nil {
29+ return "" , err
30+ }
31+
32+ if len (matches ) == 0 {
33+ return "" , nil
34+ }
35+
36+ if len (matches ) > 1 {
37+ d .context .Log .Debug ("Rejecting Dist ZIP detection - multiple bin/lib structures detected" )
38+ return "" , nil
39+ }
40+
41+ d .startScript = matches [0 ]
42+ d .context .Log .Debug ("Detected Dist ZIP application with start script: %s" , d .startScript )
43+ return "Dist ZIP" , nil
44+ }
45+
46+ func (d * DistZipContainer ) findDistZipMatches () ([]string , error ) {
2747 buildDir := d .context .Stager .BuildDir ()
48+ type candidate struct {
49+ abs string
50+ rel string
51+ }
2852
29- // Check for bin/ and lib/ directories at root (typical distZip structure)
30- binDir := filepath .Join (buildDir , "bin" )
31- libDir := filepath .Join (buildDir , "lib" )
53+ candidates := []candidate {{abs : buildDir }}
3254
33- binStat , binErr := os .Stat (binDir )
34- libStat , libErr := os .Stat (libDir )
55+ entries , err := os .ReadDir (buildDir )
56+ if err != nil {
57+ d .context .Log .Debug ("Unable to list build dir for Dist ZIP detection: %s" , err .Error ())
58+ } else {
59+ for _ , entry := range entries {
60+ if entry .IsDir () {
61+ candidates = append (candidates , candidate {
62+ abs : filepath .Join (buildDir , entry .Name ()),
63+ rel : entry .Name (),
64+ })
65+ }
66+ }
67+ }
68+
69+ var matches []string
70+ for _ , c := range candidates {
71+ binDir := filepath .Join (c .abs , "bin" )
72+ libDir := filepath .Join (c .abs , "lib" )
73+
74+ if ! isDir (binDir ) || ! isDir (libDir ) {
75+ continue
76+ }
3577
36- if binErr == nil && libErr == nil && binStat .IsDir () && libStat .IsDir () {
37- // Exclude Play Framework applications
3878 if d .isPlayFramework (libDir ) {
39- d .context .Log .Debug ("Rejecting Dist ZIP detection - Play Framework JAR found" )
40- return "" , nil
79+ d .context .Log .Debug ("Rejecting Dist ZIP detection - Play Framework JAR found in %s" , libDir )
80+ continue
4181 }
4282
43- // Check for startup scripts in bin/
44- entries , err := os .ReadDir (binDir )
45- if err == nil && len (entries ) > 0 {
46- // Find a non-.bat script (Unix startup script)
47- for _ , entry := range entries {
48- if ! entry .IsDir () && filepath .Ext (entry .Name ()) != ".bat" {
49- d .startScript = entry .Name ()
50- d .context .Log .Debug ("Detected Dist ZIP application with start script: %s" , d .startScript )
51- return "Dist ZIP" , nil
52- }
53- }
83+ script := findUnixStartScript (binDir )
84+ if script == "" {
85+ continue
5486 }
87+
88+ relPath := filepath .Join (c .rel , "bin" , script )
89+ relPath = strings .TrimPrefix (relPath , string (filepath .Separator ))
90+ matches = append (matches , relPath )
5591 }
5692
57- // Check for bin/ and lib/ directories in application-root (alternative structure)
58- binDirApp := filepath .Join (buildDir , "application-root" , "bin" )
59- libDirApp := filepath .Join (buildDir , "application-root" , "lib" )
93+ return matches , nil
94+ }
6095
61- binStatApp , binErrApp := os .Stat (binDirApp )
62- libStatApp , libErrApp := os .Stat (libDirApp )
96+ func isDir (path string ) bool {
97+ info , err := os .Stat (path )
98+ if err != nil {
99+ return false
100+ }
101+ return info .IsDir ()
102+ }
63103
64- if binErrApp == nil && libErrApp == nil && binStatApp .IsDir () && libStatApp .IsDir () {
65- // Exclude Play Framework applications
66- if d .isPlayFramework (libDirApp ) {
67- d .context .Log .Debug ("Rejecting Dist ZIP detection - Play Framework JAR found in application-root" )
68- return "" , nil
69- }
104+ func findUnixStartScript (binDir string ) string {
105+ entries , err := os .ReadDir (binDir )
106+ if err != nil {
107+ return ""
108+ }
70109
71- // Check for startup scripts in bin/
72- entriesApp , errApp := os .ReadDir (binDirApp )
73- if errApp == nil && len (entriesApp ) > 0 {
74- // Find a non-.bat script (Unix startup script)
75- for _ , entry := range entriesApp {
76- if ! entry .IsDir () && filepath .Ext (entry .Name ()) != ".bat" {
77- d .startScript = filepath .Join ("application-root" , "bin" , entry .Name ())
78- d .context .Log .Debug ("Detected Dist ZIP application (application-root) with start script: %s" , d .startScript )
79- return "Dist ZIP" , nil
80- }
81- }
110+ for _ , entry := range entries {
111+ if entry .IsDir () || filepath .Ext (entry .Name ()) == ".bat" {
112+ continue
82113 }
114+ return entry .Name ()
83115 }
84116
85- return "" , nil
117+ return ""
86118}
87119
88120// isPlayFramework checks if a lib directory contains Play Framework JARs
@@ -132,30 +164,30 @@ func (d *DistZipContainer) Supply() error {
132164func (d * DistZipContainer ) makeScriptsExecutable () error {
133165 buildDir := d .context .Stager .BuildDir ()
134166
135- // Try root bin/ directory
136- binDir := filepath .Join (buildDir , "bin" )
137- entries , err := os .ReadDir (binDir )
138- if err == nil {
139- for _ , entry := range entries {
140- if ! entry .IsDir () && filepath .Ext (entry .Name ()) != ".bat" {
141- scriptPath := filepath .Join (binDir , entry .Name ())
142- if err := os .Chmod (scriptPath , 0755 ); err != nil {
143- d .context .Log .Warning ("Could not make %s executable: %s" , entry .Name (), err .Error ())
144- }
145- }
167+ binDirs := map [string ]struct {}{
168+ filepath .Join (buildDir , "bin" ): {},
169+ filepath .Join (buildDir , "application-root" , "bin" ): {},
170+ }
171+
172+ if d .startScript != "" {
173+ scriptDir := filepath .Dir (d .startScript )
174+ if scriptDir != "" && scriptDir != "." {
175+ binDirs [filepath .Join (buildDir , scriptDir )] = struct {}{}
146176 }
147177 }
148178
149- // Try application-root/bin/ directory
150- binDirApp := filepath .Join (buildDir , "application-root" , "bin" )
151- entriesApp , errApp := os .ReadDir (binDirApp )
152- if errApp == nil {
153- for _ , entry := range entriesApp {
154- if ! entry .IsDir () && filepath .Ext (entry .Name ()) != ".bat" {
155- scriptPath := filepath .Join (binDirApp , entry .Name ())
156- if err := os .Chmod (scriptPath , 0755 ); err != nil {
157- d .context .Log .Warning ("Could not make %s executable: %s" , entry .Name (), err .Error ())
158- }
179+ for dir := range binDirs {
180+ entries , err := os .ReadDir (dir )
181+ if err != nil {
182+ continue
183+ }
184+ for _ , entry := range entries {
185+ if entry .IsDir () || filepath .Ext (entry .Name ()) == ".bat" {
186+ continue
187+ }
188+ scriptPath := filepath .Join (dir , entry .Name ())
189+ if err := os .Chmod (scriptPath , 0755 ); err != nil {
190+ d .context .Log .Warning ("Could not make %s executable: %s" , scriptPath , err .Error ())
159191 }
160192 }
161193 }
@@ -168,15 +200,11 @@ func (d *DistZipContainer) Finalize() error {
168200 d .context .Log .BeginStep ("Finalizing Dist ZIP" )
169201 d .context .Log .Info ("DistZip Finalize: Starting (startScript=%s)" , d .startScript )
170202
171- // Determine the script directory based on start script location
172- var scriptDir string
173- if strings .Contains (d .startScript , "/" ) {
174- // application-root case: extract directory from script path
175- scriptDir = filepath .Dir (d .startScript )
176- } else {
177- // root structure case: script in bin/
203+ scriptDir := filepath .Dir (d .startScript )
204+ if scriptDir == "" || scriptDir == "." {
178205 scriptDir = "bin"
179206 }
207+ scriptDir = filepath .ToSlash (scriptDir )
180208
181209 // Collect additional libraries (JVMKill agent, frameworks, etc.)
182210 additionalLibs := d .collectAdditionalLibraries ()
@@ -323,23 +351,8 @@ func (d *DistZipContainer) Release() (string, error) {
323351 }
324352 }
325353
326- // Determine the script directory based on start script location
327- var scriptDir string
328- if strings .Contains (d .startScript , "/" ) {
329- // application-root case: extract directory from script path
330- scriptDir = filepath .Dir (d .startScript )
331- } else {
332- // root structure case: script in bin/
333- scriptDir = "bin"
334- }
335-
336- // Extract just the script name (remove any directory path)
337- scriptName := filepath .Base (d .startScript )
338-
339- // Use absolute path $HOME/<scriptDir>/<scriptName>
340- // This eliminates dependency on profile.d script execution order
341- // At runtime, CF makes the application available at $HOME
342- cmd := fmt .Sprintf ("$HOME/%s/%s" , scriptDir , scriptName )
354+ scriptPath := filepath .ToSlash (d .startScript )
355+ cmd := fmt .Sprintf ("$HOME/%s" , scriptPath )
343356
344357 return cmd , nil
345358}
0 commit comments