Skip to content

Commit

Permalink
Detect duplicate object names
Browse files Browse the repository at this point in the history
This change detects duplicate object names (monikers) and issues a nice
error message with source context include.  For example:

    index.ts(260,22): error MU2006: Duplicate objects with the same name:
        prod::ec2instance:index::aws:ec2/securityGroup:SecurityGroup::group

The prior code asserted and failed abruptly, whereas this actually points
us to the offending line of code:

    let group1 = new aws.ec2.SecurityGroup("group", { ... });
    let group2 = new aws.ec2.SecurityGroup("group", { ... });
                 ^^^^^^^^^^^^^^^^^^^^^^^^^
  • Loading branch information
joeduffy committed Feb 25, 2017
1 parent 14e3f19 commit 877fa13
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 101 deletions.
2 changes: 2 additions & 0 deletions cmd/shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ func plan(cmd *cobra.Command, args []string, existfn string, delete bool) *planR
if err != nil {
result.C.Diag().Errorf(errors.ErrorCantCreateSnapshot, err)
return nil
} else if !ctx.Diag.Success() {
return nil
}

var plan resource.Plan
Expand Down
1 change: 1 addition & 0 deletions pkg/compiler/errors/planapply.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ var (
ErrorPlanApplyFailed = newError(2003, "Plan apply failed: %v")
ErrorIllegalMarkupExtension = newError(2004, "Resource serialization failed; illegal markup extension '%v'")
ErrorCantReadSnapshot = newError(2005, "Could not read snapshot file '%v': %v")
ErrorDuplicateMonikerNames = newError(2006, "Duplicate objects with the same name: %v")
)
45 changes: 23 additions & 22 deletions pkg/eval/alloc.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package eval

import (
"github.com/marapongo/mu/pkg/compiler/symbols"
"github.com/marapongo/mu/pkg/diag"
"github.com/marapongo/mu/pkg/eval/rt"
)

Expand All @@ -18,78 +19,78 @@ func NewAllocator(hooks InterpreterHooks) *Allocator {
}

// onNewObject is invoked for each allocation and emits an appropriate event.
func (a *Allocator) onNewObject(o *rt.Object) {
func (a *Allocator) onNewObject(tree diag.Diagable, o *rt.Object) {
if a.hooks != nil {
a.hooks.OnNewObject(o)
a.hooks.OnNewObject(tree, o)
}
}

// New creates a new empty object of the given type.
func (a *Allocator) New(t symbols.Type, properties rt.PropertyMap, super *rt.Object) *rt.Object {
func (a *Allocator) New(tree diag.Diagable, t symbols.Type, properties rt.PropertyMap, super *rt.Object) *rt.Object {
obj := rt.NewObject(t, nil, properties, super)
a.onNewObject(obj)
a.onNewObject(tree, obj)
return obj
}

// NewArray creates a new array object of the given element type.
func (a *Allocator) NewArray(elem symbols.Type, arr *[]*rt.Pointer) *rt.Object {
func (a *Allocator) NewArray(tree diag.Diagable, elem symbols.Type, arr *[]*rt.Pointer) *rt.Object {
obj := rt.NewArrayObject(elem, arr)
a.onNewObject(obj)
a.onNewObject(tree, obj)
return obj
}

// NewPrimitive creates a new primitive object with the given primitive type.
func (a *Allocator) NewPrimitive(t symbols.Type, v interface{}) *rt.Object {
func (a *Allocator) NewPrimitive(tree diag.Diagable, t symbols.Type, v interface{}) *rt.Object {
obj := rt.NewPrimitiveObject(t, v)
a.onNewObject(obj)
a.onNewObject(tree, obj)
return obj
}

// NewBool creates a new primitive number object.
func (a *Allocator) NewBool(v bool) *rt.Object {
func (a *Allocator) NewBool(tree diag.Diagable, v bool) *rt.Object {
obj := rt.NewBoolObject(v)
a.onNewObject(obj)
a.onNewObject(tree, obj)
return obj
}

// NewNumber creates a new primitive number object.
func (a *Allocator) NewNumber(v float64) *rt.Object {
func (a *Allocator) NewNumber(tree diag.Diagable, v float64) *rt.Object {
obj := rt.NewNumberObject(v)
a.onNewObject(obj)
a.onNewObject(tree, obj)
return obj
}

// NewNull creates a new null object.
func (a *Allocator) NewNull() *rt.Object {
func (a *Allocator) NewNull(tree diag.Diagable) *rt.Object {
obj := rt.NewNullObject()
a.onNewObject(obj)
a.onNewObject(tree, obj)
return obj
}

// NewString creates a new primitive number object.
func (a *Allocator) NewString(v string) *rt.Object {
func (a *Allocator) NewString(tree diag.Diagable, v string) *rt.Object {
obj := rt.NewStringObject(v)
a.onNewObject(obj)
a.onNewObject(tree, obj)
return obj
}

// NewFunction creates a new function object that can be invoked, with the given symbol.
func (a *Allocator) NewFunction(fnc symbols.Function, this *rt.Object) *rt.Object {
func (a *Allocator) NewFunction(tree diag.Diagable, fnc symbols.Function, this *rt.Object) *rt.Object {
obj := rt.NewFunctionObject(fnc, this)
a.onNewObject(obj)
a.onNewObject(tree, obj)
return obj
}

// NewPointer allocates a new pointer-like object that wraps the given reference.
func (a *Allocator) NewPointer(t symbols.Type, ptr *rt.Pointer) *rt.Object {
func (a *Allocator) NewPointer(tree diag.Diagable, t symbols.Type, ptr *rt.Pointer) *rt.Object {
obj := rt.NewPointerObject(t, ptr)
a.onNewObject(obj)
a.onNewObject(tree, obj)
return obj
}

// NewConstant returns a new object with the right type and value, based on some constant data.
func (a *Allocator) NewConstant(v interface{}) *rt.Object {
func (a *Allocator) NewConstant(tree diag.Diagable, v interface{}) *rt.Object {
obj := rt.NewConstantObject(v)
a.onNewObject(obj)
a.onNewObject(tree, obj)
return obj
}
Loading

0 comments on commit 877fa13

Please sign in to comment.