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 }