// Generate generates migration templates. func (g *migrationGenerator) Generate() { name := g.flag.Arg(0) if name == "" { kocha.PanicOnError(g, "abort: no NAME given") } tx := kocha.TxTypeMap[g.txType] if tx == nil { kocha.PanicOnError(g, "abort: unsupported transaction type: `%v`", g.txType) } now := Now().Format("20060102150405") data := map[string]interface{}{ "Name": kocha.ToCamelCase(name), "TimeStamp": now, "ImportPath": tx.ImportPath(), "TxType": reflect.TypeOf(tx.TransactionType()).String(), } kocha.CopyTemplate(g, filepath.Join(SkeletonDir("migration"), "migration.go.template"), filepath.Join("db", "migrations", fmt.Sprintf("%v_%v.go", now, kocha.ToSnakeCase(name))), data) initPath := filepath.Join("db", "migrations", "init.go") if _, err := os.Stat(initPath); os.IsNotExist(err) { appDir, err := kocha.FindAppDir() if err != nil { panic(err) } kocha.CopyTemplate(g, filepath.Join(SkeletonDir("migration"), "init.go.template"), initPath, map[string]interface{}{ "typeName": g.txType, "tx": strings.TrimSpace(kocha.GoString(tx)), "dbImportPath": path.Join(appDir, "db"), }) } }
func (c *migrateCommand) execCmd(cmd string, args ...string) { command := exec.Command(cmd, args...) command.Stdout, command.Stderr = os.Stdout, os.Stderr if err := command.Run(); err != nil { kocha.PanicOnError(c, "abort: migration failed: %v", err) } }
func (c *migrateCommand) Package(importPath string) *build.Package { pkg, err := build.Import(importPath, "", build.FindOnly) if err != nil { kocha.PanicOnError(c, "abort: cannot import `%s`: %v", importPath, err) } return pkg }
func (c *runCommand) execCmd(name string, args ...string) *exec.Cmd { cmd := exec.Command(name, args...) cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr if err := cmd.Start(); err != nil { kocha.PanicOnError(c, "abort: %v", err) } return cmd }
// Generate generates model templates. func (g *modelGenerator) Generate() { name := g.flag.Arg(0) if name == "" { kocha.PanicOnError(g, "abort: no NAME given") } mt := modelTypeMap[g.orm] if mt == nil { kocha.PanicOnError(g, "abort: unsupported ORM type: `%v`", g.orm) } m := mt.FieldTypeMap() var fields []modelField for _, arg := range g.flag.Args()[1:] { input := strings.Split(arg, ":") if len(input) != 2 { kocha.PanicOnError(g, "abort: invalid argument format has been specified: `%v`", strings.Join(input, ", ")) } name, t := input[0], input[1] if name == "" { kocha.PanicOnError(g, "abort: field name hasn't been specified") } ft, found := m[t] if !found { kocha.PanicOnError(g, "abort: unsupported field type: `%v`", t) } fields = append(fields, modelField{ Name: kocha.ToCamelCase(name), Type: ft.Name, Column: kocha.ToSnakeCase(name), OptionTags: ft.OptionTags, }) } camelCaseName := kocha.ToCamelCase(name) snakeCaseName := kocha.ToSnakeCase(name) data := map[string]interface{}{ "Name": camelCaseName, "Fields": fields, } templatePath, configTemplatePath := mt.TemplatePath() kocha.CopyTemplate(g, templatePath, filepath.Join("app", "models", snakeCaseName+".go"), data) initPath := filepath.Join("db", "config.go") if _, err := os.Stat(initPath); os.IsNotExist(err) { kocha.CopyTemplate(g, configTemplatePath, initPath, nil) } }
func (c *buildCommand) detectVersionTag() string { if c.versionTag != "" { return c.versionTag } var repo string for _, dir := range []string{".git", ".hg"} { if info, err := os.Stat(dir); err == nil && info.IsDir() { repo = dir break } } version := time.Now().Format(time.RFC1123Z) switch repo { case ".git": bin, err := exec.LookPath("git") if err != nil { fmt.Println("WARNING: git repository found, but `git` command not found. version uses \"%s\"", version) break } line, err := exec.Command(bin, "rev-parse", "HEAD").Output() if err != nil { kocha.PanicOnError(c, "abort: unexpected error: %v\nplease specify version explicitly with '-tag' option for avoid the this error.", err) } version = strings.TrimSpace(string(line)) case ".hg": bin, err := exec.LookPath("hg") if err != nil { fmt.Println("WARNING: hg repository found, but `hg` command not found. version uses \"%s\"", version) break } line, err := exec.Command(bin, "identify").Output() if err != nil { kocha.PanicOnError(c, "abort: unexpected error: %v\nplease specify version explicitly with '-tag' option for avoid the this error.", err) } version = strings.TrimSpace(string(line)) } if version == "" { // Probably doesn't reach here. version = time.Now().Format(time.RFC1123Z) fmt.Println("WARNING: version is empty, use \"%s\"", version) } return version }
func (c *migrateCommand) Run() { direction := c.flag.Arg(0) switch direction { case "up", "down": // do nothing. default: kocha.PanicOnError(c, `abort: no "up" or "down" specified`) } tmpDir, err := filepath.Abs("tmp") if err != nil { panic(err) } if err := os.MkdirAll(tmpDir, 0755); err != nil && !os.IsExist(err) { kocha.PanicOnError(c, "abort: failed to create directory: %v", err) } _, filename, _, _ := runtime.Caller(0) skeletonDir := filepath.Join(filepath.Dir(filename), "skeleton", "migrate") t := template.Must(template.ParseFiles(filepath.Join(skeletonDir, direction+".go.template"))) mainFilePath := filepath.ToSlash(filepath.Join(tmpDir, "migrate.go")) file, err := os.Create(mainFilePath) if err != nil { kocha.PanicOnError(c, "abort: failed to create file: %v", err) } defer file.Close() appDir, err := kocha.FindAppDir() if err != nil { panic(err) } data := map[string]interface{}{ "dbImportPath": c.Package(path.Join(appDir, "db")).ImportPath, "migrationsImportPath": c.Package(path.Join(appDir, "db", "migrations")).ImportPath, "dbconf": c.dbconf, "limit": c.limit, } if err := t.Execute(file, data); err != nil { kocha.PanicOnError(c, "abort: failed to write file: %v", err) } c.execCmd("go", "run", mainFilePath) if err := os.RemoveAll(tmpDir); err != nil { panic(err) } kocha.PrintGreen("All migrations are successful!\n") }
// Run execute the process for `generate` command. func (c *generateCommand) Run() { generatorName := c.flag.Arg(0) if generatorName == "" { kocha.PanicOnError(c, "abort: no GENERATOR given") } generator := generator.Get(generatorName) if generator == nil { kocha.PanicOnError(c, "abort: could not find generator: %v", generatorName) } flagSet := flag.NewFlagSet(generatorName, flag.ExitOnError) flagSet.Usage = func() { var flags []*flag.Flag flagSet.VisitAll(func(f *flag.Flag) { flags = append(flags, f) }) var buf bytes.Buffer template.Must(template.New("usage").Parse( `usage: %s %s %s {{if .}} Options: {{range .}} -{{.Name|printf "%-12s"}} {{.Usage}}{{end}}{{end}} `)).Execute(&buf, flags) fmt.Fprintf(os.Stderr, buf.String(), os.Args[0], c.Name(), generator.Usage()) } defer func() { if err := recover(); err != nil { if err, ok := err.(kocha.Error); ok { fmt.Fprintln(os.Stderr, err.Message) fmt.Fprintf(os.Stderr, "usage: %s %s %s\n", os.Args[0], c.Name(), err.Usager.Usage()) os.Exit(1) } panic(err) } }() generator.DefineFlags(flagSet) flagSet.Parse(c.flag.Args()[1:]) generator.Generate() }
// Run execute the process for `new` command. func (c *newCommand) Run() { appPath := c.flag.Arg(0) if appPath == "" { kocha.PanicOnError(c, "abort: no APP_PATH given") } dstBasePath := filepath.Join(filepath.SplitList(build.Default.GOPATH)[0], "src", appPath) _, filename, _, _ := runtime.Caller(0) baseDir := filepath.Dir(filename) skeletonDir := filepath.Join(baseDir, "skeleton", "new") if _, err := os.Stat(filepath.Join(dstBasePath, "config", "app.go")); err == nil { kocha.PanicOnError(c, "abort: Kocha application is already exists") } data := map[string]interface{}{ "appName": filepath.Base(appPath), "appPath": appPath, "secretKey": fmt.Sprintf("%q", string(kocha.GenerateRandomKey(32))), // AES-256 "signedKey": fmt.Sprintf("%q", string(kocha.GenerateRandomKey(16))), } filepath.Walk(skeletonDir, func(path string, info os.FileInfo, err error) error { if err != nil { panic(err) } if info.IsDir() { return nil } dstPath := filepath.Join(dstBasePath, strings.TrimSuffix(strings.TrimPrefix(path, skeletonDir), ".template")) dstDir := filepath.Dir(dstPath) dirCreated, err := mkdirAllIfNotExists(dstDir) if err != nil { kocha.PanicOnError(c, "abort: failed to create directory: %v", err) } if dirCreated { kocha.PrintCreateDirectory(dstDir) } kocha.CopyTemplate(c, path, dstPath, data) return nil }) }
// Generate generates unit templates. func (g *unitGenerator) Generate() { name := g.flag.Arg(0) if name == "" { kocha.PanicOnError(g, "abort: no NAME given") } camelCaseName := kocha.ToCamelCase(name) snakeCaseName := kocha.ToSnakeCase(name) data := map[string]interface{}{ "Name": camelCaseName, } kocha.CopyTemplate(g, filepath.Join(SkeletonDir("unit"), "unit.go.template"), filepath.Join("app", "units", snakeCaseName+".go"), data) }
// Generate generate a controller templates. func (g *controllerGenerator) Generate() { name := g.flag.Arg(0) if name == "" { kocha.PanicOnError(g, "abort: no NAME given") } camelCaseName := kocha.ToCamelCase(name) snakeCaseName := kocha.ToSnakeCase(name) data := map[string]interface{}{ "Name": camelCaseName, } kocha.CopyTemplate(g, filepath.Join(SkeletonDir("controller"), "controller.go.template"), filepath.Join("app", "controllers", snakeCaseName+".go"), data) kocha.CopyTemplate(g, filepath.Join(SkeletonDir("controller"), "view.html"), filepath.Join("app", "views", snakeCaseName+".html"), data) g.addRouteToFile(name) }
func (g *controllerGenerator) addRouteToFile(name string) { routeFilePath := filepath.Join("config", "routes.go") fset := token.NewFileSet() f, err := parser.ParseFile(fset, routeFilePath, nil, 0) if err != nil { kocha.PanicOnError(g, "abort: failed to read file: %v", err) } routeStructName := kocha.ToCamelCase(name) routeName := kocha.ToSnakeCase(name) routeTableAST := findRouteTableAST(f) if routeTableAST == nil { return } routeASTs := findRouteASTs(routeTableAST) if routeASTs == nil { return } if isRouteDefined(routeASTs, routeStructName) { return } routeFile, err := os.OpenFile(routeFilePath, os.O_RDWR, 0644) if err != nil { kocha.PanicOnError(g, "abort: failed to open file: %v", err) } defer routeFile.Close() lastRouteAST := routeASTs[len(routeASTs)-1] offset := int64(fset.Position(lastRouteAST.End()).Offset) var buf bytes.Buffer if _, err := io.CopyN(&buf, routeFile, offset); err != nil { kocha.PanicOnError(g, "abort: failed to read file: %v", err) } buf.WriteString(fmt.Sprintf(`, { Name: "%s", Path: "/%s", Controller: controllers.%s{}, }`, routeName, routeName, routeStructName)) if _, err := io.Copy(&buf, routeFile); err != nil { kocha.PanicOnError(g, "abort: failed to read file: %v", err) } formatted, err := format.Source(buf.Bytes()) if err != nil { kocha.PanicOnError(g, "abort: failed to format file: %v", err) } if _, err := routeFile.WriteAt(formatted, 0); err != nil { kocha.PanicOnError(g, "abort: failed to update file: %v", err) } }
// Run execute the process for `build` command. func (c *buildCommand) Run() { dir, err := os.Getwd() if err != nil { panic(err) } appDir, err := kocha.FindAppDir() if err != nil { panic(err) } appName := filepath.Base(dir) configPkg, err := c.Package(path.Join(appDir, "config")) if err != nil { kocha.PanicOnError(c, "abort: cannot import `%s`: %v", path.Join(appDir, "config"), err) } var dbImportPath string dbPkg, err := c.Package(path.Join(appDir, "db")) if err == nil { dbImportPath = dbPkg.ImportPath } var migrationsImportPath string migrationsPkg, err := c.Package(path.Join(appDir, "db", "migrations")) if err == nil { migrationsImportPath = migrationsPkg.ImportPath } tmpDir, err := filepath.Abs("tmp") if err != nil { panic(err) } if err := os.Mkdir(tmpDir, 0755); err != nil && !os.IsExist(err) { kocha.PanicOnError(c, "abort: failed to create directory: %v", err) } _, filename, _, _ := runtime.Caller(0) baseDir := filepath.Dir(filename) skeletonDir := filepath.Join(baseDir, "skeleton", "build") mainTemplate, err := ioutil.ReadFile(filepath.Join(skeletonDir, "main.go.template")) if err != nil { panic(err) } mainFilePath := filepath.ToSlash(filepath.Join(tmpDir, "main.go")) builderFilePath := filepath.ToSlash(filepath.Join(tmpDir, "builder.go")) file, err := os.Create(builderFilePath) if err != nil { kocha.PanicOnError(c, "abort: failed to create file: %v", err) } defer file.Close() builderTemplatePath := filepath.ToSlash(filepath.Join(skeletonDir, "builder.go.template")) t := template.Must(template.ParseFiles(builderTemplatePath)) var resources map[string]string if c.all { resources = c.collectResourcePaths(filepath.Join(dir, kocha.StaticDir)) } data := map[string]interface{}{ "configImportPath": configPkg.ImportPath, "dbImportPath": dbImportPath, "migrationsImportPath": migrationsImportPath, "mainTemplate": string(mainTemplate), "mainFilePath": mainFilePath, "resources": resources, "version": c.detectVersionTag(), } if err := t.Execute(file, data); err != nil { kocha.PanicOnError(c, "abort: failed to write file: %v", err) } execName := appName if runtime.GOOS == "windows" { execName += ".exe" } c.execCmd("go", "run", builderFilePath) c.execCmd("go", "build", "-o", execName, mainFilePath) if err := os.RemoveAll(tmpDir); err != nil { panic(err) } printSettingEnv() fmt.Printf("build all-in-one binary to %v\n", filepath.Join(dir, execName)) kocha.PrintGreen("Build successful!\n") }
func (c *buildCommand) execCmd(cmd string, args ...string) { command := exec.Command(cmd, args...) if msg, err := command.CombinedOutput(); err != nil { kocha.PanicOnError(c, "abort: build failed: %v\n%v", err, string(msg)) } }