sqlboiler/main.go

315 lines
10 KiB
Go
Raw Permalink Normal View History

2016-06-12 03:37:36 +02:00
// Package main defines a command line interface for the sqlboiler package
package main
import (
"fmt"
"os"
"path/filepath"
2016-08-16 12:38:31 +02:00
"strings"
2016-06-12 03:37:36 +02:00
"github.com/kat-co/vala"
2016-06-12 03:37:36 +02:00
"github.com/spf13/cobra"
"github.com/spf13/viper"
2017-07-31 05:34:54 +02:00
"github.com/volatiletech/sqlboiler/bdb/drivers"
"github.com/volatiletech/sqlboiler/boilingcore"
2016-06-12 03:37:36 +02:00
)
2017-08-08 00:31:16 +02:00
const sqlBoilerVersion = "2.5.1"
2016-10-05 16:44:43 +02:00
var (
cmdState *boilingcore.State
cmdConfig *boilingcore.Config
)
2016-06-12 03:37:36 +02:00
func main() {
var err error
2016-10-05 16:44:43 +02:00
// Too much happens between here and cobra's argument handling, for
// something so simple just do it immediately.
for _, arg := range os.Args {
if arg == "--version" {
fmt.Println("SQLBoiler v" + sqlBoilerVersion)
return
}
}
2016-06-12 03:37:36 +02:00
viper.SetConfigName("sqlboiler")
configHome := os.Getenv("XDG_CONFIG_HOME")
homePath := os.Getenv("HOME")
wd, err := os.Getwd()
2016-06-12 03:37:36 +02:00
if err != nil {
wd = "./"
2016-06-12 03:37:36 +02:00
}
configPaths := []string{wd}
if len(configHome) > 0 {
configPaths = append(configPaths, filepath.Join(configHome, "sqlboiler"))
} else {
configPaths = append(configPaths, filepath.Join(homePath, ".config/sqlboiler"))
}
for _, p := range configPaths {
viper.AddConfigPath(p)
}
2016-08-16 12:38:31 +02:00
// Ignore errors here, fallback to other validation methods.
// Users can use environment variables if a config is not found.
_ = viper.ReadInConfig()
2016-06-12 03:37:36 +02:00
// Set up the cobra root command
var rootCmd = &cobra.Command{
2016-06-14 16:52:58 +02:00
Use: "sqlboiler [flags] <driver>",
2016-08-15 14:42:40 +02:00
Short: "SQL Boiler generates an ORM tailored to your database schema.",
Long: "SQL Boiler generates a Go ORM from template files, tailored to your database schema.\n" +
2017-07-31 05:34:54 +02:00
`Complete documentation is available at http://github.com/volatiletech/sqlboiler`,
2016-08-15 14:42:40 +02:00
Example: `sqlboiler postgres`,
PreRunE: preRun,
RunE: run,
PostRunE: postRun,
SilenceErrors: true,
SilenceUsage: true,
2016-06-12 03:37:36 +02:00
}
// Set up the cobra root command flags
rootCmd.PersistentFlags().StringP("output", "o", "models", "The name of the folder to output to")
rootCmd.PersistentFlags().StringP("schema", "s", "", "schema name for drivers that support it (default psql: public, mssql: dbo)")
rootCmd.PersistentFlags().StringP("pkgname", "p", "models", "The name you wish to assign to your generated package")
2016-09-09 07:41:57 +02:00
rootCmd.PersistentFlags().StringP("basedir", "", "", "The base directory has the templates and templates_test folders")
rootCmd.PersistentFlags().StringSliceP("blacklist", "b", nil, "Do not include these tables in your generated package")
2016-09-05 16:41:12 +02:00
rootCmd.PersistentFlags().StringSliceP("whitelist", "w", nil, "Only include these tables in your generated package")
2016-09-04 15:44:54 +02:00
rootCmd.PersistentFlags().StringSliceP("tag", "t", nil, "Struct tags to be included on your models in addition to json, yaml, toml")
rootCmd.PersistentFlags().StringSliceP("replace", "", nil, "Replace templates by directory: relpath/to_file.tpl:relpath/to_replacement.tpl")
2016-08-16 15:54:26 +02:00
rootCmd.PersistentFlags().BoolP("debug", "d", false, "Debug mode prints stack traces on error")
rootCmd.PersistentFlags().BoolP("no-tests", "", false, "Disable generated go test files")
2016-08-28 12:48:50 +02:00
rootCmd.PersistentFlags().BoolP("no-hooks", "", false, "Disable hooks feature for your models")
rootCmd.PersistentFlags().BoolP("no-auto-timestamps", "", false, "Disable automatic timestamps for created_at/updated_at")
2016-10-05 16:44:43 +02:00
rootCmd.PersistentFlags().BoolP("version", "", false, "Print the version")
rootCmd.PersistentFlags().BoolP("tinyint-as-bool", "", false, "Map MySQL tinyint(1) in Go to bool instead of int8")
rootCmd.PersistentFlags().BoolP("wipe", "", false, "Delete the output folder (rm -rf) before generation to ensure sanity")
2016-06-12 03:37:36 +02:00
// hide flags not recommended for use
rootCmd.PersistentFlags().MarkHidden("replace")
viper.SetDefault("postgres.sslmode", "require")
viper.SetDefault("postgres.port", "5432")
2016-09-09 08:04:58 +02:00
viper.SetDefault("mysql.sslmode", "true")
viper.SetDefault("mysql.port", "3306")
viper.SetDefault("mssql.sslmode", "true")
viper.SetDefault("mssql.port", "1433")
2016-09-09 08:04:58 +02:00
2016-06-12 03:37:36 +02:00
viper.BindPFlags(rootCmd.PersistentFlags())
viper.AutomaticEnv()
2016-06-12 03:37:36 +02:00
if err := rootCmd.Execute(); err != nil {
if e, ok := err.(commandFailure); ok {
2016-08-16 16:22:41 +02:00
fmt.Printf("Error: %v\n\n", string(e))
rootCmd.Help()
2016-09-09 07:37:54 +02:00
} else if !viper.GetBool("debug") {
2016-08-16 16:22:41 +02:00
fmt.Printf("Error: %v\n", err)
2016-08-16 15:54:26 +02:00
} else {
2016-08-16 16:22:41 +02:00
fmt.Printf("Error: %+v\n", err)
}
os.Exit(1)
2016-06-12 03:37:36 +02:00
}
}
type commandFailure string
func (c commandFailure) Error() string {
return string(c)
}
2016-06-12 03:37:36 +02:00
func preRun(cmd *cobra.Command, args []string) error {
var err error
if len(args) == 0 {
2016-08-16 16:22:41 +02:00
return commandFailure("must provide a driver name")
}
driverName := args[0]
cmdConfig = &boilingcore.Config{
DriverName: driverName,
OutFolder: viper.GetString("output"),
Schema: viper.GetString("schema"),
PkgName: viper.GetString("pkgname"),
BaseDir: viper.GetString("basedir"),
2016-09-04 12:27:19 +02:00
Debug: viper.GetBool("debug"),
NoTests: viper.GetBool("no-tests"),
NoHooks: viper.GetBool("no-hooks"),
NoAutoTimestamps: viper.GetBool("no-auto-timestamps"),
Wipe: viper.GetBool("wipe"),
}
2016-06-12 03:37:36 +02:00
2016-08-16 12:38:31 +02:00
// BUG: https://github.com/spf13/viper/issues/200
2016-09-09 07:41:57 +02:00
// Look up the value of blacklist, whitelist & tags directly from PFlags in Cobra if we
2016-08-16 12:38:31 +02:00
// detect a malformed value coming out of viper.
// Once the bug is fixed we'll be able to move this into the init above
2016-09-09 07:41:57 +02:00
cmdConfig.BlacklistTables = viper.GetStringSlice("blacklist")
if len(cmdConfig.BlacklistTables) == 1 && strings.ContainsRune(cmdConfig.BlacklistTables[0], ',') {
2016-09-09 07:41:57 +02:00
cmdConfig.BlacklistTables, err = cmd.PersistentFlags().GetStringSlice("blacklist")
2016-08-16 12:38:31 +02:00
if err != nil {
return err
}
}
2016-09-05 16:41:12 +02:00
cmdConfig.WhitelistTables = viper.GetStringSlice("whitelist")
if len(cmdConfig.WhitelistTables) == 1 && strings.ContainsRune(cmdConfig.WhitelistTables[0], ',') {
2016-09-05 16:41:12 +02:00
cmdConfig.WhitelistTables, err = cmd.PersistentFlags().GetStringSlice("whitelist")
if err != nil {
return err
}
}
2016-09-04 15:44:54 +02:00
cmdConfig.Tags = viper.GetStringSlice("tag")
if len(cmdConfig.Tags) == 1 && strings.ContainsRune(cmdConfig.Tags[0], ',') {
2016-09-04 15:44:54 +02:00
cmdConfig.Tags, err = cmd.PersistentFlags().GetStringSlice("tag")
if err != nil {
return err
}
}
cmdConfig.Replacements = viper.GetStringSlice("replace")
if len(cmdConfig.Replacements) == 1 && strings.ContainsRune(cmdConfig.Replacements[0], ',') {
cmdConfig.Replacements, err = cmd.PersistentFlags().GetStringSlice("replace")
if err != nil {
return err
}
}
2016-09-11 21:07:39 +02:00
if driverName == "postgres" {
cmdConfig.Postgres = boilingcore.PostgresConfig{
2016-07-12 00:17:49 +02:00
User: viper.GetString("postgres.user"),
Pass: viper.GetString("postgres.pass"),
Host: viper.GetString("postgres.host"),
Port: viper.GetInt("postgres.port"),
DBName: viper.GetString("postgres.dbname"),
SSLMode: viper.GetString("postgres.sslmode"),
2016-06-12 03:37:36 +02:00
}
2016-09-09 08:04:58 +02:00
// BUG: https://github.com/spf13/viper/issues/71
// Despite setting defaults, nested values don't get defaults
// Set them manually
if cmdConfig.Postgres.SSLMode == "" {
2016-09-09 08:04:58 +02:00
cmdConfig.Postgres.SSLMode = "require"
viper.Set("postgres.sslmode", cmdConfig.Postgres.SSLMode)
}
if cmdConfig.Postgres.Port == 0 {
cmdConfig.Postgres.Port = 5432
viper.Set("postgres.port", cmdConfig.Postgres.Port)
}
if len(cmdConfig.Schema) == 0 {
cmdConfig.Schema = "public"
}
err = vala.BeginValidation().Validate(
vala.StringNotEmpty(cmdConfig.Postgres.User, "postgres.user"),
vala.StringNotEmpty(cmdConfig.Postgres.Host, "postgres.host"),
vala.Not(vala.Equals(cmdConfig.Postgres.Port, 0, "postgres.port")),
vala.StringNotEmpty(cmdConfig.Postgres.DBName, "postgres.dbname"),
2016-07-12 00:17:49 +02:00
vala.StringNotEmpty(cmdConfig.Postgres.SSLMode, "postgres.sslmode"),
).Check()
if err != nil {
return commandFailure(err.Error())
}
2016-06-12 03:37:36 +02:00
}
2016-09-11 21:07:39 +02:00
if driverName == "mysql" {
cmdConfig.MySQL = boilingcore.MySQLConfig{
2016-09-09 08:04:58 +02:00
User: viper.GetString("mysql.user"),
Pass: viper.GetString("mysql.pass"),
Host: viper.GetString("mysql.host"),
Port: viper.GetInt("mysql.port"),
DBName: viper.GetString("mysql.dbname"),
SSLMode: viper.GetString("mysql.sslmode"),
}
// Set MySQL TinyintAsBool global var. This flag only applies to MySQL.
drivers.TinyintAsBool = viper.GetBool("tinyint-as-bool")
2016-09-09 08:04:58 +02:00
// MySQL doesn't have schemas, just databases
cmdConfig.Schema = cmdConfig.MySQL.DBName
// BUG: https://github.com/spf13/viper/issues/71
// Despite setting defaults, nested values don't get defaults
// Set them manually
if cmdConfig.MySQL.SSLMode == "" {
cmdConfig.MySQL.SSLMode = "true"
viper.Set("mysql.sslmode", cmdConfig.MySQL.SSLMode)
}
if cmdConfig.MySQL.Port == 0 {
cmdConfig.MySQL.Port = 3306
viper.Set("mysql.port", cmdConfig.MySQL.Port)
}
err = vala.BeginValidation().Validate(
vala.StringNotEmpty(cmdConfig.MySQL.User, "mysql.user"),
vala.StringNotEmpty(cmdConfig.MySQL.Host, "mysql.host"),
vala.Not(vala.Equals(cmdConfig.MySQL.Port, 0, "mysql.port")),
vala.StringNotEmpty(cmdConfig.MySQL.DBName, "mysql.dbname"),
vala.StringNotEmpty(cmdConfig.MySQL.SSLMode, "mysql.sslmode"),
).Check()
if err != nil {
return commandFailure(err.Error())
}
}
2017-03-13 10:55:26 +01:00
if driverName == "mssql" {
cmdConfig.MSSQL = boilingcore.MSSQLConfig{
User: viper.GetString("mssql.user"),
Pass: viper.GetString("mssql.pass"),
Host: viper.GetString("mssql.host"),
Port: viper.GetInt("mssql.port"),
DBName: viper.GetString("mssql.dbname"),
SSLMode: viper.GetString("mssql.sslmode"),
}
// BUG: https://github.com/spf13/viper/issues/71
// Despite setting defaults, nested values don't get defaults
// Set them manually
if cmdConfig.MSSQL.SSLMode == "" {
cmdConfig.MSSQL.SSLMode = "true"
viper.Set("mssql.sslmode", cmdConfig.MSSQL.SSLMode)
}
if cmdConfig.MSSQL.Port == 0 {
2017-03-18 13:47:52 +01:00
cmdConfig.MSSQL.Port = 1433
2017-03-13 10:55:26 +01:00
viper.Set("mssql.port", cmdConfig.MSSQL.Port)
}
if len(cmdConfig.Schema) == 0 {
cmdConfig.Schema = "dbo"
}
2017-03-13 10:55:26 +01:00
err = vala.BeginValidation().Validate(
vala.StringNotEmpty(cmdConfig.MSSQL.User, "mssql.user"),
vala.StringNotEmpty(cmdConfig.MSSQL.Host, "mssql.host"),
vala.Not(vala.Equals(cmdConfig.MSSQL.Port, 0, "mssql.port")),
vala.StringNotEmpty(cmdConfig.MSSQL.DBName, "mssql.dbname"),
vala.StringNotEmpty(cmdConfig.MSSQL.SSLMode, "mssql.sslmode"),
).Check()
if err != nil {
return commandFailure(err.Error())
}
}
cmdState, err = boilingcore.New(cmdConfig)
2016-06-12 03:37:36 +02:00
return err
}
func run(cmd *cobra.Command, args []string) error {
return cmdState.Run(true)
2016-06-12 03:37:36 +02:00
}
func postRun(cmd *cobra.Command, args []string) error {
return cmdState.Cleanup()
2016-06-12 03:37:36 +02:00
}