mirror of
https://github.com/hanzoai/pack.git
synced 2026-09-30 23:43:13 +00:00
cleanup graph env and step environment variable handling
This commit is contained in:
+20
-7
@@ -38,7 +38,7 @@ func ConvertPlanToLLB(plan *p.BuildPlan, opts ConvertPlanOptions) (*llb.State, *
|
||||
}
|
||||
|
||||
state = *graphOutput.State
|
||||
imageEnv := getImageEnv(graphOutput)
|
||||
imageEnv := getImageEnv(graphOutput, plan)
|
||||
|
||||
state = getStartState(state, plan, platform)
|
||||
|
||||
@@ -104,8 +104,11 @@ func getStartState(buildState llb.State, plan *p.BuildPlan, platform specs.Platf
|
||||
return startState
|
||||
}
|
||||
|
||||
func getImageEnv(graphOutput *BuildGraphOutput) []string {
|
||||
pathString := strings.Join(graphOutput.PathList, ":")
|
||||
func getImageEnv(graphOutput *BuildGraphOutput, plan *p.BuildPlan) []string {
|
||||
paths := graphOutput.GraphEnv.PathList
|
||||
paths = append(paths, plan.Start.Paths...)
|
||||
|
||||
pathString := strings.Join(paths, ":")
|
||||
|
||||
var pathEnv string
|
||||
if pathString == "" {
|
||||
@@ -114,13 +117,23 @@ func getImageEnv(graphOutput *BuildGraphOutput) []string {
|
||||
pathEnv = "PATH=" + pathString + ":" + system.DefaultPathEnvUnix
|
||||
}
|
||||
|
||||
imageEnv := []string{pathEnv}
|
||||
envMap := make(map[string]string)
|
||||
envMap["PATH"] = pathEnv
|
||||
|
||||
for k, v := range graphOutput.EnvVars {
|
||||
imageEnv = append(imageEnv, fmt.Sprintf("%s=%s", k, v))
|
||||
for k, v := range graphOutput.GraphEnv.EnvVars {
|
||||
envMap[k] = v
|
||||
}
|
||||
|
||||
return imageEnv
|
||||
for k, v := range plan.Start.Variables {
|
||||
envMap[k] = v
|
||||
}
|
||||
|
||||
envVars := make([]string, 0, len(envMap))
|
||||
for k, v := range envMap {
|
||||
envVars = append(envVars, fmt.Sprintf("%s=%s", k, v))
|
||||
}
|
||||
|
||||
return envVars
|
||||
}
|
||||
|
||||
func getBaseState(plan *p.BuildPlan, platform specs.Platform) llb.State {
|
||||
|
||||
+57
-62
@@ -23,8 +23,7 @@ type BuildGraph struct {
|
||||
|
||||
type BuildGraphOutput struct {
|
||||
State *llb.State
|
||||
PathList []string
|
||||
EnvVars map[string]string
|
||||
GraphEnv GraphEnvironment
|
||||
}
|
||||
|
||||
func NewBuildGraph(plan *plan.BuildPlan, baseState *llb.State, cacheStore *BuildKitCacheStore, secretsHash string, platform *specs.Platform) (*BuildGraph, error) {
|
||||
@@ -41,12 +40,12 @@ func NewBuildGraph(plan *plan.BuildPlan, baseState *llb.State, cacheStore *Build
|
||||
for i := range plan.Steps {
|
||||
step := &plan.Steps[i]
|
||||
graph.Nodes[step.Name] = &Node{
|
||||
Step: step,
|
||||
Parents: make([]*Node, 0),
|
||||
Children: make([]*Node, 0),
|
||||
Processed: false,
|
||||
OutputEnvVars: make(map[string]string),
|
||||
OutputPathList: make([]string, 0),
|
||||
Step: step,
|
||||
Parents: make([]*Node, 0),
|
||||
Children: make([]*Node, 0),
|
||||
Processed: false,
|
||||
|
||||
OutputEnv: NewGraphEnvironment(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,18 +82,12 @@ func (g *BuildGraph) GenerateLLB() (*BuildGraphOutput, error) {
|
||||
// Find all leaf nodes and get their states
|
||||
var leafNodes []*Node
|
||||
|
||||
outputPathList := make([]string, 0)
|
||||
outputEnvVars := make(map[string]string)
|
||||
graphEnv := NewGraphEnvironment()
|
||||
|
||||
for _, node := range g.Nodes {
|
||||
if len(node.Children) == 0 && node.State != nil {
|
||||
leafNodes = append(leafNodes, node)
|
||||
|
||||
// Add output path and env vars
|
||||
outputPathList = append(outputPathList, node.OutputPathList...)
|
||||
for k, v := range node.OutputEnvVars {
|
||||
outputEnvVars[k] = v
|
||||
}
|
||||
graphEnv.Merge(node.OutputEnv)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,8 +95,7 @@ func (g *BuildGraph) GenerateLLB() (*BuildGraphOutput, error) {
|
||||
if len(leafNodes) == 0 {
|
||||
return &BuildGraphOutput{
|
||||
State: g.BaseState,
|
||||
PathList: outputPathList,
|
||||
EnvVars: outputEnvVars,
|
||||
GraphEnv: graphEnv,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -111,8 +103,7 @@ func (g *BuildGraph) GenerateLLB() (*BuildGraphOutput, error) {
|
||||
if len(leafNodes) == 1 {
|
||||
return &BuildGraphOutput{
|
||||
State: leafNodes[0].State,
|
||||
PathList: outputPathList,
|
||||
EnvVars: outputEnvVars,
|
||||
GraphEnv: graphEnv,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -120,8 +111,7 @@ func (g *BuildGraph) GenerateLLB() (*BuildGraphOutput, error) {
|
||||
|
||||
return &BuildGraphOutput{
|
||||
State: &result,
|
||||
PathList: outputPathList,
|
||||
EnvVars: outputEnvVars,
|
||||
GraphEnv: graphEnv,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -192,16 +182,17 @@ func (g *BuildGraph) processNode(node *Node) error {
|
||||
|
||||
// Determine the state to build upon
|
||||
var currentState *llb.State
|
||||
currentEnvVars := make(map[string]string)
|
||||
currentPathList := make([]string, 0)
|
||||
currentGraphEnv := NewGraphEnvironment()
|
||||
|
||||
for _, parent := range node.Parents {
|
||||
currentGraphEnv.Merge(parent.OutputEnv)
|
||||
}
|
||||
|
||||
if len(node.Parents) == 0 {
|
||||
currentState = g.BaseState
|
||||
} else if len(node.Parents) == 1 {
|
||||
// If only one parent, use its state directly
|
||||
currentState = node.Parents[0].State
|
||||
currentEnvVars = node.Parents[0].OutputEnvVars
|
||||
currentPathList = node.Parents[0].OutputPathList
|
||||
} else {
|
||||
// If multiple parents, merge their states
|
||||
parentStates := make([]llb.State, len(node.Parents))
|
||||
@@ -213,12 +204,6 @@ func (g *BuildGraph) processNode(node *Node) error {
|
||||
parent.Step.Name, node.Step.Name)
|
||||
}
|
||||
|
||||
// Build up the current path and env vars
|
||||
currentPathList = append(currentPathList, parent.OutputPathList...)
|
||||
for k, v := range parent.OutputEnvVars {
|
||||
currentEnvVars[k] = v
|
||||
}
|
||||
|
||||
parentStates[i] = *parent.State
|
||||
mergeStepNames[i] = parent.Step.Name
|
||||
}
|
||||
@@ -228,11 +213,10 @@ func (g *BuildGraph) processNode(node *Node) error {
|
||||
currentState = &merged
|
||||
}
|
||||
|
||||
node.InputPathList = currentPathList
|
||||
node.InputEnvVars = currentEnvVars
|
||||
node.InputEnv = currentGraphEnv
|
||||
|
||||
// Convert this node's step to LLB
|
||||
stepState, err := g.convertStepToLLB(node, currentState)
|
||||
stepState, err := g.convertNodeToLLB(node, currentState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -243,47 +227,30 @@ func (g *BuildGraph) processNode(node *Node) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *BuildGraph) convertStepToLLB(node *Node, baseState *llb.State) (*llb.State, error) {
|
||||
step := node.Step
|
||||
func (g *BuildGraph) convertNodeToLLB(node *Node, baseState *llb.State) (*llb.State, error) {
|
||||
state := *baseState
|
||||
state = state.Dir("/app")
|
||||
|
||||
if step.StartingImage != "" {
|
||||
state = llb.Image(step.StartingImage, llb.Platform(*g.Platform))
|
||||
}
|
||||
|
||||
// Add commands for input variables and path
|
||||
for k, v := range node.InputEnvVars {
|
||||
newState, err := g.convertCommandToLLB(node, plan.VariableCommand{Name: k, Value: v}, state, step)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
state = newState
|
||||
}
|
||||
|
||||
for _, path := range node.InputPathList {
|
||||
newState, err := g.convertCommandToLLB(node, plan.PathCommand{Path: path}, state, step)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
state = newState
|
||||
state, err := g.getNodeStartingState(state, node)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Process the step commands
|
||||
if step.Commands != nil {
|
||||
for _, cmd := range *step.Commands {
|
||||
if node.Step.Commands != nil {
|
||||
for _, cmd := range *node.Step.Commands {
|
||||
var err error
|
||||
state, err = g.convertCommandToLLB(node, cmd, state, step)
|
||||
state, err = g.convertCommandToLLB(node, cmd, state, node.Step)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if step.Outputs != nil {
|
||||
if node.Step.Outputs != nil {
|
||||
result := llb.Scratch()
|
||||
|
||||
for _, output := range *step.Outputs {
|
||||
for _, output := range *node.Step.Outputs {
|
||||
result = result.File(llb.Copy(state, output, output, &llb.CopyInfo{
|
||||
CreateDestPath: true,
|
||||
AllowWildcard: true,
|
||||
@@ -307,6 +274,34 @@ func (g *BuildGraph) convertStepToLLB(node *Node, baseState *llb.State) (*llb.St
|
||||
return &state, nil
|
||||
}
|
||||
|
||||
// Adds the input environment to the base state of the node
|
||||
// This includes things like the environment variables and accumulated paths
|
||||
func (g *BuildGraph) getNodeStartingState(baseState llb.State, node *Node) (llb.State, error) {
|
||||
state := baseState
|
||||
|
||||
if node.Step.StartingImage != "" {
|
||||
state = llb.Image(node.Step.StartingImage, llb.Platform(*g.Platform))
|
||||
}
|
||||
|
||||
for k, v := range node.InputEnv.EnvVars {
|
||||
newState, err := g.convertCommandToLLB(node, plan.VariableCommand{Name: k, Value: v}, state, node.Step)
|
||||
if err != nil {
|
||||
return state, err
|
||||
}
|
||||
state = newState
|
||||
}
|
||||
|
||||
for _, path := range node.InputEnv.PathList {
|
||||
newState, err := g.convertCommandToLLB(node, plan.PathCommand{Path: path}, state, node.Step)
|
||||
if err != nil {
|
||||
return state, err
|
||||
}
|
||||
state = newState
|
||||
}
|
||||
|
||||
return state, nil
|
||||
}
|
||||
|
||||
func (g *BuildGraph) convertCommandToLLB(node *Node, cmd plan.Command, state llb.State, step *plan.Step) (llb.State, error) {
|
||||
switch cmd := cmd.(type) {
|
||||
case plan.ExecCommand:
|
||||
@@ -349,7 +344,7 @@ func (g *BuildGraph) convertCommandToLLB(node *Node, cmd plan.Command, state llb
|
||||
|
||||
case plan.VariableCommand:
|
||||
s := state.AddEnv(cmd.Name, cmd.Value)
|
||||
node.OutputEnvVars[cmd.Name] = cmd.Value
|
||||
node.OutputEnv.AddEnvVar(cmd.Name, cmd.Value)
|
||||
|
||||
return s, nil
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package buildkit
|
||||
|
||||
type GraphEnvironment struct {
|
||||
PathList []string
|
||||
EnvVars map[string]string
|
||||
}
|
||||
|
||||
func NewGraphEnvironment() GraphEnvironment {
|
||||
return GraphEnvironment{
|
||||
PathList: make([]string, 0),
|
||||
EnvVars: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
// Merges the other environment into the current environment
|
||||
func (e *GraphEnvironment) Merge(other GraphEnvironment) {
|
||||
e.PathList = append(e.PathList, other.PathList...)
|
||||
|
||||
for k, v := range other.EnvVars {
|
||||
e.EnvVars[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
func (e *GraphEnvironment) AddPath(path string) {
|
||||
for _, existingPath := range e.PathList {
|
||||
if existingPath == path {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
e.PathList = append(e.PathList, path)
|
||||
}
|
||||
|
||||
func (e *GraphEnvironment) AddEnvVar(key, value string) {
|
||||
e.EnvVars[key] = value
|
||||
}
|
||||
+5
-15
@@ -13,27 +13,17 @@ type Node struct {
|
||||
Processed bool
|
||||
InProgress bool
|
||||
|
||||
InputPathList []string
|
||||
InputEnvVars map[string]string
|
||||
|
||||
OutputPathList []string
|
||||
OutputEnvVars map[string]string
|
||||
InputEnv GraphEnvironment
|
||||
OutputEnv GraphEnvironment
|
||||
}
|
||||
|
||||
func (node *Node) getPathList() []string {
|
||||
pathList := make([]string, 0)
|
||||
pathList = append(pathList, node.InputPathList...)
|
||||
pathList = append(pathList, node.OutputPathList...)
|
||||
pathList = append(pathList, node.InputEnv.PathList...)
|
||||
pathList = append(pathList, node.OutputEnv.PathList...)
|
||||
return pathList
|
||||
}
|
||||
|
||||
func (node *Node) appendPath(path string) {
|
||||
// Check if path already exists in input or output paths
|
||||
for _, existingPath := range node.OutputPathList {
|
||||
if existingPath == path {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
node.OutputPathList = append(node.OutputPathList, path)
|
||||
node.OutputEnv.AddPath(path)
|
||||
}
|
||||
|
||||
+7
-7
@@ -6,7 +6,6 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/charmbracelet/log"
|
||||
"github.com/railwayapp/railpack/buildkit"
|
||||
"github.com/railwayapp/railpack/core"
|
||||
"github.com/railwayapp/railpack/core/app"
|
||||
@@ -14,10 +13,6 @@ import (
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
const (
|
||||
PRINT_PLAN = false
|
||||
)
|
||||
|
||||
var BuildCommand = &cli.Command{
|
||||
Name: "build",
|
||||
Aliases: []string{"b"},
|
||||
@@ -55,6 +50,11 @@ var BuildCommand = &cli.Command{
|
||||
Usage: "buildkit progress output mode. Values: auto, plain, tty",
|
||||
Value: "auto",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "show-plan",
|
||||
Usage: "Show the build plan before building. This is useful for development and debugging.",
|
||||
Value: false,
|
||||
},
|
||||
},
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
buildResult, app, env, err := GenerateBuildResultForCommand(cmd)
|
||||
@@ -69,8 +69,8 @@ var BuildCommand = &cli.Command{
|
||||
return cli.Exit(err, 1)
|
||||
}
|
||||
|
||||
if PRINT_PLAN {
|
||||
log.Debug(string(serializedPlan))
|
||||
if cmd.Bool("show-plan") {
|
||||
fmt.Println(string(serializedPlan))
|
||||
}
|
||||
|
||||
err = validateSecrets(buildResult.Plan, env)
|
||||
|
||||
@@ -32,6 +32,12 @@ func TestMergeConfigSmall(t *testing.T) {
|
||||
"echo first"
|
||||
]
|
||||
}
|
||||
},
|
||||
"start": {
|
||||
"variables": {
|
||||
"SHARED": "one",
|
||||
"HELLO": "world"
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
@@ -43,6 +49,12 @@ func TestMergeConfigSmall(t *testing.T) {
|
||||
},
|
||||
"steps": {
|
||||
"install": {}
|
||||
},
|
||||
"start": {
|
||||
"variables": {
|
||||
"SHARED": "two",
|
||||
"FOO": "bar"
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
@@ -62,6 +74,13 @@ func TestMergeConfigSmall(t *testing.T) {
|
||||
]
|
||||
}
|
||||
},
|
||||
"start": {
|
||||
"variables": {
|
||||
"HELLO": "world",
|
||||
"SHARED": "two",
|
||||
"FOO": "bar"
|
||||
}
|
||||
},
|
||||
"caches": {}
|
||||
}`
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
|
||||
[TestGenerateContext - 1]
|
||||
{
|
||||
"baseImage": "debian:stable-slim",
|
||||
"caches": {
|
||||
"apt": {
|
||||
"directory": "/var/cache/apt",
|
||||
@@ -20,7 +21,10 @@
|
||||
"RAILWAY_SECRET_2"
|
||||
],
|
||||
"start": {
|
||||
"cmd": "npm run start"
|
||||
"cmd": "npm run start",
|
||||
"variables": {
|
||||
"HELLO": "world"
|
||||
}
|
||||
},
|
||||
"steps": [
|
||||
{
|
||||
@@ -119,10 +123,7 @@
|
||||
{
|
||||
"commands": [
|
||||
{
|
||||
"cmd": "npm run build"
|
||||
},
|
||||
{
|
||||
"cmd": "echo building"
|
||||
"cmd": "sh -c 'echo building'"
|
||||
}
|
||||
],
|
||||
"dependsOn": [
|
||||
|
||||
@@ -45,6 +45,22 @@ func (b *CommandStepBuilder) AddCommands(commands []plan.Command) {
|
||||
*b.Commands = append(*b.Commands, commands...)
|
||||
}
|
||||
|
||||
func (b *CommandStepBuilder) AddEnvVars(envVars map[string]string) {
|
||||
commands := []plan.Command{}
|
||||
for k, v := range envVars {
|
||||
commands = append(commands, plan.NewVariableCommand(k, v))
|
||||
}
|
||||
b.AddCommands(commands)
|
||||
}
|
||||
|
||||
func (b *CommandStepBuilder) AddPaths(paths []string) {
|
||||
commands := []plan.Command{}
|
||||
for _, path := range paths {
|
||||
commands = append(commands, plan.NewPathCommand(path))
|
||||
}
|
||||
b.AddCommands(commands)
|
||||
}
|
||||
|
||||
func (b *CommandStepBuilder) Name() string {
|
||||
return b.DisplayName
|
||||
}
|
||||
|
||||
@@ -138,7 +138,9 @@ func (c *GenerateContext) Generate() (*plan.BuildPlan, map[string]*resolver.Reso
|
||||
|
||||
buildPlan.Start.BaseImage = c.Start.BaseImage
|
||||
buildPlan.Start.Command = c.Start.Command
|
||||
buildPlan.Start.Paths = utils.RemoveDuplicates(c.Start.Paths)
|
||||
buildPlan.Start.Outputs = utils.RemoveDuplicates(c.Start.outputs)
|
||||
buildPlan.Start.Paths = utils.RemoveDuplicates(c.Start.paths)
|
||||
buildPlan.Start.Variables = c.Start.variables
|
||||
|
||||
return buildPlan, resolvedPackages, nil
|
||||
}
|
||||
@@ -180,9 +182,11 @@ func (c *GenerateContext) ApplyConfig(config *config.Config) error {
|
||||
if len(configStep.DependsOn) > 0 {
|
||||
commandStepBuilder.DependsOn = configStep.DependsOn
|
||||
}
|
||||
|
||||
if configStep.Commands != nil {
|
||||
commandStepBuilder.AddCommands(*configStep.Commands)
|
||||
commandStepBuilder.Commands = configStep.Commands
|
||||
}
|
||||
|
||||
if configStep.Outputs != nil {
|
||||
commandStepBuilder.Outputs = configStep.Outputs
|
||||
}
|
||||
@@ -210,8 +214,14 @@ func (c *GenerateContext) ApplyConfig(config *config.Config) error {
|
||||
c.Start.Command = config.Start.Command
|
||||
}
|
||||
|
||||
if len(config.Start.Paths) > 0 {
|
||||
c.Start.Paths = append(c.Start.Paths, config.Start.Paths...)
|
||||
if config.Start.Variables != nil {
|
||||
c.Start.AddEnvVars(config.Start.Variables)
|
||||
}
|
||||
|
||||
c.Start.AddPaths(config.Start.Paths)
|
||||
|
||||
if len(config.Start.Outputs) > 0 {
|
||||
c.Start.outputs = config.Start.Outputs
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -70,7 +70,12 @@ func TestGenerateContext(t *testing.T) {
|
||||
"commands": ["echo building"]
|
||||
}
|
||||
},
|
||||
"secrets": ["RAILWAY_SECRET_1", "RAILWAY_SECRET_2"]
|
||||
"secrets": ["RAILWAY_SECRET_1", "RAILWAY_SECRET_2"],
|
||||
"start": {
|
||||
"variables": {
|
||||
"HELLO": "world"
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
var cfg config.Config
|
||||
|
||||
@@ -3,12 +3,27 @@ package generate
|
||||
type StartContext struct {
|
||||
BaseImage string
|
||||
Command string
|
||||
Paths []string
|
||||
Env map[string]string
|
||||
outputs []string
|
||||
paths []string
|
||||
variables map[string]string
|
||||
}
|
||||
|
||||
func NewStartContext() *StartContext {
|
||||
return &StartContext{
|
||||
Env: make(map[string]string),
|
||||
variables: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StartContext) AddEnvVars(envVars map[string]string) {
|
||||
for k, v := range envVars {
|
||||
s.variables[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StartContext) AddPaths(paths []string) {
|
||||
s.paths = append(s.paths, paths...)
|
||||
}
|
||||
|
||||
func (s *StartContext) AddOutputs(outputs []string) {
|
||||
s.outputs = append(s.outputs, outputs...)
|
||||
}
|
||||
|
||||
+12
-3
@@ -69,6 +69,15 @@ func NewExecCommand(cmd string, options ...ExecOptions) Command {
|
||||
return exec
|
||||
}
|
||||
|
||||
func NewExecShellCommand(cmd string, options ...ExecOptions) Command {
|
||||
exec := ExecCommand{Cmd: "sh -c '" + cmd + "'"}
|
||||
if len(options) > 0 {
|
||||
exec.CustomName = options[0].CustomName
|
||||
exec.Caches = options[0].Caches
|
||||
}
|
||||
return exec
|
||||
}
|
||||
|
||||
func NewPathCommand(path string, customName ...string) Command {
|
||||
pathCmd := PathCommand{Path: path}
|
||||
return pathCmd
|
||||
@@ -160,7 +169,7 @@ func UnmarshalStringCommand(data []byte) (Command, error) {
|
||||
|
||||
// If no prefix, treat as exec command
|
||||
if !strings.Contains(str, ":") {
|
||||
return NewExecCommand(strings.Trim(str, "\"")), nil
|
||||
return NewExecShellCommand(strings.Trim(str, "\"")), nil
|
||||
}
|
||||
|
||||
parts := strings.SplitN(str, ":", 2)
|
||||
@@ -181,7 +190,7 @@ func UnmarshalStringCommand(data []byte) (Command, error) {
|
||||
|
||||
switch cmdType {
|
||||
case "RUN":
|
||||
return NewExecCommand(payload, ExecOptions{CustomName: customName}), nil
|
||||
return NewExecShellCommand(payload, ExecOptions{CustomName: customName}), nil
|
||||
case "PATH":
|
||||
return NewPathCommand(payload), nil
|
||||
case "ENV":
|
||||
@@ -205,5 +214,5 @@ func UnmarshalStringCommand(data []byte) (Command, error) {
|
||||
}
|
||||
|
||||
// fallback to exec command type
|
||||
return NewExecCommand(strings.Trim(str, "\""), ExecOptions{CustomName: customName}), nil
|
||||
return NewExecShellCommand(strings.Trim(str, "\""), ExecOptions{CustomName: customName}), nil
|
||||
}
|
||||
|
||||
@@ -17,14 +17,14 @@ func TestCommandMarshalUnmarshal(t *testing.T) {
|
||||
// Exec
|
||||
{
|
||||
name: "exec command without custom name",
|
||||
command: NewExecCommand("echo hello"),
|
||||
expectedJSON: `{"cmd":"echo hello"}`,
|
||||
command: NewExecShellCommand("echo hello"),
|
||||
expectedJSON: `{"cmd":"sh -c 'echo hello'"}`,
|
||||
unmarshalString: "echo hello",
|
||||
},
|
||||
{
|
||||
name: "exec command with custom name",
|
||||
command: NewExecCommand("echo hello", ExecOptions{CustomName: "Say Hello"}),
|
||||
expectedJSON: `{"cmd":"echo hello","customName":"Say Hello"}`,
|
||||
command: NewExecShellCommand("echo hello", ExecOptions{CustomName: "Say Hello"}),
|
||||
expectedJSON: `{"cmd":"sh -c 'echo hello'","customName":"Say Hello"}`,
|
||||
unmarshalString: "RUN#Say Hello:echo hello",
|
||||
},
|
||||
{
|
||||
@@ -98,6 +98,7 @@ func TestCommandMarshalUnmarshal(t *testing.T) {
|
||||
roundTrip, err = json.Marshal(cmd)
|
||||
require.NoError(t, err, "failed to marshal string-unmarshalled command")
|
||||
require.Equal(t, string(roundTrip), tt.expectedJSON, "string unmarshal to JSON result")
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -15,8 +15,14 @@ type Start struct {
|
||||
// The command to run in the container
|
||||
Command string `json:"cmd,omitempty"`
|
||||
|
||||
// Outputs to be copied from the container to the host
|
||||
Outputs []string `json:"outputs,omitempty"`
|
||||
|
||||
// $PATHs to be prefixed to the container's base $PATH
|
||||
Paths []string `json:"paths,omitempty"`
|
||||
|
||||
// Environment variables to set in the container. These are not available at build time.
|
||||
Variables map[string]string `json:"variables,omitempty"`
|
||||
}
|
||||
|
||||
func NewBuildPlan() *BuildPlan {
|
||||
|
||||
@@ -47,7 +47,7 @@ func (p *GoProvider) Plan(ctx *generate.GenerateContext) error {
|
||||
ctx.Start.Command = fmt.Sprintf("./%s", GO_BINARY_NAME)
|
||||
|
||||
if !p.hasCGOEnabled(ctx) {
|
||||
ctx.Start.Paths = []string{GO_BINARY_NAME}
|
||||
ctx.Start.AddOutputs([]string{GO_BINARY_NAME})
|
||||
|
||||
ctx.Start.BaseImage = START_IMAGE
|
||||
if startImage, _ := ctx.Env.GetConfigVariable("START_IMAGE"); startImage != "" {
|
||||
@@ -56,7 +56,7 @@ func (p *GoProvider) Plan(ctx *generate.GenerateContext) error {
|
||||
}
|
||||
|
||||
if p.isGin(ctx) {
|
||||
ctx.Start.Env["GIN_MODE"] = "release"
|
||||
ctx.Start.AddEnvVars(map[string]string{"GIN_MODE": "release"})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,8 @@ func (p *NodeProvider) start(ctx *generate.GenerateContext, packageJson *Package
|
||||
ctx.Start.Command = packageManager.RunScriptCommand(files[0])
|
||||
}
|
||||
|
||||
ctx.Start.Paths = append(ctx.Start.Paths, ".")
|
||||
ctx.Start.AddOutputs([]string{"."})
|
||||
ctx.Start.AddEnvVars(p.GetNodeEnvVars(ctx))
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -90,8 +91,13 @@ func (p *NodeProvider) Build(ctx *generate.GenerateContext, install *generate.Co
|
||||
func (p *NodeProvider) Install(ctx *generate.GenerateContext, packages *generate.MiseStepBuilder, packageJson *PackageJson) (*generate.CommandStepBuilder, error) {
|
||||
lenDeps := len(packageJson.Dependencies) + len(packageJson.DevDependencies)
|
||||
|
||||
setup, err := p.Setup(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if lenDeps == 0 {
|
||||
return nil, nil
|
||||
return setup, nil
|
||||
}
|
||||
|
||||
var corepackStepName string
|
||||
@@ -109,16 +115,25 @@ func (p *NodeProvider) Install(ctx *generate.GenerateContext, packages *generate
|
||||
pkgManager := p.getPackageManager(ctx.App)
|
||||
|
||||
install := ctx.NewCommandStep("install")
|
||||
install.DependsOn = []string{packages.DisplayName}
|
||||
install.DependsOn = append(install.DependsOn, []string{packages.DisplayName, setup.DisplayName}...)
|
||||
|
||||
pkgManager.installDependencies(ctx, packageJson, install)
|
||||
|
||||
if corepackStepName != "" {
|
||||
install.DependsOn = []string{corepackStepName}
|
||||
install.DependsOn = append(install.DependsOn, corepackStepName)
|
||||
}
|
||||
|
||||
return install, nil
|
||||
}
|
||||
|
||||
func (p *NodeProvider) Setup(ctx *generate.GenerateContext) (*generate.CommandStepBuilder, error) {
|
||||
setup := ctx.NewCommandStep("setup")
|
||||
setup.AddEnvVars(p.GetNodeEnvVars(ctx))
|
||||
setup.AddPaths([]string{"/app/node_modules/.bin"})
|
||||
|
||||
return setup, nil
|
||||
}
|
||||
|
||||
func (p *NodeProvider) Packages(ctx *generate.GenerateContext, packageJson *PackageJson) (*generate.MiseStepBuilder, error) {
|
||||
packageManager := p.getPackageManager(ctx.App)
|
||||
ctx.Metadata.Set("packageManager", string(packageManager))
|
||||
@@ -152,6 +167,17 @@ func (p *NodeProvider) Packages(ctx *generate.GenerateContext, packageJson *Pack
|
||||
return packages, nil
|
||||
}
|
||||
|
||||
func (p *NodeProvider) GetNodeEnvVars(ctx *generate.GenerateContext) map[string]string {
|
||||
envVars := map[string]string{
|
||||
"NODE_ENV": "production",
|
||||
"NPM_CONFIG_PRODUCTION": "false",
|
||||
"YARN_PRODUCTION": "false",
|
||||
"CI": "true",
|
||||
}
|
||||
|
||||
return envVars
|
||||
}
|
||||
|
||||
func (p *NodeProvider) usesCorepack(packageJson *PackageJson) bool {
|
||||
return packageJson.PackageManager != nil
|
||||
}
|
||||
|
||||
@@ -77,11 +77,11 @@ func (p PackageManager) InstallDeps(ctx *generate.GenerateContext, install *gene
|
||||
plan.ExecOptions{Caches: []string{npmCache}}))
|
||||
}
|
||||
case PackageManagerPnpm:
|
||||
install.AddCommand(plan.NewExecCommand("pnpm install --frozen-lockfile", plan.ExecOptions{
|
||||
install.AddCommand(plan.NewExecCommand("pnpm install --frozen-lockfile --prod=false", plan.ExecOptions{
|
||||
Caches: []string{ctx.Caches.AddCache("pnpm-install", "/root/.local/share/pnpm/store/v3")},
|
||||
}))
|
||||
case PackageManagerBun:
|
||||
install.AddCommand(plan.NewExecCommand("bun i --no-save", plan.ExecOptions{
|
||||
install.AddCommand(plan.NewExecCommand("bun install --frozen-lockfile", plan.ExecOptions{
|
||||
Caches: []string{ctx.Caches.AddCache("bun-install", "/root/.bun/install/cache")},
|
||||
}))
|
||||
case PackageManagerYarn1:
|
||||
|
||||
@@ -106,7 +106,7 @@ func (p *PhpProvider) Plan(ctx *generate.GenerateContext) error {
|
||||
nginxSetup.Assets["php-fpm.conf"] = configFiles.PhpFpmConf
|
||||
|
||||
ctx.Start.Command = "bash /start-nginx.sh"
|
||||
ctx.Start.Paths = []string{"."}
|
||||
ctx.Start.AddOutputs([]string{"."})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ func (p *PythonProvider) Plan(ctx *generate.GenerateContext) error {
|
||||
}
|
||||
|
||||
func (p *PythonProvider) start(ctx *generate.GenerateContext) error {
|
||||
ctx.Start.Paths = append(ctx.Start.Paths, ".")
|
||||
ctx.Start.AddOutputs([]string{"."})
|
||||
|
||||
var startCommand string
|
||||
|
||||
@@ -65,10 +65,6 @@ func (p *PythonProvider) start(ctx *generate.GenerateContext) error {
|
||||
}
|
||||
|
||||
func (p *PythonProvider) install(ctx *generate.GenerateContext) error {
|
||||
install := ctx.NewCommandStep("install")
|
||||
install.AddCommands([]plan.Command{
|
||||
plan.NewPathCommand("/root/.local/bin"),
|
||||
})
|
||||
|
||||
hasRequirements := p.hasRequirements(ctx)
|
||||
hasPyproject := p.hasPyproject(ctx)
|
||||
@@ -77,18 +73,15 @@ func (p *PythonProvider) install(ctx *generate.GenerateContext) error {
|
||||
hasPdm := p.hasPdm(ctx)
|
||||
hasUv := p.hasUv(ctx)
|
||||
|
||||
install.AddCommands([]plan.Command{
|
||||
plan.NewVariableCommand("PYTHONFAULTHANDLER", "1"),
|
||||
plan.NewVariableCommand("PYTHONUNBUFFERED", "1"),
|
||||
plan.NewVariableCommand("PYTHONHASHSEED", "random"),
|
||||
plan.NewVariableCommand("PYTHONDONTWRITEBYTECODE", "1"),
|
||||
plan.NewVariableCommand("PIP_DISABLE_PIP_VERSION_CHECK", "1"),
|
||||
plan.NewVariableCommand("PIP_DEFAULT_TIMEOUT", "100"),
|
||||
})
|
||||
setup := ctx.NewCommandStep("setup")
|
||||
setup.AddEnvVars(p.GetPythonEnvVars(ctx))
|
||||
setup.AddPaths([]string{"/root/.local/bin"})
|
||||
|
||||
install := ctx.NewCommandStep("install")
|
||||
install.DependsOn = append(install.DependsOn, setup.DisplayName)
|
||||
|
||||
if hasRequirements {
|
||||
install.AddCommands([]plan.Command{
|
||||
plan.NewVariableCommand("PIP_CACHE_DIR", PIP_CACHE_DIR),
|
||||
plan.NewCopyCommand("requirements.txt"),
|
||||
plan.NewExecCommand("pip install -r requirements.txt", plan.ExecOptions{
|
||||
Caches: []string{ctx.Caches.AddCache("pip", PIP_CACHE_DIR)},
|
||||
@@ -185,6 +178,18 @@ func (p *PythonProvider) packages(ctx *generate.GenerateContext) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PythonProvider) GetPythonEnvVars(ctx *generate.GenerateContext) map[string]string {
|
||||
return map[string]string{
|
||||
"PYTHONFAULTHANDLER": "1",
|
||||
"PYTHONUNBUFFERED": "1",
|
||||
"PYTHONHASHSEED": "random",
|
||||
"PYTHONDONTWRITEBYTECODE": "1",
|
||||
"PIP_DISABLE_PIP_VERSION_CHECK": "1",
|
||||
"PIP_DEFAULT_TIMEOUT": "100",
|
||||
"PIP_CACHE_DIR": PIP_CACHE_DIR,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PythonProvider) addMetadata(ctx *generate.GenerateContext) {
|
||||
hasPoetry := p.hasPoetry(ctx)
|
||||
hasPdm := p.hasPdm(ctx)
|
||||
|
||||
Reference in New Issue
Block a user