github.com/cheikhshift/buffalo@v0.9.5/buffalo/cmd/new.go (about)

     1  package cmd
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"os/user"
     8  	"path/filepath"
     9  	"regexp"
    10  	"strings"
    11  
    12  	"github.com/gobuffalo/buffalo/generators/newapp"
    13  	"github.com/gobuffalo/envy"
    14  	"github.com/gobuffalo/plush"
    15  	"github.com/markbates/inflect"
    16  	"github.com/spf13/cobra"
    17  )
    18  
    19  var rootPath string
    20  var app = &newapp.App{}
    21  
    22  var newCmd = &cobra.Command{
    23  	Use:   "new [name]",
    24  	Short: "Creates a new Buffalo application",
    25  	RunE: func(cmd *cobra.Command, args []string) error {
    26  		if !validDbType() {
    27  			return fmt.Errorf("Unknown db-type %s expecting one of postgres, mysql or sqlite3", app.DBType)
    28  		}
    29  
    30  		if len(args) == 0 {
    31  			return errors.New("you must enter a name for your new application")
    32  		}
    33  
    34  		app.Name = args[0]
    35  
    36  		if forbiddenName() {
    37  			return fmt.Errorf("name %s is not allowed, try a different application name", app.Name)
    38  		}
    39  
    40  		if nameHasIllegalCharacter(app.Name) {
    41  			return fmt.Errorf("name %s is not allowed, application name can only be contain [a-Z0-9-_]", app.Name)
    42  		}
    43  
    44  		if app.Name == "." {
    45  			app.Name = filepath.Base(app.RootPath)
    46  		} else {
    47  			app.RootPath = filepath.Join(app.RootPath, app.Name)
    48  		}
    49  
    50  		err := validateInGoPath()
    51  		if err != nil {
    52  			return err
    53  		}
    54  
    55  		s, _ := os.Stat(app.RootPath)
    56  		if s != nil {
    57  			if app.Force {
    58  				os.RemoveAll(app.RootPath)
    59  			} else {
    60  				return fmt.Errorf("%s already exists! Either delete it or use the -f flag to force", app.Name)
    61  			}
    62  		}
    63  
    64  		err = genNewFiles()
    65  		if err != nil {
    66  			return err
    67  		}
    68  
    69  		fmt.Printf("Congratulations! Your application, %s, has been successfully built!\n\n", app.Name)
    70  		fmt.Println("You can find your new application at:")
    71  		fmt.Println(app.RootPath)
    72  		fmt.Println("\nPlease read the README.md file in your new application for next steps on running your application.")
    73  
    74  		return nil
    75  	},
    76  }
    77  
    78  func validDbType() bool {
    79  	return app.DBType == "postgres" || app.DBType == "mysql" || app.DBType == "sqlite3"
    80  }
    81  
    82  func forbiddenName() bool {
    83  	return contains(forbiddenAppNames, strings.ToLower(app.Name))
    84  }
    85  
    86  var nameRX = regexp.MustCompile("^[\\w-]+$")
    87  
    88  func nameHasIllegalCharacter(name string) bool {
    89  	return !nameRX.MatchString(name)
    90  }
    91  
    92  func validateInGoPath() error {
    93  	gpMultiple := envy.GoPaths()
    94  
    95  	var gp string
    96  	larp := strings.ToLower(app.RootPath)
    97  	for i := 0; i < len(gpMultiple); i++ {
    98  		lgpm := strings.ToLower(filepath.Join(gpMultiple[i], "src"))
    99  		if strings.HasPrefix(larp, lgpm) {
   100  			gp = gpMultiple[i]
   101  			break
   102  		}
   103  	}
   104  
   105  	if gp == "" {
   106  		u, err := user.Current()
   107  		if err != nil {
   108  			return err
   109  		}
   110  		pwd, _ := os.Getwd()
   111  		t, err := plush.Render(notInGoWorkspace, plush.NewContextWith(map[string]interface{}{
   112  			"name":     app.Name,
   113  			"gopath":   envy.GoPath(),
   114  			"current":  pwd,
   115  			"username": u.Username,
   116  		}))
   117  		if err != nil {
   118  			return err
   119  		}
   120  		fmt.Println(t)
   121  		os.Exit(-1)
   122  	}
   123  	return nil
   124  }
   125  
   126  func goPath(root string) string {
   127  	gpMultiple := envy.GoPaths()
   128  	path := ""
   129  
   130  	for i := 0; i < len(gpMultiple); i++ {
   131  		if strings.HasPrefix(root, filepath.Join(gpMultiple[i], "src")) {
   132  			path = gpMultiple[i]
   133  			break
   134  		}
   135  	}
   136  	return path
   137  }
   138  
   139  func packagePath(rootPath string) string {
   140  	gosrcpath := strings.Replace(filepath.Join(goPath(rootPath), "src"), "\\", "/", -1)
   141  	rootPath = strings.Replace(rootPath, "\\", "/", -1)
   142  	return strings.Replace(rootPath, gosrcpath+"/", "", 2)
   143  }
   144  
   145  func genNewFiles() error {
   146  	packagePath := packagePath(app.RootPath)
   147  
   148  	data := map[string]interface{}{
   149  		"appPath":     app.RootPath,
   150  		"name":        app.Name,
   151  		"titleName":   inflect.Titleize(app.Name),
   152  		"packagePath": packagePath,
   153  		"actionsPath": packagePath + "/actions",
   154  		"modelsPath":  packagePath + "/models",
   155  		"withPop":     !app.SkipPop,
   156  		"withDep":     app.WithDep,
   157  		"withWebpack": !app.SkipWebpack && !app.API,
   158  		"skipYarn":    app.SkipYarn,
   159  		"withYarn":    !app.SkipYarn,
   160  		"dbType":      app.DBType,
   161  		"version":     Version,
   162  		"ciProvider":  app.CIProvider,
   163  		"asAPI":       app.API,
   164  		"asWeb":       !app.API,
   165  		"docker":      app.Docker,
   166  	}
   167  
   168  	g, err := app.Generator(data)
   169  	if err != nil {
   170  		return err
   171  	}
   172  	return g.Run(app.RootPath, data)
   173  }
   174  
   175  func init() {
   176  	pwd, _ := os.Getwd()
   177  
   178  	rootPath = pwd
   179  	app.RootPath = pwd
   180  
   181  	decorate("new", newCmd)
   182  	RootCmd.AddCommand(newCmd)
   183  	newCmd.Flags().BoolVar(&app.API, "api", false, "skip all front-end code and configure for an API server")
   184  	newCmd.Flags().BoolVarP(&app.Force, "force", "f", false, "delete and remake if the app already exists")
   185  	newCmd.Flags().BoolVarP(&app.Verbose, "verbose", "v", false, "verbosely print out the go get commands")
   186  	newCmd.Flags().BoolVar(&app.SkipPop, "skip-pop", false, "skips adding pop/soda to your app")
   187  	newCmd.Flags().BoolVar(&app.WithDep, "with-dep", false, "adds github.com/golang/dep to your app")
   188  	newCmd.Flags().BoolVar(&app.SkipWebpack, "skip-webpack", false, "skips adding Webpack to your app")
   189  	newCmd.Flags().BoolVar(&app.SkipYarn, "skip-yarn", false, "skip to use npm as the asset package manager")
   190  	newCmd.Flags().StringVar(&app.DBType, "db-type", "postgres", "specify the type of database you want to use [postgres, mysql, sqlite3]")
   191  	newCmd.Flags().StringVar(&app.Docker, "docker", "multi", "specify the type of Docker file to generate [none, multi, standard]")
   192  	newCmd.Flags().StringVar(&app.CIProvider, "ci-provider", "none", "specify the type of ci file you would like buffalo to generate [none, travis, gitlab-ci]")
   193  }
   194  
   195  func contains(s []string, e string) bool {
   196  	for _, a := range s {
   197  		if a == e {
   198  			return true
   199  		}
   200  	}
   201  	return false
   202  }
   203  
   204  var forbiddenAppNames = []string{"buffalo"}
   205  
   206  const notInGoWorkspace = `Oops! It would appear that you are not in your Go Workspace.
   207  
   208  Your $GOPATH is set to "<%= gopath %>".
   209  
   210  You are currently in "<%= current %>".
   211  
   212  The standard location for putting Go projects is something along the lines of "$GOPATH/src/github.com/<%= username %>/<%= name %>" (adjust accordingly).
   213  
   214  We recommend you go to "$GOPATH/src/github.com/<%= username %>/" and try "buffalo new <%= name %>" again.`
   215  
   216  const noGoPath = `You do not have a $GOPATH set. In order to work with Go, you must set up your $GOPATH and your Go Workspace.
   217  
   218  We recommend reading this tutorial on setting everything up: https://www.goinggo.net/2016/05/installing-go-and-your-workspace.html
   219  
   220  When you're ready come back and try again. Don't worry, Buffalo will be right here waiting for you. :)`