github.com/segakazzz/buffalo@v0.16.22-0.20210119082501-1f52048d3feb/buffalo/cmd/new.go (about) 1 package cmd 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 "os/exec" 8 "os/user" 9 "path/filepath" 10 "strings" 11 12 pop "github.com/gobuffalo/buffalo-pop/v2/genny/newapp" 13 "github.com/gobuffalo/buffalo/genny/assets/standard" 14 "github.com/gobuffalo/buffalo/genny/assets/webpack" 15 "github.com/gobuffalo/buffalo/genny/ci" 16 "github.com/gobuffalo/buffalo/genny/docker" 17 "github.com/gobuffalo/buffalo/genny/newapp/api" 18 "github.com/gobuffalo/buffalo/genny/newapp/core" 19 "github.com/gobuffalo/buffalo/genny/newapp/web" 20 "github.com/gobuffalo/buffalo/genny/refresh" 21 "github.com/gobuffalo/buffalo/genny/vcs" 22 "github.com/gobuffalo/envy" 23 fname "github.com/gobuffalo/flect/name" 24 "github.com/gobuffalo/genny/v2" 25 "github.com/gobuffalo/genny/v2/gogen" 26 "github.com/gobuffalo/logger" 27 "github.com/gobuffalo/meta" 28 "github.com/gobuffalo/packr/v2/plog" 29 "github.com/gobuffalo/plush/v4" 30 "github.com/segakazzz/buffalo/internal/takeon/github.com/markbates/errx" 31 "github.com/sirupsen/logrus" 32 "github.com/spf13/cobra" 33 "github.com/spf13/pflag" 34 "github.com/spf13/viper" 35 ) 36 37 type newAppOptions struct { 38 Options *core.Options 39 Module string 40 Force bool 41 Verbose bool 42 DryRun bool 43 } 44 45 func parseNewOptions(args []string) (newAppOptions, error) { 46 nopts := newAppOptions{ 47 Force: viper.GetBool("force"), 48 Verbose: viper.GetBool("verbose"), 49 DryRun: viper.GetBool("dry-run"), 50 Module: viper.GetString("module"), 51 } 52 53 if len(args) == 0 { 54 return nopts, fmt.Errorf("you must enter a name for your new application") 55 } 56 if configError != nil { 57 return nopts, configError 58 } 59 60 pwd, err := os.Getwd() 61 if err != nil { 62 return nopts, err 63 } 64 app := meta.New(pwd) 65 app.WithGrifts = true 66 app.Name = fname.New(args[0]) 67 app.Bin = filepath.Join("bin", app.Name.String()) 68 69 if app.Name.String() == "." { 70 app.Name = fname.New(filepath.Base(app.Root)) 71 } else { 72 app.Root = filepath.Join(app.Root, app.Name.File().String()) 73 } 74 75 if len(nopts.Module) == 0 { 76 aa := meta.New(app.Root) 77 app.PackageRoot(aa.PackagePkg) 78 } else { 79 app.PackageRoot(nopts.Module) 80 } 81 82 app.AsAPI = viper.GetBool("api") 83 app.VCS = viper.GetString("vcs") 84 85 app.WithPop = !viper.GetBool("skip-pop") 86 app.WithWebpack = !viper.GetBool("skip-webpack") 87 app.WithYarn = !viper.GetBool("skip-yarn") 88 app.WithNodeJs = app.WithWebpack 89 app.AsWeb = !app.AsAPI 90 91 if app.AsAPI { 92 app.WithWebpack = false 93 app.WithYarn = false 94 app.WithNodeJs = false 95 } 96 97 opts := &core.Options{} 98 99 x := viper.GetString("docker") 100 if len(x) > 0 && x != "none" { 101 opts.Docker = &docker.Options{ 102 Style: x, 103 } 104 app.WithDocker = true 105 } 106 107 x = viper.GetString("ci-provider") 108 if len(x) > 0 && x != "none" { 109 opts.CI = &ci.Options{ 110 Provider: x, 111 DBType: viper.GetString("db-type"), 112 } 113 } 114 115 if len(app.VCS) > 0 && app.VCS != "none" { 116 opts.VCS = &vcs.Options{ 117 Provider: app.VCS, 118 } 119 } 120 121 if app.WithPop { 122 d := viper.GetString("db-type") 123 if d == "sqlite3" { 124 app.WithSQLite = true 125 } 126 127 opts.Pop = &pop.Options{ 128 Prefix: app.Name.File().String(), 129 Dialect: d, 130 } 131 } 132 133 opts.Refresh = &refresh.Options{} 134 135 opts.App = app 136 nopts.Options = opts 137 return nopts, nil 138 } 139 140 var configError error 141 142 var newCmd = &cobra.Command{ 143 Use: "new [name]", 144 Short: "Creates a new Buffalo application", 145 RunE: func(cmd *cobra.Command, args []string) error { 146 // Restore default values after usage (useful for testing) 147 defer func() { 148 cmd.Flags().Visit(func(f *pflag.Flag) { 149 f.Value.Set(f.DefValue) 150 }) 151 viper.BindPFlags(cmd.Flags()) 152 }() 153 154 nopts, err := parseNewOptions(args) 155 if err != nil { 156 return err 157 } 158 159 opts := nopts.Options 160 app := opts.App 161 162 ctx := context.Background() 163 164 run := genny.WetRunner(ctx) 165 lg := logger.New(logger.DebugLevel) 166 run.Logger = lg 167 if nopts.Verbose { 168 plog.Logger = lg 169 } 170 171 if nopts.DryRun { 172 run = genny.DryRunner(ctx) 173 } 174 run.Root = app.Root 175 if nopts.Force { 176 os.RemoveAll(app.Root) 177 } 178 179 var gg *genny.Group 180 181 if app.AsAPI { 182 gg, err = api.New(&api.Options{ 183 Options: opts, 184 }) 185 } else { 186 wo := &web.Options{ 187 Options: opts, 188 } 189 if app.WithWebpack { 190 wo.Webpack = &webpack.Options{} 191 } else if !app.AsAPI { 192 wo.Standard = &standard.Options{} 193 } 194 gg, err = web.New(wo) 195 } 196 if err != nil { 197 if errx.Unwrap(err) == core.ErrNotInGoPath { 198 return notInGoPath(app) 199 } 200 return err 201 } 202 run.WithGroup(gg) 203 204 if err := run.WithNew(gogen.Fmt(app.Root)); err != nil { 205 return err 206 } 207 208 // setup VCS last 209 if opts.VCS != nil { 210 // add the VCS generator 211 if err := run.WithNew(vcs.New(opts.VCS)); err != nil { 212 return err 213 } 214 } 215 216 if err := run.Run(); err != nil { 217 return err 218 } 219 220 run.Logger.Infof("Congratulations! Your application, %s, has been successfully built!", app.Name) 221 run.Logger.Infof("You can find your new application at: %v", app.Root) 222 run.Logger.Info("Please read the README.md file in your new application for next steps on running your application.") 223 return nil 224 }, 225 } 226 227 func currentUser() (string, error) { 228 if _, err := exec.LookPath("git"); err == nil { 229 if b, err := exec.Command("git", "config", "github.user").Output(); err == nil { 230 return string(b), nil 231 } 232 } 233 u, err := user.Current() 234 if err != nil { 235 return "", err 236 } 237 username := u.Username 238 if t := strings.Split(username, `\`); len(t) > 0 { 239 username = t[len(t)-1] 240 } 241 return username, nil 242 } 243 244 func notInGoPath(app meta.App) error { 245 username, err := currentUser() 246 if err != nil { 247 return err 248 } 249 pwd, _ := os.Getwd() 250 t, err := plush.Render(notInGoWorkspace, plush.NewContextWith(map[string]interface{}{ 251 "name": app.Name, 252 "gopath": envy.GoPath(), 253 "current": pwd, 254 "username": username, 255 })) 256 if err != nil { 257 return err 258 } 259 logrus.Error(t) 260 os.Exit(-1) 261 return nil 262 } 263 264 func init() { 265 decorate("new", newCmd) 266 RootCmd.AddCommand(newCmd) 267 newCmd.Flags().Bool("api", false, "skip all front-end code and configure for an API server") 268 newCmd.Flags().BoolP("force", "f", false, "delete and remake if the app already exists") 269 newCmd.Flags().BoolP("dry-run", "d", false, "dry run") 270 newCmd.Flags().BoolP("verbose", "v", false, "verbosely print out the go get commands") 271 newCmd.Flags().Bool("skip-pop", false, "skips adding pop/soda to your app") 272 newCmd.Flags().Bool("skip-webpack", false, "skips adding Webpack to your app") 273 newCmd.Flags().Bool("skip-yarn", false, "use npm instead of yarn for frontend dependencies management") 274 newCmd.Flags().String("db-type", "postgres", fmt.Sprintf("specify the type of database you want to use [%s]", strings.Join(pop.AvailableDialects, ", "))) 275 newCmd.Flags().String("docker", "multi", "specify the type of Docker file to generate [none, multi, standard]") 276 newCmd.Flags().String("ci-provider", "none", "specify the type of ci file you would like buffalo to generate [none, travis, gitlab-ci, circleci]") 277 newCmd.Flags().String("vcs", "git", "specify the Version control system you would like to use [none, git, bzr]") 278 newCmd.Flags().String("module", "", "specify the root module (package) name. [defaults to 'automatic']") 279 viper.BindPFlags(newCmd.Flags()) 280 cfgFile := newCmd.PersistentFlags().String("config", "", "config file (default is $HOME/.buffalo.yaml)") 281 skipConfig := newCmd.Flags().Bool("skip-config", false, "skips using the config file") 282 cobra.OnInitialize(initConfig(skipConfig, cfgFile)) 283 } 284 285 func initConfig(skipConfig *bool, cfgFile *string) func() { 286 return func() { 287 if *skipConfig { 288 return 289 } 290 291 var err error 292 if *cfgFile != "" { // enable ability to specify config file via flag 293 viper.SetConfigFile(*cfgFile) 294 // Will error only if the --config flag is used 295 if err = viper.ReadInConfig(); err != nil { 296 configError = err 297 } 298 } else { 299 viper.SetConfigName(".buffalo") // name of config file (without extension) 300 viper.AddConfigPath("$HOME") // adding home directory as first search path 301 viper.AutomaticEnv() // read in environment variables that match 302 viper.ReadInConfig() 303 } 304 305 } 306 } 307 308 const notInGoWorkspace = `Oops! It would appear that you are not in your Go Workspace. 309 310 Your $GOPATH is set to "<%= gopath %>". 311 312 You are currently in "<%= current %>". 313 314 The standard location for putting Go projects is something along the lines of "$GOPATH/src/github.com/<%= username %>/<%= name %>" (adjust accordingly). 315 316 We recommend you go to "$GOPATH/src/github.com/<%= username %>/" and try "buffalo new <%= name %>" again.`