mirror of
https://github.com/hanzoai/pack.git
synced 2026-09-30 23:43:13 +00:00
* rename plan inputs to layers and use deploy base layer * runtime deps installed * step builders can create multiple steps * support config step deploy outputs * optimize when we merge vs copy layers * update snapshots * validate the deploy layers * fix tests * dont add mise if no packages * fix pruning for php * update layer merging and snapshot tests * dont include mise commands or variables if no packages * update docs * update snapshots and normalization * add guide for adding custom steps * support .node-version file * fix compile errors * update snapshot tests
189 lines
4.2 KiB
Go
189 lines
4.2 KiB
Go
package plan
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/invopop/jsonschema"
|
|
)
|
|
|
|
type Layer struct {
|
|
Image string `json:"image,omitempty" jsonschema:"description=The image to use as input"`
|
|
Step string `json:"step,omitempty" jsonschema:"description=The step to use as input"`
|
|
Local bool `json:"local,omitempty" jsonschema:"description=Whether to use local files as input"`
|
|
Spread bool `json:"spread,omitempty" jsonschema:"description=Whether to spread the input"`
|
|
|
|
Filter
|
|
}
|
|
|
|
func NewStepLayer(stepName string, filter ...Filter) Layer {
|
|
input := Layer{
|
|
Step: stepName,
|
|
}
|
|
|
|
if len(filter) > 0 {
|
|
input.Include = filter[0].Include
|
|
input.Exclude = filter[0].Exclude
|
|
}
|
|
|
|
return input
|
|
}
|
|
|
|
func NewImageLayer(image string, filter ...Filter) Layer {
|
|
input := Layer{
|
|
Image: image,
|
|
}
|
|
|
|
if len(filter) > 0 {
|
|
input.Include = filter[0].Include
|
|
input.Exclude = filter[0].Exclude
|
|
}
|
|
|
|
return input
|
|
}
|
|
|
|
func NewLocalLayer(path string) Layer {
|
|
return Layer{
|
|
Local: true,
|
|
Filter: NewIncludeFilter([]string{path}),
|
|
}
|
|
}
|
|
|
|
func (i Layer) IsEmpty() bool {
|
|
return i.Step == "" && i.Image == "" && !i.Local && !i.Spread
|
|
}
|
|
|
|
func (i Layer) IsSpread() bool {
|
|
return i.Spread
|
|
}
|
|
|
|
func (i *Layer) String() string {
|
|
bytes, _ := json.Marshal(i)
|
|
return string(bytes)
|
|
}
|
|
|
|
func (i *Layer) DisplayName() string {
|
|
include := strings.Join(i.Include, ", ")
|
|
|
|
if i.Local {
|
|
return fmt.Sprintf("local %s", include)
|
|
}
|
|
|
|
if i.Spread {
|
|
return fmt.Sprintf("spread %s", include)
|
|
}
|
|
|
|
if i.Step != "" {
|
|
return fmt.Sprintf("$%s", i.Step)
|
|
}
|
|
|
|
if i.Image != "" {
|
|
return i.Image
|
|
}
|
|
|
|
return fmt.Sprintf("input %s", include)
|
|
}
|
|
|
|
func (i *Layer) UnmarshalJSON(data []byte) error {
|
|
// First try normal JSON unmarshal
|
|
type Alias Layer
|
|
aux := &struct {
|
|
*Alias
|
|
}{
|
|
Alias: (*Alias)(i),
|
|
}
|
|
if err := json.Unmarshal(data, &aux); err == nil {
|
|
return nil
|
|
}
|
|
|
|
str := string(data)
|
|
|
|
str = strings.Trim(str, "\"")
|
|
switch str {
|
|
case ".":
|
|
*i = NewLocalLayer(".")
|
|
return nil
|
|
case "...":
|
|
*i = Layer{Spread: true}
|
|
return nil
|
|
default:
|
|
if strings.HasPrefix(str, "$") {
|
|
stepName := strings.TrimPrefix(str, "$")
|
|
*i = NewStepLayer(stepName)
|
|
return nil
|
|
}
|
|
return fmt.Errorf("invalid input format: %s", str)
|
|
}
|
|
}
|
|
|
|
func (Layer) JSONSchema() *jsonschema.Schema {
|
|
// Create common schemas for include/exclude
|
|
includeSchema := &jsonschema.Schema{
|
|
Type: "array",
|
|
Description: "Files or directories to include",
|
|
Items: &jsonschema.Schema{
|
|
Type: "string",
|
|
},
|
|
}
|
|
excludeSchema := &jsonschema.Schema{
|
|
Type: "array",
|
|
Description: "Files or directories to exclude",
|
|
Items: &jsonschema.Schema{
|
|
Type: "string",
|
|
},
|
|
}
|
|
|
|
// Step input schema
|
|
stepSchema := &jsonschema.Schema{
|
|
Type: "object",
|
|
Properties: jsonschema.NewProperties(),
|
|
}
|
|
stepSchema.Properties.Set("step", &jsonschema.Schema{
|
|
Type: "string",
|
|
Description: "The step to use as input",
|
|
})
|
|
stepSchema.Properties.Set("include", includeSchema)
|
|
stepSchema.Properties.Set("exclude", excludeSchema)
|
|
stepSchema.Required = []string{"step"}
|
|
|
|
// Image input schema
|
|
imageSchema := &jsonschema.Schema{
|
|
Type: "object",
|
|
Properties: jsonschema.NewProperties(),
|
|
}
|
|
imageSchema.Properties.Set("image", &jsonschema.Schema{
|
|
Type: "string",
|
|
Description: "The image to use as input",
|
|
})
|
|
imageSchema.Properties.Set("include", includeSchema)
|
|
imageSchema.Properties.Set("exclude", excludeSchema)
|
|
imageSchema.Required = []string{"image"}
|
|
|
|
// Local input schema
|
|
localSchema := &jsonschema.Schema{
|
|
Type: "object",
|
|
Properties: jsonschema.NewProperties(),
|
|
}
|
|
localSchema.Properties.Set("local", &jsonschema.Schema{
|
|
Type: "boolean",
|
|
Description: "Whether to use local files as input",
|
|
})
|
|
localSchema.Properties.Set("include", includeSchema)
|
|
localSchema.Properties.Set("exclude", excludeSchema)
|
|
localSchema.Required = []string{"local"}
|
|
|
|
// String input schema
|
|
stringSchema := &jsonschema.Schema{
|
|
Type: "string",
|
|
Description: "Strings will be parsed and interpreted as an input. Valid formats are: '.', '...', or '$step'",
|
|
Enum: []interface{}{".", "..."},
|
|
}
|
|
|
|
availableInputs := []*jsonschema.Schema{stepSchema, imageSchema, localSchema, stringSchema}
|
|
|
|
return &jsonschema.Schema{
|
|
OneOf: availableInputs,
|
|
}
|
|
}
|