Files
zeekayandHanzo Dev bc404adbb6 core: pull the builder and runtime image from hanzoai/pack
RailpackBuilderImage and RailpackRuntimeImage named
ghcr.io/railwayapp/railpack-{builder,runtime}, so every `pack build`
pulled the upstream vendor's images instead of our own. Point them at
ghcr.io/hanzoai/pack-{builder,runtime}, published by the release
pipeline as of the prior commit.

Also updates the local-dev mirrors of the same reference: the
mise-builder-shell task, the run-with-frontend script, the mise clean
task's image cleanup list, and a stale comment in buildkit/frontend.go.

Snapshots refreshed with the project's own task
(UPDATE_SNAPS=true go test -short ./...) and inspected line by line:
every changed line is exactly the builder/runtime image string, nothing
else. The pre-existing, unrelated php-vanilla frankenphp version drift
that the same refresh also touches was left untouched here.

Do not merge until a release tag has gone through the pipeline from the
prior commit and ghcr.io/hanzoai/pack-builder and pack-runtime actually
exist -- until then this is a correct diff sitting ahead of its own
prerequisite, not something to land on main.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-04 03:57:43 -07:00

149 lines
3.8 KiB
Go

package plan
import (
"fmt"
"github.com/hanzoai/pack/core/mise"
)
var (
RailpackRuntimeImage = fmt.Sprintf("ghcr.io/hanzoai/pack-runtime:mise-%s", mise.Version)
)
// serialized to railpack.json
type BuildPlan struct {
Steps []Step `json:"steps,omitempty"`
Caches map[string]*Cache `json:"caches,omitempty"`
Secrets []string `json:"secrets,omitempty"`
Deploy Deploy `json:"deploy"`
Exclude []string `json:"exclude,omitempty"`
}
type Deploy struct {
// The base layer for the deploy step
Base Layer `json:"base"`
// The layers for the deploy step
Inputs []Layer `json:"inputs,omitempty"`
// The command to run in the container
StartCmd string `json:"startCommand,omitempty"`
// The variables available to this step. The key is the name of the variable that is referenced in a variable command
Variables map[string]string `json:"variables,omitempty"`
// The paths to prepend to the $PATH environment variable
Paths []string `json:"paths,omitempty"`
}
func NewBuildPlan() *BuildPlan {
return &BuildPlan{
Steps: []Step{},
Deploy: Deploy{},
Caches: make(map[string]*Cache),
Secrets: []string{},
Exclude: []string{},
}
}
func (p *BuildPlan) AddStep(step Step) {
p.Steps = append(p.Steps, step)
}
func (p *BuildPlan) Normalize() {
// Remove empty inputs from steps
for i := range p.Steps {
if p.Steps[i].Inputs == nil {
continue
}
normalizedInputs := []Layer{}
for _, input := range p.Steps[i].Inputs {
if !input.IsEmpty() {
normalizedInputs = append(normalizedInputs, input)
}
}
p.Steps[i].Inputs = normalizedInputs
}
// Remove empty inputs from deploy
if p.Deploy.Inputs != nil {
normalizedDeployInputs := []Layer{}
for _, input := range p.Deploy.Inputs {
if !input.IsEmpty() {
normalizedDeployInputs = append(normalizedDeployInputs, input)
}
}
if len(normalizedDeployInputs) == 0 {
p.Deploy.Inputs = nil
} else {
p.Deploy.Inputs = normalizedDeployInputs
}
}
// Track which steps are referenced by deploy or transitively referenced steps
referencedSteps := make(map[string]bool)
// Start with steps referenced directly by deploy
if p.Deploy.Base.Step != "" {
referencedSteps[p.Deploy.Base.Step] = true
}
if p.Deploy.Inputs != nil {
for _, input := range p.Deploy.Inputs {
if input.Step != "" {
referencedSteps[input.Step] = true
}
}
}
// Keep finding new referenced steps until no more are found
// Use a map to track which steps we've already checked to avoid infinite loops
checkedSteps := make(map[string]bool)
// We use maxIterations to prevent infinite loops from circular dependencies.
// If we exceed this maximum possible number of unique edges, we can safely
// break as we've already collected all reachable steps.
maxIterations := len(p.Steps) * len(p.Steps) // Maximum possible unique edges in a directed graph
for range maxIterations {
newReferences := false
for _, step := range p.Steps {
// Skip if this step isn't referenced
if !referencedSteps[step.Name] {
continue
}
// Skip if we've already checked this step's inputs
if checkedSteps[step.Name] {
continue
}
// Mark this step as checked
checkedSteps[step.Name] = true
// Check this step's inputs for references
if step.Inputs != nil {
for _, input := range step.Inputs {
if input.Step != "" && !referencedSteps[input.Step] {
referencedSteps[input.Step] = true
newReferences = true
}
}
}
}
if !newReferences {
break
}
}
// Keep only steps that are referenced
if len(referencedSteps) > 0 {
normalizedSteps := make([]Step, 0, len(p.Steps))
for _, step := range p.Steps {
if referencedSteps[step.Name] {
normalizedSteps = append(normalizedSteps, step)
}
}
p.Steps = normalizedSteps
}
}