github.com/jacobsoderblom/buffalo@v0.11.0/buffalo/cmd/setup.go (about)

     1  package cmd
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"os"
     7  	"os/exec"
     8  	"strings"
     9  
    10  	"golang.org/x/sync/errgroup"
    11  
    12  	"github.com/gobuffalo/buffalo/meta"
    13  	"github.com/gobuffalo/envy"
    14  	"github.com/markbates/deplist"
    15  	"github.com/pkg/errors"
    16  	"github.com/sirupsen/logrus"
    17  	"github.com/spf13/cobra"
    18  )
    19  
    20  var setupOptions = struct {
    21  	verbose       bool
    22  	updateGoDeps  bool
    23  	dropDatabases bool
    24  }{}
    25  
    26  type setupCheck func(meta.App) error
    27  
    28  var setupCmd = &cobra.Command{
    29  	Use:   "setup",
    30  	Short: "Setups a newly created, or recently checked out application.",
    31  	Long: `Setup runs through checklist to make sure dependencies are setup correcly.
    32  
    33  Dependencies (if used):
    34  * Runs "dep ensure" to install required Go dependencies.
    35  
    36  Asset Pipeline (if used):
    37  * Runs "npm install" or "yarn install" to install asset dependencies.
    38  
    39  Database (if used):
    40  * Runs "buffalo db create -a" to create databases.
    41  * Runs "buffalo db migrate" to run database migrations.
    42  * Runs "buffalo task db:seed" to seed the database (if the task exists).
    43  
    44  Tests:
    45  * Runs "buffalo test" to confirm the application's tests are running properly.
    46  `,
    47  	RunE: func(cmd *cobra.Command, args []string) error {
    48  		app := meta.New(".")
    49  		for _, check := range []setupCheck{assetCheck, updateGoDepsCheck, databaseCheck, testCheck} {
    50  			err := check(app)
    51  			if err != nil {
    52  				return errors.WithStack(err)
    53  			}
    54  		}
    55  		return nil
    56  	},
    57  }
    58  
    59  func updateGoDepsCheck(app meta.App) error {
    60  	deps, _ := deplist.List()
    61  	if app.WithDep {
    62  		// use github.com/golang/dep
    63  		args := []string{"ensure"}
    64  		if setupOptions.verbose {
    65  			args = append(args, "-v")
    66  		}
    67  		if setupOptions.updateGoDeps {
    68  			args = append(args, "--update")
    69  		}
    70  		err := run(exec.Command("dep", args...))
    71  		if err != nil {
    72  			return errors.WithStack(err)
    73  		}
    74  		return nil
    75  	}
    76  
    77  	// go old school with the installation
    78  	ctx, cancel := context.WithCancel(context.Background())
    79  	defer cancel()
    80  	wg, _ := errgroup.WithContext(ctx)
    81  	deps, err := deplist.List()
    82  	if err != nil {
    83  		return errors.WithStack(err)
    84  	}
    85  
    86  	deps["github.com/gobuffalo/suite"] = "github.com/gobuffalo/suite"
    87  
    88  	for dep := range deps {
    89  		args := []string{"get"}
    90  		if setupOptions.verbose {
    91  			args = append(args, "-v")
    92  		}
    93  		if setupOptions.updateGoDeps {
    94  			args = append(args, "-u")
    95  		}
    96  		args = append(args, dep)
    97  		c := exec.Command(envy.Get("GO_BIN", "go"), args...)
    98  		f := func() error {
    99  			return run(c)
   100  		}
   101  		wg.Go(f)
   102  	}
   103  	err = wg.Wait()
   104  	if err != nil {
   105  		return errors.Errorf("We encountered the following error trying to install and update the dependencies for this application:\n%s", err)
   106  	}
   107  	return nil
   108  }
   109  
   110  func testCheck(meta.App) error {
   111  	err := run(exec.Command("buffalo", "test"))
   112  	if err != nil {
   113  		return errors.Errorf("We encountered the following error when trying to run your applications tests:\n%s", err)
   114  	}
   115  	return nil
   116  }
   117  
   118  func databaseCheck(app meta.App) error {
   119  	if !app.WithPop {
   120  		return nil
   121  	}
   122  	for _, check := range []setupCheck{dbCreateCheck, dbMigrateCheck, dbSeedCheck} {
   123  		err := check(app)
   124  		if err != nil {
   125  			return err
   126  		}
   127  	}
   128  	return nil
   129  }
   130  
   131  func dbCreateCheck(meta.App) error {
   132  	if setupOptions.dropDatabases {
   133  		err := run(exec.Command("buffalo", "db", "drop", "-a"))
   134  		if err != nil {
   135  			return errors.Errorf("We encountered an error when trying to drop your application's databases. Please check to make sure that your database server is running and that the username and passwords found in the database.yml are properly configured and set up on your database server.\n %s", err)
   136  		}
   137  	}
   138  	err := run(exec.Command("buffalo", "db", "create", "-a"))
   139  	if err != nil {
   140  		return errors.Errorf("We encountered an error when trying to create your application's databases. Please check to make sure that your database server is running and that the username and passwords found in the database.yml are properly configured and set up on your database server.\n %s", err)
   141  	}
   142  	return nil
   143  }
   144  
   145  func dbMigrateCheck(meta.App) error {
   146  	err := run(exec.Command("buffalo", "db", "migrate"))
   147  	if err != nil {
   148  		return errors.Errorf("We encountered the following error when trying to migrate your database:\n%s", err)
   149  	}
   150  	return nil
   151  }
   152  
   153  func dbSeedCheck(meta.App) error {
   154  	cmd := exec.Command("buffalo", "t", "list")
   155  	out, err := cmd.Output()
   156  	if err != nil {
   157  		// no tasks configured, so return
   158  		return nil
   159  	}
   160  	if bytes.Contains(out, []byte("db:seed")) {
   161  		err := run(exec.Command("buffalo", "task", "db:seed"))
   162  		if err != nil {
   163  			return errors.Errorf("We encountered the following error when trying to seed your database:\n%s", err)
   164  		}
   165  	}
   166  	return nil
   167  }
   168  
   169  func assetCheck(app meta.App) error {
   170  	if !app.WithWebpack {
   171  		return nil
   172  	}
   173  	if app.WithYarn {
   174  		return yarnCheck(app)
   175  	}
   176  	return npmCheck(app)
   177  }
   178  
   179  func npmCheck(app meta.App) error {
   180  	err := nodeCheck(app)
   181  	if err != nil {
   182  		return errors.WithStack(err)
   183  	}
   184  	err = run(exec.Command("npm", "install", "--no-progress"))
   185  	if err != nil {
   186  		return errors.Errorf("We encountered the following error when trying to install your asset dependencies using npm:\n%s", err)
   187  	}
   188  	return nil
   189  }
   190  
   191  func yarnCheck(app meta.App) error {
   192  	err := nodeCheck(app)
   193  	if err != nil {
   194  		return errors.WithStack(err)
   195  	}
   196  	if _, err := exec.LookPath("yarn"); err != nil {
   197  		err := run(exec.Command("npm", "install", "-g", "yarn"))
   198  		if err != nil {
   199  			return errors.Errorf("This application require yarn, and we could not find it installed on your system. We tried to install it for you, but ran into the following error:\n%s", err)
   200  		}
   201  	}
   202  	err = run(exec.Command("yarn", "install", "--no-progress"))
   203  	if err != nil {
   204  		return errors.Errorf("We encountered the following error when trying to install your asset dependencies using yarn:\n%s", err)
   205  	}
   206  	return nil
   207  }
   208  
   209  func nodeCheck(meta.App) error {
   210  	if _, err := exec.LookPath("node"); err != nil {
   211  		return errors.New("this application requires node, and we could not find it installed on your system please install node and try again")
   212  	}
   213  	if _, err := exec.LookPath("npm"); err != nil {
   214  		return errors.New("this application requires npm, and we could not find it installed on your system please install npm and try again")
   215  	}
   216  	return nil
   217  }
   218  
   219  func run(cmd *exec.Cmd) error {
   220  	logrus.Infof("--> %s\n", strings.Join(cmd.Args, " "))
   221  	cmd.Stdin = os.Stdin
   222  	cmd.Stderr = os.Stderr
   223  	cmd.Stdout = os.Stdout
   224  	return cmd.Run()
   225  }
   226  
   227  func init() {
   228  	setupCmd.Flags().BoolVarP(&setupOptions.verbose, "verbose", "v", false, "run with verbose output")
   229  	setupCmd.Flags().BoolVarP(&setupOptions.updateGoDeps, "update", "u", false, "run go get -u against the application's Go dependencies")
   230  	setupCmd.Flags().BoolVarP(&setupOptions.dropDatabases, "drop", "d", false, "drop existing databases")
   231  
   232  	decorate("setup", setupCmd)
   233  	RootCmd.AddCommand(setupCmd)
   234  }