github.com/gobuffalo/buffalo-cli/v2@v2.0.0-alpha.15.0.20200919213536-a7350c8e6799/cli/cmds/newapp/cmd.go (about)

     1  package newapp
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"io"
     8  	"os"
     9  	"os/exec"
    10  	"path"
    11  	"path/filepath"
    12  	"text/template"
    13  
    14  	"github.com/gobuffalo/buffalo-cli/v2/cli/cmds/newapp/presets"
    15  	"github.com/gobuffalo/buffalo-cli/v2/cli/internal/cligen"
    16  	"github.com/gobuffalo/plugins"
    17  	"github.com/gobuffalo/plugins/plugcmd"
    18  	"github.com/gobuffalo/plugins/plugio"
    19  	"github.com/spf13/pflag"
    20  )
    21  
    22  var _ plugins.Plugin = &Cmd{}
    23  var _ plugcmd.Commander = &Cmd{}
    24  var _ plugcmd.Namer = &Cmd{}
    25  var _ plugins.Needer = &Cmd{}
    26  var _ plugins.Scoper = &Cmd{}
    27  
    28  type Cmd struct {
    29  	pluginsFn plugins.Feeder
    30  	flags     *pflag.FlagSet
    31  	help      bool
    32  	force     bool
    33  	presets   []string
    34  	usePlugs  map[string]string
    35  }
    36  
    37  func (Cmd) PluginName() string {
    38  	return "newapp/cmd"
    39  }
    40  
    41  func (Cmd) CmdName() string {
    42  	return "new"
    43  }
    44  
    45  func (cmd *Cmd) WithPlugins(f plugins.Feeder) {
    46  	cmd.pluginsFn = f
    47  }
    48  
    49  func (cmd *Cmd) ScopedPlugins() []plugins.Plugin {
    50  	if cmd.pluginsFn == nil {
    51  		return nil
    52  	}
    53  
    54  	var plugs []plugins.Plugin
    55  
    56  	for _, p := range cmd.pluginsFn() {
    57  		switch p.(type) {
    58  		case Stdouter:
    59  			plugs = append(plugs, p)
    60  		case Stdiner:
    61  			plugs = append(plugs, p)
    62  		case Stderrer:
    63  			plugs = append(plugs, p)
    64  		case NewCommandRunner:
    65  			plugs = append(plugs, p)
    66  		}
    67  	}
    68  
    69  	return plugs
    70  }
    71  
    72  func (cmd *Cmd) Main(ctx context.Context, root string, args []string) error {
    73  	flags := cmd.Flags()
    74  	flags.BoolVarP(&cmd.help, "help", "h", false, "print this help")
    75  	if err := flags.Parse(args); err != nil {
    76  		return plugins.Wrap(cmd, err)
    77  	}
    78  
    79  	var modName string
    80  	plugs := cmd.ScopedPlugins()
    81  	if cmd.help {
    82  		modName = "clitmp"
    83  		defer os.RemoveAll(filepath.Join(root, modName))
    84  	}
    85  
    86  	if len(modName) == 0 {
    87  		modName = flags.Args()[0]
    88  	}
    89  
    90  	if len(args) == 0 {
    91  		return plugins.Wrap(cmd, fmt.Errorf("missing application name"))
    92  	}
    93  
    94  	sargs := make([]string, 0, len(args))
    95  	for _, a := range args {
    96  		if a == modName {
    97  			continue
    98  		}
    99  		sargs = append(sargs, a)
   100  	}
   101  	args = sargs
   102  
   103  	dirName := path.Base(modName)
   104  
   105  	root = filepath.Join(root, dirName)
   106  	if cmd.force {
   107  		os.RemoveAll(root)
   108  	}
   109  
   110  	if err := os.MkdirAll(root, 0755); err != nil {
   111  		return plugins.Wrap(cmd, err)
   112  	}
   113  
   114  	os.Chdir(root)
   115  
   116  	if err := cmd.modInit(ctx, root, modName); err != nil {
   117  		return plugins.Wrap(cmd, err)
   118  	}
   119  
   120  	if cmd.usePlugs == nil {
   121  		cmd.usePlugs = map[string]string{}
   122  	}
   123  	if len(cmd.presets) == 0 {
   124  		cmd.presets = append(cmd.presets, "web")
   125  	}
   126  
   127  	pres := presets.Presets()
   128  	for _, p := range cmd.presets {
   129  		if v, ok := pres[p]; ok {
   130  			cmd.usePlugs[p] = v
   131  			continue
   132  		}
   133  		cmd.usePlugs[path.Base(p)] = p
   134  	}
   135  
   136  	tmpl, err := template.New("").Parse(cliMain)
   137  	if err != nil {
   138  		return plugins.Wrap(cmd, err)
   139  	}
   140  
   141  	cd := filepath.Join(root, "cmd", "newapp")
   142  	if err := os.MkdirAll(cd, 0755); err != nil {
   143  		return plugins.Wrap(cmd, err)
   144  	}
   145  
   146  	w, err := os.Create(filepath.Join(cd, "main.go"))
   147  	if err != nil {
   148  		return err
   149  	}
   150  	defer w.Close()
   151  
   152  	err = tmpl.Execute(w, map[string]interface{}{
   153  		"Plugs": cmd.usePlugs,
   154  		"Args":  fmt.Sprintf("%#v", args),
   155  		"Name":  modName,
   156  	})
   157  	if err != nil {
   158  		return plugins.Wrap(cmd, err)
   159  	}
   160  
   161  	g := &cligen.Generator{
   162  		Plugins: cmd.usePlugs,
   163  	}
   164  	if err := g.Generate(ctx, root, args); err != nil {
   165  		return plugins.Wrap(cmd, err)
   166  	}
   167  
   168  	os.Chdir(root)
   169  
   170  	c := exec.CommandContext(ctx, "go", "run", "./cmd/newapp")
   171  	c.Args = append(c.Args, args...)
   172  	c.Stdout = plugio.Stdout(plugs...)
   173  	c.Stderr = plugio.Stderr(plugs...)
   174  	c.Stdin = plugio.Stdin(plugs...)
   175  
   176  	for _, p := range plugs {
   177  		if vr, ok := p.(NewCommandRunner); ok {
   178  			if err := vr.RunNewCommand(ctx, root, c); err != nil {
   179  				return plugins.Wrap(cmd, err)
   180  			}
   181  			return nil
   182  		}
   183  	}
   184  
   185  	bb := &bytes.Buffer{}
   186  	c.Stderr = io.MultiWriter(bb, c.Stderr)
   187  	if err := c.Run(); err != nil {
   188  		return plugins.Wrap(cmd, fmt.Errorf("%w: %s", err, bb.String()))
   189  	}
   190  	return nil
   191  }
   192  
   193  const cliMain = `
   194  package main
   195  
   196  import (
   197  	"context"
   198  	"log"
   199  	"os"
   200  
   201  	"github.com/gobuffalo/buffalo-cli/v2/cli/cmds/newapp"
   202  	"github.com/gobuffalo/plugins"
   203  {{range $k,$v := .Plugs }}
   204  	{{$k}} "{{$v}}"{{end}}
   205  )
   206  
   207  func main() {
   208  	ctx := context.Background()
   209  	pwd, err := os.Getwd()
   210  	if err != nil {
   211  		log.Fatal(err)
   212  	}
   213  
   214  	var plugs []plugins.Plugin
   215  {{range $k,$v := .Plugs }}
   216  	plugs = append(plugs, {{$k}}.Plugins()...){{end}}
   217  
   218  	args := {{.Args}}
   219  	if err := newapp.Execute(plugs, ctx, pwd, "{{.Name}}", args); err != nil {
   220  		log.Fatal(err)
   221  	}
   222  }
   223  `