We are going to be changing the configuration model. To begin, let's take most of the existing stuff and mark it as "deprecated" so we can keep the existing behavior (to help transition newer code forward) while making it clear what APIs should not be called in the implementation of `pulumi` itself.
142 lines
4.7 KiB
Go
142 lines
4.7 KiB
Go
// Copyright 2016-2017, Pulumi Corporation. All rights reserved.
|
|
|
|
package workspace
|
|
|
|
import (
|
|
"io/ioutil"
|
|
"path/filepath"
|
|
|
|
"github.com/pulumi/pulumi/pkg/resource/config"
|
|
"github.com/pulumi/pulumi/pkg/util/contract"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/pulumi/pulumi/pkg/encoding"
|
|
"github.com/pulumi/pulumi/pkg/tokens"
|
|
)
|
|
|
|
// Analyzers is a list of analyzers to run on this project.
|
|
type Analyzers []tokens.QName
|
|
|
|
// Project is a Pulumi project manifest..
|
|
//
|
|
// We explicitly add yaml tags (instead of using the default behavior from https://github.com/ghodss/yaml which works
|
|
// in terms of the JSON tags) so we can directly marshall and unmarshall this struct using go-yaml an have the fields
|
|
// in the serialized object match the order they are defined in this struct.
|
|
//
|
|
// TODO[pulumi/pulumi#423]: use DOM based marshalling so we can roundtrip the seralized structure perfectly.
|
|
// nolint: lll
|
|
type Project struct {
|
|
Name tokens.PackageName `json:"name" yaml:"name"` // a required fully qualified name.
|
|
Runtime string `json:"runtime" yaml:"runtime"` // a required runtime that executes code.
|
|
Main string `json:"main,omitempty" yaml:"main,omitempty"` // an optional override for the main program location.
|
|
|
|
Description *string `json:"description,omitempty" yaml:"description,omitempty"` // an optional informational description.
|
|
Author *string `json:"author,omitempty" yaml:"author,omitempty"` // an optional author.
|
|
Website *string `json:"website,omitempty" yaml:"website,omitempty"` // an optional website for additional info.
|
|
License *string `json:"license,omitempty" yaml:"license,omitempty"` // an optional license governing this project's usage.
|
|
|
|
Analyzers *Analyzers `json:"analyzers,omitempty" yaml:"analyzers,omitempty"` // any analyzers enabled for this project.
|
|
|
|
EncryptionSaltDeprecated string `json:"encryptionsalt,omitempty" yaml:"encryptionsalt,omitempty"` // base64 encoded encryption salt.
|
|
Context string `json:"context,omitempty" yaml:"context,omitempty"` // an optional path (combined with the on disk location of Pulumi.yaml) to control the data uploaded to the service.
|
|
NoDefaultIgnores *bool `json:"nodefaultignores,omitempty" yaml:"nodefaultignores,omitempty"` // true if we should only respect .pulumiignore when archiving
|
|
|
|
ConfigDeprecated map[tokens.ModuleMember]config.Value `json:"config,omitempty" yaml:"config,omitempty"` // optional config (applies to all stacks).
|
|
|
|
StacksDeprecated map[tokens.QName]ProjectStack `json:"stacks,omitempty" yaml:"stacks,omitempty"` // optional stack specific information.
|
|
}
|
|
|
|
func (proj *Project) Validate() error {
|
|
if proj.Name == "" {
|
|
return errors.New("project is missing a 'name' attribute")
|
|
}
|
|
if proj.Runtime == "" {
|
|
return errors.New("project is missing a 'runtime' attribute")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (proj *Project) UseDefaultIgnores() bool {
|
|
if proj.NoDefaultIgnores == nil {
|
|
return true
|
|
}
|
|
|
|
return !(*proj.NoDefaultIgnores)
|
|
}
|
|
|
|
// Save writes a project defitiniton to a file.
|
|
func (proj *Project) Save(path string) error {
|
|
contract.Require(path != "", "path")
|
|
contract.Require(proj != nil, "proj")
|
|
contract.Requiref(proj.Validate() == nil, "proj", "Validate()")
|
|
|
|
for name, info := range proj.StacksDeprecated {
|
|
if info.IsEmpty() {
|
|
delete(proj.StacksDeprecated, name)
|
|
}
|
|
}
|
|
|
|
m, err := marshallerForPath(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
b, err := m.Marshal(proj)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return ioutil.WriteFile(path, b, 0644)
|
|
}
|
|
|
|
// ProjectStack holds stack specific information about a project.
|
|
// nolint: lll
|
|
type ProjectStack struct {
|
|
EncryptionSalt string `json:"encryptionsalt,omitempty" yaml:"encryptionsalt,omitempty"` // base64 encoded encryption salt.
|
|
Config config.Map `json:"config,omitempty" yaml:"config,omitempty"` // optional config.
|
|
}
|
|
|
|
// IsEmpty returns True if this object contains no information (i.e. all members have their zero values)
|
|
func (s *ProjectStack) IsEmpty() bool {
|
|
return len(s.Config) == 0 && s.EncryptionSalt == ""
|
|
}
|
|
|
|
// LoadProject reads a project definition from a file.
|
|
func LoadProject(path string) (*Project, error) {
|
|
contract.Require(path != "", "proj")
|
|
|
|
m, err := marshallerForPath(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
b, err := ioutil.ReadFile(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var proj Project
|
|
err = m.Unmarshal(b, &proj)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = proj.Validate()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &proj, err
|
|
}
|
|
|
|
func marshallerForPath(path string) (encoding.Marshaler, error) {
|
|
ext := filepath.Ext(path)
|
|
m, has := encoding.Marshalers[ext]
|
|
if !has {
|
|
return nil, errors.Errorf("no marshaler found for file format '%v'", ext)
|
|
}
|
|
|
|
return m, nil
|
|
}
|