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

     1  package cmd
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"io/ioutil"
     7  	"os"
     8  	"os/exec"
     9  	"path/filepath"
    10  	"runtime"
    11  
    12  	"github.com/fatih/color"
    13  	"github.com/gobuffalo/buffalo/generators/assets/webpack"
    14  	rg "github.com/gobuffalo/buffalo/generators/refresh"
    15  	"github.com/gobuffalo/buffalo/meta"
    16  	"github.com/markbates/refresh/refresh"
    17  	"github.com/pkg/errors"
    18  	"github.com/sirupsen/logrus"
    19  	"github.com/spf13/cobra"
    20  	"golang.org/x/sync/errgroup"
    21  )
    22  
    23  var devOptions = struct {
    24  	Debug bool
    25  }{}
    26  
    27  // devCmd represents the dev command
    28  var devCmd = &cobra.Command{
    29  	Use:   "dev",
    30  	Short: "Runs your Buffalo app in 'development' mode",
    31  	Long: `Runs your Buffalo app in 'development' mode.
    32  This includes rebuilding your application when files change.
    33  This behavior can be changed in your .buffalo.dev.yml file.`,
    34  	RunE: func(c *cobra.Command, args []string) error {
    35  		if runtime.GOOS == "windows" {
    36  			color.NoColor = true
    37  		}
    38  		defer func() {
    39  			msg := "There was a problem starting the dev server, Please review the troubleshooting docs: %s\n"
    40  			cause := "Unknown"
    41  			if r := recover(); r != nil {
    42  				if err, ok := r.(error); ok {
    43  					cause = err.Error()
    44  				}
    45  			}
    46  			logrus.Errorf(msg, cause)
    47  		}()
    48  		os.Setenv("GO_ENV", "development")
    49  
    50  		ctx, cancel := context.WithCancel(context.Background())
    51  		defer cancel()
    52  
    53  		wg, ctx := errgroup.WithContext(ctx)
    54  
    55  		wg.Go(func() error {
    56  			return startDevServer(ctx)
    57  		})
    58  
    59  		wg.Go(func() error {
    60  			return startWebpack(ctx)
    61  		})
    62  
    63  		err := wg.Wait()
    64  		if err != context.Canceled {
    65  			return errors.WithStack(err)
    66  		}
    67  		return nil
    68  	},
    69  }
    70  
    71  func startWebpack(ctx context.Context) error {
    72  	app := meta.New(".")
    73  	if !app.WithWebpack {
    74  		// there's no webpack, so don't do anything
    75  		return nil
    76  	}
    77  
    78  	if _, err := os.Stat(filepath.Join(app.Root, "node_modules")); err != nil {
    79  		tool := "yarn"
    80  		if !app.WithYarn {
    81  			tool = "npm"
    82  		}
    83  		if _, err := exec.LookPath(tool); err != nil {
    84  			return errors.Errorf("no node_modules directory found, and couldn't find %s to install it with", tool)
    85  		}
    86  		cmd := exec.CommandContext(ctx, tool, "install")
    87  		cmd.Stdin = os.Stdin
    88  		cmd.Stderr = os.Stderr
    89  		cmd.Stdout = os.Stdout
    90  		if err := cmd.Run(); err != nil {
    91  			return errors.WithStack(err)
    92  		}
    93  	}
    94  
    95  	cmd := exec.CommandContext(ctx, webpack.BinPath, "--watch")
    96  	cmd.Stdin = os.Stdin
    97  	cmd.Stderr = os.Stderr
    98  	cmd.Stdout = os.Stdout
    99  	return cmd.Run()
   100  }
   101  
   102  func startDevServer(ctx context.Context) error {
   103  	cfgFile := "./.buffalo.dev.yml"
   104  	_, err := os.Stat(cfgFile)
   105  	if err != nil {
   106  		err = rg.Run("./", map[string]interface{}{
   107  			"name": "buffalo",
   108  		})
   109  	}
   110  	c := &refresh.Configuration{}
   111  	err = c.Load(cfgFile)
   112  	if err != nil {
   113  		return err
   114  	}
   115  	c.Debug = devOptions.Debug
   116  	if b, err := ioutil.ReadFile("database.yml"); err == nil {
   117  		if bytes.Contains(b, []byte("sqlite")) {
   118  			c.BuildFlags = append(c.BuildFlags, "-tags", "sqlite")
   119  		}
   120  	}
   121  	r := refresh.NewWithContext(c, ctx)
   122  	return r.Start()
   123  }
   124  
   125  func init() {
   126  	devCmd.Flags().BoolVarP(&devOptions.Debug, "debug", "d", false, "use delve to debug the app")
   127  	decorate("dev", devCmd)
   128  	RootCmd.AddCommand(devCmd)
   129  }