mirror of
https://github.com/hanzoai/pack.git
synced 2026-09-30 23:43:13 +00:00
change how config is applied
This commit is contained in:
+23
-19
@@ -6,27 +6,30 @@ import (
|
||||
"github.com/railwayapp/railpack/core/utils"
|
||||
)
|
||||
|
||||
type DeployConfig struct {
|
||||
AptPackages []string `json:"aptPackages,omitempty" jsonschema:"description=List of apt packages to include at runtime"`
|
||||
Inputs []plan.Input `json:"inputs,omitempty" jsonschema:"description=The inputs for the deploy step"`
|
||||
StartCmd string `json:"startCommand,omitempty" jsonschema:"description=The command to run in the container"`
|
||||
Variables map[string]string `json:"variables,omitempty" jsonschema:"description=The variables available to this step. The key is the name of the variable that is referenced in a variable command"`
|
||||
Paths []string `json:"paths,omitempty" jsonschema:"description=The paths to prepend to the $PATH environment variable"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
// List of providers to use
|
||||
Providers *[]string `json:"providers,omitempty" jsonschema:"description=List of providers to use"`
|
||||
Providers []string `json:"providers" jsonschema:"description=List of providers to use"`
|
||||
BuildAptPackages []string `json:"buildAptPackages,omitempty" jsonschema:"description=List of apt packages to install during the build step"`
|
||||
Steps map[string]*plan.Step `json:"steps,omitempty" jsonschema:"description=Map of step names to step definitions"`
|
||||
Deploy *DeployConfig `json:"deploy,omitempty" jsonschema:"description=Deploy configuration"`
|
||||
Packages map[string]string `json:"packages,omitempty" jsonschema:"description=Map of package name to package version"`
|
||||
Caches map[string]*plan.Cache `json:"caches,omitempty" jsonschema:"description=Map of cache name to cache definitions. The cache key can be referenced in an exec command"`
|
||||
Secrets []string `json:"secrets,omitempty" jsonschema:"description=Secrets that should be made available to commands that have useSecrets set to true"`
|
||||
}
|
||||
|
||||
// Map of step names to step definitions
|
||||
Steps map[string]*plan.Step `json:"steps,omitempty" jsonschema:"description=Map of step names to step definitions"`
|
||||
|
||||
// Deploy configuration
|
||||
Deploy plan.Deploy `json:"deploy,omitempty" jsonschema:"description=Deploy configuration"`
|
||||
|
||||
// Map of package name to package version
|
||||
Packages map[string]string `json:"packages,omitempty" jsonschema:"description=Map of package name to package version"`
|
||||
|
||||
// List of apt packages to install
|
||||
AptPackages []string `json:"aptPackages,omitempty" jsonschema:"description=List of apt packages to install"`
|
||||
|
||||
// Map of cache name to cache definitions. The cache key can be referenced in an exec command.
|
||||
Caches map[string]*plan.Cache `json:"caches,omitempty" jsonschema:"description=Map of cache name to cache definitions. The cache key can be referenced in an exec command"`
|
||||
|
||||
// Secrets that should be made available to commands that have useSecrets set to true
|
||||
Secrets []string `json:"secrets,omitempty" jsonschema:"description=Secrets that should be made available to commands that have useSecrets set to true"`
|
||||
func EmptyDeployConfig() *DeployConfig {
|
||||
return &DeployConfig{
|
||||
AptPackages: []string{},
|
||||
StartCmd: "",
|
||||
Variables: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
func EmptyConfig() *Config {
|
||||
@@ -34,6 +37,7 @@ func EmptyConfig() *Config {
|
||||
Steps: make(map[string]*plan.Step),
|
||||
Packages: make(map[string]string),
|
||||
Caches: make(map[string]*plan.Cache),
|
||||
Deploy: EmptyDeployConfig(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+18
-15
@@ -1,6 +1,7 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
@@ -33,7 +34,13 @@ type BuildResult struct {
|
||||
}
|
||||
|
||||
func GenerateBuildPlan(app *app.App, env *app.Environment, options *GenerateBuildPlanOptions) (*BuildResult, error) {
|
||||
ctx, err := generate.NewGenerateContext(app, env)
|
||||
// Get the full user config based on file config, env config, and options
|
||||
config, err := GetConfig(app, env, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, err := generate.NewGenerateContext(app, env, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -45,12 +52,6 @@ func GenerateBuildPlan(app *app.App, env *app.Environment, options *GenerateBuil
|
||||
}
|
||||
}
|
||||
|
||||
// Get the full user config based on file config, env config, and options
|
||||
config, err := GetConfig(app, env, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Figure out what providers to use
|
||||
providersToUse, detectedProviderNames := getProviders(ctx, config)
|
||||
providerNames := make([]string, len(providersToUse))
|
||||
@@ -82,11 +83,6 @@ func GenerateBuildPlan(app *app.App, env *app.Environment, options *GenerateBuil
|
||||
return nil, fmt.Errorf("failed to run procfile provider: %w", err)
|
||||
}
|
||||
|
||||
// Update the context with the config
|
||||
if err := ctx.ApplyConfig(config); err != nil {
|
||||
return nil, fmt.Errorf("failed to apply config: %w", err)
|
||||
}
|
||||
|
||||
buildPlan, resolvedPackages, err := ctx.Generate()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate build plan: %w", err)
|
||||
@@ -173,8 +169,12 @@ func GenerateConfigFromEnvironment(app *app.App, env *app.Environment) *config.C
|
||||
}
|
||||
}
|
||||
|
||||
if envAptPackages, _ := env.GetConfigVariable("APT_PACKAGES"); envAptPackages != "" {
|
||||
config.AptPackages = strings.Split(envAptPackages, " ")
|
||||
if envAptPackages, _ := env.GetConfigVariable("BUILD_APT_PACKAGES"); envAptPackages != "" {
|
||||
config.BuildAptPackages = strings.Split(envAptPackages, " ")
|
||||
}
|
||||
|
||||
if envAptPackages, _ := env.GetConfigVariable("DEPLOY_APT_PACKAGES"); envAptPackages != "" {
|
||||
config.Deploy.AptPackages = strings.Split(envAptPackages, " ")
|
||||
}
|
||||
|
||||
for name := range env.Variables {
|
||||
@@ -213,6 +213,9 @@ func getProviders(ctx *generate.GenerateContext, config *config.Config) ([]provi
|
||||
allProviders := providers.GetLanguageProviders()
|
||||
detectedProviders := []string{}
|
||||
|
||||
configJson, _ := json.MarshalIndent(config, "", " ")
|
||||
fmt.Printf("Config: %s\n", string(configJson))
|
||||
|
||||
// Even if there are providers manually specified, we want to detect to see what type of app this is
|
||||
for _, provider := range allProviders {
|
||||
matched, err := provider.Detect(ctx)
|
||||
@@ -238,7 +241,7 @@ func getProviders(ctx *generate.GenerateContext, config *config.Config) ([]provi
|
||||
}
|
||||
|
||||
if config.Providers != nil {
|
||||
for _, providerName := range *config.Providers {
|
||||
for _, providerName := range config.Providers {
|
||||
provider := providers.GetProvider(providerName)
|
||||
if provider == nil {
|
||||
log.Warnf("Provider `%s` not found", providerName)
|
||||
|
||||
+112
-114
@@ -27,8 +27,9 @@ type StepBuilder interface {
|
||||
}
|
||||
|
||||
type GenerateContext struct {
|
||||
App *a.App
|
||||
Env *a.Environment
|
||||
App *a.App
|
||||
Env *a.Environment
|
||||
Config *config.Config
|
||||
|
||||
BaseImage string
|
||||
Steps []StepBuilder
|
||||
@@ -39,14 +40,12 @@ type GenerateContext struct {
|
||||
|
||||
SubContexts []string
|
||||
|
||||
Metadata *Metadata
|
||||
|
||||
Resolver *resolver.Resolver
|
||||
|
||||
miseStepBuilder *MiseStepBuilder
|
||||
Metadata *Metadata
|
||||
Resolver *resolver.Resolver
|
||||
MiseStepBuilder *MiseStepBuilder
|
||||
}
|
||||
|
||||
func NewGenerateContext(app *a.App, env *a.Environment) (*GenerateContext, error) {
|
||||
func NewGenerateContext(app *a.App, env *a.Environment, config *config.Config) (*GenerateContext, error) {
|
||||
resolver, err := resolver.NewResolver(mise.InstallDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -55,6 +54,7 @@ func NewGenerateContext(app *a.App, env *a.Environment) (*GenerateContext, error
|
||||
return &GenerateContext{
|
||||
App: app,
|
||||
Env: env,
|
||||
Config: config,
|
||||
Steps: make([]StepBuilder, 0),
|
||||
Deploy: NewDeployBuilder(),
|
||||
Caches: NewCacheContext(),
|
||||
@@ -65,10 +65,10 @@ func NewGenerateContext(app *a.App, env *a.Environment) (*GenerateContext, error
|
||||
}
|
||||
|
||||
func (c *GenerateContext) GetMiseStepBuilder() *MiseStepBuilder {
|
||||
if c.miseStepBuilder == nil {
|
||||
c.miseStepBuilder = c.newMiseStepBuilder()
|
||||
if c.MiseStepBuilder == nil {
|
||||
c.MiseStepBuilder = c.newMiseStepBuilder()
|
||||
}
|
||||
return c.miseStepBuilder
|
||||
return c.MiseStepBuilder
|
||||
}
|
||||
|
||||
func (c *GenerateContext) EnterSubContext(subContext string) *GenerateContext {
|
||||
@@ -104,13 +104,23 @@ func (c *GenerateContext) ResolvePackages() (map[string]*resolver.ResolvedPackag
|
||||
|
||||
// Generate a build plan from the context
|
||||
func (c *GenerateContext) Generate() (*plan.BuildPlan, map[string]*resolver.ResolvedPackage, error) {
|
||||
// Add all packages from the config to the mise step
|
||||
miseStep := c.GetMiseStepBuilder()
|
||||
for _, pkg := range slices.Sorted(maps.Keys(c.Config.Packages)) {
|
||||
version := c.Config.Packages[pkg]
|
||||
pkgRef := miseStep.Default(pkg, version)
|
||||
miseStep.Version(pkgRef, version, "custom config")
|
||||
}
|
||||
|
||||
c.applyConfig()
|
||||
|
||||
// Resolve all package versions into a fully qualified and valid version
|
||||
resolvedPackages, err := c.ResolvePackages()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to resolve packages: %w", err)
|
||||
}
|
||||
|
||||
// Generate the plan based on the context and resolved packages
|
||||
// Create the actual build plan
|
||||
buildPlan := plan.NewBuildPlan()
|
||||
|
||||
buildStepOptions := &BuildStepOptions{
|
||||
@@ -130,115 +140,27 @@ func (c *GenerateContext) Generate() (*plan.BuildPlan, map[string]*resolver.Reso
|
||||
|
||||
buildPlan.Caches = c.Caches.Caches
|
||||
buildPlan.Secrets = utils.RemoveDuplicates(c.Secrets)
|
||||
buildPlan.Deploy = *c.Deploy.Build()
|
||||
buildPlan.Deploy = c.Deploy.Build()
|
||||
|
||||
return buildPlan, resolvedPackages, nil
|
||||
}
|
||||
|
||||
func (c *GenerateContext) ApplyConfig(config *config.Config) error {
|
||||
// Mise package config
|
||||
miseStep := c.GetMiseStepBuilder()
|
||||
for _, pkg := range slices.Sorted(maps.Keys(config.Packages)) {
|
||||
version := config.Packages[pkg]
|
||||
pkgRef := miseStep.Default(pkg, version)
|
||||
miseStep.Version(pkgRef, version, "custom config")
|
||||
func (c *GenerateContext) DefaultRuntimeInput() plan.Input {
|
||||
return c.DefaultRuntimeInputWithPackages([]string{})
|
||||
}
|
||||
|
||||
func (c *GenerateContext) DefaultRuntimeInputWithPackages(additionalAptPackages []string) plan.Input {
|
||||
aptPackages := append(c.Config.Deploy.AptPackages, additionalAptPackages...)
|
||||
|
||||
if len(aptPackages) == 0 {
|
||||
return plan.NewImageInput(plan.RAILPACK_RUNTIME_IMAGE)
|
||||
}
|
||||
|
||||
// Apt package config
|
||||
// aptStepName := ""
|
||||
if len(config.AptPackages) > 0 {
|
||||
aptStep := c.NewAptStepBuilder("config")
|
||||
// aptStepName = aptStep.Name()
|
||||
aptStep.Packages = config.AptPackages
|
||||
runtimeAptStep := c.NewAptStepBuilder("runtime")
|
||||
runtimeAptStep.Packages = aptPackages
|
||||
runtimeAptStep.AddInput(plan.NewImageInput(plan.RAILPACK_RUNTIME_IMAGE))
|
||||
|
||||
// We install the apt packages again in the mise step since they may be required for install mise packages
|
||||
miseStep.SupportingAptPackages = append(miseStep.SupportingAptPackages, config.AptPackages...)
|
||||
}
|
||||
|
||||
// Step config
|
||||
for _, name := range slices.Sorted(maps.Keys(config.Steps)) {
|
||||
configStep := config.Steps[name]
|
||||
|
||||
var commandStepBuilder *CommandStepBuilder
|
||||
|
||||
// We need to use the key as the step name and not `configStep.Name`
|
||||
if existingStep := c.GetStepByName(name); existingStep != nil {
|
||||
if csb, ok := (*existingStep).(*CommandStepBuilder); ok {
|
||||
commandStepBuilder = csb
|
||||
} else {
|
||||
log.Warnf("Step `%s` exists, but it is not a command step. Skipping...", name)
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
commandStepBuilder = c.NewCommandStep(name)
|
||||
}
|
||||
|
||||
// Overwrite the step with values from the config if they exist
|
||||
|
||||
// if len(configStep.DependsOn) > 0 {
|
||||
// commandStepBuilder.DependsOn = configStep.DependsOn
|
||||
// }
|
||||
|
||||
// if aptStepName != "" {
|
||||
// commandStepBuilder.DependsOn = append(commandStepBuilder.DependsOn, aptStepName)
|
||||
// }
|
||||
|
||||
if configStep.Commands != nil {
|
||||
commandStepBuilder.Commands = configStep.Commands
|
||||
}
|
||||
|
||||
// if configStep.Outputs != nil {
|
||||
// commandStepBuilder.Outputs = configStep.Outputs
|
||||
// }
|
||||
for k, v := range configStep.Assets {
|
||||
commandStepBuilder.Assets[k] = v
|
||||
}
|
||||
|
||||
if configStep.Secrets != nil {
|
||||
commandStepBuilder.Secrets = configStep.Secrets
|
||||
}
|
||||
|
||||
// if configStep.UseSecrets != nil {
|
||||
// commandStepBuilder.UseSecrets = *configStep.UseSecrets
|
||||
// }
|
||||
|
||||
if len(configStep.Caches) > 0 {
|
||||
commandStepBuilder.Caches = configStep.Caches
|
||||
}
|
||||
|
||||
if configStep.Variables != nil {
|
||||
commandStepBuilder.AddEnvVars(configStep.Variables)
|
||||
}
|
||||
}
|
||||
|
||||
// Cache config
|
||||
for name, cache := range config.Caches {
|
||||
c.Caches.SetCache(name, cache)
|
||||
}
|
||||
|
||||
// Secret config
|
||||
c.Secrets = append(c.Secrets, config.Secrets...)
|
||||
|
||||
// Start config
|
||||
// if config.Start.BaseImage != "" {
|
||||
// c.Start.BaseImage = config.Start.BaseImage
|
||||
// }
|
||||
|
||||
// if config.Start.Command != "" {
|
||||
// c.Start.Command = config.Start.Command
|
||||
// }
|
||||
|
||||
// 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
|
||||
return plan.NewStepInput(runtimeAptStep.Name())
|
||||
}
|
||||
|
||||
func (o *BuildStepOptions) NewAptInstallCommand(pkgs []string) plan.Command {
|
||||
@@ -249,3 +171,79 @@ func (o *BuildStepOptions) NewAptInstallCommand(pkgs []string) plan.Command {
|
||||
CustomName: "install apt packages: " + strings.Join(pkgs, " "),
|
||||
})
|
||||
}
|
||||
|
||||
func (c *GenerateContext) applyConfig() {
|
||||
miseStep := c.GetMiseStepBuilder()
|
||||
|
||||
// Apply the cache config to the context
|
||||
maps.Copy(c.Caches.Caches, c.Config.Caches)
|
||||
|
||||
// Apply step config to the context
|
||||
for _, name := range slices.Sorted(maps.Keys(c.Config.Steps)) {
|
||||
configStep := c.Config.Steps[name]
|
||||
|
||||
var commandStepBuilder *CommandStepBuilder
|
||||
|
||||
if existingStep := c.GetStepByName(name); existingStep != nil {
|
||||
if csb, ok := (*existingStep).(*CommandStepBuilder); ok {
|
||||
commandStepBuilder = csb
|
||||
} else {
|
||||
log.Warnf("Step `%s` exists, but it is not a command step. Skipping...", name)
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
// If no build step found, create a new one
|
||||
// Run the build in the builder context and copy the /app contents to the final image
|
||||
commandStepBuilder = c.NewCommandStep(name)
|
||||
commandStepBuilder.AddInput(plan.NewStepInput(miseStep.Name()))
|
||||
c.Deploy.Inputs = append(c.Deploy.Inputs, plan.NewStepInput(commandStepBuilder.Name(), plan.InputOptions{
|
||||
Include: []string{"."},
|
||||
}))
|
||||
}
|
||||
|
||||
if configStep.Commands != nil {
|
||||
commandStepBuilder.Commands = configStep.Commands
|
||||
}
|
||||
|
||||
if configStep.Inputs != nil {
|
||||
commandStepBuilder.Inputs = configStep.Inputs
|
||||
}
|
||||
|
||||
for k, v := range configStep.Assets {
|
||||
commandStepBuilder.Assets[k] = v
|
||||
}
|
||||
|
||||
if configStep.Secrets != nil {
|
||||
commandStepBuilder.Secrets = configStep.Secrets
|
||||
}
|
||||
|
||||
if len(configStep.Caches) > 0 {
|
||||
commandStepBuilder.Caches = configStep.Caches
|
||||
}
|
||||
|
||||
if configStep.Variables != nil {
|
||||
commandStepBuilder.AddEnvVars(configStep.Variables)
|
||||
}
|
||||
|
||||
// Secret config
|
||||
if configStep.Secrets != nil {
|
||||
commandStepBuilder.Secrets = configStep.Secrets
|
||||
}
|
||||
}
|
||||
|
||||
// Update deploy from config
|
||||
if c.Config.Deploy.StartCmd != "" {
|
||||
c.Deploy.StartCmd = c.Config.Deploy.StartCmd
|
||||
}
|
||||
|
||||
if c.Config.Deploy.Inputs != nil {
|
||||
fmt.Printf("Inputs: %v\n", c.Config.Deploy.Inputs)
|
||||
c.Deploy.Inputs = c.Config.Deploy.Inputs
|
||||
}
|
||||
|
||||
if c.Config.Deploy.Paths != nil {
|
||||
c.Deploy.Paths = c.Config.Deploy.Paths
|
||||
}
|
||||
|
||||
maps.Copy(c.Deploy.Variables, c.Config.Deploy.Variables)
|
||||
}
|
||||
|
||||
@@ -3,23 +3,28 @@ package generate
|
||||
import "github.com/railwayapp/railpack/core/plan"
|
||||
|
||||
type DeployBuilder struct {
|
||||
Inputs []plan.Input
|
||||
StartCmd string
|
||||
Variables map[string]string
|
||||
Inputs []plan.Input
|
||||
StartCmd string
|
||||
Variables map[string]string
|
||||
Paths []string
|
||||
AptPackages []string
|
||||
}
|
||||
|
||||
func NewDeployBuilder() *DeployBuilder {
|
||||
return &DeployBuilder{
|
||||
Inputs: []plan.Input{},
|
||||
StartCmd: "",
|
||||
Variables: map[string]string{},
|
||||
Inputs: []plan.Input{},
|
||||
StartCmd: "",
|
||||
Variables: map[string]string{},
|
||||
Paths: []string{},
|
||||
AptPackages: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
func (b *DeployBuilder) Build() *plan.Deploy {
|
||||
return &plan.Deploy{
|
||||
func (b *DeployBuilder) Build() plan.Deploy {
|
||||
return plan.Deploy{
|
||||
Inputs: b.Inputs,
|
||||
StartCmd: b.StartCmd,
|
||||
Variables: b.Variables,
|
||||
Paths: b.Paths,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ type ImageStepBuilder struct {
|
||||
Resolver *resolver.Resolver
|
||||
Packages []*resolver.PackageRef
|
||||
ResolveStepImage func(options *BuildStepOptions) string
|
||||
AptPackages []string
|
||||
}
|
||||
|
||||
func (c *GenerateContext) NewImageStep(name string, resolveStepImage func(options *BuildStepOptions) string) *ImageStepBuilder {
|
||||
@@ -48,11 +49,24 @@ func (b *ImageStepBuilder) Build(options *BuildStepOptions) (*plan.Step, error)
|
||||
step := plan.NewStep(b.DisplayName)
|
||||
|
||||
image := b.ResolveStepImage(options)
|
||||
step.Inputs = []plan.Input{
|
||||
plan.NewImageInput(image),
|
||||
}
|
||||
|
||||
step.Secrets = []string{}
|
||||
if len(b.AptPackages) > 0 {
|
||||
runtimeAptStep := plan.NewStep("packages:apt")
|
||||
runtimeAptStep.Inputs = []plan.Input{
|
||||
plan.NewImageInput(image),
|
||||
}
|
||||
runtimeAptStep.Commands = []plan.Command{
|
||||
options.NewAptInstallCommand(b.AptPackages),
|
||||
}
|
||||
|
||||
step.Inputs = []plan.Input{
|
||||
plan.NewStepInput(runtimeAptStep.Name),
|
||||
}
|
||||
} else {
|
||||
step.Inputs = []plan.Input{
|
||||
plan.NewImageInput(image),
|
||||
}
|
||||
}
|
||||
|
||||
return step, nil
|
||||
}
|
||||
|
||||
@@ -30,11 +30,13 @@ type MiseStepBuilder struct {
|
||||
}
|
||||
|
||||
func (c *GenerateContext) newMiseStepBuilder() *MiseStepBuilder {
|
||||
supportingAptPackages := c.Config.BuildAptPackages
|
||||
|
||||
step := &MiseStepBuilder{
|
||||
DisplayName: MisePackageStepName,
|
||||
Resolver: c.Resolver,
|
||||
MisePackages: []*resolver.PackageRef{},
|
||||
SupportingAptPackages: []string{},
|
||||
SupportingAptPackages: append(supportingAptPackages, c.Config.BuildAptPackages...),
|
||||
Assets: map[string]string{},
|
||||
Inputs: []plan.Input{},
|
||||
Variables: map[string]string{},
|
||||
@@ -89,8 +91,6 @@ func (b *MiseStepBuilder) Build(options *BuildStepOptions) (*plan.Step, error) {
|
||||
return step, nil
|
||||
}
|
||||
|
||||
// step.StartingImage = BuilderBaseImage
|
||||
|
||||
step.Inputs = []plan.Input{
|
||||
plan.NewImageInput(plan.RAILPACK_BUILDER_IMAGE),
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ const (
|
||||
DEFAULT_GO_VERSION = "1.23"
|
||||
GO_BUILD_CACHE_KEY = "go-build"
|
||||
GO_BINARY_NAME = "out"
|
||||
START_IMAGE = "alpine:latest"
|
||||
)
|
||||
|
||||
type GoProvider struct{}
|
||||
@@ -31,36 +30,38 @@ func (p *GoProvider) Initialize(ctx *generate.GenerateContext) error {
|
||||
}
|
||||
|
||||
func (p *GoProvider) Plan(ctx *generate.GenerateContext) error {
|
||||
packages, err := p.Packages(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
builder := p.GetBuilder(ctx)
|
||||
p.InstallGoPackages(ctx, builder)
|
||||
|
||||
install, err := p.Install(ctx, packages)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
install := ctx.NewCommandStep("install")
|
||||
install.AddInput(plan.NewStepInput(builder.Name()))
|
||||
p.InstallGoDeps(ctx, install)
|
||||
|
||||
build, err := p.Build(ctx, packages, install)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
build := ctx.NewCommandStep("build")
|
||||
build.AddInput(plan.NewStepInput(install.Name()))
|
||||
p.Build(ctx, build)
|
||||
|
||||
if build != nil {
|
||||
ctx.Deploy.StartCmd = fmt.Sprintf("./%s", GO_BINARY_NAME)
|
||||
ctx.Deploy.StartCmd = fmt.Sprintf("./%s", GO_BINARY_NAME)
|
||||
|
||||
if !p.hasCGOEnabled(ctx) {
|
||||
// ctx.Deploy.Outputs = []string{GO_BINARY_NAME}
|
||||
if p.hasCGOEnabled(ctx) {
|
||||
runtimeAptStep := ctx.NewAptStepBuilder("runtime")
|
||||
runtimeAptStep.AddInput(ctx.DefaultRuntimeInputWithPackages([]string{"libc6"}))
|
||||
|
||||
// ctx.Start.BaseImage = START_IMAGE
|
||||
// if startImage, _ := ctx.Env.GetConfigVariable("START_IMAGE"); startImage != "" {
|
||||
// ctx.Start.BaseImage = startImage
|
||||
// }
|
||||
}
|
||||
|
||||
if p.isGin(ctx) {
|
||||
ctx.Deploy.Variables["GIN_MODE"] = "release"
|
||||
}
|
||||
ctx.Deploy.Inputs = append(ctx.Deploy.Inputs, []plan.Input{
|
||||
plan.NewStepInput(runtimeAptStep.Name()),
|
||||
plan.NewStepInput(build.Name(), plan.InputOptions{
|
||||
Include: []string{"."},
|
||||
}),
|
||||
plan.NewLocalInput("."),
|
||||
}...)
|
||||
} else {
|
||||
ctx.Deploy.Inputs = append(ctx.Deploy.Inputs, []plan.Input{
|
||||
ctx.DefaultRuntimeInput(),
|
||||
plan.NewStepInput(build.Name(), plan.InputOptions{
|
||||
Include: []string{"."},
|
||||
}),
|
||||
plan.NewLocalInput("."),
|
||||
}...)
|
||||
}
|
||||
|
||||
p.addMetadata(ctx)
|
||||
@@ -68,52 +69,43 @@ func (p *GoProvider) Plan(ctx *generate.GenerateContext) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *GoProvider) Build(ctx *generate.GenerateContext, packages *generate.MiseStepBuilder, install *generate.CommandStepBuilder) (*generate.CommandStepBuilder, error) {
|
||||
func (p *GoProvider) Build(ctx *generate.GenerateContext, build *generate.CommandStepBuilder) {
|
||||
var buildCmd string
|
||||
|
||||
flags := "-w -s"
|
||||
baseBuildCmd := fmt.Sprintf("go build -ldflags=\"%s\" -o %s", flags, GO_BINARY_NAME)
|
||||
|
||||
if binName, _ := ctx.Env.GetConfigVariable("GO_BIN"); binName != "" {
|
||||
// If there is a RAILPACK_GO_BIN variable, use that
|
||||
buildCmd = fmt.Sprintf("go build -o %s ./cmd/%s", GO_BINARY_NAME, binName)
|
||||
buildCmd = fmt.Sprintf("%s ./cmd/%s", baseBuildCmd, binName)
|
||||
} else if p.isGoMod(ctx) && p.hasRootGoFiles(ctx) {
|
||||
buildCmd = fmt.Sprintf("go build -o %s", GO_BINARY_NAME)
|
||||
buildCmd = baseBuildCmd
|
||||
} else if dirs, err := ctx.App.FindDirectories("cmd/*"); err == nil && len(dirs) > 0 {
|
||||
// Try to find a command in the cmd directory
|
||||
cmdName := filepath.Base(dirs[0])
|
||||
buildCmd = fmt.Sprintf("go build -o %s ./cmd/%s", GO_BINARY_NAME, cmdName)
|
||||
buildCmd = fmt.Sprintf("%s ./cmd/%s", baseBuildCmd, cmdName)
|
||||
} else if p.isGoMod(ctx) {
|
||||
buildCmd = fmt.Sprintf("go build -o %s", GO_BINARY_NAME)
|
||||
buildCmd = baseBuildCmd
|
||||
} else if ctx.App.HasMatch("main.go") {
|
||||
buildCmd = fmt.Sprintf("go build -o %s main.go", GO_BINARY_NAME)
|
||||
buildCmd = fmt.Sprintf("%s main.go", baseBuildCmd)
|
||||
}
|
||||
|
||||
if buildCmd == "" {
|
||||
return nil, nil
|
||||
return
|
||||
}
|
||||
|
||||
build := ctx.NewCommandStep("build")
|
||||
build.AddCache(p.goBuildCache(ctx))
|
||||
build.AddCommands([]plan.Command{
|
||||
plan.NewCopyCommand("."),
|
||||
plan.NewExecCommand(buildCmd),
|
||||
})
|
||||
|
||||
if packages != nil {
|
||||
// build.DependsOn = append(build.DependsOn, packages.DisplayName)
|
||||
}
|
||||
|
||||
if install != nil {
|
||||
// build.DependsOn = append(build.DependsOn, install.DisplayName)
|
||||
}
|
||||
|
||||
return build, nil
|
||||
}
|
||||
|
||||
func (p *GoProvider) Install(ctx *generate.GenerateContext, packages *generate.MiseStepBuilder) (*generate.CommandStepBuilder, error) {
|
||||
func (p *GoProvider) InstallGoDeps(ctx *generate.GenerateContext, install *generate.CommandStepBuilder) {
|
||||
if !p.isGoMod(ctx) {
|
||||
return nil, nil
|
||||
return
|
||||
}
|
||||
|
||||
install := ctx.NewCommandStep("install")
|
||||
install.AddCache(p.goBuildCache(ctx))
|
||||
install.AddCommand(plan.NewCopyCommand("go.mod"))
|
||||
|
||||
@@ -123,24 +115,13 @@ func (p *GoProvider) Install(ctx *generate.GenerateContext, packages *generate.M
|
||||
|
||||
install.AddCommand(plan.NewExecCommand("go mod download"))
|
||||
|
||||
// If CGO is enabled, we need to install the gcc packages
|
||||
if p.hasCGOEnabled(ctx) {
|
||||
aptStep := ctx.NewAptStepBuilder("cgo")
|
||||
aptStep.Packages = []string{"gcc", "g++", "libc6-dev"}
|
||||
// install.DependsOn = append(install.DependsOn, aptStep.DisplayName)
|
||||
} else {
|
||||
if !p.hasCGOEnabled(ctx) {
|
||||
install.AddEnvVars(map[string]string{"CGO_ENABLED": "0"})
|
||||
}
|
||||
|
||||
// install.DependsOn = []string{packages.DisplayName}
|
||||
|
||||
return install, nil
|
||||
}
|
||||
|
||||
func (p *GoProvider) Packages(ctx *generate.GenerateContext) (*generate.MiseStepBuilder, error) {
|
||||
packages := ctx.GetMiseStepBuilder()
|
||||
|
||||
goPkg := packages.Default("go", DEFAULT_GO_VERSION)
|
||||
func (p *GoProvider) InstallGoPackages(ctx *generate.GenerateContext, miseStep *generate.MiseStepBuilder) {
|
||||
goPkg := miseStep.Default("go", DEFAULT_GO_VERSION)
|
||||
|
||||
if goModContents, err := ctx.App.ReadFile("go.mod"); err == nil {
|
||||
// Split content into lines and look for "go X.XX" line
|
||||
@@ -149,7 +130,7 @@ func (p *GoProvider) Packages(ctx *generate.GenerateContext) (*generate.MiseStep
|
||||
if strings.HasPrefix(strings.TrimSpace(line), "go ") {
|
||||
// Extract version number
|
||||
if goVersion := strings.TrimSpace(strings.TrimPrefix(line, "go")); goVersion != "" {
|
||||
packages.Version(goPkg, goVersion, "go.mod")
|
||||
miseStep.Version(goPkg, goVersion, "go.mod")
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -157,10 +138,18 @@ func (p *GoProvider) Packages(ctx *generate.GenerateContext) (*generate.MiseStep
|
||||
}
|
||||
|
||||
if envVersion, varName := ctx.Env.GetConfigVariable("GO_VERSION"); envVersion != "" {
|
||||
packages.Version(goPkg, envVersion, varName)
|
||||
miseStep.Version(goPkg, envVersion, varName)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *GoProvider) GetBuilder(ctx *generate.GenerateContext) *generate.MiseStepBuilder {
|
||||
miseStep := ctx.GetMiseStepBuilder()
|
||||
|
||||
if p.hasCGOEnabled(ctx) {
|
||||
miseStep.SupportingAptPackages = append(miseStep.SupportingAptPackages, "gcc", "g++", "libc6-dev")
|
||||
}
|
||||
|
||||
return packages, nil
|
||||
return miseStep
|
||||
}
|
||||
|
||||
func (p *GoProvider) addMetadata(ctx *generate.GenerateContext) {
|
||||
|
||||
@@ -78,7 +78,7 @@ func (p *NodeProvider) Plan(ctx *generate.GenerateContext) error {
|
||||
maps.Copy(ctx.Deploy.Variables, p.GetNodeEnvVars(ctx))
|
||||
|
||||
ctx.Deploy.Inputs = append(ctx.Deploy.Inputs, []plan.Input{
|
||||
plan.NewImageInput(plan.RAILPACK_RUNTIME_IMAGE),
|
||||
ctx.DefaultRuntimeInput(),
|
||||
plan.NewStepInput(miseStep.Name(), plan.InputOptions{
|
||||
Include: miseStep.GetOutputPaths(),
|
||||
}),
|
||||
|
||||
@@ -38,12 +38,8 @@ func (p *PhpProvider) Plan(ctx *generate.GenerateContext) error {
|
||||
}
|
||||
|
||||
// Nginx
|
||||
nginxPackages := ctx.NewAptStepBuilder("nginx")
|
||||
nginxPackages.AddInput(plan.NewStepInput(phpImageStep.Name()))
|
||||
nginxPackages.Packages = []string{"nginx", "git", "zip", "unzip"}
|
||||
|
||||
nginx := ctx.NewCommandStep("nginx")
|
||||
nginx.AddInput(plan.NewStepInput(nginxPackages.Name()))
|
||||
nginx.AddInput(plan.NewStepInput(phpImageStep.Name()))
|
||||
nginx.AddCommands([]plan.Command{
|
||||
plan.NewFileCommand("/etc/nginx/railpack.conf", "nginx.conf", plan.FileOptions{CustomName: "create nginx config"}),
|
||||
plan.NewExecCommand("nginx -t -c /etc/nginx/railpack.conf"),
|
||||
@@ -128,8 +124,7 @@ func (p *PhpProvider) Plan(ctx *generate.GenerateContext) error {
|
||||
build.AddInput(plan.NewStepInput(composer.Name()))
|
||||
|
||||
ctx.Deploy.Inputs = []plan.Input{
|
||||
// plan.NewStepInput(build.Name()),
|
||||
plan.NewStepInput(composer.Name()),
|
||||
plan.NewStepInput(build.Name()),
|
||||
plan.NewLocalInput("."),
|
||||
}
|
||||
}
|
||||
@@ -191,6 +186,12 @@ func (p *PhpProvider) phpImagePackage(ctx *generate.GenerateContext) (*generate.
|
||||
return getPhpImage(DEFAULT_PHP_VERSION)
|
||||
})
|
||||
|
||||
imageStep.AptPackages = append(imageStep.AptPackages, "nginx", "git", "zip", "unzip")
|
||||
|
||||
// Include both build and runtime apt packages since we don't have a separate runtime image
|
||||
imageStep.AptPackages = append(imageStep.AptPackages, ctx.Config.BuildAptPackages...)
|
||||
imageStep.AptPackages = append(imageStep.AptPackages, ctx.Config.Deploy.AptPackages...)
|
||||
|
||||
php := imageStep.Default("php", DEFAULT_PHP_VERSION)
|
||||
|
||||
// Read composer.json to get the PHP version
|
||||
|
||||
@@ -144,14 +144,20 @@ func (p *PythonProvider) PlanPipenv(ctx *generate.GenerateContext) {
|
||||
install.Secrets = []string{}
|
||||
install.UseSecretsWithPrefixes([]string{"PYTHON", "PIP"})
|
||||
|
||||
install.AddCommands([]plan.Command{
|
||||
plan.NewExecCommand("pipx install pipenv"),
|
||||
plan.NewPathCommand(LOCAL_BIN_PATH),
|
||||
plan.NewCopyCommand("Pipfile"),
|
||||
plan.NewCopyCommand("Pipfile.lock"),
|
||||
plan.NewExecCommand("pipenv install --deploy --ignore-pipfile"),
|
||||
plan.NewPathCommand(VENV_PATH + "/bin"),
|
||||
})
|
||||
|
||||
if ctx.App.HasMatch("Pipfile.lock") {
|
||||
install.AddCommands([]plan.Command{
|
||||
plan.NewExecCommand("pipx install pipenv"),
|
||||
plan.NewPathCommand(LOCAL_BIN_PATH),
|
||||
plan.NewCopyCommand("Pipfile"),
|
||||
plan.NewCopyCommand("Pipfile.lock"),
|
||||
plan.NewExecCommand("pipenv install --deploy --ignore-pipfile"),
|
||||
plan.NewPathCommand(VENV_PATH + "/bin"),
|
||||
})
|
||||
} else {
|
||||
install.AddCommands([]plan.Command{
|
||||
@@ -160,6 +166,10 @@ func (p *PythonProvider) PlanPipenv(ctx *generate.GenerateContext) {
|
||||
})
|
||||
}
|
||||
|
||||
install.AddCommands([]plan.Command{
|
||||
plan.NewPathCommand(VENV_PATH + "/bin"),
|
||||
})
|
||||
|
||||
build := ctx.NewCommandStep("build")
|
||||
build.AddInput(plan.NewStepInput(install.Name()))
|
||||
|
||||
@@ -294,7 +304,7 @@ func (p *PythonProvider) PlanPip(ctx *generate.GenerateContext) {
|
||||
func (p *PythonProvider) GetImageWithRuntimeDeps(ctx *generate.GenerateContext) *generate.AptStepBuilder {
|
||||
aptStep := ctx.NewAptStepBuilder("python-runtime-deps")
|
||||
aptStep.Inputs = []plan.Input{
|
||||
plan.NewImageInput(plan.RAILPACK_RUNTIME_IMAGE),
|
||||
ctx.DefaultRuntimeInput(),
|
||||
}
|
||||
|
||||
for dep, requiredPkgs := range pythonRuntimeDepRequirements {
|
||||
@@ -306,15 +316,11 @@ func (p *PythonProvider) GetImageWithRuntimeDeps(ctx *generate.GenerateContext)
|
||||
return aptStep
|
||||
}
|
||||
|
||||
func (p *PythonProvider) GetBuilderDeps(ctx *generate.GenerateContext) *generate.AptStepBuilder {
|
||||
aptStep := ctx.NewAptStepBuilder("python-builder-deps")
|
||||
aptStep.Inputs = []plan.Input{
|
||||
plan.NewStepInput(ctx.GetMiseStepBuilder().Name()),
|
||||
}
|
||||
func (p *PythonProvider) GetBuilderDeps(ctx *generate.GenerateContext) *generate.MiseStepBuilder {
|
||||
miseStep := ctx.GetMiseStepBuilder()
|
||||
miseStep.SupportingAptPackages = append(miseStep.SupportingAptPackages, "python3-dev", "libpq-dev")
|
||||
|
||||
aptStep.Packages = []string{"python3-dev", "libpq-dev"}
|
||||
|
||||
return aptStep
|
||||
return miseStep
|
||||
}
|
||||
|
||||
func (p *PythonProvider) InstallPythonDeps(ctx *generate.GenerateContext, install *generate.CommandStepBuilder) {
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
[
|
||||
{
|
||||
"expectedOutput": "Hello from Python-PDM"
|
||||
}
|
||||
]
|
||||
@@ -7,4 +7,4 @@ print("numpy", np.__version__)
|
||||
print("pandas", pd.__version__)
|
||||
print("psycopg2", psycopg2.__version__)
|
||||
|
||||
print("Hello from Python")
|
||||
print("Hello from UV")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[
|
||||
{
|
||||
"expectedOutput": "Hello from Python"
|
||||
"expectedOutput": "Hello from UV"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import cowsay
|
||||
|
||||
cowsay.cow("Hello, world!")
|
||||
cowsay.cow("Hello from Python-Pipfile")
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
[
|
||||
{
|
||||
"expectedOutput": "Hello from Python-Pipfile"
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user