//
// This file is automatically generated by scripts/generate-plugins.go -- Do not edit!
//

package command

import (
	"flag"
	"fmt"
	"regexp"
	"strings"

	packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
	"github.com/hashicorp/packer-plugin-sdk/plugin"

	filebuilder "github.com/hashicorp/packer/builder/file"
	nullbuilder "github.com/hashicorp/packer/builder/null"
	hcppackerartifactdatasource "github.com/hashicorp/packer/datasource/hcp-packer-artifact"
	hcppackerimagedatasource "github.com/hashicorp/packer/datasource/hcp-packer-image"
	hcppackeriterationdatasource "github.com/hashicorp/packer/datasource/hcp-packer-iteration"
	hcppackerversiondatasource "github.com/hashicorp/packer/datasource/hcp-packer-version"
	httpdatasource "github.com/hashicorp/packer/datasource/http"
	nulldatasource "github.com/hashicorp/packer/datasource/null"
	artificepostprocessor "github.com/hashicorp/packer/post-processor/artifice"
	checksumpostprocessor "github.com/hashicorp/packer/post-processor/checksum"
	compresspostprocessor "github.com/hashicorp/packer/post-processor/compress"
	manifestpostprocessor "github.com/hashicorp/packer/post-processor/manifest"
	shelllocalpostprocessor "github.com/hashicorp/packer/post-processor/shell-local"
	breakpointprovisioner "github.com/hashicorp/packer/provisioner/breakpoint"
	fileprovisioner "github.com/hashicorp/packer/provisioner/file"
	hcpsbomprovisioner "github.com/hashicorp/packer/provisioner/hcp-sbom"
	powershellprovisioner "github.com/hashicorp/packer/provisioner/powershell"
	shellprovisioner "github.com/hashicorp/packer/provisioner/shell"
	shelllocalprovisioner "github.com/hashicorp/packer/provisioner/shell-local"
	sleepprovisioner "github.com/hashicorp/packer/provisioner/sleep"
	windowsrestartprovisioner "github.com/hashicorp/packer/provisioner/windows-restart"
	windowsshellprovisioner "github.com/hashicorp/packer/provisioner/windows-shell"
)

type ExecuteCommand struct {
	Meta
}

var Builders = map[string]packersdk.Builder{
	"file": new(filebuilder.Builder),
	"null": new(nullbuilder.Builder),
}

var Provisioners = map[string]packersdk.Provisioner{
	"breakpoint":      new(breakpointprovisioner.Provisioner),
	"file":            new(fileprovisioner.Provisioner),
	"hcp-sbom":        new(hcpsbomprovisioner.Provisioner),
	"powershell":      new(powershellprovisioner.Provisioner),
	"shell":           new(shellprovisioner.Provisioner),
	"shell-local":     new(shelllocalprovisioner.Provisioner),
	"sleep":           new(sleepprovisioner.Provisioner),
	"windows-restart": new(windowsrestartprovisioner.Provisioner),
	"windows-shell":   new(windowsshellprovisioner.Provisioner),
}

var PostProcessors = map[string]packersdk.PostProcessor{
	"artifice":    new(artificepostprocessor.PostProcessor),
	"checksum":    new(checksumpostprocessor.PostProcessor),
	"compress":    new(compresspostprocessor.PostProcessor),
	"manifest":    new(manifestpostprocessor.PostProcessor),
	"shell-local": new(shelllocalpostprocessor.PostProcessor),
}

var Datasources = map[string]packersdk.Datasource{
	"hcp-packer-artifact":  new(hcppackerartifactdatasource.Datasource),
	"hcp-packer-image":     new(hcppackerimagedatasource.Datasource),
	"hcp-packer-iteration": new(hcppackeriterationdatasource.Datasource),
	"hcp-packer-version":   new(hcppackerversiondatasource.Datasource),
	"http":                 new(httpdatasource.Datasource),
	"null":                 new(nulldatasource.Datasource),
}

var pluginRegexp = regexp.MustCompile("packer-(builder|post-processor|provisioner|datasource)-(.+)")

type ExecuteArgs struct {
	UseProtobuf bool
	CommandType string
}

func (ea *ExecuteArgs) AddFlagSets(flags *flag.FlagSet) {
	flags.BoolVar(&ea.UseProtobuf, "protobuf", false, "Use protobuf for serialising data over the wire instead of gob")
}

func (c *ExecuteCommand) ParseArgs(args []string) (*ExecuteArgs, int) {
	var cfg ExecuteArgs
	flags := c.Meta.FlagSet("")
	flags.Usage = func() { c.Ui.Say(c.Help()) }
	cfg.AddFlagSets(flags)
	if err := flags.Parse(args); err != nil {
		return &cfg, 1
	}

	args = flags.Args()
	if len(args) != 1 {
		flags.Usage()
		return &cfg, 1
	}
	cfg.CommandType = args[0]
	return &cfg, 0
}

func (c *ExecuteCommand) Run(args []string) int {
	cfg, ret := c.ParseArgs(args)
	if ret != 0 {
		return ret
	}

	return c.RunContext(cfg)
}

func (c *ExecuteCommand) RunContext(args *ExecuteArgs) int {
	// Plugin will match something like "packer-builder-amazon-ebs"
	parts := pluginRegexp.FindStringSubmatch(args.CommandType)
	if len(parts) != 3 {
		c.Ui.Error(c.Help())
		return 1
	}
	pluginType := parts[1] // capture group 1 (builder|post-processor|provisioner)
	pluginName := parts[2] // capture group 2 (.+)

	server, err := plugin.Server()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error starting plugin server: %s", err))
		return 1
	}

	if args.UseProtobuf {
		server.UseProto = true
	}

	switch pluginType {
	case "builder":
		builder, found := Builders[pluginName]
		if !found {
			c.Ui.Error(fmt.Sprintf("Could not load builder: %s", pluginName))
			return 1
		}
		server.RegisterBuilder(builder)
	case "provisioner":
		provisioner, found := Provisioners[pluginName]
		if !found {
			c.Ui.Error(fmt.Sprintf("Could not load provisioner: %s", pluginName))
			return 1
		}
		server.RegisterProvisioner(provisioner)
	case "post-processor":
		postProcessor, found := PostProcessors[pluginName]
		if !found {
			c.Ui.Error(fmt.Sprintf("Could not load post-processor: %s", pluginName))
			return 1
		}
		server.RegisterPostProcessor(postProcessor)
	case "datasource":
		datasource, found := Datasources[pluginName]
		if !found {
			c.Ui.Error(fmt.Sprintf("Could not load datasource: %s", pluginName))
			return 1
		}
		server.RegisterDatasource(datasource)
	}

	server.Serve()

	return 0
}

func (*ExecuteCommand) Help() string {
	helpText := `
Usage: packer execute [options] PLUGIN

  Runs an internally-compiled version of a plugin from the packer binary.

  NOTE: this is an internal command and you should not call it yourself.

Options:

  --protobuf: use protobuf for serialising data over-the-wire instead of gob.
`

	return strings.TrimSpace(helpText)
}

func (c *ExecuteCommand) Synopsis() string {
	return "internal plugin command"
}
