mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-04 18:13:42 +08:00 
			
		
		
		
	This patch adds support for block-based interpolation, so that properties of blocks can be referenced in the current block and across other blocks. Previously, order-of-evaluation did not matter for blocks, and could be evaluated in any order. However, now that blocks can refer to each other, we split out this dynamic evaluation order into a separate resolveBlock function. Additionally, we need to support partial block evaluations - if block A refers to property X of block B, when we should only evaluate property X, and not the entire block. This ensures that we can safely evaluate blocks that refer to other properties within themselves, and allows sequences that would otherwise be co-recursive. We take special care in this logic to ensure that each property is evaluated once *and only* once - this could otherwise present inconsistencies with stateful functions, and could risk inconsistent results. Signed-off-by: Justin Chadwell <me@jedevc.com>
		
			
				
	
	
		
			104 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			104 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package hclparser
 | 
						|
 | 
						|
import (
 | 
						|
	"github.com/hashicorp/hcl/v2"
 | 
						|
)
 | 
						|
 | 
						|
type filterBody struct {
 | 
						|
	body    hcl.Body
 | 
						|
	schema  *hcl.BodySchema
 | 
						|
	exclude bool
 | 
						|
}
 | 
						|
 | 
						|
func FilterIncludeBody(body hcl.Body, schema *hcl.BodySchema) hcl.Body {
 | 
						|
	return &filterBody{
 | 
						|
		body:   body,
 | 
						|
		schema: schema,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func FilterExcludeBody(body hcl.Body, schema *hcl.BodySchema) hcl.Body {
 | 
						|
	return &filterBody{
 | 
						|
		body:    body,
 | 
						|
		schema:  schema,
 | 
						|
		exclude: true,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (b *filterBody) Content(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Diagnostics) {
 | 
						|
	if b.exclude {
 | 
						|
		schema = subtractSchemas(schema, b.schema)
 | 
						|
	} else {
 | 
						|
		schema = intersectSchemas(schema, b.schema)
 | 
						|
	}
 | 
						|
	content, _, diag := b.body.PartialContent(schema)
 | 
						|
	return content, diag
 | 
						|
}
 | 
						|
 | 
						|
func (b *filterBody) PartialContent(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Body, hcl.Diagnostics) {
 | 
						|
	if b.exclude {
 | 
						|
		schema = subtractSchemas(schema, b.schema)
 | 
						|
	} else {
 | 
						|
		schema = intersectSchemas(schema, b.schema)
 | 
						|
	}
 | 
						|
	return b.body.PartialContent(schema)
 | 
						|
}
 | 
						|
 | 
						|
func (b *filterBody) JustAttributes() (hcl.Attributes, hcl.Diagnostics) {
 | 
						|
	return b.body.JustAttributes()
 | 
						|
}
 | 
						|
 | 
						|
func (b *filterBody) MissingItemRange() hcl.Range {
 | 
						|
	return b.body.MissingItemRange()
 | 
						|
}
 | 
						|
 | 
						|
func intersectSchemas(a, b *hcl.BodySchema) *hcl.BodySchema {
 | 
						|
	result := &hcl.BodySchema{}
 | 
						|
	for _, blockA := range a.Blocks {
 | 
						|
		for _, blockB := range b.Blocks {
 | 
						|
			if blockA.Type == blockB.Type {
 | 
						|
				result.Blocks = append(result.Blocks, blockA)
 | 
						|
				break
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	for _, attrA := range a.Attributes {
 | 
						|
		for _, attrB := range b.Attributes {
 | 
						|
			if attrA.Name == attrB.Name {
 | 
						|
				result.Attributes = append(result.Attributes, attrA)
 | 
						|
				break
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return result
 | 
						|
}
 | 
						|
 | 
						|
func subtractSchemas(a, b *hcl.BodySchema) *hcl.BodySchema {
 | 
						|
	result := &hcl.BodySchema{}
 | 
						|
	for _, blockA := range a.Blocks {
 | 
						|
		found := false
 | 
						|
		for _, blockB := range b.Blocks {
 | 
						|
			if blockA.Type == blockB.Type {
 | 
						|
				found = true
 | 
						|
				break
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if !found {
 | 
						|
			result.Blocks = append(result.Blocks, blockA)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	for _, attrA := range a.Attributes {
 | 
						|
		found := false
 | 
						|
		for _, attrB := range b.Attributes {
 | 
						|
			if attrA.Name == attrB.Name {
 | 
						|
				found = true
 | 
						|
				break
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if !found {
 | 
						|
			result.Attributes = append(result.Attributes, attrA)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return result
 | 
						|
}
 |