buildkit/convert.go
buildkit/convert.goBrowse 1970 files
912 tokens
3,393 bytes
Token encoding: o200k_base
Snapshot 21a254f
← Back to SKILL.md
1// converts a railpack build plan to a BuildKit LLB state and image config2package buildkit3 4import (5 "fmt"6 "maps"7 "slices"8 "strconv"9 "strings"10 "time"11 12 "github.com/moby/buildkit/client/llb"13 "github.com/moby/buildkit/util/system"14 specs "github.com/opencontainers/image-spec/specs-go/v1"15 "github.com/railwayapp/railpack/buildkit/build_llb"16 p "github.com/railwayapp/railpack/core/plan"17)18 19type ConvertPlanOptions struct {20 BuildPlatform specs.Platform21 22 // Hash of all the secrets values that can be used to invalidate the layer cache when a secret changes23 SecretsHash string24 25 // Unique value prepended to all cache mount keys26 CacheKey string27 28 // BuildKit session ID29 SessionID string30 31 // Token used to make authenticated API requests to GitHub to increase rate limits32 GitHubToken string33 // Do not use cache when building34 NoCache bool35}36 37const WorkingDir = "/app"38 39func ConvertPlanToLLB(plan *p.BuildPlan, opts ConvertPlanOptions) (*llb.State, *Image, error) {40 platform := opts.BuildPlatform41 42 // by default, the whole directory is transferred into context, we don't need to explicitly include it43 localOpts := []llb.LocalOption{44 llb.SharedKeyHint("local"),45 llb.SessionID(opts.SessionID),46 llb.WithCustomName("loading ."),47 }48 49 // note that exclude patterns can contain inverse (inclusions) patterns. The llb.IncludePatterns should *not* be used for this50 if len(plan.Exclude) > 0 {51 localOpts = append(localOpts, llb.ExcludePatterns(plan.Exclude))52 }53 54 localState := llb.Local("context", localOpts...)55 56 cacheStore := build_llb.NewBuildKitCacheStore(opts.CacheKey)57 graph, err := build_llb.NewBuildGraph(plan, &localState, cacheStore, opts.SecretsHash, &platform, opts.GitHubToken, opts.NoCache)58 if err != nil {59 return nil, nil, err60 }61 62 graphOutput, err := graph.GenerateLLB()63 if err != nil {64 return nil, nil, err65 }66 67 state := getStartState(*graphOutput.State)68 imageEnv := getImageEnv(graphOutput, plan)69 70 startCommand := plan.Deploy.StartCmd71 if startCommand == "" {72 startCommand = "/bin/bash"73 }74 75 image := Image{76 Image: specs.Image{77 Platform: specs.Platform{78 OS: platform.OS,79 Architecture: platform.Architecture,80 },81 RootFS: specs.RootFS{82 Type: "layers",83 },84 },85 Variant: platform.Variant,86 Config: specs.ImageConfig{87 Env: imageEnv,88 WorkingDir: WorkingDir,89 Entrypoint: []string{"/bin/bash", "-c"},90 Cmd: []string{startCommand},91 },92 }93 94 return &state, &image, nil95}96 97func getStartState(buildState llb.State) llb.State {98 startState := buildState.Dir(WorkingDir)99 return startState100}101 102func getImageEnv(graphOutput *build_llb.BuildGraphOutput, plan *p.BuildPlan) []string {103 paths := []string{}104 paths = append(paths, plan.Deploy.Paths...)105 paths = append(paths, graphOutput.GraphEnv.PathList...)106 paths = append(paths, system.DefaultPathEnvUnix)107 slices.Sort(paths)108 pathString := strings.Join(paths, ":")109 110 envMap := make(map[string]string, len(graphOutput.GraphEnv.EnvVars)+len(plan.Deploy.Variables)+2)111 maps.Copy(envMap, graphOutput.GraphEnv.EnvVars)112 maps.Copy(envMap, plan.Deploy.Variables)113 114 envMap["PATH"] = pathString115 envMap["RAILPACK_BUILT_AT"] = strconv.FormatInt(time.Now().Unix(), 10)116 117 envVars := make([]string, 0, len(envMap))118 for _, k := range slices.Sorted(maps.Keys(envMap)) {119 v := envMap[k]120 envVars = append(envVars, fmt.Sprintf("%s=%s", k, v))121 }122 123 return envVars124}125