Beispiel #1
0
// Generate generates migration templates.
func (g *migrationGenerator) Generate() {
	name := g.flag.Arg(0)
	if name == "" {
		util.PanicOnError(g, "abort: no NAME given")
	}
	tx := kocha.TxTypeMap[g.txType]
	if tx == nil {
		util.PanicOnError(g, "abort: unsupported transaction type: `%v`", g.txType)
	}
	now := Now().Format("20060102150405")
	data := map[string]interface{}{
		"Name":       util.ToCamelCase(name),
		"TimeStamp":  now,
		"ImportPath": tx.ImportPath(),
		"TxType":     reflect.TypeOf(tx.TransactionType()).String(),
	}
	util.CopyTemplate(g,
		filepath.Join(SkeletonDir("migration"), "migration.go.template"),
		filepath.Join("db", "migrations", fmt.Sprintf("%v_%v.go", now, util.ToSnakeCase(name))), data)
	initPath := filepath.Join("db", "migrations", "init.go")
	if _, err := os.Stat(initPath); os.IsNotExist(err) {
		appDir, err := util.FindAppDir()
		if err != nil {
			panic(err)
		}
		util.CopyTemplate(g,
			filepath.Join(SkeletonDir("migration"), "init.go.template"),
			initPath, map[string]interface{}{
				"typeName":     g.txType,
				"tx":           strings.TrimSpace(util.GoString(tx)),
				"dbImportPath": path.Join(appDir, "db"),
			})
	}
}
Beispiel #2
0
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 {
		util.PanicOnError(c, "abort: migration failed: %v", err)
	}
}
Beispiel #3
0
func (c *migrateCommand) Package(importPath string) *build.Package {
	pkg, err := build.Import(importPath, "", build.FindOnly)
	if err != nil {
		util.PanicOnError(c, "abort: cannot import `%s`: %v", importPath, err)
	}
	return pkg
}
Beispiel #4
0
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 {
		util.PanicOnError(c, "abort: %v", err)
	}
	return cmd
}
Beispiel #5
0
// Generate generates model templates.
func (g *modelGenerator) Generate() {
	name := g.flag.Arg(0)
	if name == "" {
		util.PanicOnError(g, "abort: no NAME given")
	}
	mt := modelTypeMap[g.orm]
	if mt == nil {
		util.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 {
			util.PanicOnError(g, "abort: invalid argument format has been specified: `%v`", strings.Join(input, ", "))
		}
		name, t := input[0], input[1]
		if name == "" {
			util.PanicOnError(g, "abort: field name hasn't been specified")
		}
		ft, found := m[t]
		if !found {
			util.PanicOnError(g, "abort: unsupported field type: `%v`", t)
		}
		fields = append(fields, modelField{
			Name:       util.ToCamelCase(name),
			Type:       ft.Name,
			Column:     util.ToSnakeCase(name),
			OptionTags: ft.OptionTags,
		})
	}
	camelCaseName := util.ToCamelCase(name)
	snakeCaseName := util.ToSnakeCase(name)
	data := map[string]interface{}{
		"Name":   camelCaseName,
		"Fields": fields,
	}
	templatePath, configTemplatePath := mt.TemplatePath()
	util.CopyTemplate(g, templatePath, filepath.Join("app", "models", snakeCaseName+".go"), data)
	initPath := filepath.Join("db", "config.go")
	if _, err := os.Stat(initPath); os.IsNotExist(err) {
		util.CopyTemplate(g, configTemplatePath, initPath, nil)
	}
}
Beispiel #6
0
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 {
			util.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 {
			util.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
}
Beispiel #7
0
func (c *migrateCommand) Run() {
	direction := c.flag.Arg(0)
	switch direction {
	case "up", "down":
		// do nothing.
	default:
		util.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) {
		util.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 {
		util.PanicOnError(c, "abort: failed to create file: %v", err)
	}
	defer file.Close()
	appDir, err := util.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 {
		util.PanicOnError(c, "abort: failed to write file: %v", err)
	}
	c.execCmd("go", "run", mainFilePath)
	if err := os.RemoveAll(tmpDir); err != nil {
		panic(err)
	}
	util.PrintGreen("All migrations are successful!\n")
}
Beispiel #8
0
// Run execute the process for `generate` command.
func (c *generateCommand) Run() {
	generatorName := c.flag.Arg(0)
	if generatorName == "" {
		util.PanicOnError(c, "abort: no GENERATOR given")
	}
	generator := generator.Get(generatorName)
	if generator == nil {
		util.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.(util.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()
}
Beispiel #9
0
// Run execute the process for `new` command.
func (c *newCommand) Run() {
	appPath := c.flag.Arg(0)
	if appPath == "" {
		util.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 {
		util.PanicOnError(c, "abort: Kocha application is already exists")
	}
	data := map[string]interface{}{
		"appName":   filepath.Base(appPath),
		"appPath":   appPath,
		"secretKey": fmt.Sprintf("%q", string(util.GenerateRandomKey(32))), // AES-256
		"signedKey": fmt.Sprintf("%q", string(util.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 {
			util.PanicOnError(c, "abort: failed to create directory: %v", err)
		}
		if dirCreated {
			util.PrintCreateDirectory(dstDir)
		}
		util.CopyTemplate(c, path, dstPath, data)
		return nil
	})
}
Beispiel #10
0
// Generate generates unit templates.
func (g *unitGenerator) Generate() {
	name := g.flag.Arg(0)
	if name == "" {
		util.PanicOnError(g, "abort: no NAME given")
	}
	camelCaseName := util.ToCamelCase(name)
	snakeCaseName := util.ToSnakeCase(name)
	data := map[string]interface{}{
		"Name": camelCaseName,
	}
	util.CopyTemplate(g,
		filepath.Join(SkeletonDir("unit"), "unit.go.template"),
		filepath.Join("app", "units", snakeCaseName+".go"), data)
}
Beispiel #11
0
// Generate generate a controller templates.
func (g *controllerGenerator) Generate() {
	name := g.flag.Arg(0)
	if name == "" {
		util.PanicOnError(g, "abort: no NAME given")
	}
	camelCaseName := util.ToCamelCase(name)
	snakeCaseName := util.ToSnakeCase(name)
	data := map[string]interface{}{
		"Name": camelCaseName,
	}
	util.CopyTemplate(g,
		filepath.Join(SkeletonDir("controller"), "controller.go.template"),
		filepath.Join("app", "controllers", snakeCaseName+".go"), data)
	util.CopyTemplate(g,
		filepath.Join(SkeletonDir("controller"), "view.html"),
		filepath.Join("app", "views", snakeCaseName+".html"), data)
	g.addRouteToFile(name)
}
Beispiel #12
0
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 {
		util.PanicOnError(g, "abort: failed to read file: %v", err)
	}
	routeStructName := util.ToCamelCase(name)
	routeName := util.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 {
		util.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 {
		util.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 {
		util.PanicOnError(g, "abort: failed to read file: %v", err)
	}
	formatted, err := format.Source(buf.Bytes())
	if err != nil {
		util.PanicOnError(g, "abort: failed to format file: %v", err)
	}
	if _, err := routeFile.WriteAt(formatted, 0); err != nil {
		util.PanicOnError(g, "abort: failed to update file: %v", err)
	}
}
Beispiel #13
0
// Run execute the process for `build` command.
func (c *buildCommand) Run() {
	dir, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	appDir, err := util.FindAppDir()
	if err != nil {
		panic(err)
	}
	appName := filepath.Base(dir)
	configPkg, err := c.Package(path.Join(appDir, "config"))
	if err != nil {
		util.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) {
		util.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 {
		util.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 {
		util.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))
	util.PrintGreen("Build successful!\n")
}
Beispiel #14
0
func (c *buildCommand) execCmd(cmd string, args ...string) {
	command := exec.Command(cmd, args...)
	if msg, err := command.CombinedOutput(); err != nil {
		util.PanicOnError(c, "abort: build failed: %v\n%v", err, string(msg))
	}
}