github.com/yuk1ty/readygo@v0.2.1-0.20220502041311-7a0cf7a1a1aa/cmd/root.go (about) 1 package cmd 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "os/exec" 8 "strings" 9 10 "github.com/spf13/cobra" 11 ) 12 13 var rootCmd = &cobra.Command{ 14 Use: "readygo", 15 Short: "The easiest way to get started with Go.", 16 Long: `readygo is a tiny CLI tool for creating basic Go project.`, 17 Run: func(cmd *cobra.Command, args []string) { 18 pkgName, err := parsePackagePath(cmd) 19 if err != nil { 20 fmt.Println(err) 21 return 22 } 23 24 name, err := parseDirectoryName(cmd, pkgName) 25 if err != nil { 26 fmt.Println(err) 27 return 28 } 29 30 layout, err := parseLayout(cmd) 31 if err != nil { 32 fmt.Println(err) 33 return 34 } 35 36 err = runCmd(pkgName, name, layout) 37 if err != nil { 38 fmt.Println(err) 39 return 40 } 41 }, 42 } 43 44 func parsePackagePath(cmd *cobra.Command) (*string, error) { 45 pkgName, err := cmd.Flags().GetString("module-path") 46 if err != nil { 47 fmt.Println(err) 48 return nil, err 49 } 50 if pkgName == "" { 51 return nil, errors.New("[ERROR] Module path should be set! Please use `--module-path` option. For more details, please hit --help option") 52 } 53 return &pkgName, nil 54 } 55 56 func parseDirectoryName(cmd *cobra.Command, pkgPath *string) (*string, error) { 57 name, err := cmd.Flags().GetString("dir-name") 58 if err != nil { 59 return nil, err 60 } 61 if name == "" { 62 // e.g. If passed `github.com/yuk1ty/readygo` then extract `readygo` 63 splitted := strings.Split(*pkgPath, "/") 64 name = splitted[len(splitted)-1] 65 } 66 return &name, nil 67 } 68 69 const ( 70 Default = "default" 71 Standard = "standard" 72 ) 73 74 func parseLayout(cmd *cobra.Command) (*string, error) { 75 layout, err := cmd.Flags().GetString("layout") 76 if err != nil { 77 return nil, err 78 } 79 80 if layout != Default && layout != Standard { 81 return nil, fmt.Errorf("[ERROR] Layout name should be `%s` or `%s`", Default, Standard) 82 } 83 84 return &layout, nil 85 } 86 87 func runCmd(pkgName *string, dirName *string, layout *string) error { 88 err := os.Mkdir(*dirName, 0777) 89 if err != nil { 90 return err 91 } 92 93 err = os.Chdir(*dirName) 94 if err != nil { 95 return err 96 } 97 98 cmd := exec.Command("go", "mod", "init", *pkgName) 99 err = cmd.Run() 100 if err != nil { 101 return err 102 } 103 104 git := exec.Command("git", "init") 105 err = git.Run() 106 if err != nil { 107 return err 108 } 109 110 err = createGitIgnore() 111 if err != nil { 112 return err 113 } 114 115 err = createMainGo() 116 if err != nil { 117 return err 118 } 119 120 if *layout == Standard { 121 err = createStandardLayoutDirs() 122 if err != nil { 123 return err 124 } 125 } 126 127 return nil 128 } 129 130 func createMainGo() error { 131 mainGo := `package main 132 133 import "fmt" 134 135 func main() { 136 fmt.Println("Hello, world") 137 }` 138 139 f, err := os.Create("main.go") 140 if err != nil { 141 return err 142 } 143 defer f.Close() 144 145 _, err = f.WriteString(mainGo) 146 if err != nil { 147 return err 148 } 149 150 return nil 151 } 152 153 func createGitIgnore() error { 154 gitignoreBoilerplate := `*.exe 155 *.exe~ 156 *.dll 157 *.so 158 *.dylib 159 *.test 160 *.out 161 vendor/ 162 ` 163 f, err := os.Create(".gitignore") 164 if err != nil { 165 return err 166 } 167 defer f.Close() 168 169 _, err = f.WriteString(gitignoreBoilerplate) 170 if err != nil { 171 return err 172 } 173 return nil 174 } 175 176 func createStandardLayoutDirs() error { 177 var dirs [3]string = [3]string{ 178 "cmd", 179 "internal", 180 "pkg", 181 } 182 183 for _, name := range dirs { 184 err := os.Mkdir(name, 0777) 185 if err != nil { 186 return err 187 } 188 } 189 return nil 190 } 191 192 func Execute() { 193 err := rootCmd.Execute() 194 if err != nil { 195 os.Exit(1) 196 } 197 } 198 199 func init() { 200 rootCmd.Flags().StringP("module-path", "p", "", "Define your module path. This is used for go mod init [module path].") 201 rootCmd.Flags().StringP("dir-name", "n", "", "Define the directory name of your project. This can be omitted. If you do so, the name will be extracted from its package name.") 202 rootCmd.Flags().StringP("layout", "l", "default", "Define your project layout. You can choose `default` or `standard`. If you omit this option, the value becomes `default`.") 203 }