This reverts commit 3a2890c0cd
.
This commit is contained in:
parent
3a2890c0cd
commit
81b6afa3c7
|
@ -2,12 +2,10 @@ CHANGELOG
|
|||
=========
|
||||
|
||||
## HEAD (Unreleased)
|
||||
- Fix Kubernetes YAML parsing error in .NET.
|
||||
* Fix Kubernetes YAML parsing error in .NET.
|
||||
[#4023](https://github.com/pulumi/pulumi/pull/4023)
|
||||
- Avoid projects beginning with `Pulumi` to stop cyclic imports
|
||||
[#4013](https://github.com/pulumi/pulumi/pull/4013)
|
||||
- Add support for plugin acquisition for Go programs
|
||||
[#3830](https://github.com/pulumi/pulumi/pull/3830)
|
||||
|
||||
## 1.12.0 (2020-03-04)
|
||||
- Avoid Configuring providers which are not used during preview.
|
||||
|
|
|
@ -600,7 +600,7 @@ func (pkg *pkgContext) genResource(w io.Writer, r *schema.Resource) error {
|
|||
fmt.Fprintf(w, "// Get%[1]s gets an existing %[1]s resource's state with the given name, ID, and optional\n", name)
|
||||
fmt.Fprintf(w, "// state properties that are used to uniquely qualify the lookup (nil if not required).\n")
|
||||
fmt.Fprintf(w, "func Get%s(ctx *pulumi.Context,\n", name)
|
||||
fmt.Fprintf(w, "\tname string, id pulumi.StringInput, state *%[1]sState, opts ...pulumi.ResourceOption) (*%[1]s, error) {\n", name)
|
||||
fmt.Fprintf(w, "\tname string, id pulumi.IDInput, state *%[1]sState, opts ...pulumi.ResourceOption) (*%[1]s, error) {\n", name)
|
||||
fmt.Fprintf(w, "\tvar resource %s\n", name)
|
||||
fmt.Fprintf(w, "\terr := ctx.ReadResource(\"%s\", name, id, state, &resource, opts...)\n", r.Token)
|
||||
fmt.Fprintf(w, "\tif err != nil {\n")
|
||||
|
@ -720,7 +720,7 @@ func (pkg *pkgContext) genType(w io.Writer, obj *schema.ObjectType) {
|
|||
pkg.genOutputTypes(w, obj, pkg.details(obj))
|
||||
}
|
||||
|
||||
func (pkg *pkgContext) genTypeRegistrations(w io.Writer, types []*schema.ObjectType) {
|
||||
func (pkg *pkgContext) genInitFn(w io.Writer, types []*schema.ObjectType) {
|
||||
fmt.Fprintf(w, "func init() {\n")
|
||||
for _, obj := range types {
|
||||
name, details := pkg.tokenToType(obj.Token), pkg.details(obj)
|
||||
|
@ -879,12 +879,6 @@ func (pkg *pkgContext) genConfig(w io.Writer, variables []*schema.Property) erro
|
|||
return nil
|
||||
}
|
||||
|
||||
func (pkg *pkgContext) genPackageRegistration(w io.Writer) {
|
||||
fmt.Fprintf(w, "func init() {\n")
|
||||
fmt.Fprintf(w, "\tpulumi.RegisterPackage(pulumi.PackageInfo{Name:\"%s\", Version:\"%s\"})\n", pkg.pkg.Name, pkg.pkg.Version.String())
|
||||
fmt.Fprintf(w, "}\n")
|
||||
}
|
||||
|
||||
func GeneratePackage(tool string, pkg *schema.Package) (map[string][]byte, error) {
|
||||
// group resources, types, and functions into Go packages
|
||||
packages := map[string]*pkgContext{}
|
||||
|
@ -998,7 +992,7 @@ func GeneratePackage(tool string, pkg *schema.Package) (map[string][]byte, error
|
|||
files[relPath] = []byte(contents)
|
||||
}
|
||||
|
||||
name, registerPackage := pkg.Name, pkg.Provider != nil
|
||||
name := pkg.Name
|
||||
for _, mod := range pkgMods {
|
||||
pkg := packages[mod]
|
||||
|
||||
|
@ -1070,21 +1064,11 @@ func GeneratePackage(tool string, pkg *schema.Package) (map[string][]byte, error
|
|||
pkg.genType(buffer, t)
|
||||
}
|
||||
|
||||
pkg.genTypeRegistrations(buffer, pkg.types)
|
||||
pkg.genInitFn(buffer, pkg.types)
|
||||
|
||||
setFile(path.Join(mod, "pulumiTypes.go"), buffer.String())
|
||||
}
|
||||
|
||||
// Package registration
|
||||
if registerPackage {
|
||||
buffer := &bytes.Buffer{}
|
||||
|
||||
pkg.genHeader(buffer, []string{"github.com/pulumi/pulumi/sdk/go/pulumi"}, nil)
|
||||
pkg.genPackageRegistration(buffer)
|
||||
|
||||
setFile(path.Join(mod, "pulumiManifest.go"), buffer.String())
|
||||
}
|
||||
|
||||
// Utilities
|
||||
if pkg.needsUtils {
|
||||
buffer := &bytes.Buffer{}
|
||||
|
|
|
@ -36,73 +36,6 @@ import (
|
|||
pulumirpc "github.com/pulumi/pulumi/sdk/proto/go"
|
||||
)
|
||||
|
||||
const unableToFindProgramTemplate = "unable to find program: %s"
|
||||
|
||||
// findExecutable attempts to find the needed executable in various locations on the
|
||||
// filesystem, eventually resorting to searching in $PATH.
|
||||
func findExecutable(program string) (string, error) {
|
||||
// look in the same directory
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "unable to get current working directory")
|
||||
}
|
||||
|
||||
cwdProgram := filepath.Join(cwd, program)
|
||||
if fileInfo, err := os.Stat(cwdProgram); !os.IsNotExist(err) && !fileInfo.Mode().IsDir() {
|
||||
logging.V(5).Infof("program %s found in CWD", program)
|
||||
return cwdProgram, nil
|
||||
}
|
||||
|
||||
// look in $GOPATH/bin
|
||||
if goPath := os.Getenv("GOPATH"); len(goPath) > 0 {
|
||||
goPathProgram := filepath.Join(goPath, "bin", program)
|
||||
if fileInfo, err := os.Stat(goPathProgram); !os.IsNotExist(err) && !fileInfo.Mode().IsDir() {
|
||||
logging.V(5).Infof("program %s found in $GOPATH/bin", program)
|
||||
return goPathProgram, nil
|
||||
}
|
||||
}
|
||||
|
||||
// look in the $PATH somewhere
|
||||
if fullPath, err := exec.LookPath(program); err == nil {
|
||||
logging.V(5).Infof("program %s found in $PATH", program)
|
||||
return fullPath, nil
|
||||
}
|
||||
|
||||
return "", errors.Errorf(unableToFindProgramTemplate, program)
|
||||
}
|
||||
|
||||
func findProgram(project string) (*exec.Cmd, error) {
|
||||
// The program to execute is simply the name of the project. This ensures good Go toolability, whereby
|
||||
// you can simply run `go install .` to build a Pulumi program prior to running it, among other benefits.
|
||||
// For ease of use, if we don't find a pre-built program, we attempt to invoke via 'go run' on behalf of the user.
|
||||
program, err := findExecutable(project)
|
||||
if err == nil {
|
||||
return exec.Command(program), nil
|
||||
}
|
||||
|
||||
const message = "problem executing program (could not run language executor)"
|
||||
if err.Error() == fmt.Sprintf(unableToFindProgramTemplate, project) {
|
||||
logging.V(5).Infof("Unable to find program %s in $PATH, attempting invocation via 'go run'", program)
|
||||
program, err = findExecutable("go")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, message)
|
||||
}
|
||||
|
||||
// Fall back to 'go run' style execution
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to get current working directory")
|
||||
}
|
||||
|
||||
goFileSearchPattern := filepath.Join(cwd, "*.go")
|
||||
if matches, err := filepath.Glob(goFileSearchPattern); err != nil || len(matches) == 0 {
|
||||
return nil, errors.Errorf("Failed to find go files for 'go run' matching %s", goFileSearchPattern)
|
||||
}
|
||||
|
||||
return exec.Command(program, "run", cwd), nil
|
||||
}
|
||||
|
||||
// Launches the language host, which in turn fires up an RPC server implementing the LanguageRuntimeServer endpoint.
|
||||
func main() {
|
||||
var tracing string
|
||||
|
@ -156,33 +89,43 @@ func newLanguageHost(engineAddress, tracing string) pulumirpc.LanguageRuntimeSer
|
|||
// GetRequiredPlugins computes the complete set of anticipated plugins required by a program.
|
||||
func (host *goLanguageHost) GetRequiredPlugins(ctx context.Context,
|
||||
req *pulumirpc.GetRequiredPluginsRequest) (*pulumirpc.GetRequiredPluginsResponse, error) {
|
||||
return &pulumirpc.GetRequiredPluginsResponse{}, nil
|
||||
}
|
||||
|
||||
cmd, err := findProgram(req.GetProject())
|
||||
const unableToFindProgramTemplate = "unable to find program: %s"
|
||||
|
||||
// findProgram attempts to find the needed program in various locations on the
|
||||
// filesystem, eventually resorting to searching in $PATH.
|
||||
func findProgram(program string) (string, error) {
|
||||
|
||||
// look in the same directory
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", errors.Wrap(err, "unable to get current working directory")
|
||||
}
|
||||
|
||||
cmd.Env = []string{"PULUMI_PLUGINS=true"}
|
||||
stdout, err := cmd.Output()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
cwdProgram := filepath.Join(cwd, program)
|
||||
if fileInfo, err := os.Stat(cwdProgram); !os.IsNotExist(err) && !fileInfo.Mode().IsDir() {
|
||||
logging.V(5).Infof("program %s found in CWD", program)
|
||||
return cwdProgram, nil
|
||||
}
|
||||
|
||||
var infos map[string][]pulumi.PackageInfo
|
||||
if err := json.Unmarshal(stdout, &infos); err != nil {
|
||||
return nil, err
|
||||
// look in $GOPATH/bin
|
||||
if goPath := os.Getenv("GOPATH"); len(goPath) > 0 {
|
||||
goPathProgram := filepath.Join(goPath, "bin", program)
|
||||
if fileInfo, err := os.Stat(goPathProgram); !os.IsNotExist(err) && !fileInfo.Mode().IsDir() {
|
||||
logging.V(5).Infof("program %s found in $GOPATH/bin", program)
|
||||
return goPathProgram, nil
|
||||
}
|
||||
}
|
||||
|
||||
var plugins []*pulumirpc.PluginDependency
|
||||
for _, info := range infos["plugins"] {
|
||||
plugins = append(plugins, &pulumirpc.PluginDependency{
|
||||
Name: info.Name,
|
||||
Kind: "resource",
|
||||
Version: info.Version,
|
||||
Server: info.Server,
|
||||
})
|
||||
// look in the $PATH somewhere
|
||||
if fullPath, err := exec.LookPath(program); err == nil {
|
||||
logging.V(5).Infof("program %s found in $PATH", program)
|
||||
return fullPath, nil
|
||||
}
|
||||
return &pulumirpc.GetRequiredPluginsResponse{Plugins: plugins}, nil
|
||||
|
||||
return "", errors.Errorf(unableToFindProgramTemplate, program)
|
||||
}
|
||||
|
||||
// RPC endpoint for LanguageRuntimeServer::Run
|
||||
|
@ -194,14 +137,54 @@ func (host *goLanguageHost) Run(ctx context.Context, req *pulumirpc.RunRequest)
|
|||
return nil, errors.Wrap(err, "failed to prepare environment")
|
||||
}
|
||||
|
||||
cmd, err := findProgram(req.GetProject())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cmd.Env = env
|
||||
cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
|
||||
// by default we try to run a named executable on the path, but we will fallback to 'go run' style execution
|
||||
goRunInvoke := false
|
||||
|
||||
// The program to execute is simply the name of the project. This ensures good Go toolability, whereby
|
||||
// you can simply run `go install .` to build a Pulumi program prior to running it, among other benefits.
|
||||
// For ease of use, if we don't find a pre-built program, we attempt to invoke via 'go run' on behalf of the user.
|
||||
program, err := findProgram(req.GetProject())
|
||||
if err != nil {
|
||||
const message = "problem executing program (could not run language executor)"
|
||||
if err.Error() == fmt.Sprintf(unableToFindProgramTemplate, req.GetProject()) {
|
||||
logging.V(5).Infof("Unable to find program %s in $PATH, attempting invocation via 'go run'", program)
|
||||
program, err = findProgram("go")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, message)
|
||||
}
|
||||
goRunInvoke = true
|
||||
} else {
|
||||
return nil, errors.Wrap(err, message)
|
||||
}
|
||||
}
|
||||
|
||||
logging.V(5).Infof("language host launching process: %s", program)
|
||||
|
||||
// Now simply spawn a process to execute the requested program, wiring up stdout/stderr directly.
|
||||
var errResult string
|
||||
var cmd *exec.Cmd
|
||||
|
||||
if goRunInvoke {
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to get current working directory")
|
||||
}
|
||||
|
||||
goFileSearchPattern := filepath.Join(cwd, "*.go")
|
||||
if matches, err := filepath.Glob(goFileSearchPattern); err != nil || len(matches) == 0 {
|
||||
return nil, errors.Errorf("Failed to find go files for 'go run' matching %s", goFileSearchPattern)
|
||||
}
|
||||
|
||||
args := []string{"run", cwd}
|
||||
// go run $cwd
|
||||
cmd = exec.Command(program, args...)
|
||||
} else {
|
||||
cmd = exec.Command(program)
|
||||
}
|
||||
|
||||
cmd.Env = env
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
if exiterr, ok := err.(*exec.ExitError); ok {
|
||||
// If the program ran, but exited with a non-zero error code. This will happen often, since user
|
||||
|
|
|
@ -27,8 +27,6 @@ import (
|
|||
"github.com/pulumi/pulumi/pkg/util/contract"
|
||||
)
|
||||
|
||||
var ErrPlugins = errors.New("pulumi: plugins requested")
|
||||
|
||||
// A RunOption is used to control the behavior of Run and RunErr.
|
||||
type RunOption func(*RunInfo)
|
||||
|
||||
|
@ -37,13 +35,8 @@ type RunOption func(*RunInfo)
|
|||
// If the program fails, the process will be terminated and the function will not return.
|
||||
func Run(body RunFunc, opts ...RunOption) {
|
||||
if err := RunErr(body, opts...); err != nil {
|
||||
if err != ErrPlugins {
|
||||
fmt.Fprintf(os.Stderr, "error: program failed: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
printRequiredPlugins()
|
||||
os.Exit(0)
|
||||
fmt.Fprintf(os.Stderr, "error: program failed: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,9 +46,6 @@ func RunErr(body RunFunc, opts ...RunOption) error {
|
|||
// Parse the info out of environment variables. This is a lame contract with the caller, but helps to keep
|
||||
// boilerplate to a minimum in the average Pulumi Go program.
|
||||
info := getEnvInfo()
|
||||
if info.getPlugins {
|
||||
return ErrPlugins
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&info)
|
||||
|
@ -131,7 +121,6 @@ type RunInfo struct {
|
|||
MonitorAddr string
|
||||
EngineAddr string
|
||||
Mocks MockResourceMonitor
|
||||
getPlugins bool
|
||||
}
|
||||
|
||||
// getEnvInfo reads various program information from the process environment.
|
||||
|
@ -139,7 +128,6 @@ func getEnvInfo() RunInfo {
|
|||
// Most of the variables are just strings, and we can read them directly. A few of them require more parsing.
|
||||
parallel, _ := strconv.Atoi(os.Getenv(EnvParallel))
|
||||
dryRun, _ := strconv.ParseBool(os.Getenv(EnvDryRun))
|
||||
getPlugins, _ := strconv.ParseBool(os.Getenv(envPlugins))
|
||||
|
||||
var config map[string]string
|
||||
if cfg := os.Getenv(EnvConfig); cfg != "" {
|
||||
|
@ -154,7 +142,6 @@ func getEnvInfo() RunInfo {
|
|||
DryRun: dryRun,
|
||||
MonitorAddr: os.Getenv(EnvMonitor),
|
||||
EngineAddr: os.Getenv(EnvEngine),
|
||||
getPlugins: getPlugins,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -173,28 +160,4 @@ const (
|
|||
EnvMonitor = "PULUMI_MONITOR"
|
||||
// EnvEngine is the envvar used to read the current Pulumi engine RPC address.
|
||||
EnvEngine = "PULUMI_ENGINE"
|
||||
// envPlugins is the envvar used to request that the Pulumi program print its set of required plugins and exit.
|
||||
envPlugins = "PULUMI_PLUGINS"
|
||||
)
|
||||
|
||||
type PackageInfo struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version,omitempty"`
|
||||
Server string `json:"server,omitempty"`
|
||||
}
|
||||
|
||||
var packageRegistry = map[PackageInfo]struct{}{}
|
||||
|
||||
func RegisterPackage(info PackageInfo) {
|
||||
packageRegistry[info] = struct{}{}
|
||||
}
|
||||
|
||||
func printRequiredPlugins() {
|
||||
plugins := []PackageInfo{}
|
||||
for info := range packageRegistry {
|
||||
plugins = append(plugins, info)
|
||||
}
|
||||
|
||||
err := json.NewEncoder(os.Stdout).Encode(map[string]interface{}{"plugins": plugins})
|
||||
contract.IgnoreError(err)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue