// 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.

package main

import (
	"github.com/spf13/cobra"

	"github.com/pulumi/pulumi/pkg/v2/engine"
	"github.com/pulumi/pulumi/sdk/v2/go/common/resource/plugin"
	"github.com/pulumi/pulumi/sdk/v2/go/common/util/cmdutil"
	"github.com/pulumi/pulumi/sdk/v2/go/common/util/contract"
	"github.com/pulumi/pulumi/sdk/v2/go/common/workspace"
)

func newPluginCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "plugin",
		Short: "Manage language and resource provider plugins",
		Long: "Manage language and resource provider plugins.\n" +
			"\n" +
			"Pulumi uses dynamically loaded plugins as an extensibility mechanism for\n" +
			"supporting any number of languages and resource providers.  These plugins are\n" +
			"distributed out of band and must be installed manually.  Attempting to use a\n" +
			"package that provisions resources without the corresponding plugin will fail.\n" +
			"\n" +
			"You may write your own plugins, for example to implement custom languages or\n" +
			"resources, although most people will never need to do this.  To understand how to\n" +
			"write and distribute your own plugins, please consult the relevant documentation.\n" +
			"\n" +
			"The plugin family of commands provides a way of explicitly managing plugins.",
		Args: cmdutil.NoArgs,
	}

	cmd.AddCommand(newPluginInstallCmd())
	cmd.AddCommand(newPluginLsCmd())
	cmd.AddCommand(newPluginRmCmd())

	return cmd
}

// getProjectPlugins fetches a list of plugins used by this project.
func getProjectPlugins() ([]workspace.PluginInfo, error) {
	proj, root, err := readProject()
	if err != nil {
		return nil, err
	}

	projinfo := &engine.Projinfo{Proj: proj, Root: root}
	pwd, main, ctx, err := engine.ProjectInfoContext(projinfo, nil, nil, cmdutil.Diag(),
		cmdutil.Diag(), nil)
	if err != nil {
		return nil, err
	}

	// Get the required plugins and then ensure they have metadata populated about them.  Because it's possible
	// a plugin required by the project hasn't yet been installed, we will simply skip any errors we encounter.
	var results []workspace.PluginInfo
	plugins, err := ctx.Host.GetRequiredPlugins(plugin.ProgInfo{
		Proj:    proj,
		Pwd:     pwd,
		Program: main,
	}, plugin.AllPlugins)
	if err != nil {
		return nil, err
	}
	for _, plugin := range plugins {
		if _, path, _ := workspace.GetPluginPath(plugin.Kind, plugin.Name, plugin.Version); path != "" {
			err = plugin.SetFileMetadata(path)
			if err != nil {
				return nil, err
			}
			contract.IgnoreError(err)
		}
		results = append(results, plugin)
	}
	return results, nil
}
