Merge pull request #3898 from crazy-max/compose-go-2.11.0
vendor: update compose-go to v2.11.0
This commit is contained in:
@@ -266,10 +266,6 @@ func loadComposeFiles(cfgs []composetypes.ConfigFile, envs map[string]string, op
|
|||||||
return nil, errors.New("empty compose file")
|
return nil, errors.New("empty compose file")
|
||||||
}
|
}
|
||||||
|
|
||||||
// compose-go schema validation does a JSON round trip that converts nil slices
|
|
||||||
// from YAML [] values into null, so keep empty lists as arrays before validation.
|
|
||||||
// buildx#3849
|
|
||||||
normalizeEmptyLists(filtered)
|
|
||||||
if err := composeschema.Validate(filtered); err != nil {
|
if err := composeschema.Validate(filtered); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -283,23 +279,6 @@ func loadComposeFiles(cfgs []composetypes.ConfigFile, envs map[string]string, op
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func normalizeEmptyLists(value any) any {
|
|
||||||
switch v := value.(type) {
|
|
||||||
case []any:
|
|
||||||
if v == nil {
|
|
||||||
return []any{}
|
|
||||||
}
|
|
||||||
for i, e := range v {
|
|
||||||
v[i] = normalizeEmptyLists(e)
|
|
||||||
}
|
|
||||||
case map[string]any:
|
|
||||||
for k, e := range v {
|
|
||||||
v[k] = normalizeEmptyLists(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateComposeFile(dt []byte, fn string, envOverrides map[string]string) (bool, error) {
|
func validateComposeFile(dt []byte, fn string, envOverrides map[string]string) (bool, error) {
|
||||||
envs, err := composeEnv(envOverrides)
|
envs, err := composeEnv(envOverrides)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ require (
|
|||||||
github.com/Microsoft/go-winio v0.6.2
|
github.com/Microsoft/go-winio v0.6.2
|
||||||
github.com/ProtonMail/go-crypto v1.3.0
|
github.com/ProtonMail/go-crypto v1.3.0
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.32.24
|
github.com/aws/aws-sdk-go-v2/config v1.32.24
|
||||||
github.com/compose-spec/compose-go/v2 v2.10.2
|
github.com/compose-spec/compose-go/v2 v2.11.0
|
||||||
github.com/containerd/console v1.0.5
|
github.com/containerd/console v1.0.5
|
||||||
github.com/containerd/containerd/v2 v2.2.4
|
github.com/containerd/containerd/v2 v2.2.4
|
||||||
github.com/containerd/continuity v0.5.0
|
github.com/containerd/continuity v0.5.0
|
||||||
|
|||||||
@@ -112,8 +112,8 @@ github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg
|
|||||||
github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
|
github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
|
||||||
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE=
|
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE=
|
||||||
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4=
|
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4=
|
||||||
github.com/compose-spec/compose-go/v2 v2.10.2 h1:USa1NUbDcl/cjb8T9iwnuFsnO79H+2ho2L5SjFKz3uI=
|
github.com/compose-spec/compose-go/v2 v2.11.0 h1:xoq/ootgIL6TsHmbJHrkuh7+bzjhPV3NHftHRPPyVXM=
|
||||||
github.com/compose-spec/compose-go/v2 v2.10.2/go.mod h1:ZU6zlcweCZKyiB7BVfCizQT9XmkEIMFE+PRZydVcsZg=
|
github.com/compose-spec/compose-go/v2 v2.11.0/go.mod h1:ZU6zlcweCZKyiB7BVfCizQT9XmkEIMFE+PRZydVcsZg=
|
||||||
github.com/containerd/cgroups/v3 v3.1.3 h1:eUNflyMddm18+yrDmZPn3jI7C5hJ9ahABE5q6dyLYXQ=
|
github.com/containerd/cgroups/v3 v3.1.3 h1:eUNflyMddm18+yrDmZPn3jI7C5hJ9ahABE5q6dyLYXQ=
|
||||||
github.com/containerd/cgroups/v3 v3.1.3/go.mod h1:PKZ2AcWmSBsY/tJUVhtS/rluX0b1uq1GmPO1ElCmbOw=
|
github.com/containerd/cgroups/v3 v3.1.3/go.mod h1:PKZ2AcWmSBsY/tJUVhtS/rluX0b1uq1GmPO1ElCmbOw=
|
||||||
github.com/containerd/console v1.0.5 h1:R0ymNeydRqH2DmakFNdmjR2k0t7UPuiOV/N/27/qqsc=
|
github.com/containerd/console v1.0.5 h1:R0ymNeydRqH2DmakFNdmjR2k0t7UPuiOV/N/27/qqsc=
|
||||||
|
|||||||
+12
-6
@@ -84,6 +84,9 @@ type Options struct {
|
|||||||
KnownExtensions map[string]any
|
KnownExtensions map[string]any
|
||||||
// Metada for telemetry
|
// Metada for telemetry
|
||||||
Listeners []Listener
|
Listeners []Listener
|
||||||
|
// MaxNodeVisits caps total YAML node visits during reset/override resolution.
|
||||||
|
// Zero means use the default. Useful for very large compose files that exceed the default cap.
|
||||||
|
MaxNodeVisits int
|
||||||
}
|
}
|
||||||
|
|
||||||
var versionWarning []string
|
var versionWarning []string
|
||||||
@@ -446,8 +449,10 @@ func loadYamlFile(ctx context.Context,
|
|||||||
|
|
||||||
fixEmptyNotNull(cfg)
|
fixEmptyNotNull(cfg)
|
||||||
|
|
||||||
if !opts.SkipExtends {
|
// Process includes first so that extended services have all merged attributes
|
||||||
err = ApplyExtends(ctx, cfg, opts, ct, processor)
|
if !opts.SkipInclude {
|
||||||
|
included = append(included, file.Filename)
|
||||||
|
err = ApplyInclude(ctx, workingDir, environment, cfg, opts, included, processor)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -457,12 +462,13 @@ func loadYamlFile(ctx context.Context,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !opts.SkipInclude {
|
// Process extends after includes so base services are fully merged
|
||||||
included = append(included, file.Filename)
|
if !opts.SkipExtends {
|
||||||
err = ApplyInclude(ctx, workingDir, environment, cfg, opts, included, processor)
|
err = ApplyExtends(ctx, cfg, opts, ct, processor)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dict, err = override.Merge(dict, cfg)
|
dict, err = override.Merge(dict, cfg)
|
||||||
@@ -503,7 +509,7 @@ func loadYamlFile(ctx context.Context,
|
|||||||
decoder := yaml.NewDecoder(r)
|
decoder := yaml.NewDecoder(r)
|
||||||
for {
|
for {
|
||||||
var raw interface{}
|
var raw interface{}
|
||||||
reset := &ResetProcessor{target: &raw}
|
reset := &ResetProcessor{target: &raw, maxNodeVisits: opts.MaxNodeVisits}
|
||||||
err := decoder.Decode(reset)
|
err := decoder.Decode(reset)
|
||||||
if err != nil && errors.Is(err, io.EOF) {
|
if err != nil && errors.Is(err, io.EOF) {
|
||||||
break
|
break
|
||||||
|
|||||||
+1
-1
@@ -41,7 +41,7 @@ func omitEmpty(data any, p tree.Path) any {
|
|||||||
}
|
}
|
||||||
return v
|
return v
|
||||||
case []any:
|
case []any:
|
||||||
var c []any
|
c := make([]any, 0, len(v))
|
||||||
for _, e := range v {
|
for _, e := range v {
|
||||||
if isEmpty(e) && mustOmit(p) {
|
if isEmpty(e) && mustOmit(p) {
|
||||||
continue
|
continue
|
||||||
|
|||||||
+142
-20
@@ -25,17 +25,38 @@ import (
|
|||||||
"go.yaml.in/yaml/v4"
|
"go.yaml.in/yaml/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// defaultMaxNodeVisits caps total resolveReset calls per document.
|
||||||
|
// Sized to accommodate large real-world compose files while rejecting documents that would
|
||||||
|
// cause unbounded traversal. Callers can override this via Options.MaxNodeVisits.
|
||||||
|
const defaultMaxNodeVisits = 100_000
|
||||||
|
|
||||||
|
// nodeCache stores a resolved node and the relative sub-paths within its subtree that
|
||||||
|
// carried !reset/!override tags, so cache hits at different call sites can replay them.
|
||||||
|
type nodeCache struct {
|
||||||
|
node *yaml.Node
|
||||||
|
relativePaths []tree.Path
|
||||||
|
}
|
||||||
|
|
||||||
type ResetProcessor struct {
|
type ResetProcessor struct {
|
||||||
target interface{}
|
target any
|
||||||
paths []tree.Path
|
paths []tree.Path
|
||||||
visitedNodes map[*yaml.Node][]string
|
visitedNodes map[*yaml.Node][]string
|
||||||
|
resolvedNodes map[*yaml.Node]nodeCache
|
||||||
|
visitCount int
|
||||||
|
// maxNodeVisits is the per-document cap; when zero, defaultMaxNodeVisits is used.
|
||||||
|
maxNodeVisits int
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalYAML implement yaml.Unmarshaler
|
// UnmarshalYAML implement yaml.Unmarshaler
|
||||||
func (p *ResetProcessor) UnmarshalYAML(value *yaml.Node) error {
|
func (p *ResetProcessor) UnmarshalYAML(value *yaml.Node) error {
|
||||||
p.visitedNodes = make(map[*yaml.Node][]string)
|
p.visitedNodes = make(map[*yaml.Node][]string)
|
||||||
|
p.resolvedNodes = make(map[*yaml.Node]nodeCache)
|
||||||
|
p.visitCount = 0
|
||||||
|
defer func() {
|
||||||
|
p.visitedNodes = nil
|
||||||
|
p.resolvedNodes = nil
|
||||||
|
}()
|
||||||
resolved, err := p.resolveReset(value, tree.NewPath())
|
resolved, err := p.resolveReset(value, tree.NewPath())
|
||||||
p.visitedNodes = nil
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -44,21 +65,21 @@ func (p *ResetProcessor) UnmarshalYAML(value *yaml.Node) error {
|
|||||||
|
|
||||||
// resolveReset detects `!reset` tag being set on yaml nodes and record position in the yaml tree
|
// resolveReset detects `!reset` tag being set on yaml nodes and record position in the yaml tree
|
||||||
func (p *ResetProcessor) resolveReset(node *yaml.Node, path tree.Path) (*yaml.Node, error) {
|
func (p *ResetProcessor) resolveReset(node *yaml.Node, path tree.Path) (*yaml.Node, error) {
|
||||||
|
p.visitCount++
|
||||||
|
limit := p.maxNodeVisits
|
||||||
|
if limit <= 0 {
|
||||||
|
limit = defaultMaxNodeVisits
|
||||||
|
}
|
||||||
|
if p.visitCount > limit {
|
||||||
|
return nil, fmt.Errorf("compose file exceeds maximum node visit limit (%d)", limit)
|
||||||
|
}
|
||||||
|
|
||||||
pathStr := path.String()
|
pathStr := path.String()
|
||||||
// If the path contains "<<", removing the "<<" element and merging the path
|
// If the path contains "<<", removing the "<<" element and merging the path
|
||||||
if strings.Contains(pathStr, ".<<") {
|
if strings.Contains(pathStr, ".<<") {
|
||||||
path = tree.NewPath(strings.Replace(pathStr, ".<<", "", 1))
|
path = tree.NewPath(strings.Replace(pathStr, ".<<", "", 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the node is an alias, We need to process the alias field in order to consider the !override and !reset tags
|
|
||||||
if node.Kind == yaml.AliasNode {
|
|
||||||
if err := p.checkForCycle(node.Alias, path); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return p.resolveReset(node.Alias, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
if node.Tag == "!reset" {
|
if node.Tag == "!reset" {
|
||||||
p.paths = append(p.paths, path)
|
p.paths = append(p.paths, path)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -68,7 +89,69 @@ func (p *ResetProcessor) resolveReset(node *yaml.Node, path tree.Path) (*yaml.No
|
|||||||
return node, nil
|
return node, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
keys := map[string]int{}
|
// If the node is an alias, process the alias target via the cache so each anchor is
|
||||||
|
// processed at most once.
|
||||||
|
if node.Kind == yaml.AliasNode {
|
||||||
|
if err := p.checkForCycle(node.Alias, path); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Handle !reset/!override on the alias target before delegating to the cache,
|
||||||
|
// keeping all tag-handling logic in resolveReset rather than split across functions.
|
||||||
|
target := node.Alias
|
||||||
|
if target.Tag == "!reset" {
|
||||||
|
p.paths = append(p.paths, path)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if target.Tag == "!override" {
|
||||||
|
p.paths = append(p.paths, path)
|
||||||
|
return target, nil
|
||||||
|
}
|
||||||
|
return p.cachedResolve(target, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Container nodes are resolved through the cache, ensuring resolved containers are
|
||||||
|
// not re-traversed.
|
||||||
|
if node.Kind == yaml.SequenceNode || node.Kind == yaml.MappingNode {
|
||||||
|
return p.cachedResolve(node, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
return node, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// cachedResolve resolves node (a container without !reset/!override), serving from cache on
|
||||||
|
// repeat visits to prevent re-traversal. It is only called after tag checks are done in
|
||||||
|
// resolveReset, so it never receives !reset/!override-tagged nodes.
|
||||||
|
func (p *ResetProcessor) cachedResolve(node *yaml.Node, path tree.Path) (*yaml.Node, error) {
|
||||||
|
if cached, ok := p.resolvedNodes[node]; ok {
|
||||||
|
for _, rel := range cached.relativePaths {
|
||||||
|
p.paths = append(p.paths, joinPath(path, rel))
|
||||||
|
}
|
||||||
|
return cached.node, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
startIdx := len(p.paths)
|
||||||
|
resolved, err := p.resolveContainer(node, path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var relPaths []tree.Path
|
||||||
|
for _, addedPath := range p.paths[startIdx:] {
|
||||||
|
rel, err := subPath(addedPath, path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
relPaths = append(relPaths, rel)
|
||||||
|
}
|
||||||
|
p.resolvedNodes[node] = nodeCache{node: resolved, relativePaths: relPaths}
|
||||||
|
return resolved, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolveContainer processes the children of a Sequence or Mapping node.
|
||||||
|
// AliasNodes must be kept as-is in the output Content; the resolved value is used only
|
||||||
|
// for tag inspection. Changing this will affect how the YAML library handles the document
|
||||||
|
// during decoding.
|
||||||
|
func (p *ResetProcessor) resolveContainer(node *yaml.Node, path tree.Path) (*yaml.Node, error) {
|
||||||
switch node.Kind {
|
switch node.Kind {
|
||||||
case yaml.SequenceNode:
|
case yaml.SequenceNode:
|
||||||
var nodes []*yaml.Node
|
var nodes []*yaml.Node
|
||||||
@@ -78,12 +161,18 @@ func (p *ResetProcessor) resolveReset(node *yaml.Node, path tree.Path) (*yaml.No
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if resolved != nil {
|
if resolved == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if v.Kind == yaml.AliasNode {
|
||||||
|
nodes = append(nodes, v)
|
||||||
|
} else {
|
||||||
nodes = append(nodes, resolved)
|
nodes = append(nodes, resolved)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
node.Content = nodes
|
node.Content = nodes
|
||||||
case yaml.MappingNode:
|
case yaml.MappingNode:
|
||||||
|
keys := map[string]int{}
|
||||||
var key string
|
var key string
|
||||||
var nodes []*yaml.Node
|
var nodes []*yaml.Node
|
||||||
for idx, v := range node.Content {
|
for idx, v := range node.Content {
|
||||||
@@ -98,7 +187,12 @@ func (p *ResetProcessor) resolveReset(node *yaml.Node, path tree.Path) (*yaml.No
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if resolved != nil {
|
if resolved == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if v.Kind == yaml.AliasNode {
|
||||||
|
nodes = append(nodes, node.Content[idx-1], v)
|
||||||
|
} else {
|
||||||
nodes = append(nodes, node.Content[idx-1], resolved)
|
nodes = append(nodes, node.Content[idx-1], resolved)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,6 +202,38 @@ func (p *ResetProcessor) resolveReset(node *yaml.Node, path tree.Path) (*yaml.No
|
|||||||
return node, nil
|
return node, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// subPath strips base from full to produce a relative path for cache storage.
|
||||||
|
// Returns "" when full == base (the !reset/!override tag is on the node root itself).
|
||||||
|
// Returns an error when full is not rooted at base, which would indicate a logic error
|
||||||
|
// in resolveReset/cachedResolve.
|
||||||
|
func subPath(full, base tree.Path) (tree.Path, error) {
|
||||||
|
if base == "" {
|
||||||
|
return full, nil
|
||||||
|
}
|
||||||
|
fullStr := string(full)
|
||||||
|
baseStr := string(base)
|
||||||
|
if fullStr == baseStr {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
prefix := baseStr + "."
|
||||||
|
if strings.HasPrefix(fullStr, prefix) {
|
||||||
|
return tree.Path(fullStr[len(prefix):]), nil
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("internal error: path %q is not a sub-path of %q", fullStr, baseStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// joinPath reconstructs an absolute path from a call-site base and a cached relative path.
|
||||||
|
// A relative path of "" means the tag was on the node root, so base is returned unchanged.
|
||||||
|
func joinPath(base, rel tree.Path) tree.Path {
|
||||||
|
if rel == "" {
|
||||||
|
return base
|
||||||
|
}
|
||||||
|
if base == "" {
|
||||||
|
return rel
|
||||||
|
}
|
||||||
|
return tree.Path(string(base) + "." + string(rel))
|
||||||
|
}
|
||||||
|
|
||||||
// Apply finds the go attributes matching recorded paths and reset them to zero value
|
// Apply finds the go attributes matching recorded paths and reset them to zero value
|
||||||
func (p *ResetProcessor) Apply(target any) error {
|
func (p *ResetProcessor) Apply(target any) error {
|
||||||
return p.applyNullOverrides(target, tree.NewPath())
|
return p.applyNullOverrides(target, tree.NewPath())
|
||||||
@@ -180,15 +306,11 @@ func (p *ResetProcessor) checkForCycle(node *yaml.Node, path tree.Path) error {
|
|||||||
|
|
||||||
// areInDifferentServices checks if two paths are in different service definitions
|
// areInDifferentServices checks if two paths are in different service definitions
|
||||||
func areInDifferentServices(path1, path2 string) bool {
|
func areInDifferentServices(path1, path2 string) bool {
|
||||||
// Split paths into components
|
|
||||||
parts1 := strings.Split(path1, ".")
|
parts1 := strings.Split(path1, ".")
|
||||||
parts2 := strings.Split(path2, ".")
|
parts2 := strings.Split(path2, ".")
|
||||||
|
|
||||||
// Look for the services component and compare the service names
|
|
||||||
for i := 0; i < len(parts1) && i < len(parts2); i++ {
|
for i := 0; i < len(parts1) && i < len(parts2); i++ {
|
||||||
if parts1[i] == "services" && i+1 < len(parts1) &&
|
if parts1[i] == "services" && i+1 < len(parts1) &&
|
||||||
parts2[i] == "services" && i+1 < len(parts2) {
|
parts2[i] == "services" && i+1 < len(parts2) {
|
||||||
// If they're different services, it's not a cycle
|
|
||||||
return parts1[i+1] != parts2[i+1]
|
return parts1[i+1] != parts2[i+1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+72
-72
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json-schema.org/draft-07/schema",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"$id": "compose_spec.json",
|
"$id": "compose_spec.json",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"title": "Compose Specification",
|
"title": "Compose Specification",
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
"include": {
|
"include": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/definitions/include"
|
"$ref": "#/$defs/include"
|
||||||
},
|
},
|
||||||
"description": "compose sub-projects to be included."
|
"description": "compose sub-projects to be included."
|
||||||
},
|
},
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"patternProperties": {
|
"patternProperties": {
|
||||||
"^[a-zA-Z0-9._-]+$": {
|
"^[a-zA-Z0-9._-]+$": {
|
||||||
"$ref": "#/definitions/service"
|
"$ref": "#/$defs/service"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"patternProperties": {
|
"patternProperties": {
|
||||||
"^[a-zA-Z0-9._-]+$": {
|
"^[a-zA-Z0-9._-]+$": {
|
||||||
"$ref": "#/definitions/model"
|
"$ref": "#/$defs/model"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "Language models that will be used by your application."
|
"description": "Language models that will be used by your application."
|
||||||
@@ -51,7 +51,7 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"patternProperties": {
|
"patternProperties": {
|
||||||
"^[a-zA-Z0-9._-]+$": {
|
"^[a-zA-Z0-9._-]+$": {
|
||||||
"$ref": "#/definitions/network"
|
"$ref": "#/$defs/network"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "Networks that are shared among multiple services."
|
"description": "Networks that are shared among multiple services."
|
||||||
@@ -61,7 +61,7 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"patternProperties": {
|
"patternProperties": {
|
||||||
"^[a-zA-Z0-9._-]+$": {
|
"^[a-zA-Z0-9._-]+$": {
|
||||||
"$ref": "#/definitions/volume"
|
"$ref": "#/$defs/volume"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"patternProperties": {
|
"patternProperties": {
|
||||||
"^[a-zA-Z0-9._-]+$": {
|
"^[a-zA-Z0-9._-]+$": {
|
||||||
"$ref": "#/definitions/secret"
|
"$ref": "#/$defs/secret"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
@@ -83,7 +83,7 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"patternProperties": {
|
"patternProperties": {
|
||||||
"^[a-zA-Z0-9._-]+$": {
|
"^[a-zA-Z0-9._-]+$": {
|
||||||
"$ref": "#/definitions/config"
|
"$ref": "#/$defs/config"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
@@ -94,15 +94,15 @@
|
|||||||
"patternProperties": {"^x-": {}},
|
"patternProperties": {"^x-": {}},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
|
|
||||||
"definitions": {
|
"$defs": {
|
||||||
|
|
||||||
"service": {
|
"service": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "Configuration for a service.",
|
"description": "Configuration for a service.",
|
||||||
"properties": {
|
"properties": {
|
||||||
"develop": {"$ref": "#/definitions/development"},
|
"develop": {"$ref": "#/$defs/development"},
|
||||||
"deploy": {"$ref": "#/definitions/deployment"},
|
"deploy": {"$ref": "#/$defs/deployment"},
|
||||||
"annotations": {"$ref": "#/definitions/list_or_dict"},
|
"annotations": {"$ref": "#/$defs/list_or_dict"},
|
||||||
"attach": {"type": ["boolean", "string"]},
|
"attach": {"type": ["boolean", "string"]},
|
||||||
"build": {
|
"build": {
|
||||||
"description": "Configuration options for building the service's image.",
|
"description": "Configuration options for building the service's image.",
|
||||||
@@ -115,26 +115,26 @@
|
|||||||
"dockerfile": {"type": "string", "description": "Name of the Dockerfile to use for building the image."},
|
"dockerfile": {"type": "string", "description": "Name of the Dockerfile to use for building the image."},
|
||||||
"dockerfile_inline": {"type": "string", "description": "Inline Dockerfile content to use instead of a Dockerfile from the build context."},
|
"dockerfile_inline": {"type": "string", "description": "Inline Dockerfile content to use instead of a Dockerfile from the build context."},
|
||||||
"entitlements": {"type": "array", "items": {"type": "string"}, "description": "List of extra privileged entitlements to grant to the build process."},
|
"entitlements": {"type": "array", "items": {"type": "string"}, "description": "List of extra privileged entitlements to grant to the build process."},
|
||||||
"args": {"$ref": "#/definitions/list_or_dict", "description": "Build-time variables, specified as a map or a list of KEY=VAL pairs."},
|
"args": {"$ref": "#/$defs/list_or_dict", "description": "Build-time variables, specified as a map or a list of KEY=VAL pairs."},
|
||||||
"ssh": {"$ref": "#/definitions/list_or_dict", "description": "SSH agent socket or keys to expose to the build. Format is either a string or a list of 'default|<id>[=<socket>|<key>[,<key>]]'."},
|
"ssh": {"$ref": "#/$defs/list_or_dict", "description": "SSH agent socket or keys to expose to the build. Format is either a string or a list of 'default|<id>[=<socket>|<key>[,<key>]]'."},
|
||||||
"labels": {"$ref": "#/definitions/list_or_dict", "description": "Labels to apply to the built image."},
|
"labels": {"$ref": "#/$defs/list_or_dict", "description": "Labels to apply to the built image."},
|
||||||
"cache_from": {"type": "array", "items": {"type": "string"}, "description": "List of sources the image builder should use for cache resolution"},
|
"cache_from": {"type": "array", "items": {"type": "string"}, "description": "List of sources the image builder should use for cache resolution"},
|
||||||
"cache_to": {"type": "array", "items": {"type": "string"}, "description": "Cache destinations for the build cache."},
|
"cache_to": {"type": "array", "items": {"type": "string"}, "description": "Cache destinations for the build cache."},
|
||||||
"no_cache": {"type": ["boolean", "string"], "description": "Do not use cache when building the image."},
|
"no_cache": {"type": ["boolean", "string"], "description": "Do not use cache when building the image."},
|
||||||
"no_cache_filter": {"$ref": "#/definitions/string_or_list", "description": "Do not use build cache for the specified stages."},
|
"no_cache_filter": {"$ref": "#/$defs/string_or_list", "description": "Do not use build cache for the specified stages."},
|
||||||
"additional_contexts": {"$ref": "#/definitions/list_or_dict", "description": "Additional build contexts to use, specified as a map of name to context path or URL."},
|
"additional_contexts": {"$ref": "#/$defs/list_or_dict", "description": "Additional build contexts to use, specified as a map of name to context path or URL."},
|
||||||
"network": {"type": "string", "description": "Network mode to use for the build. Options include 'default', 'none', 'host', or a network name."},
|
"network": {"type": "string", "description": "Network mode to use for the build. Options include 'default', 'none', 'host', or a network name."},
|
||||||
"provenance": {"type": ["string","boolean"], "description": "Add a provenance attestation"},
|
"provenance": {"type": ["string","boolean"], "description": "Add a provenance attestation"},
|
||||||
"sbom": {"type": ["string","boolean"], "description": "Add a SBOM attestation"},
|
"sbom": {"type": ["string","boolean"], "description": "Add a SBOM attestation"},
|
||||||
"pull": {"type": ["boolean", "string"], "description": "Always attempt to pull a newer version of the image."},
|
"pull": {"type": ["boolean", "string"], "description": "Always attempt to pull a newer version of the image."},
|
||||||
"target": {"type": "string", "description": "Build stage to target in a multi-stage Dockerfile."},
|
"target": {"type": "string", "description": "Build stage to target in a multi-stage Dockerfile."},
|
||||||
"shm_size": {"type": ["integer", "string"], "description": "Size of /dev/shm for the build container. A string value can use suffix like '2g' for 2 gigabytes."},
|
"shm_size": {"type": ["integer", "string"], "description": "Size of /dev/shm for the build container. A string value can use suffix like '2g' for 2 gigabytes."},
|
||||||
"extra_hosts": {"$ref": "#/definitions/extra_hosts", "description": "Add hostname mappings for the build container."},
|
"extra_hosts": {"$ref": "#/$defs/extra_hosts", "description": "Add hostname mappings for the build container."},
|
||||||
"isolation": {"type": "string", "description": "Container isolation technology to use for the build process."},
|
"isolation": {"type": "string", "description": "Container isolation technology to use for the build process."},
|
||||||
"privileged": {"type": ["boolean", "string"], "description": "Give extended privileges to the build container."},
|
"privileged": {"type": ["boolean", "string"], "description": "Give extended privileges to the build container."},
|
||||||
"secrets": {"$ref": "#/definitions/service_config_or_secret", "description": "Secrets to expose to the build. These are accessible at build-time."},
|
"secrets": {"$ref": "#/$defs/service_config_or_secret", "description": "Secrets to expose to the build. These are accessible at build-time."},
|
||||||
"tags": {"type": "array", "items": {"type": "string"}, "description": "Additional tags to apply to the built image."},
|
"tags": {"type": "array", "items": {"type": "string"}, "description": "Additional tags to apply to the built image."},
|
||||||
"ulimits": {"$ref": "#/definitions/ulimits", "description": "Override the default ulimits for the build container."},
|
"ulimits": {"$ref": "#/$defs/ulimits", "description": "Override the default ulimits for the build container."},
|
||||||
"platforms": {"type": "array", "items": {"type": "string"}, "description": "Platforms to build for, e.g., 'linux/amd64', 'linux/arm64', or 'windows/amd64'."}
|
"platforms": {"type": "array", "items": {"type": "string"}, "description": "Platforms to build for, e.g., 'linux/amd64', 'linux/arm64', or 'windows/amd64'."}
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
@@ -149,22 +149,22 @@
|
|||||||
"device_read_bps": {
|
"device_read_bps": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"description": "Limit read rate (bytes per second) from a device.",
|
"description": "Limit read rate (bytes per second) from a device.",
|
||||||
"items": {"$ref": "#/definitions/blkio_limit"}
|
"items": {"$ref": "#/$defs/blkio_limit"}
|
||||||
},
|
},
|
||||||
"device_read_iops": {
|
"device_read_iops": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"description": "Limit read rate (IO per second) from a device.",
|
"description": "Limit read rate (IO per second) from a device.",
|
||||||
"items": {"$ref": "#/definitions/blkio_limit"}
|
"items": {"$ref": "#/$defs/blkio_limit"}
|
||||||
},
|
},
|
||||||
"device_write_bps": {
|
"device_write_bps": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"description": "Limit write rate (bytes per second) to a device.",
|
"description": "Limit write rate (bytes per second) to a device.",
|
||||||
"items": {"$ref": "#/definitions/blkio_limit"}
|
"items": {"$ref": "#/$defs/blkio_limit"}
|
||||||
},
|
},
|
||||||
"device_write_iops": {
|
"device_write_iops": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"description": "Limit write rate (IO per second) to a device.",
|
"description": "Limit write rate (IO per second) to a device.",
|
||||||
"items": {"$ref": "#/definitions/blkio_limit"}
|
"items": {"$ref": "#/$defs/blkio_limit"}
|
||||||
},
|
},
|
||||||
"weight": {
|
"weight": {
|
||||||
"type": ["integer", "string"],
|
"type": ["integer", "string"],
|
||||||
@@ -173,7 +173,7 @@
|
|||||||
"weight_device": {
|
"weight_device": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"description": "Block IO weight (relative weight) for specific devices.",
|
"description": "Block IO weight (relative weight) for specific devices.",
|
||||||
"items": {"$ref": "#/definitions/blkio_weight"}
|
"items": {"$ref": "#/$defs/blkio_weight"}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
@@ -200,11 +200,11 @@
|
|||||||
"description": "Specify an optional parent cgroup for the container."
|
"description": "Specify an optional parent cgroup for the container."
|
||||||
},
|
},
|
||||||
"command": {
|
"command": {
|
||||||
"$ref": "#/definitions/command",
|
"$ref": "#/$defs/command",
|
||||||
"description": "Override the default command declared by the container image, for example 'CMD' in Dockerfile."
|
"description": "Override the default command declared by the container image, for example 'CMD' in Dockerfile."
|
||||||
},
|
},
|
||||||
"configs": {
|
"configs": {
|
||||||
"$ref": "#/definitions/service_config_or_secret",
|
"$ref": "#/$defs/service_config_or_secret",
|
||||||
"description": "Grant access to Configs on a per-service basis."
|
"description": "Grant access to Configs on a per-service basis."
|
||||||
},
|
},
|
||||||
"container_name": {
|
"container_name": {
|
||||||
@@ -276,7 +276,7 @@
|
|||||||
},
|
},
|
||||||
"depends_on": {
|
"depends_on": {
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{"$ref": "#/definitions/list_of_strings"},
|
{"$ref": "#/$defs/list_of_strings"},
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
@@ -309,7 +309,7 @@
|
|||||||
"description": "Express dependency between services. Service dependencies cause services to be started in dependency order. The dependent service will wait for the dependency to be ready before starting."
|
"description": "Express dependency between services. Service dependencies cause services to be started in dependency order. The dependent service will wait for the dependency to be ready before starting."
|
||||||
},
|
},
|
||||||
"device_cgroup_rules": {
|
"device_cgroup_rules": {
|
||||||
"$ref": "#/definitions/list_of_strings",
|
"$ref": "#/$defs/list_of_strings",
|
||||||
"description": "Add rules to the cgroup allowed devices list."
|
"description": "Add rules to the cgroup allowed devices list."
|
||||||
},
|
},
|
||||||
"devices": {
|
"devices": {
|
||||||
@@ -342,7 +342,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dns": {
|
"dns": {
|
||||||
"$ref": "#/definitions/string_or_list",
|
"$ref": "#/$defs/string_or_list",
|
||||||
"description": "Custom DNS servers to set for the service container."
|
"description": "Custom DNS servers to set for the service container."
|
||||||
},
|
},
|
||||||
"dns_opt": {
|
"dns_opt": {
|
||||||
@@ -352,7 +352,7 @@
|
|||||||
"description": "Custom DNS options to be passed to the container's DNS resolver."
|
"description": "Custom DNS options to be passed to the container's DNS resolver."
|
||||||
},
|
},
|
||||||
"dns_search": {
|
"dns_search": {
|
||||||
"$ref": "#/definitions/string_or_list",
|
"$ref": "#/$defs/string_or_list",
|
||||||
"description": "Custom DNS search domains to set on the service container."
|
"description": "Custom DNS search domains to set on the service container."
|
||||||
},
|
},
|
||||||
"domainname": {
|
"domainname": {
|
||||||
@@ -360,19 +360,19 @@
|
|||||||
"description": "Custom domain name to use for the service container."
|
"description": "Custom domain name to use for the service container."
|
||||||
},
|
},
|
||||||
"entrypoint": {
|
"entrypoint": {
|
||||||
"$ref": "#/definitions/command",
|
"$ref": "#/$defs/command",
|
||||||
"description": "Override the default entrypoint declared by the container image, for example 'ENTRYPOINT' in Dockerfile."
|
"description": "Override the default entrypoint declared by the container image, for example 'ENTRYPOINT' in Dockerfile."
|
||||||
},
|
},
|
||||||
"env_file": {
|
"env_file": {
|
||||||
"$ref": "#/definitions/env_file",
|
"$ref": "#/$defs/env_file",
|
||||||
"description": "Add environment variables from a file or multiple files. Can be a single file path or a list of file paths."
|
"description": "Add environment variables from a file or multiple files. Can be a single file path or a list of file paths."
|
||||||
},
|
},
|
||||||
"label_file": {
|
"label_file": {
|
||||||
"$ref": "#/definitions/label_file",
|
"$ref": "#/$defs/label_file",
|
||||||
"description": "Add metadata to containers using files containing Docker labels."
|
"description": "Add metadata to containers using files containing Docker labels."
|
||||||
},
|
},
|
||||||
"environment": {
|
"environment": {
|
||||||
"$ref": "#/definitions/list_or_dict",
|
"$ref": "#/$defs/list_or_dict",
|
||||||
"description": "Add environment variables. You can use either an array or a list of KEY=VAL pairs."
|
"description": "Add environment variables. You can use either an array or a list of KEY=VAL pairs."
|
||||||
},
|
},
|
||||||
"expose": {
|
"expose": {
|
||||||
@@ -434,11 +434,11 @@
|
|||||||
"description": "Link to services started outside this Compose application. Specify services as <service_name>:<alias>."
|
"description": "Link to services started outside this Compose application. Specify services as <service_name>:<alias>."
|
||||||
},
|
},
|
||||||
"extra_hosts": {
|
"extra_hosts": {
|
||||||
"$ref": "#/definitions/extra_hosts",
|
"$ref": "#/$defs/extra_hosts",
|
||||||
"description": "Add hostname mappings to the container network interface configuration."
|
"description": "Add hostname mappings to the container network interface configuration."
|
||||||
},
|
},
|
||||||
"gpus": {
|
"gpus": {
|
||||||
"$ref": "#/definitions/gpus",
|
"$ref": "#/$defs/gpus",
|
||||||
"description": "Define GPU devices to use. Can be set to 'all' to use all GPUs, or a list of specific GPU devices."
|
"description": "Define GPU devices to use. Can be set to 'all' to use all GPUs, or a list of specific GPU devices."
|
||||||
},
|
},
|
||||||
"group_add": {
|
"group_add": {
|
||||||
@@ -450,7 +450,7 @@
|
|||||||
"description": "Add additional groups which user inside the container should be member of."
|
"description": "Add additional groups which user inside the container should be member of."
|
||||||
},
|
},
|
||||||
"healthcheck": {
|
"healthcheck": {
|
||||||
"$ref": "#/definitions/healthcheck",
|
"$ref": "#/$defs/healthcheck",
|
||||||
"description": "Configure a health check for the container to monitor its health status."
|
"description": "Configure a health check for the container to monitor its health status."
|
||||||
},
|
},
|
||||||
"hostname": {
|
"hostname": {
|
||||||
@@ -474,7 +474,7 @@
|
|||||||
"description": "Container isolation technology to use. Supported values are platform-specific."
|
"description": "Container isolation technology to use. Supported values are platform-specific."
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"$ref": "#/definitions/list_or_dict",
|
"$ref": "#/$defs/list_or_dict",
|
||||||
"description": "Add metadata to containers using Docker labels. You can use either an array or a list."
|
"description": "Add metadata to containers using Docker labels. You can use either an array or a list."
|
||||||
},
|
},
|
||||||
"links": {
|
"links": {
|
||||||
@@ -528,7 +528,7 @@
|
|||||||
},
|
},
|
||||||
"models": {
|
"models": {
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{"$ref": "#/definitions/list_of_strings"},
|
{"$ref": "#/$defs/list_of_strings"},
|
||||||
{"type": "object",
|
{"type": "object",
|
||||||
"patternProperties": {
|
"patternProperties": {
|
||||||
"^[a-zA-Z0-9._-]+$": {
|
"^[a-zA-Z0-9._-]+$": {
|
||||||
@@ -558,7 +558,7 @@
|
|||||||
},
|
},
|
||||||
"networks": {
|
"networks": {
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{"$ref": "#/definitions/list_of_strings"},
|
{"$ref": "#/$defs/list_of_strings"},
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"patternProperties": {
|
"patternProperties": {
|
||||||
@@ -568,7 +568,7 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"aliases": {
|
"aliases": {
|
||||||
"$ref": "#/definitions/list_of_strings",
|
"$ref": "#/$defs/list_of_strings",
|
||||||
"description": "Alternative hostnames for this service on the network."
|
"description": "Alternative hostnames for this service on the network."
|
||||||
},
|
},
|
||||||
"interface_name": {
|
"interface_name": {
|
||||||
@@ -584,7 +584,7 @@
|
|||||||
"description": "Specify a static IPv6 address for this service on this network."
|
"description": "Specify a static IPv6 address for this service on this network."
|
||||||
},
|
},
|
||||||
"link_local_ips": {
|
"link_local_ips": {
|
||||||
"$ref": "#/definitions/list_of_strings",
|
"$ref": "#/$defs/list_of_strings",
|
||||||
"description": "List of link-local IPs."
|
"description": "List of link-local IPs."
|
||||||
},
|
},
|
||||||
"mac_address": {
|
"mac_address": {
|
||||||
@@ -690,12 +690,12 @@
|
|||||||
},
|
},
|
||||||
"post_start": {
|
"post_start": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {"$ref": "#/definitions/service_hook"},
|
"items": {"$ref": "#/$defs/service_hook"},
|
||||||
"description": "Commands to run after the container starts. If any command fails, the container stops."
|
"description": "Commands to run after the container starts. If any command fails, the container stops."
|
||||||
},
|
},
|
||||||
"pre_stop": {
|
"pre_stop": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {"$ref": "#/definitions/service_hook"},
|
"items": {"$ref": "#/$defs/service_hook"},
|
||||||
"description": "Commands to run before the container stops. If any command fails, the container stop is aborted."
|
"description": "Commands to run before the container stops. If any command fails, the container stop is aborted."
|
||||||
},
|
},
|
||||||
"privileged": {
|
"privileged": {
|
||||||
@@ -703,7 +703,7 @@
|
|||||||
"description": "Give extended privileges to the service container."
|
"description": "Give extended privileges to the service container."
|
||||||
},
|
},
|
||||||
"profiles": {
|
"profiles": {
|
||||||
"$ref": "#/definitions/list_of_strings",
|
"$ref": "#/$defs/list_of_strings",
|
||||||
"description": "List of profiles for this service. When profiles are specified, services are only started when the profile is activated."
|
"description": "List of profiles for this service. When profiles are specified, services are only started when the profile is activated."
|
||||||
},
|
},
|
||||||
"pull_policy": {
|
"pull_policy": {
|
||||||
@@ -742,11 +742,11 @@
|
|||||||
"description": "Size of /dev/shm. A string value can use suffix like '2g' for 2 gigabytes."
|
"description": "Size of /dev/shm. A string value can use suffix like '2g' for 2 gigabytes."
|
||||||
},
|
},
|
||||||
"secrets": {
|
"secrets": {
|
||||||
"$ref": "#/definitions/service_config_or_secret",
|
"$ref": "#/$defs/service_config_or_secret",
|
||||||
"description": "Grant access to Secrets on a per-service basis."
|
"description": "Grant access to Secrets on a per-service basis."
|
||||||
},
|
},
|
||||||
"sysctls": {
|
"sysctls": {
|
||||||
"$ref": "#/definitions/list_or_dict",
|
"$ref": "#/$defs/list_or_dict",
|
||||||
"description": "Kernel parameters to set in the container. You can use either an array or a list."
|
"description": "Kernel parameters to set in the container. You can use either an array or a list."
|
||||||
},
|
},
|
||||||
"stdin_open": {
|
"stdin_open": {
|
||||||
@@ -766,7 +766,7 @@
|
|||||||
"description": "Storage driver options for the container."
|
"description": "Storage driver options for the container."
|
||||||
},
|
},
|
||||||
"tmpfs": {
|
"tmpfs": {
|
||||||
"$ref": "#/definitions/string_or_list",
|
"$ref": "#/$defs/string_or_list",
|
||||||
"description": "Mount a temporary filesystem (tmpfs) into the container. Can be a single value or a list."
|
"description": "Mount a temporary filesystem (tmpfs) into the container. Can be a single value or a list."
|
||||||
},
|
},
|
||||||
"tty": {
|
"tty": {
|
||||||
@@ -774,7 +774,7 @@
|
|||||||
"description": "Allocate a pseudo-TTY to service container."
|
"description": "Allocate a pseudo-TTY to service container."
|
||||||
},
|
},
|
||||||
"ulimits": {
|
"ulimits": {
|
||||||
"$ref": "#/definitions/ulimits",
|
"$ref": "#/$defs/ulimits",
|
||||||
"description": "Override the default ulimits for a container."
|
"description": "Override the default ulimits for a container."
|
||||||
},
|
},
|
||||||
"use_api_socket": {
|
"use_api_socket": {
|
||||||
@@ -855,7 +855,7 @@
|
|||||||
"description": "Configuration specific to volume mounts.",
|
"description": "Configuration specific to volume mounts.",
|
||||||
"properties": {
|
"properties": {
|
||||||
"labels": {
|
"labels": {
|
||||||
"$ref": "#/definitions/list_or_dict",
|
"$ref": "#/$defs/list_or_dict",
|
||||||
"description": "Labels to apply to the volume."
|
"description": "Labels to apply to the volume."
|
||||||
},
|
},
|
||||||
"nocopy": {
|
"nocopy": {
|
||||||
@@ -975,11 +975,11 @@
|
|||||||
"required": ["path", "action"],
|
"required": ["path", "action"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"ignore": {
|
"ignore": {
|
||||||
"$ref": "#/definitions/string_or_list",
|
"$ref": "#/$defs/string_or_list",
|
||||||
"description": "Patterns to exclude from watching."
|
"description": "Patterns to exclude from watching."
|
||||||
},
|
},
|
||||||
"include": {
|
"include": {
|
||||||
"$ref": "#/definitions/string_or_list",
|
"$ref": "#/$defs/string_or_list",
|
||||||
"description": "Patterns to include in watching."
|
"description": "Patterns to include in watching."
|
||||||
},
|
},
|
||||||
"path": {
|
"path": {
|
||||||
@@ -996,7 +996,7 @@
|
|||||||
"description": "Target path in the container for sync operations."
|
"description": "Target path in the container for sync operations."
|
||||||
},
|
},
|
||||||
"exec": {
|
"exec": {
|
||||||
"$ref": "#/definitions/service_hook",
|
"$ref": "#/$defs/service_hook",
|
||||||
"description": "Command to execute when a change is detected and action is sync+exec."
|
"description": "Command to execute when a change is detected and action is sync+exec."
|
||||||
},
|
},
|
||||||
"initial_sync": {
|
"initial_sync": {
|
||||||
@@ -1029,7 +1029,7 @@
|
|||||||
"description": "Number of replicas of the service container to run."
|
"description": "Number of replicas of the service container to run."
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"$ref": "#/definitions/list_or_dict",
|
"$ref": "#/$defs/list_or_dict",
|
||||||
"description": "Labels to apply to the service."
|
"description": "Labels to apply to the service."
|
||||||
},
|
},
|
||||||
"rollback_config": {
|
"rollback_config": {
|
||||||
@@ -1135,11 +1135,11 @@
|
|||||||
"description": "Reservation on the amount of memory a container can allocate (e.g., '1g', '1024m')."
|
"description": "Reservation on the amount of memory a container can allocate (e.g., '1g', '1024m')."
|
||||||
},
|
},
|
||||||
"generic_resources": {
|
"generic_resources": {
|
||||||
"$ref": "#/definitions/generic_resources",
|
"$ref": "#/$defs/generic_resources",
|
||||||
"description": "User-defined resources to reserve."
|
"description": "User-defined resources to reserve."
|
||||||
},
|
},
|
||||||
"devices": {
|
"devices": {
|
||||||
"$ref": "#/definitions/devices",
|
"$ref": "#/$defs/devices",
|
||||||
"description": "Device reservations for the container."
|
"description": "Device reservations for the container."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1246,7 +1246,7 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"capabilities": {
|
"capabilities": {
|
||||||
"$ref": "#/definitions/list_of_strings",
|
"$ref": "#/$defs/list_of_strings",
|
||||||
"description": "List of capabilities the device needs to have (e.g., 'gpu', 'compute', 'utility')."
|
"description": "List of capabilities the device needs to have (e.g., 'gpu', 'compute', 'utility')."
|
||||||
},
|
},
|
||||||
"count": {
|
"count": {
|
||||||
@@ -1254,7 +1254,7 @@
|
|||||||
"description": "Number of devices of this type to reserve."
|
"description": "Number of devices of this type to reserve."
|
||||||
},
|
},
|
||||||
"device_ids": {
|
"device_ids": {
|
||||||
"$ref": "#/definitions/list_of_strings",
|
"$ref": "#/$defs/list_of_strings",
|
||||||
"description": "List of specific device IDs to reserve."
|
"description": "List of specific device IDs to reserve."
|
||||||
},
|
},
|
||||||
"driver": {
|
"driver": {
|
||||||
@@ -1262,7 +1262,7 @@
|
|||||||
"description": "Device driver to use (e.g., 'nvidia')."
|
"description": "Device driver to use (e.g., 'nvidia')."
|
||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"$ref": "#/definitions/list_or_dict",
|
"$ref": "#/$defs/list_or_dict",
|
||||||
"description": "Driver-specific options for the device."
|
"description": "Driver-specific options for the device."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1288,7 +1288,7 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"capabilities": {
|
"capabilities": {
|
||||||
"$ref": "#/definitions/list_of_strings",
|
"$ref": "#/$defs/list_of_strings",
|
||||||
"description": "List of capabilities the GPU needs to have (e.g., 'compute', 'utility')."
|
"description": "List of capabilities the GPU needs to have (e.g., 'compute', 'utility')."
|
||||||
},
|
},
|
||||||
"count": {
|
"count": {
|
||||||
@@ -1296,7 +1296,7 @@
|
|||||||
"description": "Number of GPUs to use."
|
"description": "Number of GPUs to use."
|
||||||
},
|
},
|
||||||
"device_ids": {
|
"device_ids": {
|
||||||
"$ref": "#/definitions/list_of_strings",
|
"$ref": "#/$defs/list_of_strings",
|
||||||
"description": "List of specific GPU device IDs to use."
|
"description": "List of specific GPU device IDs to use."
|
||||||
},
|
},
|
||||||
"driver": {
|
"driver": {
|
||||||
@@ -1304,7 +1304,7 @@
|
|||||||
"description": "GPU driver to use (e.g., 'nvidia')."
|
"description": "GPU driver to use (e.g., 'nvidia')."
|
||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"$ref": "#/definitions/list_or_dict",
|
"$ref": "#/$defs/list_or_dict",
|
||||||
"description": "Driver-specific options for the GPU."
|
"description": "Driver-specific options for the GPU."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1323,11 +1323,11 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"path": {
|
"path": {
|
||||||
"$ref": "#/definitions/string_or_list",
|
"$ref": "#/$defs/string_or_list",
|
||||||
"description": "Path to the Compose application or sub-project files to include."
|
"description": "Path to the Compose application or sub-project files to include."
|
||||||
},
|
},
|
||||||
"env_file": {
|
"env_file": {
|
||||||
"$ref": "#/definitions/string_or_list",
|
"$ref": "#/$defs/string_or_list",
|
||||||
"description": "Path to the environment files to use to define default values when interpolating variables in the Compose files being parsed."
|
"description": "Path to the environment files to use to define default values when interpolating variables in the Compose files being parsed."
|
||||||
},
|
},
|
||||||
"project_directory": {
|
"project_directory": {
|
||||||
@@ -1436,7 +1436,7 @@
|
|||||||
"description": "If true, standalone containers can attach to this network."
|
"description": "If true, standalone containers can attach to this network."
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"$ref": "#/definitions/list_or_dict",
|
"$ref": "#/$defs/list_or_dict",
|
||||||
"description": "Add metadata to the network using labels."
|
"description": "Add metadata to the network using labels."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1477,7 +1477,7 @@
|
|||||||
"patternProperties": {"^x-": {}}
|
"patternProperties": {"^x-": {}}
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"$ref": "#/definitions/list_or_dict",
|
"$ref": "#/$defs/list_or_dict",
|
||||||
"description": "Add metadata to the volume using labels."
|
"description": "Add metadata to the volume using labels."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1512,7 +1512,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"$ref": "#/definitions/list_or_dict",
|
"$ref": "#/$defs/list_or_dict",
|
||||||
"description": "Add metadata to the secret using labels."
|
"description": "Add metadata to the secret using labels."
|
||||||
},
|
},
|
||||||
"driver": {
|
"driver": {
|
||||||
@@ -1567,7 +1567,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"$ref": "#/definitions/list_or_dict",
|
"$ref": "#/$defs/list_or_dict",
|
||||||
"description": "Add metadata to the config using labels."
|
"description": "Add metadata to the config using labels."
|
||||||
},
|
},
|
||||||
"template_driver": {
|
"template_driver": {
|
||||||
@@ -1632,7 +1632,7 @@
|
|||||||
"description": "Configuration for service lifecycle hooks, which are commands executed at specific points in a container's lifecycle.",
|
"description": "Configuration for service lifecycle hooks, which are commands executed at specific points in a container's lifecycle.",
|
||||||
"properties": {
|
"properties": {
|
||||||
"command": {
|
"command": {
|
||||||
"$ref": "#/definitions/command",
|
"$ref": "#/$defs/command",
|
||||||
"description": "Command to execute as part of the hook."
|
"description": "Command to execute as part of the hook."
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
@@ -1648,7 +1648,7 @@
|
|||||||
"description": "Working directory for the command."
|
"description": "Working directory for the command."
|
||||||
},
|
},
|
||||||
"environment": {
|
"environment": {
|
||||||
"$ref": "#/definitions/list_or_dict",
|
"$ref": "#/$defs/list_or_dict",
|
||||||
"description": "Environment variables for the command."
|
"description": "Environment variables for the command."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1725,7 +1725,7 @@
|
|||||||
"description": "A single string value."
|
"description": "A single string value."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$ref": "#/definitions/list_of_strings",
|
"$ref": "#/$defs/list_of_strings",
|
||||||
"description": "A list of string values."
|
"description": "A list of string values."
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
+45
-3
@@ -17,9 +17,12 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
|
"go.yaml.in/yaml/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
// UnitBytes is the bytes type
|
// UnitBytes is the bytes type
|
||||||
@@ -35,14 +38,53 @@ func (u UnitBytes) MarshalJSON() ([]byte, error) {
|
|||||||
return []byte(fmt.Sprintf(`"%d"`, u)), nil
|
return []byte(fmt.Sprintf(`"%d"`, u)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseString parses a string into a UnitBytes value, supporting plain
|
||||||
|
// integers, negative values (e.g., "-1"), and human-readable byte units
|
||||||
|
// (e.g., "1g", "512m").
|
||||||
|
func (u *UnitBytes) parseString(s string) error {
|
||||||
|
if n, err := strconv.ParseInt(s, 10, 64); err == nil {
|
||||||
|
*u = UnitBytes(n)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
b, err := units.RAMInBytes(s)
|
||||||
|
*u = UnitBytes(b)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON makes UnitBytes implement json.Unmarshaler
|
||||||
|
func (u *UnitBytes) UnmarshalJSON(data []byte) error {
|
||||||
|
var v int64
|
||||||
|
if err := json.Unmarshal(data, &v); err == nil {
|
||||||
|
*u = UnitBytes(v)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var s string
|
||||||
|
if err := json.Unmarshal(data, &s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return u.parseString(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalYAML makes UnitBytes implement yaml.Unmarshaler
|
||||||
|
func (u *UnitBytes) UnmarshalYAML(value *yaml.Node) error {
|
||||||
|
var v int64
|
||||||
|
if err := value.Decode(&v); err == nil {
|
||||||
|
*u = UnitBytes(v)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var s string
|
||||||
|
if err := value.Decode(&s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return u.parseString(s)
|
||||||
|
}
|
||||||
|
|
||||||
func (u *UnitBytes) DecodeMapstructure(value interface{}) error {
|
func (u *UnitBytes) DecodeMapstructure(value interface{}) error {
|
||||||
switch v := value.(type) {
|
switch v := value.(type) {
|
||||||
case int:
|
case int:
|
||||||
*u = UnitBytes(v)
|
*u = UnitBytes(v)
|
||||||
case string:
|
case string:
|
||||||
b, err := units.RAMInBytes(fmt.Sprint(value))
|
return u.parseString(v)
|
||||||
*u = UnitBytes(b)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+1
-1
@@ -190,7 +190,7 @@ github.com/cloudflare/circl/math/mlsbset
|
|||||||
github.com/cloudflare/circl/sign
|
github.com/cloudflare/circl/sign
|
||||||
github.com/cloudflare/circl/sign/ed25519
|
github.com/cloudflare/circl/sign/ed25519
|
||||||
github.com/cloudflare/circl/sign/ed448
|
github.com/cloudflare/circl/sign/ed448
|
||||||
# github.com/compose-spec/compose-go/v2 v2.10.2
|
# github.com/compose-spec/compose-go/v2 v2.11.0
|
||||||
## explicit; go 1.24
|
## explicit; go 1.24
|
||||||
github.com/compose-spec/compose-go/v2/cli
|
github.com/compose-spec/compose-go/v2/cli
|
||||||
github.com/compose-spec/compose-go/v2/consts
|
github.com/compose-spec/compose-go/v2/consts
|
||||||
|
|||||||
Reference in New Issue
Block a user