Merge remote-tracking branch 'aosp/upstream' into master am: 86286b9ac9
am: 2ad0aebc37
Change-Id: If811a4aff87b0be85e0519925bfb7938024c22c0
This commit is contained in:
commit
e356e519fd
10 changed files with 300 additions and 126 deletions
|
@ -19,7 +19,6 @@ bootstrap_go_package {
|
|||
"package_ctx.go",
|
||||
"scope.go",
|
||||
"singleton_ctx.go",
|
||||
"unpack.go",
|
||||
],
|
||||
testSrcs: [
|
||||
"context_test.go",
|
||||
|
@ -28,7 +27,6 @@ bootstrap_go_package {
|
|||
"ninja_strings_test.go",
|
||||
"ninja_writer_test.go",
|
||||
"splice_modules_test.go",
|
||||
"unpack_test.go",
|
||||
"visit_test.go",
|
||||
],
|
||||
}
|
||||
|
@ -76,6 +74,9 @@ bootstrap_go_package {
|
|||
bootstrap_go_package {
|
||||
name: "blueprint-proptools",
|
||||
pkgPath: "github.com/google/blueprint/proptools",
|
||||
deps: [
|
||||
"blueprint-parser",
|
||||
],
|
||||
srcs: [
|
||||
"proptools/clone.go",
|
||||
"proptools/escape.go",
|
||||
|
@ -84,6 +85,7 @@ bootstrap_go_package {
|
|||
"proptools/proptools.go",
|
||||
"proptools/tag.go",
|
||||
"proptools/typeequal.go",
|
||||
"proptools/unpack.go",
|
||||
],
|
||||
testSrcs: [
|
||||
"proptools/clone_test.go",
|
||||
|
@ -92,6 +94,7 @@ bootstrap_go_package {
|
|||
"proptools/filter_test.go",
|
||||
"proptools/tag_test.go",
|
||||
"proptools/typeequal_test.go",
|
||||
"proptools/unpack_test.go",
|
||||
],
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"reflect"
|
||||
"sort"
|
||||
|
||||
"github.com/google/blueprint"
|
||||
"github.com/google/blueprint/proptools"
|
||||
)
|
||||
|
||||
|
@ -146,7 +145,7 @@ func assembleModuleTypeInfo(r *Reader, name string, factory reflect.Value,
|
|||
return nil, fmt.Errorf("nesting point %q not found", nestedName)
|
||||
}
|
||||
|
||||
key, value, err := blueprint.HasFilter(nestPoint.Tag)
|
||||
key, value, err := proptools.HasFilter(nestPoint.Tag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -140,7 +140,7 @@ func Main(ctx *blueprint.Context, config interface{}, extraNinjaFileDeps ...stri
|
|||
|
||||
ctx.RegisterSingletonType("glob", globSingletonFactory(ctx))
|
||||
|
||||
deps, errs := ctx.ParseFileList(filepath.Dir(bootstrapConfig.topLevelBlueprintsFile), filesToParse)
|
||||
deps, errs := ctx.ParseFileList(filepath.Dir(bootstrapConfig.topLevelBlueprintsFile), filesToParse, config)
|
||||
if len(errs) > 0 {
|
||||
fatalErrors(errs)
|
||||
}
|
||||
|
|
79
context.go
79
context.go
|
@ -631,17 +631,19 @@ type fileParseContext struct {
|
|||
// which the future output will depend is returned. This list will include both
|
||||
// Blueprints file paths as well as directory paths for cases where wildcard
|
||||
// subdirs are found.
|
||||
func (c *Context) ParseBlueprintsFiles(rootFile string) (deps []string, errs []error) {
|
||||
func (c *Context) ParseBlueprintsFiles(rootFile string,
|
||||
config interface{}) (deps []string, errs []error) {
|
||||
|
||||
baseDir := filepath.Dir(rootFile)
|
||||
pathsToParse, err := c.ListModulePaths(baseDir)
|
||||
if err != nil {
|
||||
return nil, []error{err}
|
||||
}
|
||||
return c.ParseFileList(baseDir, pathsToParse)
|
||||
return c.ParseFileList(baseDir, pathsToParse, config)
|
||||
}
|
||||
|
||||
func (c *Context) ParseFileList(rootDir string, filePaths []string) (deps []string,
|
||||
errs []error) {
|
||||
func (c *Context) ParseFileList(rootDir string, filePaths []string,
|
||||
config interface{}) (deps []string, errs []error) {
|
||||
|
||||
if len(filePaths) < 1 {
|
||||
return nil, []error{fmt.Errorf("no paths provided to parse")}
|
||||
|
@ -649,7 +651,12 @@ func (c *Context) ParseFileList(rootDir string, filePaths []string) (deps []stri
|
|||
|
||||
c.dependenciesReady = false
|
||||
|
||||
moduleCh := make(chan *moduleInfo)
|
||||
type newModuleInfo struct {
|
||||
*moduleInfo
|
||||
added chan<- struct{}
|
||||
}
|
||||
|
||||
moduleCh := make(chan newModuleInfo)
|
||||
errsCh := make(chan []error)
|
||||
doneCh := make(chan struct{})
|
||||
var numErrs uint32
|
||||
|
@ -661,24 +668,47 @@ func (c *Context) ParseFileList(rootDir string, filePaths []string) (deps []stri
|
|||
return
|
||||
}
|
||||
|
||||
addedCh := make(chan struct{})
|
||||
|
||||
var scopedModuleFactories map[string]ModuleFactory
|
||||
|
||||
var addModule func(module *moduleInfo) []error
|
||||
addModule = func(module *moduleInfo) (errs []error) {
|
||||
moduleCh <- newModuleInfo{module, addedCh}
|
||||
<-addedCh
|
||||
var newModules []*moduleInfo
|
||||
newModules, errs = runAndRemoveLoadHooks(c, config, module, &scopedModuleFactories)
|
||||
if len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
for _, n := range newModules {
|
||||
errs = addModule(n)
|
||||
if len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, def := range file.Defs {
|
||||
var module *moduleInfo
|
||||
var errs []error
|
||||
switch def := def.(type) {
|
||||
case *parser.Module:
|
||||
module, errs = c.processModuleDef(def, file.Name)
|
||||
module, errs := c.processModuleDef(def, file.Name, scopedModuleFactories)
|
||||
if len(errs) == 0 && module != nil {
|
||||
errs = addModule(module)
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
atomic.AddUint32(&numErrs, uint32(len(errs)))
|
||||
errsCh <- errs
|
||||
}
|
||||
|
||||
case *parser.Assignment:
|
||||
// Already handled via Scope object
|
||||
default:
|
||||
panic("unknown definition type")
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
atomic.AddUint32(&numErrs, uint32(len(errs)))
|
||||
errsCh <- errs
|
||||
} else if module != nil {
|
||||
moduleCh <- module
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -698,7 +728,10 @@ loop:
|
|||
case newErrs := <-errsCh:
|
||||
errs = append(errs, newErrs...)
|
||||
case module := <-moduleCh:
|
||||
newErrs := c.addModule(module)
|
||||
newErrs := c.addModule(module.moduleInfo)
|
||||
if module.added != nil {
|
||||
module.added <- struct{}{}
|
||||
}
|
||||
if len(newErrs) > 0 {
|
||||
errs = append(errs, newErrs...)
|
||||
}
|
||||
|
@ -1307,9 +1340,12 @@ func (c *Context) newModule(factory ModuleFactory) *moduleInfo {
|
|||
}
|
||||
|
||||
func (c *Context) processModuleDef(moduleDef *parser.Module,
|
||||
relBlueprintsFile string) (*moduleInfo, []error) {
|
||||
relBlueprintsFile string, scopedModuleFactories map[string]ModuleFactory) (*moduleInfo, []error) {
|
||||
|
||||
factory, ok := c.moduleFactories[moduleDef.Type]
|
||||
if !ok && scopedModuleFactories != nil {
|
||||
factory, ok = scopedModuleFactories[moduleDef.Type]
|
||||
}
|
||||
if !ok {
|
||||
if c.ignoreUnknownModuleTypes {
|
||||
return nil, nil
|
||||
|
@ -1328,8 +1364,17 @@ func (c *Context) processModuleDef(moduleDef *parser.Module,
|
|||
|
||||
module.relBlueprintsFile = relBlueprintsFile
|
||||
|
||||
propertyMap, errs := unpackProperties(moduleDef.Properties, module.properties...)
|
||||
propertyMap, errs := proptools.UnpackProperties(moduleDef.Properties, module.properties...)
|
||||
if len(errs) > 0 {
|
||||
for i, err := range errs {
|
||||
if unpackErr, ok := err.(*proptools.UnpackError); ok {
|
||||
err = &BlueprintError{
|
||||
Err: unpackErr.Err,
|
||||
Pos: unpackErr.Pos,
|
||||
}
|
||||
errs[i] = err
|
||||
}
|
||||
}
|
||||
return nil, errs
|
||||
}
|
||||
|
||||
|
|
|
@ -168,7 +168,7 @@ func TestWalkDeps(t *testing.T) {
|
|||
|
||||
ctx.RegisterModuleType("foo_module", newFooModule)
|
||||
ctx.RegisterModuleType("bar_module", newBarModule)
|
||||
_, errs := ctx.ParseBlueprintsFiles("Blueprints")
|
||||
_, errs := ctx.ParseBlueprintsFiles("Blueprints", nil)
|
||||
if len(errs) > 0 {
|
||||
t.Errorf("unexpected parse errors:")
|
||||
for _, err := range errs {
|
||||
|
@ -260,7 +260,7 @@ func TestWalkDepsDuplicates(t *testing.T) {
|
|||
|
||||
ctx.RegisterModuleType("foo_module", newFooModule)
|
||||
ctx.RegisterModuleType("bar_module", newBarModule)
|
||||
_, errs := ctx.ParseBlueprintsFiles("Blueprints")
|
||||
_, errs := ctx.ParseBlueprintsFiles("Blueprints", nil)
|
||||
if len(errs) > 0 {
|
||||
t.Errorf("unexpected parse errors:")
|
||||
for _, err := range errs {
|
||||
|
@ -316,7 +316,7 @@ func TestCreateModule(t *testing.T) {
|
|||
|
||||
ctx.RegisterModuleType("foo_module", newFooModule)
|
||||
ctx.RegisterModuleType("bar_module", newBarModule)
|
||||
_, errs := ctx.ParseBlueprintsFiles("Blueprints")
|
||||
_, errs := ctx.ParseBlueprintsFiles("Blueprints", nil)
|
||||
if len(errs) > 0 {
|
||||
t.Errorf("unexpected parse errors:")
|
||||
for _, err := range errs {
|
||||
|
@ -499,7 +499,7 @@ func TestParseFailsForModuleWithoutName(t *testing.T) {
|
|||
ctx.RegisterModuleType("foo_module", newFooModule)
|
||||
ctx.RegisterModuleType("bar_module", newBarModule)
|
||||
|
||||
_, errs := ctx.ParseBlueprintsFiles("Blueprints")
|
||||
_, errs := ctx.ParseBlueprintsFiles("Blueprints", nil)
|
||||
|
||||
expectedErrs := []error{
|
||||
errors.New(`Blueprints:6:4: property 'name' is missing from a module`),
|
||||
|
|
122
module_ctx.go
122
module_ctx.go
|
@ -17,6 +17,7 @@ package blueprint
|
|||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"text/scanner"
|
||||
|
||||
"github.com/google/blueprint/pathtools"
|
||||
|
@ -120,7 +121,7 @@ type DynamicDependerModule interface {
|
|||
DynamicDependencies(DynamicDependerModuleContext) []string
|
||||
}
|
||||
|
||||
type BaseModuleContext interface {
|
||||
type EarlyModuleContext interface {
|
||||
// Module returns the current module as a Module. It should rarely be necessary, as the module already has a
|
||||
// reference to itself.
|
||||
Module() Module
|
||||
|
@ -179,6 +180,13 @@ type BaseModuleContext interface {
|
|||
// default SimpleNameInterface if Context.SetNameInterface was not called.
|
||||
Namespace() Namespace
|
||||
|
||||
// ModuleFactories returns a map of all of the global ModuleFactories by name.
|
||||
ModuleFactories() map[string]ModuleFactory
|
||||
}
|
||||
|
||||
type BaseModuleContext interface {
|
||||
EarlyModuleContext
|
||||
|
||||
// GetDirectDepWithTag returns the Module the direct dependency with the specified name, or nil if
|
||||
// none exists. It panics if the dependency does not have the specified tag.
|
||||
GetDirectDepWithTag(name string, tag DependencyTag) Module
|
||||
|
@ -597,6 +605,14 @@ func (m *baseModuleContext) AddNinjaFileDeps(deps ...string) {
|
|||
m.ninjaFileDeps = append(m.ninjaFileDeps, deps...)
|
||||
}
|
||||
|
||||
func (m *baseModuleContext) ModuleFactories() map[string]ModuleFactory {
|
||||
ret := make(map[string]ModuleFactory)
|
||||
for k, v := range m.context.moduleFactories {
|
||||
ret[k] = v
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (m *moduleContext) ModuleSubDir() string {
|
||||
return m.module.variantName
|
||||
}
|
||||
|
@ -995,3 +1011,107 @@ type SimpleName struct {
|
|||
func (s *SimpleName) Name() string {
|
||||
return s.Properties.Name
|
||||
}
|
||||
|
||||
// Load Hooks
|
||||
|
||||
type LoadHookContext interface {
|
||||
EarlyModuleContext
|
||||
|
||||
// CreateModule creates a new module by calling the factory method for the specified moduleType, and applies
|
||||
// the specified property structs to it as if the properties were set in a blueprint file.
|
||||
CreateModule(ModuleFactory, ...interface{}) Module
|
||||
|
||||
// RegisterScopedModuleType creates a new module type that is scoped to the current Blueprints
|
||||
// file.
|
||||
RegisterScopedModuleType(name string, factory ModuleFactory)
|
||||
}
|
||||
|
||||
func (l *loadHookContext) CreateModule(factory ModuleFactory, props ...interface{}) Module {
|
||||
module := l.context.newModule(factory)
|
||||
|
||||
module.relBlueprintsFile = l.module.relBlueprintsFile
|
||||
module.pos = l.module.pos
|
||||
module.propertyPos = l.module.propertyPos
|
||||
module.createdBy = l.module
|
||||
|
||||
for _, p := range props {
|
||||
err := proptools.AppendMatchingProperties(module.properties, p, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
l.newModules = append(l.newModules, module)
|
||||
|
||||
return module.logicModule
|
||||
}
|
||||
|
||||
func (l *loadHookContext) RegisterScopedModuleType(name string, factory ModuleFactory) {
|
||||
if _, exists := l.context.moduleFactories[name]; exists {
|
||||
panic(fmt.Errorf("A global module type named %q already exists", name))
|
||||
}
|
||||
|
||||
if _, exists := (*l.scopedModuleFactories)[name]; exists {
|
||||
panic(fmt.Errorf("A module type named %q already exists in this scope", name))
|
||||
}
|
||||
|
||||
if *l.scopedModuleFactories == nil {
|
||||
(*l.scopedModuleFactories) = make(map[string]ModuleFactory)
|
||||
}
|
||||
|
||||
(*l.scopedModuleFactories)[name] = factory
|
||||
}
|
||||
|
||||
type loadHookContext struct {
|
||||
baseModuleContext
|
||||
newModules []*moduleInfo
|
||||
scopedModuleFactories *map[string]ModuleFactory
|
||||
}
|
||||
|
||||
type LoadHook func(ctx LoadHookContext)
|
||||
|
||||
// Load hooks need to be added by module factories, which don't have any parameter to get to the
|
||||
// Context, and only produce a Module interface with no base implementation, so the load hooks
|
||||
// must be stored in a global map. The key is a pointer allocated by the module factory, so there
|
||||
// is no chance of collisions even if tests are running in parallel with multiple contexts. The
|
||||
// contents should be short-lived, they are added during a module factory and removed immediately
|
||||
// after the module factory returns.
|
||||
var pendingHooks sync.Map
|
||||
|
||||
func AddLoadHook(module Module, hook LoadHook) {
|
||||
// Only one goroutine can be processing a given module, so no additional locking is required
|
||||
// for the slice stored in the sync.Map.
|
||||
v, exists := pendingHooks.Load(module)
|
||||
if !exists {
|
||||
v, _ = pendingHooks.LoadOrStore(module, new([]LoadHook))
|
||||
}
|
||||
hooks := v.(*[]LoadHook)
|
||||
*hooks = append(*hooks, hook)
|
||||
}
|
||||
|
||||
func runAndRemoveLoadHooks(ctx *Context, config interface{}, module *moduleInfo,
|
||||
scopedModuleFactories *map[string]ModuleFactory) (newModules []*moduleInfo, errs []error) {
|
||||
|
||||
if v, exists := pendingHooks.Load(module.logicModule); exists {
|
||||
hooks := v.(*[]LoadHook)
|
||||
mctx := &loadHookContext{
|
||||
baseModuleContext: baseModuleContext{
|
||||
context: ctx,
|
||||
config: config,
|
||||
module: module,
|
||||
},
|
||||
scopedModuleFactories: scopedModuleFactories,
|
||||
}
|
||||
|
||||
for _, hook := range *hooks {
|
||||
hook(mctx)
|
||||
newModules = append(newModules, mctx.newModules...)
|
||||
errs = append(errs, mctx.errs...)
|
||||
}
|
||||
pendingHooks.Delete(module.logicModule)
|
||||
|
||||
return newModules, errs
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ func TestAliases(t *testing.T) {
|
|||
|
||||
ctx.MockFileSystem(mockFS)
|
||||
|
||||
_, errs := ctx.ParseFileList(".", []string{"Blueprints"})
|
||||
_, errs := ctx.ParseFileList(".", []string{"Blueprints"}, nil)
|
||||
if len(errs) > 0 {
|
||||
t.Errorf("unexpected parse errors:")
|
||||
for _, err := range errs {
|
||||
|
|
|
@ -12,24 +12,35 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package blueprint
|
||||
package proptools
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/scanner"
|
||||
|
||||
"github.com/google/blueprint/parser"
|
||||
"github.com/google/blueprint/proptools"
|
||||
)
|
||||
|
||||
const maxUnpackErrors = 10
|
||||
|
||||
type UnpackError struct {
|
||||
Err error
|
||||
Pos scanner.Position
|
||||
}
|
||||
|
||||
func (e *UnpackError) Error() string {
|
||||
return fmt.Sprintf("%s: %s", e.Pos, e.Err)
|
||||
}
|
||||
|
||||
type packedProperty struct {
|
||||
property *parser.Property
|
||||
unpacked bool
|
||||
}
|
||||
|
||||
func unpackProperties(propertyDefs []*parser.Property,
|
||||
func UnpackProperties(propertyDefs []*parser.Property,
|
||||
propertiesStructs ...interface{}) (map[string]*parser.Property, []error) {
|
||||
|
||||
propertyMap := make(map[string]*packedProperty)
|
||||
|
@ -52,7 +63,7 @@ func unpackProperties(propertyDefs []*parser.Property,
|
|||
newErrs := unpackStructValue("", propertiesValue, propertyMap, "", "")
|
||||
errs = append(errs, newErrs...)
|
||||
|
||||
if len(errs) >= maxErrors {
|
||||
if len(errs) >= maxUnpackErrors {
|
||||
return nil, errs
|
||||
}
|
||||
}
|
||||
|
@ -63,7 +74,7 @@ func unpackProperties(propertyDefs []*parser.Property,
|
|||
for name, packedProperty := range propertyMap {
|
||||
result[name] = packedProperty.property
|
||||
if !packedProperty.unpacked {
|
||||
err := &BlueprintError{
|
||||
err := &UnpackError{
|
||||
Err: fmt.Errorf("unrecognized property %q", name),
|
||||
Pos: packedProperty.property.ColonPos,
|
||||
}
|
||||
|
@ -88,15 +99,15 @@ func buildPropertyMap(namePrefix string, propertyDefs []*parser.Property,
|
|||
// We've already added this property.
|
||||
continue
|
||||
}
|
||||
errs = append(errs, &BlueprintError{
|
||||
errs = append(errs, &UnpackError{
|
||||
Err: fmt.Errorf("property %q already defined", name),
|
||||
Pos: propertyDef.ColonPos,
|
||||
})
|
||||
errs = append(errs, &BlueprintError{
|
||||
errs = append(errs, &UnpackError{
|
||||
Err: fmt.Errorf("<-- previous definition here"),
|
||||
Pos: first.property.ColonPos,
|
||||
})
|
||||
if len(errs) >= maxErrors {
|
||||
if len(errs) >= maxUnpackErrors {
|
||||
return errs
|
||||
}
|
||||
continue
|
||||
|
@ -142,7 +153,7 @@ func unpackStructValue(namePrefix string, structValue reflect.Value,
|
|||
continue
|
||||
}
|
||||
|
||||
propertyName := namePrefix + proptools.PropertyNameForField(field.Name)
|
||||
propertyName := namePrefix + PropertyNameForField(field.Name)
|
||||
|
||||
if !fieldValue.CanSet() {
|
||||
panic(fmt.Errorf("field %s is not settable", propertyName))
|
||||
|
@ -163,7 +174,7 @@ func unpackStructValue(namePrefix string, structValue reflect.Value,
|
|||
case reflect.Slice:
|
||||
elemType := field.Type.Elem()
|
||||
if elemType.Kind() != reflect.String {
|
||||
if !proptools.HasTag(field, "blueprint", "mutated") {
|
||||
if !HasTag(field, "blueprint", "mutated") {
|
||||
panic(fmt.Errorf("field %s is a non-string slice", propertyName))
|
||||
}
|
||||
}
|
||||
|
@ -195,7 +206,7 @@ func unpackStructValue(namePrefix string, structValue reflect.Value,
|
|||
}
|
||||
|
||||
case reflect.Int, reflect.Uint:
|
||||
if !proptools.HasTag(field, "blueprint", "mutated") {
|
||||
if !HasTag(field, "blueprint", "mutated") {
|
||||
panic(fmt.Errorf(`int field %s must be tagged blueprint:"mutated"`, propertyName))
|
||||
}
|
||||
|
||||
|
@ -216,25 +227,25 @@ func unpackStructValue(namePrefix string, structValue reflect.Value,
|
|||
|
||||
packedProperty.unpacked = true
|
||||
|
||||
if proptools.HasTag(field, "blueprint", "mutated") {
|
||||
if HasTag(field, "blueprint", "mutated") {
|
||||
errs = append(errs,
|
||||
&BlueprintError{
|
||||
&UnpackError{
|
||||
Err: fmt.Errorf("mutated field %s cannot be set in a Blueprint file", propertyName),
|
||||
Pos: packedProperty.property.ColonPos,
|
||||
})
|
||||
if len(errs) >= maxErrors {
|
||||
if len(errs) >= maxUnpackErrors {
|
||||
return errs
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if filterKey != "" && !proptools.HasTag(field, filterKey, filterValue) {
|
||||
if filterKey != "" && !HasTag(field, filterKey, filterValue) {
|
||||
errs = append(errs,
|
||||
&BlueprintError{
|
||||
&UnpackError{
|
||||
Err: fmt.Errorf("filtered field %s cannot be set in a Blueprint file", propertyName),
|
||||
Pos: packedProperty.property.ColonPos,
|
||||
})
|
||||
if len(errs) >= maxErrors {
|
||||
if len(errs) >= maxUnpackErrors {
|
||||
return errs
|
||||
}
|
||||
continue
|
||||
|
@ -246,14 +257,14 @@ func unpackStructValue(namePrefix string, structValue reflect.Value,
|
|||
localFilterKey, localFilterValue := filterKey, filterValue
|
||||
if k, v, err := HasFilter(field.Tag); err != nil {
|
||||
errs = append(errs, err)
|
||||
if len(errs) >= maxErrors {
|
||||
if len(errs) >= maxUnpackErrors {
|
||||
return errs
|
||||
}
|
||||
} else if k != "" {
|
||||
if filterKey != "" {
|
||||
errs = append(errs, fmt.Errorf("nested filter tag not supported on field %q",
|
||||
field.Name))
|
||||
if len(errs) >= maxErrors {
|
||||
if len(errs) >= maxUnpackErrors {
|
||||
return errs
|
||||
}
|
||||
} else {
|
||||
|
@ -264,7 +275,7 @@ func unpackStructValue(namePrefix string, structValue reflect.Value,
|
|||
packedProperty.property, propertyMap, localFilterKey, localFilterValue)
|
||||
|
||||
errs = append(errs, newErrs...)
|
||||
if len(errs) >= maxErrors {
|
||||
if len(errs) >= maxUnpackErrors {
|
||||
return errs
|
||||
}
|
||||
|
||||
|
@ -276,12 +287,12 @@ func unpackStructValue(namePrefix string, structValue reflect.Value,
|
|||
propertyValue, err := propertyToValue(fieldValue.Type(), packedProperty.property)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
if len(errs) >= maxErrors {
|
||||
if len(errs) >= maxUnpackErrors {
|
||||
return errs
|
||||
}
|
||||
}
|
||||
|
||||
proptools.ExtendBasicType(fieldValue, propertyValue, proptools.Append)
|
||||
ExtendBasicType(fieldValue, propertyValue, Append)
|
||||
}
|
||||
|
||||
return errs
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package blueprint
|
||||
package proptools
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
@ -22,7 +22,6 @@ import (
|
|||
"text/scanner"
|
||||
|
||||
"github.com/google/blueprint/parser"
|
||||
"github.com/google/blueprint/proptools"
|
||||
)
|
||||
|
||||
var validUnpackTestCases = []struct {
|
||||
|
@ -34,18 +33,18 @@ var validUnpackTestCases = []struct {
|
|||
{
|
||||
input: `
|
||||
m {
|
||||
name: "abc",
|
||||
s: "abc",
|
||||
blank: "",
|
||||
}
|
||||
`,
|
||||
output: []interface{}{
|
||||
struct {
|
||||
Name *string
|
||||
S *string
|
||||
Blank *string
|
||||
Unset *string
|
||||
}{
|
||||
Name: proptools.StringPtr("abc"),
|
||||
Blank: proptools.StringPtr(""),
|
||||
S: StringPtr("abc"),
|
||||
Blank: StringPtr(""),
|
||||
Unset: nil,
|
||||
},
|
||||
},
|
||||
|
@ -54,14 +53,14 @@ var validUnpackTestCases = []struct {
|
|||
{
|
||||
input: `
|
||||
m {
|
||||
name: "abc",
|
||||
s: "abc",
|
||||
}
|
||||
`,
|
||||
output: []interface{}{
|
||||
struct {
|
||||
Name string
|
||||
S string
|
||||
}{
|
||||
Name: "abc",
|
||||
S: "abc",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -94,8 +93,8 @@ var validUnpackTestCases = []struct {
|
|||
IsBad *bool
|
||||
IsUgly *bool
|
||||
}{
|
||||
IsGood: proptools.BoolPtr(true),
|
||||
IsBad: proptools.BoolPtr(false),
|
||||
IsGood: BoolPtr(true),
|
||||
IsBad: BoolPtr(false),
|
||||
IsUgly: nil,
|
||||
},
|
||||
},
|
||||
|
@ -128,18 +127,18 @@ var validUnpackTestCases = []struct {
|
|||
input: `
|
||||
m {
|
||||
nested: {
|
||||
name: "abc",
|
||||
s: "abc",
|
||||
}
|
||||
}
|
||||
`,
|
||||
output: []interface{}{
|
||||
struct {
|
||||
Nested struct {
|
||||
Name string
|
||||
S string
|
||||
}
|
||||
}{
|
||||
Nested: struct{ Name string }{
|
||||
Name: "abc",
|
||||
Nested: struct{ S string }{
|
||||
S: "abc",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -149,7 +148,7 @@ var validUnpackTestCases = []struct {
|
|||
input: `
|
||||
m {
|
||||
nested: {
|
||||
name: "def",
|
||||
s: "def",
|
||||
}
|
||||
}
|
||||
`,
|
||||
|
@ -157,8 +156,8 @@ var validUnpackTestCases = []struct {
|
|||
struct {
|
||||
Nested interface{}
|
||||
}{
|
||||
Nested: &struct{ Name string }{
|
||||
Name: "def",
|
||||
Nested: &struct{ S string }{
|
||||
S: "def",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -246,7 +245,7 @@ var validUnpackTestCases = []struct {
|
|||
},
|
||||
},
|
||||
errs: []error{
|
||||
&BlueprintError{
|
||||
&UnpackError{
|
||||
Err: fmt.Errorf("filtered field nested.foo cannot be set in a Blueprint file"),
|
||||
Pos: mkpos(30, 4, 9),
|
||||
},
|
||||
|
@ -257,9 +256,9 @@ var validUnpackTestCases = []struct {
|
|||
{
|
||||
input: `
|
||||
m {
|
||||
name: "abc",
|
||||
s: "abc",
|
||||
nested: {
|
||||
name: "def",
|
||||
s: "def",
|
||||
},
|
||||
}
|
||||
`,
|
||||
|
@ -271,13 +270,13 @@ var validUnpackTestCases = []struct {
|
|||
}
|
||||
}{
|
||||
EmbeddedStruct: EmbeddedStruct{
|
||||
Name: "abc",
|
||||
S: "abc",
|
||||
},
|
||||
Nested: struct {
|
||||
EmbeddedStruct
|
||||
}{
|
||||
EmbeddedStruct: EmbeddedStruct{
|
||||
Name: "def",
|
||||
S: "def",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -288,9 +287,9 @@ var validUnpackTestCases = []struct {
|
|||
{
|
||||
input: `
|
||||
m {
|
||||
name: "abc",
|
||||
s: "abc",
|
||||
nested: {
|
||||
name: "def",
|
||||
s: "def",
|
||||
},
|
||||
}
|
||||
`,
|
||||
|
@ -301,14 +300,14 @@ var validUnpackTestCases = []struct {
|
|||
EmbeddedInterface
|
||||
}
|
||||
}{
|
||||
EmbeddedInterface: &struct{ Name string }{
|
||||
Name: "abc",
|
||||
EmbeddedInterface: &struct{ S string }{
|
||||
S: "abc",
|
||||
},
|
||||
Nested: struct {
|
||||
EmbeddedInterface
|
||||
}{
|
||||
EmbeddedInterface: &struct{ Name string }{
|
||||
Name: "def",
|
||||
EmbeddedInterface: &struct{ S string }{
|
||||
S: "def",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -319,32 +318,32 @@ var validUnpackTestCases = []struct {
|
|||
{
|
||||
input: `
|
||||
m {
|
||||
name: "abc",
|
||||
s: "abc",
|
||||
nested: {
|
||||
name: "def",
|
||||
s: "def",
|
||||
},
|
||||
}
|
||||
`,
|
||||
output: []interface{}{
|
||||
struct {
|
||||
Name string
|
||||
S string
|
||||
EmbeddedStruct
|
||||
Nested struct {
|
||||
Name string
|
||||
S string
|
||||
EmbeddedStruct
|
||||
}
|
||||
}{
|
||||
Name: "abc",
|
||||
S: "abc",
|
||||
EmbeddedStruct: EmbeddedStruct{
|
||||
Name: "abc",
|
||||
S: "abc",
|
||||
},
|
||||
Nested: struct {
|
||||
Name string
|
||||
S string
|
||||
EmbeddedStruct
|
||||
}{
|
||||
Name: "def",
|
||||
S: "def",
|
||||
EmbeddedStruct: EmbeddedStruct{
|
||||
Name: "def",
|
||||
S: "def",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -355,32 +354,32 @@ var validUnpackTestCases = []struct {
|
|||
{
|
||||
input: `
|
||||
m {
|
||||
name: "abc",
|
||||
s: "abc",
|
||||
nested: {
|
||||
name: "def",
|
||||
s: "def",
|
||||
},
|
||||
}
|
||||
`,
|
||||
output: []interface{}{
|
||||
struct {
|
||||
Name string
|
||||
S string
|
||||
EmbeddedInterface
|
||||
Nested struct {
|
||||
Name string
|
||||
S string
|
||||
EmbeddedInterface
|
||||
}
|
||||
}{
|
||||
Name: "abc",
|
||||
EmbeddedInterface: &struct{ Name string }{
|
||||
Name: "abc",
|
||||
S: "abc",
|
||||
EmbeddedInterface: &struct{ S string }{
|
||||
S: "abc",
|
||||
},
|
||||
Nested: struct {
|
||||
Name string
|
||||
S string
|
||||
EmbeddedInterface
|
||||
}{
|
||||
Name: "def",
|
||||
EmbeddedInterface: &struct{ Name string }{
|
||||
Name: "def",
|
||||
S: "def",
|
||||
EmbeddedInterface: &struct{ S string }{
|
||||
S: "def",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -394,18 +393,18 @@ var validUnpackTestCases = []struct {
|
|||
string = "def"
|
||||
list_with_variable = [string]
|
||||
m {
|
||||
name: string,
|
||||
s: string,
|
||||
list: list,
|
||||
list2: list_with_variable,
|
||||
}
|
||||
`,
|
||||
output: []interface{}{
|
||||
struct {
|
||||
Name string
|
||||
S string
|
||||
List []string
|
||||
List2 []string
|
||||
}{
|
||||
Name: "def",
|
||||
S: "def",
|
||||
List: []string{"abc"},
|
||||
List2: []string{"def"},
|
||||
},
|
||||
|
@ -417,27 +416,27 @@ var validUnpackTestCases = []struct {
|
|||
input: `
|
||||
m {
|
||||
nested: {
|
||||
name: "abc",
|
||||
s: "abc",
|
||||
}
|
||||
}
|
||||
`,
|
||||
output: []interface{}{
|
||||
struct {
|
||||
Nested struct {
|
||||
Name string
|
||||
S string
|
||||
}
|
||||
}{
|
||||
Nested: struct{ Name string }{
|
||||
Name: "abc",
|
||||
Nested: struct{ S string }{
|
||||
S: "abc",
|
||||
},
|
||||
},
|
||||
struct {
|
||||
Nested struct {
|
||||
Name string
|
||||
S string
|
||||
}
|
||||
}{
|
||||
Nested: struct{ Name string }{
|
||||
Name: "abc",
|
||||
Nested: struct{ S string }{
|
||||
S: "abc",
|
||||
},
|
||||
},
|
||||
struct {
|
||||
|
@ -450,25 +449,25 @@ var validUnpackTestCases = []struct {
|
|||
input: `
|
||||
m {
|
||||
nested: {
|
||||
name: "abc",
|
||||
s: "abc",
|
||||
}
|
||||
}
|
||||
`,
|
||||
output: []interface{}{
|
||||
struct {
|
||||
Nested *struct {
|
||||
Name string
|
||||
S string
|
||||
}
|
||||
}{
|
||||
Nested: &struct{ Name string }{
|
||||
Name: "abc",
|
||||
Nested: &struct{ S string }{
|
||||
S: "abc",
|
||||
},
|
||||
},
|
||||
},
|
||||
empty: []interface{}{
|
||||
&struct {
|
||||
Nested *struct {
|
||||
Name string
|
||||
S string
|
||||
}
|
||||
}{},
|
||||
},
|
||||
|
@ -479,7 +478,7 @@ var validUnpackTestCases = []struct {
|
|||
input: `
|
||||
m {
|
||||
nested: {
|
||||
name: "abc",
|
||||
s: "abc",
|
||||
}
|
||||
}
|
||||
`,
|
||||
|
@ -488,7 +487,7 @@ var validUnpackTestCases = []struct {
|
|||
Nested interface{}
|
||||
}{
|
||||
Nested: &EmbeddedStruct{
|
||||
Name: "abc",
|
||||
S: "abc",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -521,9 +520,9 @@ var validUnpackTestCases = []struct {
|
|||
List []string
|
||||
}{
|
||||
String: "012abc",
|
||||
String_ptr: proptools.StringPtr("abc"),
|
||||
String_ptr: StringPtr("abc"),
|
||||
Bool: true,
|
||||
Bool_ptr: proptools.BoolPtr(false),
|
||||
Bool_ptr: BoolPtr(false),
|
||||
List: []string{"0", "1", "2", "a", "b", "c"},
|
||||
},
|
||||
},
|
||||
|
@ -536,18 +535,15 @@ var validUnpackTestCases = []struct {
|
|||
List []string
|
||||
}{
|
||||
String: "012",
|
||||
String_ptr: proptools.StringPtr("012"),
|
||||
String_ptr: StringPtr("012"),
|
||||
Bool: true,
|
||||
Bool_ptr: proptools.BoolPtr(true),
|
||||
Bool_ptr: BoolPtr(true),
|
||||
List: []string{"0", "1", "2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
type EmbeddedStruct struct{ Name string }
|
||||
type EmbeddedInterface interface{}
|
||||
|
||||
func TestUnpackProperties(t *testing.T) {
|
||||
for _, testCase := range validUnpackTestCases {
|
||||
r := bytes.NewBufferString(testCase.input)
|
||||
|
@ -572,10 +568,10 @@ func TestUnpackProperties(t *testing.T) {
|
|||
output = testCase.empty
|
||||
} else {
|
||||
for _, p := range testCase.output {
|
||||
output = append(output, proptools.CloneEmptyProperties(reflect.ValueOf(p)).Interface())
|
||||
output = append(output, CloneEmptyProperties(reflect.ValueOf(p)).Interface())
|
||||
}
|
||||
}
|
||||
_, errs = unpackProperties(module.Properties, output...)
|
||||
_, errs = UnpackProperties(module.Properties, output...)
|
||||
if len(errs) != 0 && len(testCase.errs) == 0 {
|
||||
t.Errorf("test case: %s", testCase.input)
|
||||
t.Errorf("unexpected unpack errors:")
|
|
@ -125,7 +125,7 @@ func setupVisitTest(t *testing.T) *Context {
|
|||
`),
|
||||
})
|
||||
|
||||
_, errs := ctx.ParseBlueprintsFiles("Blueprints")
|
||||
_, errs := ctx.ParseBlueprintsFiles("Blueprints", nil)
|
||||
if len(errs) > 0 {
|
||||
t.Errorf("unexpected parse errors:")
|
||||
for _, err := range errs {
|
||||
|
|
Loading…
Reference in a new issue