github.com/rpdict/ponzu@v0.10.1-0.20190226054626-477f29d6bf5e/cmd/ponzu/new.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "os" 6 "os/exec" 7 "path/filepath" 8 "strings" 9 10 "github.com/spf13/cobra" 11 ) 12 13 var newCmd = &cobra.Command{ 14 Use: "new [flags] <project name>", 15 Short: "creates a project directory of the name supplied as a parameter", 16 Long: `Creates a project directory of the name supplied as a parameter 17 immediately following the 'new' option in the $GOPATH/src directory. Note: 18 'new' depends on the program 'git' and possibly a network connection. If 19 there is no local repository to clone from at the local machine's $GOPATH, 20 'new' will attempt to clone the 'github.com/rpdict/ponzu' package from 21 over the network.`, 22 Example: `$ ponzu new github.com/nilslice/proj 23 > New ponzu project created at $GOPATH/src/github.com/nilslice/proj`, 24 RunE: func(cmd *cobra.Command, args []string) error { 25 projectName := "ponzu" 26 if len(args) > 0 { 27 projectName = args[0] 28 } else { 29 msg := "Please provide a project name." 30 msg += "\nThis will create a directory within your $GOPATH/src." 31 return fmt.Errorf("%s", msg) 32 } 33 return newProjectInDir(projectName) 34 }, 35 } 36 37 // name2path transforns a project name to an absolute path 38 func name2path(projectName string) (string, error) { 39 gopath, err := getGOPATH() 40 if err != nil { 41 return "", err 42 } 43 gosrc := filepath.Join(gopath, "src") 44 45 path := projectName 46 // support current directory 47 if path == "." { 48 path, err = os.Getwd() 49 if err != nil { 50 return "", err 51 } 52 } else { 53 path = filepath.Join(gosrc, path) 54 } 55 56 // make sure path is inside $GOPATH/src 57 srcrel, err := filepath.Rel(gosrc, path) 58 if err != nil { 59 return "", err 60 } 61 if len(srcrel) >= 2 && srcrel[:2] == ".." { 62 return "", fmt.Errorf("path '%s' must be inside '%s'", projectName, gosrc) 63 } 64 if srcrel == "." { 65 return "", fmt.Errorf("path '%s' must not be %s", path, filepath.Join("GOPATH", "src")) 66 } 67 68 _, err = os.Stat(path) 69 if err != nil && !os.IsNotExist(err) { 70 return "", err 71 } 72 if err == nil { 73 err = os.ErrExist 74 } else if os.IsNotExist(err) { 75 err = nil 76 } 77 78 return path, err 79 } 80 81 func newProjectInDir(path string) error { 82 path, err := name2path(path) 83 if err != nil && !os.IsNotExist(err) { 84 return err 85 } 86 87 // path exists, ask if it should be overwritten 88 if os.IsNotExist(err) { 89 fmt.Printf("Using '%s' as project directory\n", path) 90 fmt.Println("Path exists, overwrite contents? (y/N):") 91 92 answer, err := getAnswer() 93 if err != nil { 94 return err 95 } 96 97 switch answer { 98 case "n", "no", "\r\n", "\n", "": 99 fmt.Println("") 100 101 case "y", "yes": 102 err := os.RemoveAll(path) 103 if err != nil { 104 return fmt.Errorf("Failed to overwrite %s. \n%s", path, err) 105 } 106 107 return createProjectInDir(path) 108 109 default: 110 fmt.Println("Input not recognized. No files overwritten. Answer as 'y' or 'n' only.") 111 } 112 113 return nil 114 } 115 116 return createProjectInDir(path) 117 } 118 119 func createProjectInDir(path string) error { 120 gopath, err := getGOPATH() 121 if err != nil { 122 return err 123 } 124 repo := ponzuRepo 125 local := filepath.Join(gopath, "src", filepath.Join(repo...)) 126 network := "https://" + strings.Join(repo, "/") + ".git" 127 if !strings.HasPrefix(path, gopath) { 128 path = filepath.Join(gopath, path) 129 } 130 131 // create the directory or overwrite it 132 err = os.MkdirAll(path, os.ModeDir|os.ModePerm) 133 if err != nil { 134 return err 135 } 136 137 if dev { 138 if fork != "" { 139 local = filepath.Join(gopath, "src", fork) 140 } 141 142 err = execAndWait("git", "clone", local, "--branch", "ponzu-dev", "--single-branch", path) 143 if err != nil { 144 return err 145 } 146 147 err = vendorCorePackages(path) 148 if err != nil { 149 return err 150 } 151 152 fmt.Println("Dev build cloned from " + local + ":ponzu-dev") 153 return nil 154 } 155 156 // try to git clone the repository from the local machine's $GOPATH 157 err = execAndWait("git", "clone", local, path) 158 if err != nil { 159 fmt.Println("Couldn't clone from", local, "- trying network...") 160 161 // try to git clone the repository over the network 162 networkClone := exec.Command("git", "clone", network, path) 163 networkClone.Stdout = os.Stdout 164 networkClone.Stderr = os.Stderr 165 166 err = networkClone.Start() 167 if err != nil { 168 fmt.Println("Network clone failed to start. Try again and make sure you have a network connection.") 169 return err 170 } 171 err = networkClone.Wait() 172 if err != nil { 173 fmt.Println("Network clone failure.") 174 // failed 175 return fmt.Errorf("Failed to clone files from local machine [%s] and over the network [%s].\n%s", local, network, err) 176 } 177 } 178 179 // create an internal vendor directory in ./cmd/ponzu and move content, 180 // management and system packages into it 181 err = vendorCorePackages(path) 182 if err != nil { 183 return err 184 } 185 186 // remove non-project files and directories 187 rmPaths := []string{".git", ".circleci"} 188 for _, rm := range rmPaths { 189 dir := filepath.Join(path, rm) 190 err = os.RemoveAll(dir) 191 if err != nil { 192 fmt.Println("Failed to remove directory from your project path. Consider removing it manually:", dir) 193 } 194 } 195 196 fmt.Println("New ponzu project created at", path) 197 return nil 198 } 199 200 func init() { 201 newCmd.Flags().StringVar(&fork, "fork", "", "modify repo source for Ponzu core development") 202 newCmd.Flags().BoolVar(&dev, "dev", false, "modify environment for Ponzu core development") 203 204 RegisterCmdlineCommand(newCmd) 205 }