2018-05-22 21:43:36 +02:00
|
|
|
// Copyright 2016-2018, Pulumi Corporation.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
2017-01-13 23:32:10 +01:00
|
|
|
|
2018-02-14 22:56:16 +01:00
|
|
|
package workspace
|
2017-01-13 23:32:10 +01:00
|
|
|
|
|
|
|
import (
|
2018-06-25 07:47:54 +02:00
|
|
|
"encoding/json"
|
2017-10-17 20:27:54 +02:00
|
|
|
"io/ioutil"
|
2018-02-28 00:51:19 +01:00
|
|
|
"os"
|
2017-10-17 20:27:54 +02:00
|
|
|
"path/filepath"
|
|
|
|
|
2017-10-19 00:37:18 +02:00
|
|
|
"github.com/pulumi/pulumi/pkg/resource/config"
|
2017-10-17 20:27:54 +02:00
|
|
|
"github.com/pulumi/pulumi/pkg/util/contract"
|
|
|
|
|
2017-08-31 19:21:17 +02:00
|
|
|
"github.com/pkg/errors"
|
|
|
|
|
2017-10-17 20:27:54 +02:00
|
|
|
"github.com/pulumi/pulumi/pkg/encoding"
|
2017-09-22 04:18:21 +02:00
|
|
|
"github.com/pulumi/pulumi/pkg/tokens"
|
2017-01-13 23:32:10 +01:00
|
|
|
)
|
|
|
|
|
2018-02-14 22:56:16 +01:00
|
|
|
// Analyzers is a list of analyzers to run on this project.
|
|
|
|
type Analyzers []tokens.QName
|
|
|
|
|
Initial support for passing URLs to `new` and `up` (#1727)
* Initial support for passing URLs to `new` and `up`
This PR adds initial support for `pulumi new` using Git under the covers
to manage Pulumi templates, providing the same experience as before.
You can now also optionally pass a URL to a Git repository, e.g.
`pulumi new [<url>]`, including subdirectories within the repository,
and arbitrary branches, tags, or commits.
The following commands result in the same behavior from the user's
perspective:
- `pulumi new javascript`
- `pulumi new https://github.com/pulumi/templates/templates/javascript`
- `pulumi new https://github.com/pulumi/templates/tree/master/templates/javascript`
- `pulumi new https://github.com/pulumi/templates/tree/HEAD/templates/javascript`
To specify an arbitrary branch, tag, or commit:
- `pulumi new https://github.com/pulumi/templates/tree/<branch>/templates/javascript`
- `pulumi new https://github.com/pulumi/templates/tree/<tag>/templates/javascript`
- `pulumi new https://github.com/pulumi/templates/tree/<commit>/templates/javascript`
Branches and tags can include '/' separators, and `pulumi` will still
find the right subdirectory.
URLs to Gists are also supported, e.g.:
`pulumi new https://gist.github.com/justinvp/6673959ceb9d2ac5a14c6d536cb871a6`
If the specified subdirectory in the repository does not contain a
`Pulumi.yaml`, it will look for subdirectories within containing
`Pulumi.yaml` files, and prompt the user to choose a template, along the
lines of how `pulumi new` behaves when no template is specified.
The following commands result in the CLI prompting to choose a template:
- `pulumi new`
- `pulumi new https://github.com/pulumi/templates/templates`
- `pulumi new https://github.com/pulumi/templates/tree/master/templates`
- `pulumi new https://github.com/pulumi/templates/tree/HEAD/templates`
Of course, arbitrary branches, tags, or commits can be specified as well:
- `pulumi new https://github.com/pulumi/templates/tree/<branch>/templates`
- `pulumi new https://github.com/pulumi/templates/tree/<tag>/templates`
- `pulumi new https://github.com/pulumi/templates/tree/<commit>/templates`
This PR also includes initial support for passing URLs to `pulumi up`,
providing a streamlined way to deploy installable cloud applications
with Pulumi, without having to manage source code locally before doing
a deployment.
For example, `pulumi up https://github.com/justinvp/aws` can be used to
deploy a sample AWS app. The stack can be updated with different
versions, e.g.
`pulumi up https://github.com/justinvp/aws/tree/v2 -s <stack-to-update>`
Config values can optionally be passed via command line flags, e.g.
`pulumi up https://github.com/justinvp/aws -c aws:region=us-west-2 -c foo:bar=blah`
Gists can also be used, e.g.
`pulumi up https://gist.github.com/justinvp/62fde0463f243fcb49f5a7222e51bc76`
* Fix panic when hitting ^C from "choose template" prompt
* Add description to templates
When running `pulumi new` without specifying a template, include the template description along with the name in the "choose template" display.
```
$ pulumi new
Please choose a template:
aws-go A minimal AWS Go program
aws-javascript A minimal AWS JavaScript program
aws-python A minimal AWS Python program
aws-typescript A minimal AWS TypeScript program
> go A minimal Go program
hello-aws-javascript A simple AWS serverless JavaScript program
javascript A minimal JavaScript program
python A minimal Python program
typescript A minimal TypeScript program
```
* React to changes to the pulumi/templates repo.
We restructured the `pulumi/templates` repo to have all the templates in the root instead of in a `templates` subdirectory, so make the change here to no longer look for templates in `templates`.
This also fixes an issue around using `Depth: 1` that I found while testing this. When a named template is used, we attempt to clone or pull from the `pulumi/templates` repo to `~/.pulumi/templates`. Having it go in this well-known directory allows us to maintain previous behavior around allowing offline use of templates. If we use `Depth: 1` for the initial clone, it will fail when attempting to pull when there are updates to the remote repository. Unfortunately, there's no built-in `--unshallow` support in `go-git` and setting a larger `Depth` doesn't appear to help. There may be a workaround, but for now, if we're cloning the pulumi templates directory to `~/.pulumi/templates`, we won't use `Depth: 1`. For template URLs, we will continue to use `Depth: 1` as we clone those to a temp directory (which gets deleted) that we'll never try to update.
* List available templates in help text
* Address PR Feedback
* Don't show "Installing dependencies" message for `up`
* Fix secrets handling
When prompting for config, if the existing stack value is a secret, keep it a secret and mask the prompt. If the template says it should be secret, make it a secret.
* Fix ${PROJECT} and ${DESCRIPTION} handling for `up`
Templates used with `up` should already have a filled-in project name and description, but if it's a `new`-style template, that has `${PROJECT}` and/or `${DESCRIPTION}`, be helpful and just replace these with better values.
* Fix stack handling
Add a bool `setCurrent` param to `requireStack` to control whether the current stack should be saved in workspace settings. For the `up <url>` case, we don't want to save. Also, split the `up` code into two separate functions: one for the `up <url>` case and another for the normal `up` case where you have workspace in your current directory. While we may be able to combine them back into a single function, right now it's a bit cleaner being separate, even with some small amount of duplication.
* Fix panic due to nil crypter
Lazily get the crypter only if needed inside `promptForConfig`.
* Embellish comment
* Harden isPreconfiguredEmptyStack check
Fix the code to check to make sure the URL specified on the command line matches the URL stored in the `pulumi:template` config value, and that the rest of the config from the stack satisfies the config requirements of the template.
2018-08-11 03:08:16 +02:00
|
|
|
// ProjectTemplate is a Pulumi project template manifest.
|
|
|
|
type ProjectTemplate struct {
|
2018-11-01 16:28:11 +01:00
|
|
|
// Description is an optional description of the template.
|
|
|
|
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
|
|
|
// Quickstart contains optional text to be displayed after template creation.
|
|
|
|
Quickstart string `json:"quickstart,omitempty" yaml:"quickstart,omitempty"`
|
|
|
|
// Config is an optional template config.
|
|
|
|
Config map[string]ProjectTemplateConfigValue `json:"config,omitempty" yaml:"config,omitempty"`
|
2019-08-28 02:56:49 +02:00
|
|
|
// Important indicates the template is important and should be listed by default.
|
|
|
|
Important bool `json:"important,omitempty" yaml:"important,omitempty"`
|
Initial support for passing URLs to `new` and `up` (#1727)
* Initial support for passing URLs to `new` and `up`
This PR adds initial support for `pulumi new` using Git under the covers
to manage Pulumi templates, providing the same experience as before.
You can now also optionally pass a URL to a Git repository, e.g.
`pulumi new [<url>]`, including subdirectories within the repository,
and arbitrary branches, tags, or commits.
The following commands result in the same behavior from the user's
perspective:
- `pulumi new javascript`
- `pulumi new https://github.com/pulumi/templates/templates/javascript`
- `pulumi new https://github.com/pulumi/templates/tree/master/templates/javascript`
- `pulumi new https://github.com/pulumi/templates/tree/HEAD/templates/javascript`
To specify an arbitrary branch, tag, or commit:
- `pulumi new https://github.com/pulumi/templates/tree/<branch>/templates/javascript`
- `pulumi new https://github.com/pulumi/templates/tree/<tag>/templates/javascript`
- `pulumi new https://github.com/pulumi/templates/tree/<commit>/templates/javascript`
Branches and tags can include '/' separators, and `pulumi` will still
find the right subdirectory.
URLs to Gists are also supported, e.g.:
`pulumi new https://gist.github.com/justinvp/6673959ceb9d2ac5a14c6d536cb871a6`
If the specified subdirectory in the repository does not contain a
`Pulumi.yaml`, it will look for subdirectories within containing
`Pulumi.yaml` files, and prompt the user to choose a template, along the
lines of how `pulumi new` behaves when no template is specified.
The following commands result in the CLI prompting to choose a template:
- `pulumi new`
- `pulumi new https://github.com/pulumi/templates/templates`
- `pulumi new https://github.com/pulumi/templates/tree/master/templates`
- `pulumi new https://github.com/pulumi/templates/tree/HEAD/templates`
Of course, arbitrary branches, tags, or commits can be specified as well:
- `pulumi new https://github.com/pulumi/templates/tree/<branch>/templates`
- `pulumi new https://github.com/pulumi/templates/tree/<tag>/templates`
- `pulumi new https://github.com/pulumi/templates/tree/<commit>/templates`
This PR also includes initial support for passing URLs to `pulumi up`,
providing a streamlined way to deploy installable cloud applications
with Pulumi, without having to manage source code locally before doing
a deployment.
For example, `pulumi up https://github.com/justinvp/aws` can be used to
deploy a sample AWS app. The stack can be updated with different
versions, e.g.
`pulumi up https://github.com/justinvp/aws/tree/v2 -s <stack-to-update>`
Config values can optionally be passed via command line flags, e.g.
`pulumi up https://github.com/justinvp/aws -c aws:region=us-west-2 -c foo:bar=blah`
Gists can also be used, e.g.
`pulumi up https://gist.github.com/justinvp/62fde0463f243fcb49f5a7222e51bc76`
* Fix panic when hitting ^C from "choose template" prompt
* Add description to templates
When running `pulumi new` without specifying a template, include the template description along with the name in the "choose template" display.
```
$ pulumi new
Please choose a template:
aws-go A minimal AWS Go program
aws-javascript A minimal AWS JavaScript program
aws-python A minimal AWS Python program
aws-typescript A minimal AWS TypeScript program
> go A minimal Go program
hello-aws-javascript A simple AWS serverless JavaScript program
javascript A minimal JavaScript program
python A minimal Python program
typescript A minimal TypeScript program
```
* React to changes to the pulumi/templates repo.
We restructured the `pulumi/templates` repo to have all the templates in the root instead of in a `templates` subdirectory, so make the change here to no longer look for templates in `templates`.
This also fixes an issue around using `Depth: 1` that I found while testing this. When a named template is used, we attempt to clone or pull from the `pulumi/templates` repo to `~/.pulumi/templates`. Having it go in this well-known directory allows us to maintain previous behavior around allowing offline use of templates. If we use `Depth: 1` for the initial clone, it will fail when attempting to pull when there are updates to the remote repository. Unfortunately, there's no built-in `--unshallow` support in `go-git` and setting a larger `Depth` doesn't appear to help. There may be a workaround, but for now, if we're cloning the pulumi templates directory to `~/.pulumi/templates`, we won't use `Depth: 1`. For template URLs, we will continue to use `Depth: 1` as we clone those to a temp directory (which gets deleted) that we'll never try to update.
* List available templates in help text
* Address PR Feedback
* Don't show "Installing dependencies" message for `up`
* Fix secrets handling
When prompting for config, if the existing stack value is a secret, keep it a secret and mask the prompt. If the template says it should be secret, make it a secret.
* Fix ${PROJECT} and ${DESCRIPTION} handling for `up`
Templates used with `up` should already have a filled-in project name and description, but if it's a `new`-style template, that has `${PROJECT}` and/or `${DESCRIPTION}`, be helpful and just replace these with better values.
* Fix stack handling
Add a bool `setCurrent` param to `requireStack` to control whether the current stack should be saved in workspace settings. For the `up <url>` case, we don't want to save. Also, split the `up` code into two separate functions: one for the `up <url>` case and another for the normal `up` case where you have workspace in your current directory. While we may be able to combine them back into a single function, right now it's a bit cleaner being separate, even with some small amount of duplication.
* Fix panic due to nil crypter
Lazily get the crypter only if needed inside `promptForConfig`.
* Embellish comment
* Harden isPreconfiguredEmptyStack check
Fix the code to check to make sure the URL specified on the command line matches the URL stored in the `pulumi:template` config value, and that the rest of the config from the stack satisfies the config requirements of the template.
2018-08-11 03:08:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// ProjectTemplateConfigValue is a config value included in the project template manifest.
|
|
|
|
type ProjectTemplateConfigValue struct {
|
2018-11-01 16:28:11 +01:00
|
|
|
// Description is an optional description for the config value.
|
|
|
|
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
|
|
|
// Default is an optional default value for the config value.
|
|
|
|
Default string `json:"default,omitempty" yaml:"default,omitempty"`
|
|
|
|
// Secret may be set to true to indicate that the config value should be encrypted.
|
|
|
|
Secret bool `json:"secret,omitempty" yaml:"secret,omitempty"`
|
Initial support for passing URLs to `new` and `up` (#1727)
* Initial support for passing URLs to `new` and `up`
This PR adds initial support for `pulumi new` using Git under the covers
to manage Pulumi templates, providing the same experience as before.
You can now also optionally pass a URL to a Git repository, e.g.
`pulumi new [<url>]`, including subdirectories within the repository,
and arbitrary branches, tags, or commits.
The following commands result in the same behavior from the user's
perspective:
- `pulumi new javascript`
- `pulumi new https://github.com/pulumi/templates/templates/javascript`
- `pulumi new https://github.com/pulumi/templates/tree/master/templates/javascript`
- `pulumi new https://github.com/pulumi/templates/tree/HEAD/templates/javascript`
To specify an arbitrary branch, tag, or commit:
- `pulumi new https://github.com/pulumi/templates/tree/<branch>/templates/javascript`
- `pulumi new https://github.com/pulumi/templates/tree/<tag>/templates/javascript`
- `pulumi new https://github.com/pulumi/templates/tree/<commit>/templates/javascript`
Branches and tags can include '/' separators, and `pulumi` will still
find the right subdirectory.
URLs to Gists are also supported, e.g.:
`pulumi new https://gist.github.com/justinvp/6673959ceb9d2ac5a14c6d536cb871a6`
If the specified subdirectory in the repository does not contain a
`Pulumi.yaml`, it will look for subdirectories within containing
`Pulumi.yaml` files, and prompt the user to choose a template, along the
lines of how `pulumi new` behaves when no template is specified.
The following commands result in the CLI prompting to choose a template:
- `pulumi new`
- `pulumi new https://github.com/pulumi/templates/templates`
- `pulumi new https://github.com/pulumi/templates/tree/master/templates`
- `pulumi new https://github.com/pulumi/templates/tree/HEAD/templates`
Of course, arbitrary branches, tags, or commits can be specified as well:
- `pulumi new https://github.com/pulumi/templates/tree/<branch>/templates`
- `pulumi new https://github.com/pulumi/templates/tree/<tag>/templates`
- `pulumi new https://github.com/pulumi/templates/tree/<commit>/templates`
This PR also includes initial support for passing URLs to `pulumi up`,
providing a streamlined way to deploy installable cloud applications
with Pulumi, without having to manage source code locally before doing
a deployment.
For example, `pulumi up https://github.com/justinvp/aws` can be used to
deploy a sample AWS app. The stack can be updated with different
versions, e.g.
`pulumi up https://github.com/justinvp/aws/tree/v2 -s <stack-to-update>`
Config values can optionally be passed via command line flags, e.g.
`pulumi up https://github.com/justinvp/aws -c aws:region=us-west-2 -c foo:bar=blah`
Gists can also be used, e.g.
`pulumi up https://gist.github.com/justinvp/62fde0463f243fcb49f5a7222e51bc76`
* Fix panic when hitting ^C from "choose template" prompt
* Add description to templates
When running `pulumi new` without specifying a template, include the template description along with the name in the "choose template" display.
```
$ pulumi new
Please choose a template:
aws-go A minimal AWS Go program
aws-javascript A minimal AWS JavaScript program
aws-python A minimal AWS Python program
aws-typescript A minimal AWS TypeScript program
> go A minimal Go program
hello-aws-javascript A simple AWS serverless JavaScript program
javascript A minimal JavaScript program
python A minimal Python program
typescript A minimal TypeScript program
```
* React to changes to the pulumi/templates repo.
We restructured the `pulumi/templates` repo to have all the templates in the root instead of in a `templates` subdirectory, so make the change here to no longer look for templates in `templates`.
This also fixes an issue around using `Depth: 1` that I found while testing this. When a named template is used, we attempt to clone or pull from the `pulumi/templates` repo to `~/.pulumi/templates`. Having it go in this well-known directory allows us to maintain previous behavior around allowing offline use of templates. If we use `Depth: 1` for the initial clone, it will fail when attempting to pull when there are updates to the remote repository. Unfortunately, there's no built-in `--unshallow` support in `go-git` and setting a larger `Depth` doesn't appear to help. There may be a workaround, but for now, if we're cloning the pulumi templates directory to `~/.pulumi/templates`, we won't use `Depth: 1`. For template URLs, we will continue to use `Depth: 1` as we clone those to a temp directory (which gets deleted) that we'll never try to update.
* List available templates in help text
* Address PR Feedback
* Don't show "Installing dependencies" message for `up`
* Fix secrets handling
When prompting for config, if the existing stack value is a secret, keep it a secret and mask the prompt. If the template says it should be secret, make it a secret.
* Fix ${PROJECT} and ${DESCRIPTION} handling for `up`
Templates used with `up` should already have a filled-in project name and description, but if it's a `new`-style template, that has `${PROJECT}` and/or `${DESCRIPTION}`, be helpful and just replace these with better values.
* Fix stack handling
Add a bool `setCurrent` param to `requireStack` to control whether the current stack should be saved in workspace settings. For the `up <url>` case, we don't want to save. Also, split the `up` code into two separate functions: one for the `up <url>` case and another for the normal `up` case where you have workspace in your current directory. While we may be able to combine them back into a single function, right now it's a bit cleaner being separate, even with some small amount of duplication.
* Fix panic due to nil crypter
Lazily get the crypter only if needed inside `promptForConfig`.
* Embellish comment
* Harden isPreconfiguredEmptyStack check
Fix the code to check to make sure the URL specified on the command line matches the URL stored in the `pulumi:template` config value, and that the rest of the config from the stack satisfies the config requirements of the template.
2018-08-11 03:08:16 +02:00
|
|
|
}
|
|
|
|
|
2019-06-11 00:07:21 +02:00
|
|
|
// ProjectBackend is a configuration for backend used by project
|
|
|
|
type ProjectBackend struct {
|
|
|
|
// URL is optional field to explicitly set backend url
|
|
|
|
URL string `json:"url,omitempty" yaml:"url,omitempty"`
|
|
|
|
}
|
|
|
|
|
2018-11-01 16:28:11 +01:00
|
|
|
// Project is a Pulumi project manifest.
|
2017-10-17 19:48:53 +02:00
|
|
|
//
|
2017-11-16 16:49:07 +01:00
|
|
|
// 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.
|
2018-02-14 22:56:16 +01:00
|
|
|
type Project struct {
|
2018-11-01 16:28:11 +01:00
|
|
|
// Name is a required fully qualified name.
|
|
|
|
Name tokens.PackageName `json:"name" yaml:"name"`
|
|
|
|
// Runtime is a required runtime that executes code.
|
|
|
|
Runtime ProjectRuntimeInfo `json:"runtime" yaml:"runtime"`
|
|
|
|
// Main is an optional override for the program's main entry-point location.
|
|
|
|
Main string `json:"main,omitempty" yaml:"main,omitempty"`
|
|
|
|
|
|
|
|
// Description is an optional informational description.
|
|
|
|
Description *string `json:"description,omitempty" yaml:"description,omitempty"`
|
|
|
|
// Author is an optional author that created this project.
|
|
|
|
Author *string `json:"author,omitempty" yaml:"author,omitempty"`
|
|
|
|
// Website is an optional website for additional info about this project.
|
|
|
|
Website *string `json:"website,omitempty" yaml:"website,omitempty"`
|
|
|
|
// License is the optional license governing this project's usage.
|
|
|
|
License *string `json:"license,omitempty" yaml:"license,omitempty"`
|
|
|
|
|
|
|
|
// Config indicates where to store the Pulumi.<stack-name>.yaml files, combined with the folder Pulumi.yaml is in.
|
|
|
|
Config string `json:"config,omitempty" yaml:"config,omitempty"`
|
|
|
|
|
|
|
|
// Template is an optional template manifest, if this project is a template.
|
|
|
|
Template *ProjectTemplate `json:"template,omitempty" yaml:"template,omitempty"`
|
2019-06-11 00:07:21 +02:00
|
|
|
|
|
|
|
// Backend is an optional backend configuration
|
|
|
|
Backend *ProjectBackend `json:"backend,omitempty" yaml:"backend,omitempty"`
|
2017-01-13 23:32:10 +01:00
|
|
|
}
|
|
|
|
|
2018-02-14 22:56:16 +01:00
|
|
|
func (proj *Project) Validate() error {
|
|
|
|
if proj.Name == "" {
|
|
|
|
return errors.New("project is missing a 'name' attribute")
|
2017-08-31 19:21:17 +02:00
|
|
|
}
|
2018-11-01 16:28:11 +01:00
|
|
|
if proj.Runtime.Name() == "" {
|
2018-02-14 22:56:16 +01:00
|
|
|
return errors.New("project is missing a 'runtime' attribute")
|
2017-08-31 19:21:17 +02:00
|
|
|
}
|
2018-06-25 07:47:54 +02:00
|
|
|
|
2017-08-31 19:21:17 +02:00
|
|
|
return nil
|
2017-01-13 23:32:10 +01:00
|
|
|
}
|
Overhaul names versus tokens
I was sloppy in my use of names versus tokens in the original AST.
Now that we're actually binding things to concrete symbols, etc., we
need to be more precise. In particular, names are just identifiers
that must be "interpreted" in a given lexical context for them to
make any sense; whereas, tokens stand alone and can be resolved without
context other than the set of imported packages, modules, and overall
module structure. As such, names are much simpler than tokens.
As explained in the comments, tokens.Names are simple identifiers:
Name = [A-Za-z_][A-Za-z0-9_]*
and tokens.QNames are fully qualified identifiers delimited by "/":
QName = [ <Name> "/" ]* <Name>
The legal grammar for a token depends on the subset of symbols that
token is meant to represent. However, the most general case, that
accepts all specializations of tokens, is roughly as follows:
Token = <Name> |
<PackageName>
[ ":" <ModuleName>
[ "/" <ModuleMemberName>
[ "." <Class MemberName> ]
]
]
where:
PackageName = <QName>
ModuleName = <QName>
ModuleMemberName = <Name>
ClassMemberName = <Name>
Please refer to the comments in pkg/tokens/tokens.go for more details.
2017-01-20 02:57:20 +01:00
|
|
|
|
2018-09-28 00:49:08 +02:00
|
|
|
// TrustResourceDependencies returns whether or not this project's runtime can be trusted to accurately report
|
2019-02-12 23:49:43 +01:00
|
|
|
// dependencies. All languages supported by Pulumi today do this correctly. This option remains useful when bringing
|
|
|
|
// up new Pulumi languages.
|
2018-09-28 00:49:08 +02:00
|
|
|
func (proj *Project) TrustResourceDependencies() bool {
|
2019-02-12 23:49:43 +01:00
|
|
|
return true
|
2018-09-28 00:49:08 +02:00
|
|
|
}
|
|
|
|
|
2018-02-28 00:51:19 +01:00
|
|
|
// Save writes a project definition to a file.
|
2018-02-14 22:56:16 +01:00
|
|
|
func (proj *Project) Save(path string) error {
|
|
|
|
contract.Require(path != "", "path")
|
|
|
|
contract.Require(proj != nil, "proj")
|
|
|
|
contract.Requiref(proj.Validate() == nil, "proj", "Validate()")
|
2017-10-17 20:27:54 +02:00
|
|
|
|
|
|
|
m, err := marshallerForPath(path)
|
|
|
|
if err != nil {
|
2018-02-14 22:56:16 +01:00
|
|
|
return err
|
2017-10-17 20:27:54 +02:00
|
|
|
}
|
|
|
|
|
2018-02-14 22:56:16 +01:00
|
|
|
b, err := m.Marshal(proj)
|
2017-10-17 20:27:54 +02:00
|
|
|
if err != nil {
|
2018-02-14 22:56:16 +01:00
|
|
|
return err
|
2017-10-17 20:27:54 +02:00
|
|
|
}
|
|
|
|
|
2018-02-14 22:56:16 +01:00
|
|
|
return ioutil.WriteFile(path, b, 0644)
|
|
|
|
}
|
|
|
|
|
2019-10-10 00:33:35 +02:00
|
|
|
type PolicyPackProject struct {
|
|
|
|
// Runtime is a required runtime that executes code.
|
|
|
|
Runtime ProjectRuntimeInfo `json:"runtime" yaml:"runtime"`
|
|
|
|
// Main is an optional override for the program's main entry-point location.
|
|
|
|
Main string `json:"main,omitempty" yaml:"main,omitempty"`
|
|
|
|
|
|
|
|
// Description is an optional informational description.
|
|
|
|
Description *string `json:"description,omitempty" yaml:"description,omitempty"`
|
|
|
|
// Author is an optional author that created this project.
|
|
|
|
Author *string `json:"author,omitempty" yaml:"author,omitempty"`
|
|
|
|
// Website is an optional website for additional info about this project.
|
|
|
|
Website *string `json:"website,omitempty" yaml:"website,omitempty"`
|
|
|
|
// License is the optional license governing this project's usage.
|
|
|
|
License *string `json:"license,omitempty" yaml:"license,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (proj *PolicyPackProject) Validate() error {
|
|
|
|
if proj.Runtime.Name() == "" {
|
|
|
|
return errors.New("project is missing a 'runtime' attribute")
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-02-14 22:56:16 +01:00
|
|
|
// ProjectStack holds stack specific information about a project.
|
|
|
|
type ProjectStack struct {
|
2019-08-03 01:12:16 +02:00
|
|
|
// SecretsProvider is this stack's secrets provider.
|
|
|
|
SecretsProvider string `json:"secretsprovider,omitempty" yaml:"secretsprovider,omitempty"`
|
|
|
|
// EncryptedKey is the KMS-encrypted ciphertext for the data key used for secrets encryption.
|
|
|
|
// Only used for cloud-based secrets providers.
|
|
|
|
EncryptedKey string `json:"encryptedkey,omitempty" yaml:"encryptedkey,omitempty"`
|
|
|
|
// EncryptionSalt is this stack's base64 encoded encryption salt. Only used for
|
|
|
|
// passphrase-based secrets providers.
|
2018-11-01 16:28:11 +01:00
|
|
|
EncryptionSalt string `json:"encryptionsalt,omitempty" yaml:"encryptionsalt,omitempty"`
|
|
|
|
// Config is an optional config bag.
|
|
|
|
Config config.Map `json:"config,omitempty" yaml:"config,omitempty"`
|
2018-02-14 22:56:16 +01:00
|
|
|
}
|
|
|
|
|
2018-02-28 00:51:19 +01:00
|
|
|
// Save writes a project definition to a file.
|
|
|
|
func (ps *ProjectStack) Save(path string) error {
|
|
|
|
contract.Require(path != "", "path")
|
|
|
|
contract.Require(ps != nil, "ps")
|
|
|
|
|
|
|
|
m, err := marshallerForPath(path)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
b, err := m.Marshal(ps)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-05-17 04:42:50 +02:00
|
|
|
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-02-28 00:51:19 +01:00
|
|
|
return ioutil.WriteFile(path, b, 0644)
|
2018-02-14 22:56:16 +01:00
|
|
|
}
|
|
|
|
|
2018-06-25 07:47:54 +02:00
|
|
|
type ProjectRuntimeInfo struct {
|
|
|
|
name string
|
2018-08-06 20:05:44 +02:00
|
|
|
options map[string]interface{}
|
2018-06-25 07:47:54 +02:00
|
|
|
}
|
|
|
|
|
2018-08-06 20:05:44 +02:00
|
|
|
func NewProjectRuntimeInfo(name string, options map[string]interface{}) ProjectRuntimeInfo {
|
2018-06-25 07:47:54 +02:00
|
|
|
return ProjectRuntimeInfo{
|
|
|
|
name: name,
|
|
|
|
options: options,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (info *ProjectRuntimeInfo) Name() string {
|
|
|
|
return info.name
|
|
|
|
}
|
|
|
|
|
2018-08-06 20:05:44 +02:00
|
|
|
func (info *ProjectRuntimeInfo) Options() map[string]interface{} {
|
2018-06-25 07:47:54 +02:00
|
|
|
return info.options
|
|
|
|
}
|
|
|
|
|
|
|
|
func (info ProjectRuntimeInfo) MarshalYAML() (interface{}, error) {
|
|
|
|
if info.options == nil || len(info.options) == 0 {
|
|
|
|
return info.name, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return map[string]interface{}{
|
|
|
|
"name": info.name,
|
|
|
|
"options": info.options,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (info ProjectRuntimeInfo) MarshalJSON() ([]byte, error) {
|
|
|
|
if info.options == nil || len(info.options) == 0 {
|
|
|
|
return json.Marshal(info.name)
|
|
|
|
}
|
|
|
|
|
|
|
|
return json.Marshal(map[string]interface{}{
|
|
|
|
"name": info.name,
|
|
|
|
"options": info.options,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (info *ProjectRuntimeInfo) UnmarshalJSON(data []byte) error {
|
|
|
|
if err := json.Unmarshal(data, &info.name); err == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var payload struct {
|
2018-08-06 20:05:44 +02:00
|
|
|
Name string `json:"name"`
|
|
|
|
Options map[string]interface{} `json:"options"`
|
2018-06-25 07:47:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if err := json.Unmarshal(data, &payload); err == nil {
|
|
|
|
info.name = payload.Name
|
|
|
|
info.options = payload.Options
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return errors.New("runtime section must be a string or an object with name and options attributes")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (info *ProjectRuntimeInfo) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
|
|
if err := unmarshal(&info.name); err == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var payload struct {
|
2018-08-06 20:05:44 +02:00
|
|
|
Name string `yaml:"name"`
|
|
|
|
Options map[string]interface{} `yaml:"options"`
|
2018-06-25 07:47:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if err := unmarshal(&payload); err == nil {
|
|
|
|
info.name = payload.Name
|
|
|
|
info.options = payload.Options
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return errors.New("runtime section must be a string or an object with name and options attributes")
|
|
|
|
}
|
|
|
|
|
2018-02-14 22:56:16 +01:00
|
|
|
// LoadProject reads a project definition from a file.
|
|
|
|
func LoadProject(path string) (*Project, error) {
|
2018-02-28 00:51:19 +01:00
|
|
|
contract.Require(path != "", "path")
|
2018-02-14 22:56:16 +01:00
|
|
|
|
|
|
|
m, err := marshallerForPath(path)
|
2017-10-17 20:27:54 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-02-14 22:56:16 +01:00
|
|
|
b, err := ioutil.ReadFile(path)
|
2017-10-17 20:27:54 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-02-14 22:56:16 +01:00
|
|
|
var proj Project
|
|
|
|
err = m.Unmarshal(b, &proj)
|
2017-10-17 20:27:54 +02:00
|
|
|
if err != nil {
|
2018-02-14 22:56:16 +01:00
|
|
|
return nil, err
|
2017-10-17 20:27:54 +02:00
|
|
|
}
|
|
|
|
|
2018-02-14 22:56:16 +01:00
|
|
|
err = proj.Validate()
|
2017-10-17 20:27:54 +02:00
|
|
|
if err != nil {
|
2018-02-14 22:56:16 +01:00
|
|
|
return nil, err
|
2017-10-17 20:27:54 +02:00
|
|
|
}
|
|
|
|
|
2018-02-14 22:56:16 +01:00
|
|
|
return &proj, err
|
2017-10-17 20:27:54 +02:00
|
|
|
}
|
|
|
|
|
2019-10-10 00:33:35 +02:00
|
|
|
// LoadPolicyPack reads a policy pack definition from a file.
|
|
|
|
func LoadPolicyPack(path string) (*PolicyPackProject, error) {
|
|
|
|
contract.Require(path != "", "path")
|
|
|
|
|
|
|
|
m, err := marshallerForPath(path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
b, err := ioutil.ReadFile(path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var proj PolicyPackProject
|
|
|
|
err = m.Unmarshal(b, &proj)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = proj.Validate()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &proj, err
|
|
|
|
}
|
|
|
|
|
2018-02-28 00:51:19 +01:00
|
|
|
// LoadProjectStack reads a stack definition from a file.
|
|
|
|
func LoadProjectStack(path string) (*ProjectStack, error) {
|
|
|
|
contract.Require(path != "", "path")
|
|
|
|
|
|
|
|
m, err := marshallerForPath(path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
b, err := ioutil.ReadFile(path)
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
return &ProjectStack{
|
|
|
|
Config: make(config.Map),
|
|
|
|
}, nil
|
|
|
|
} else if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var ps ProjectStack
|
|
|
|
err = m.Unmarshal(b, &ps)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if ps.Config == nil {
|
|
|
|
ps.Config = make(config.Map)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &ps, err
|
|
|
|
}
|
|
|
|
|
2017-10-17 20:27:54 +02:00
|
|
|
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
|
|
|
|
}
|