122 lines
3.2 KiB
Go
122 lines
3.2 KiB
Go
package launch
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/buildpacks/lifecycle/api"
|
|
)
|
|
|
|
type Shell interface {
|
|
Launch(ShellProcess) error
|
|
}
|
|
|
|
type ShellProcess struct {
|
|
Script bool // Script indicates whether Command is a script or should be a token in a generated script
|
|
Args []string
|
|
Command string
|
|
Caller string // Caller used to set argv0 for Bash profile scripts and is ignored in Cmd
|
|
Profiles []string
|
|
Env []string
|
|
WorkingDirectory string
|
|
}
|
|
|
|
func (l *Launcher) launchWithShell(self string, proc Process) error {
|
|
profs, err := l.getProfiles(proc.Type)
|
|
if err != nil {
|
|
return errors.Wrap(err, "find profiles")
|
|
}
|
|
script, err := l.isScript(proc)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
command := ""
|
|
if len(proc.Command.Entries) > 0 {
|
|
command = strings.Join(proc.Command.Entries, " ")
|
|
}
|
|
return l.Shell.Launch(ShellProcess{
|
|
Script: script,
|
|
Caller: self,
|
|
Command: command,
|
|
Args: proc.Args,
|
|
Profiles: profs,
|
|
Env: l.Env.List(),
|
|
WorkingDirectory: proc.WorkingDirectory,
|
|
})
|
|
}
|
|
|
|
func (l *Launcher) getProfiles(procType string) ([]string, error) {
|
|
var profiles []string
|
|
if err := l.eachBuildpack(func(_ *api.Version, bpDir string) error {
|
|
return eachLayer(bpDir, l.populateLayerProfiles(procType, &profiles))
|
|
}); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
fi, err := os.Stat(filepath.Join(l.AppDir, appProfile))
|
|
if os.IsNotExist(err) {
|
|
return profiles, nil
|
|
} else if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to determine if app profile script exists at path '%s'", filepath.Join(l.AppDir, appProfile))
|
|
}
|
|
if !fi.IsDir() {
|
|
profiles = append(profiles, appProfile)
|
|
}
|
|
|
|
return profiles, nil
|
|
}
|
|
|
|
func (l *Launcher) populateLayerProfiles(procType string, profiles *[]string) dirAction {
|
|
return func(layerDir string) error {
|
|
if err := eachFile(filepath.Join(layerDir, "profile.d"), func(path string) error {
|
|
*profiles = append(*profiles, path)
|
|
return nil
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
if procType == "" {
|
|
return nil
|
|
}
|
|
return eachFile(filepath.Join(layerDir, "profile.d", procType), func(path string) error {
|
|
*profiles = append(*profiles, path)
|
|
return nil
|
|
})
|
|
}
|
|
}
|
|
|
|
func (l *Launcher) isScript(proc Process) (bool, error) {
|
|
if len(proc.Args) == 0 {
|
|
return true, nil
|
|
}
|
|
bpAPI, err := l.buildpackAPI(proc)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if bpAPI == nil {
|
|
return false, err
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
// buildpackAPI returns the API of the buildpack that contributed the process and true if the process was contributed
|
|
// by a buildpack. If the process was not provided by a buildpack it returns nil.
|
|
func (l *Launcher) buildpackAPI(proc Process) (*api.Version, error) {
|
|
if proc.BuildpackID == "" {
|
|
return nil, nil
|
|
}
|
|
for _, bp := range l.Buildpacks {
|
|
if bp.ID == proc.BuildpackID {
|
|
api, err := api.NewVersion(bp.API)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to parse api '%s' of buildpack '%s'", bp.API, bp.ID)
|
|
}
|
|
return api, nil
|
|
}
|
|
}
|
|
return nil, fmt.Errorf("process type '%s' provided by unknown buildpack '%s'", proc.Type, proc.BuildpackID)
|
|
}
|