2017-06-26 23:46:34 +02:00
|
|
|
// Copyright 2016-2017, Pulumi Corporation. All rights reserved.
|
2017-02-22 03:31:43 +01:00
|
|
|
|
2017-10-16 21:04:35 +02:00
|
|
|
package stack
|
2017-02-22 03:31:43 +01:00
|
|
|
|
|
|
|
import (
|
2017-02-22 23:32:03 +01:00
|
|
|
"reflect"
|
2017-02-26 20:20:14 +01:00
|
|
|
"time"
|
2017-02-22 23:32:03 +01:00
|
|
|
|
2017-09-22 04:18:21 +02:00
|
|
|
"github.com/pulumi/pulumi/pkg/resource"
|
|
|
|
"github.com/pulumi/pulumi/pkg/resource/deploy"
|
|
|
|
"github.com/pulumi/pulumi/pkg/tokens"
|
|
|
|
"github.com/pulumi/pulumi/pkg/util/contract"
|
2017-02-22 03:31:43 +01:00
|
|
|
)
|
|
|
|
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
// Deployment is a serializable, flattened LumiGL graph structure, representing a deploy. It is similar
|
2017-06-10 03:34:37 +02:00
|
|
|
// to the actual Snapshot structure, except that it flattens and rearranges a few data structures for serializability.
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
// Over time, we also expect this to gather more information about deploys themselves.
|
Overhaul resources, planning, and environments
This change, part of pulumi/lumi#90, overhauls quite a bit of the
core resource, planning, environments, and related areas.
The biggest amount of movement comes from the splitting of pkg/resource
into multiple sub-packages. This results in:
- pkg/resource: just the core resource data structures.
- pkg/resource/deployment: all planning and deployment logic.
- pkg/resource/environment: all environment, configuration, and
serialized checkpoint structures and logic.
- pkg/resource/plugin: all dynamically loaded analyzer and
provider logic, including the actual loading and RPC mechanisms.
This also splits the resource abstraction up. We now have:
- resource.Resource: a shared interface.
- resource.Object: a resource that is connected to a live object
that will periodically observe mutations due to ongoing
evaluation of computations. Snapshots of its state may be
taken; however, this is purely a "pre-planning" abstraction.
- resource.State: a snapshot of a resource's state that is frozen.
In other words, it is no longer connected to a live object.
This is what will store provider outputs (ID and properties),
and is what may be serialized into a deployment record.
The branch is in a half-baked state as of this change; more changes
are to come...
2017-06-09 01:37:40 +02:00
|
|
|
type Deployment struct {
|
2017-10-19 00:37:18 +02:00
|
|
|
Time time.Time `json:"time" yaml:"time"` // the time of the deploy.
|
|
|
|
Resources []Resource `json:"resources,omitempty" yaml:"resources,omitempty"` // an array of resources.
|
2017-02-22 03:31:43 +01:00
|
|
|
}
|
|
|
|
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
// Resource is a serializable vertex within a LumiGL graph, specifically for resource snapshots.
|
|
|
|
type Resource struct {
|
2017-10-20 22:21:04 +02:00
|
|
|
URN resource.URN `json:"urn" yaml:"urn"` // the URN for this resource.
|
|
|
|
Custom bool `json:"custom" yaml:"custom"` // if this is a custom resource managed by a plugin.
|
|
|
|
Delete bool `json:"delete,omitempty" yaml:"delete,omitempty"` // if this should be deleted during the next update.
|
|
|
|
ID resource.ID `json:"id,omitempty" yaml:"id,omitempty"` // the provider ID for this resource, if any.
|
|
|
|
Type tokens.Type `json:"type" yaml:"type"` // this resource's full type token.
|
|
|
|
Inputs map[string]interface{} `json:"inputs,omitempty" yaml:"inputs,omitempty"` // the input properties from the program.
|
|
|
|
Defaults map[string]interface{} `json:"defaults,omitempty" yaml:"defaults,omitempty"` // the default property values from the provider.
|
|
|
|
Outputs map[string]interface{} `json:"outputs,omitempty" yaml:"outputs,omitempty"` // the output properties from the resource provider.
|
2017-11-17 03:21:41 +01:00
|
|
|
Parent resource.URN `json:"parent,omitempty" yaml:"parent,omitempty"` // an optional parent URN if this is a child resource.
|
2017-02-22 03:31:43 +01:00
|
|
|
}
|
|
|
|
|
2017-11-18 00:22:41 +01:00
|
|
|
// RootPulumiStackTypeName is the type name that will be used for the root component in the Pulumi resource tree.
|
|
|
|
const RootPulumiStackTypeName tokens.Type = "pulumi:pulumi:Stack"
|
|
|
|
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
// SerializeDeployment serializes an entire snapshot as a deploy record.
|
|
|
|
func SerializeDeployment(snap *deploy.Snapshot) *Deployment {
|
2017-02-22 03:31:43 +01:00
|
|
|
// Serialize all vertices and only include a vertex section if non-empty.
|
2017-10-05 23:08:35 +02:00
|
|
|
var resources []Resource
|
|
|
|
for _, res := range snap.Resources {
|
|
|
|
resources = append(resources, SerializeResource(res))
|
2017-02-22 03:31:43 +01:00
|
|
|
}
|
|
|
|
|
Overhaul resources, planning, and environments
This change, part of pulumi/lumi#90, overhauls quite a bit of the
core resource, planning, environments, and related areas.
The biggest amount of movement comes from the splitting of pkg/resource
into multiple sub-packages. This results in:
- pkg/resource: just the core resource data structures.
- pkg/resource/deployment: all planning and deployment logic.
- pkg/resource/environment: all environment, configuration, and
serialized checkpoint structures and logic.
- pkg/resource/plugin: all dynamically loaded analyzer and
provider logic, including the actual loading and RPC mechanisms.
This also splits the resource abstraction up. We now have:
- resource.Resource: a shared interface.
- resource.Object: a resource that is connected to a live object
that will periodically observe mutations due to ongoing
evaluation of computations. Snapshots of its state may be
taken; however, this is purely a "pre-planning" abstraction.
- resource.State: a snapshot of a resource's state that is frozen.
In other words, it is no longer connected to a live object.
This is what will store provider outputs (ID and properties),
and is what may be serialized into a deployment record.
The branch is in a half-baked state as of this change; more changes
are to come...
2017-06-09 01:37:40 +02:00
|
|
|
return &Deployment{
|
2017-10-10 03:02:27 +02:00
|
|
|
Time: snap.Time,
|
2017-10-05 23:08:35 +02:00
|
|
|
Resources: resources,
|
2017-02-22 03:31:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-05 23:08:35 +02:00
|
|
|
// SerializeResource turns a resource into a structure suitable for serialization.
|
|
|
|
func SerializeResource(res *resource.State) Resource {
|
2017-02-22 03:31:43 +01:00
|
|
|
contract.Assert(res != nil)
|
2017-10-05 23:08:35 +02:00
|
|
|
contract.Assertf(string(res.URN) != "", "Unexpected empty resource resource.URN")
|
2017-02-22 03:31:43 +01:00
|
|
|
|
2017-06-05 04:24:48 +02:00
|
|
|
// Serialize all input and output properties recursively, and add them if non-empty.
|
2017-06-07 01:42:14 +02:00
|
|
|
var inputs map[string]interface{}
|
2017-08-01 03:26:15 +02:00
|
|
|
if inp := res.Inputs; inp != nil {
|
2017-06-10 03:34:37 +02:00
|
|
|
inputs = SerializeProperties(inp)
|
2017-06-07 01:42:14 +02:00
|
|
|
}
|
2017-08-01 03:26:15 +02:00
|
|
|
var defaults map[string]interface{}
|
|
|
|
if defp := res.Defaults; defp != nil {
|
|
|
|
defaults = SerializeProperties(defp)
|
|
|
|
}
|
2017-06-07 01:42:14 +02:00
|
|
|
var outputs map[string]interface{}
|
2017-08-01 03:26:15 +02:00
|
|
|
if outp := res.Outputs; outp != nil {
|
2017-06-10 03:34:37 +02:00
|
|
|
outputs = SerializeProperties(outp)
|
2017-06-07 01:42:14 +02:00
|
|
|
}
|
2017-02-22 03:31:43 +01:00
|
|
|
|
2017-10-05 23:08:35 +02:00
|
|
|
return Resource{
|
|
|
|
URN: res.URN,
|
2017-10-15 12:52:04 +02:00
|
|
|
Custom: res.Custom,
|
2017-10-05 23:08:35 +02:00
|
|
|
Delete: res.Delete,
|
2017-08-01 03:26:15 +02:00
|
|
|
ID: res.ID,
|
2017-08-30 03:24:12 +02:00
|
|
|
Type: res.Type,
|
2017-11-17 03:21:41 +01:00
|
|
|
Parent: res.Parent,
|
2017-08-01 03:26:15 +02:00
|
|
|
Inputs: inputs,
|
|
|
|
Defaults: defaults,
|
|
|
|
Outputs: outputs,
|
2017-02-22 03:31:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-10 03:34:37 +02:00
|
|
|
// SerializeProperties serializes a resource property bag so that it's suitable for serialization.
|
|
|
|
func SerializeProperties(props resource.PropertyMap) map[string]interface{} {
|
2017-06-07 01:42:14 +02:00
|
|
|
dst := make(map[string]interface{})
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
for _, k := range props.StableKeys() {
|
2017-06-10 03:34:37 +02:00
|
|
|
if v := SerializePropertyValue(props[k]); v != nil {
|
2017-06-05 04:24:48 +02:00
|
|
|
dst[string(k)] = v
|
2017-02-22 23:32:03 +01:00
|
|
|
}
|
|
|
|
}
|
2017-06-05 04:24:48 +02:00
|
|
|
return dst
|
2017-02-22 23:32:03 +01:00
|
|
|
}
|
|
|
|
|
2017-06-10 03:34:37 +02:00
|
|
|
// SerializePropertyValue serializes a resource property value so that it's suitable for serialization.
|
|
|
|
func SerializePropertyValue(prop resource.PropertyValue) interface{} {
|
2017-06-05 04:24:48 +02:00
|
|
|
// Skip nulls and "outputs"; the former needn't be serialized, and the latter happens if there is an output
|
|
|
|
// that hasn't materialized (either because we're serializing inputs or the provider didn't give us the value).
|
2017-10-24 01:02:28 +02:00
|
|
|
if prop.IsComputed() || !prop.HasValue() {
|
2017-06-01 17:23:59 +02:00
|
|
|
return nil
|
2017-02-22 03:31:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// For arrays, make sure to recurse.
|
|
|
|
if prop.IsArray() {
|
2017-06-07 01:42:14 +02:00
|
|
|
srcarr := prop.ArrayValue()
|
|
|
|
dstarr := make([]interface{}, len(srcarr))
|
|
|
|
for i, elem := range prop.ArrayValue() {
|
2017-06-10 03:34:37 +02:00
|
|
|
dstarr[i] = SerializePropertyValue(elem)
|
2017-02-22 03:31:43 +01:00
|
|
|
}
|
2017-06-07 01:42:14 +02:00
|
|
|
return dstarr
|
2017-02-22 03:31:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Also for objects, recurse and use naked properties.
|
|
|
|
if prop.IsObject() {
|
2017-06-10 03:34:37 +02:00
|
|
|
return SerializeProperties(prop.ObjectValue())
|
2017-02-22 03:31:43 +01:00
|
|
|
}
|
|
|
|
|
2017-07-17 19:38:57 +02:00
|
|
|
// For assets, we need to serialize them a little carefully, so we can recover them afterwards.
|
|
|
|
if prop.IsAsset() {
|
|
|
|
return prop.AssetValue().Serialize()
|
|
|
|
} else if prop.IsArchive() {
|
|
|
|
return prop.ArchiveValue().Serialize()
|
|
|
|
}
|
|
|
|
|
2017-02-22 03:31:43 +01:00
|
|
|
// All others are returned as-is.
|
2017-06-01 17:23:59 +02:00
|
|
|
return prop.V
|
2017-02-22 03:31:43 +01:00
|
|
|
}
|
|
|
|
|
2017-10-05 23:08:35 +02:00
|
|
|
// DeserializeResource turns a serialized resource back into its usual form.
|
2017-10-22 22:39:21 +02:00
|
|
|
func DeserializeResource(res Resource) (*resource.State, error) {
|
2017-10-05 23:08:35 +02:00
|
|
|
// Deserialize the resource properties, if they exist.
|
2017-10-22 22:39:21 +02:00
|
|
|
inputs, err := DeserializeProperties(res.Inputs)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defaults, err := DeserializeProperties(res.Defaults)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
outputs, err := DeserializeProperties(res.Outputs)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-10-05 23:08:35 +02:00
|
|
|
|
2017-10-22 22:39:21 +02:00
|
|
|
return resource.NewState(
|
2017-11-17 03:21:41 +01:00
|
|
|
res.Type, res.URN, res.Custom, res.Delete, res.ID, inputs, defaults, outputs, res.Parent), nil
|
2017-10-05 23:08:35 +02:00
|
|
|
}
|
|
|
|
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
// DeserializeProperties deserializes an entire map of deploy properties into a resource property map.
|
2017-10-22 22:39:21 +02:00
|
|
|
func DeserializeProperties(props map[string]interface{}) (resource.PropertyMap, error) {
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
result := make(resource.PropertyMap)
|
2017-02-22 23:32:03 +01:00
|
|
|
for k, prop := range props {
|
2017-10-22 22:39:21 +02:00
|
|
|
desprop, err := DeserializePropertyValue(prop)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
result[resource.PropertyKey(k)] = desprop
|
2017-02-22 23:32:03 +01:00
|
|
|
}
|
2017-10-22 22:39:21 +02:00
|
|
|
return result, nil
|
2017-02-22 23:32:03 +01:00
|
|
|
}
|
|
|
|
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
// DeserializePropertyValue deserializes a single deploy property into a resource property value.
|
2017-10-22 22:39:21 +02:00
|
|
|
func DeserializePropertyValue(v interface{}) (resource.PropertyValue, error) {
|
2017-02-22 23:32:03 +01:00
|
|
|
if v != nil {
|
|
|
|
switch w := v.(type) {
|
|
|
|
case bool:
|
2017-10-22 22:39:21 +02:00
|
|
|
return resource.NewBoolProperty(w), nil
|
2017-02-22 23:32:03 +01:00
|
|
|
case float64:
|
2017-10-22 22:39:21 +02:00
|
|
|
return resource.NewNumberProperty(w), nil
|
2017-02-22 23:32:03 +01:00
|
|
|
case string:
|
2017-10-22 22:39:21 +02:00
|
|
|
return resource.NewStringProperty(w), nil
|
2017-02-22 23:32:03 +01:00
|
|
|
case []interface{}:
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
var arr []resource.PropertyValue
|
2017-02-22 23:32:03 +01:00
|
|
|
for _, elem := range w {
|
2017-10-22 22:39:21 +02:00
|
|
|
ev, err := DeserializePropertyValue(elem)
|
|
|
|
if err != nil {
|
|
|
|
return resource.PropertyValue{}, err
|
|
|
|
}
|
|
|
|
arr = append(arr, ev)
|
2017-02-22 23:32:03 +01:00
|
|
|
}
|
2017-10-22 22:39:21 +02:00
|
|
|
return resource.NewArrayProperty(arr), nil
|
2017-02-22 23:32:03 +01:00
|
|
|
case map[string]interface{}:
|
2017-10-22 22:39:21 +02:00
|
|
|
obj, err := DeserializeProperties(w)
|
|
|
|
if err != nil {
|
|
|
|
return resource.PropertyValue{}, err
|
|
|
|
}
|
2017-07-17 19:38:57 +02:00
|
|
|
// This could be an asset or archive; if so, recover its type.
|
|
|
|
objmap := obj.Mappable()
|
2017-10-23 00:54:44 +02:00
|
|
|
asset, isasset, err := resource.DeserializeAsset(objmap)
|
2017-10-22 22:39:21 +02:00
|
|
|
if err != nil {
|
|
|
|
return resource.PropertyValue{}, err
|
|
|
|
} else if isasset {
|
|
|
|
return resource.NewAssetProperty(asset), nil
|
|
|
|
}
|
2017-10-23 00:54:44 +02:00
|
|
|
archive, isarchive, err := resource.DeserializeArchive(objmap)
|
2017-10-22 22:39:21 +02:00
|
|
|
if err != nil {
|
|
|
|
return resource.PropertyValue{}, err
|
|
|
|
} else if isarchive {
|
|
|
|
return resource.NewArchiveProperty(archive), nil
|
2017-07-17 19:38:57 +02:00
|
|
|
}
|
|
|
|
// Otherwise, it's just a weakly typed object map.
|
2017-10-22 22:39:21 +02:00
|
|
|
return resource.NewObjectProperty(obj), nil
|
2017-02-22 23:32:03 +01:00
|
|
|
default:
|
|
|
|
contract.Failf("Unrecognized property type: %v", reflect.ValueOf(v))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-22 22:39:21 +02:00
|
|
|
return resource.NewNullProperty(), nil
|
2017-02-22 03:31:43 +01:00
|
|
|
}
|