2016-06-12 03:37:36 +02:00
|
|
|
// Package main defines a command line interface for the sqlboiler package
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
2016-06-12 20:19:23 +02:00
|
|
|
"path/filepath"
|
2016-08-16 12:38:31 +02:00
|
|
|
"strings"
|
2016-06-12 03:37:36 +02:00
|
|
|
|
2016-06-19 23:47:50 +02:00
|
|
|
"github.com/kat-co/vala"
|
2016-06-12 03:37:36 +02:00
|
|
|
"github.com/spf13/cobra"
|
|
|
|
"github.com/spf13/viper"
|
2017-01-02 06:16:08 +01:00
|
|
|
"github.com/vattle/sqlboiler/bdb/drivers"
|
2017-01-14 04:38:40 +01:00
|
|
|
"github.com/vattle/sqlboiler/boilingcore"
|
2016-06-12 03:37:36 +02:00
|
|
|
)
|
|
|
|
|
2017-03-02 03:31:16 +01:00
|
|
|
const sqlBoilerVersion = "2.2.0"
|
2016-10-05 16:44:43 +02:00
|
|
|
|
2016-06-12 20:19:23 +02:00
|
|
|
var (
|
2017-01-14 04:38:40 +01:00
|
|
|
cmdState *boilingcore.State
|
|
|
|
cmdConfig *boilingcore.Config
|
2016-06-12 20:19:23 +02:00
|
|
|
)
|
|
|
|
|
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")
|
|
|
|
|
2016-06-12 20:19:23 +02:00
|
|
|
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 {
|
2016-06-12 20:19:23 +02:00
|
|
|
wd = "./"
|
2016-06-12 03:37:36 +02:00
|
|
|
}
|
|
|
|
|
2016-06-12 20:19:23 +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 20:19:23 +02:00
|
|
|
|
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" +
|
2016-08-09 09:59:30 +02:00
|
|
|
`Complete documentation is available at http://github.com/vattle/sqlboiler`,
|
2016-08-15 14:42:40 +02:00
|
|
|
Example: `sqlboiler postgres`,
|
2016-06-19 23:47:50 +02:00
|
|
|
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
|
2016-06-14 14:58:46 +02:00
|
|
|
rootCmd.PersistentFlags().StringP("output", "o", "models", "The name of the folder to output to")
|
2017-04-02 18:40:08 +02:00
|
|
|
rootCmd.PersistentFlags().StringP("schema", "s", "", "schema name for drivers that support it (default psql: public, mssql: dbo)")
|
2016-06-14 14:58:46 +02:00
|
|
|
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")
|
2017-01-16 06:21:04 +01:00
|
|
|
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")
|
2016-09-02 03:22:56 +02:00
|
|
|
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")
|
2016-08-28 16:12:37 +02:00
|
|
|
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")
|
2017-01-02 06:16:08 +01:00
|
|
|
rootCmd.PersistentFlags().BoolP("tinyint-as-bool", "", false, "Map MySQL tinyint(1) in Go to bool instead of int8")
|
2017-01-27 05:42:14 +01:00
|
|
|
rootCmd.PersistentFlags().BoolP("wipe", "", false, "Delete the output folder (rm -rf) before generation to ensure sanity")
|
2016-06-12 03:37:36 +02:00
|
|
|
|
2017-02-04 06:51:07 +01:00
|
|
|
// hide flags not recommended for use
|
|
|
|
rootCmd.PersistentFlags().MarkHidden("replace")
|
|
|
|
|
2016-08-06 07:14:28 +02:00
|
|
|
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")
|
2017-03-18 13:50:03 +01:00
|
|
|
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())
|
2016-08-06 07:14:28 +02:00
|
|
|
viper.AutomaticEnv()
|
2016-06-12 03:37:36 +02:00
|
|
|
|
|
|
|
if err := rootCmd.Execute(); err != nil {
|
2016-06-19 23:47:50 +02:00
|
|
|
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)
|
2016-06-19 23:47:50 +02:00
|
|
|
}
|
|
|
|
|
2016-06-13 00:34:57 +02:00
|
|
|
os.Exit(1)
|
2016-06-12 03:37:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-19 23:47:50 +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 {
|
2016-06-13 00:34:57 +02:00
|
|
|
var err error
|
|
|
|
|
2016-06-12 20:19:23 +02:00
|
|
|
if len(args) == 0 {
|
2016-08-16 16:22:41 +02:00
|
|
|
return commandFailure("must provide a driver name")
|
2016-06-12 20:19:23 +02:00
|
|
|
}
|
|
|
|
|
2016-08-01 04:04:48 +02:00
|
|
|
driverName := args[0]
|
|
|
|
|
2017-01-14 04:38:40 +01:00
|
|
|
cmdConfig = &boilingcore.Config{
|
2016-08-28 16:12:37 +02:00
|
|
|
DriverName: driverName,
|
|
|
|
OutFolder: viper.GetString("output"),
|
2016-09-08 23:23:10 +02:00
|
|
|
Schema: viper.GetString("schema"),
|
2016-08-28 16:12:37 +02:00
|
|
|
PkgName: viper.GetString("pkgname"),
|
2016-11-12 04:08:36 +01:00
|
|
|
BaseDir: viper.GetString("basedir"),
|
2016-09-04 12:27:19 +02:00
|
|
|
Debug: viper.GetBool("debug"),
|
2016-09-02 03:22:56 +02:00
|
|
|
NoTests: viper.GetBool("no-tests"),
|
2016-08-28 16:12:37 +02:00
|
|
|
NoHooks: viper.GetBool("no-hooks"),
|
|
|
|
NoAutoTimestamps: viper.GetBool("no-auto-timestamps"),
|
2017-01-27 05:42:14 +01:00
|
|
|
Wipe: viper.GetBool("wipe"),
|
2016-06-13 00:34:57 +02:00
|
|
|
}
|
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")
|
2017-01-14 05:01:00 +01:00
|
|
|
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")
|
2017-01-14 05:01:00 +01:00
|
|
|
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")
|
2017-01-14 05:01:00 +01:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-16 06:21:04 +01:00
|
|
|
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" {
|
2017-01-14 04:38:40 +01:00
|
|
|
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-06-19 23:47:50 +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
|
2016-07-13 18:51:40 +02:00
|
|
|
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)
|
2016-07-13 18:51:40 +02:00
|
|
|
}
|
|
|
|
|
2017-04-02 18:40:08 +02:00
|
|
|
if len(cmdConfig.Schema) == 0 {
|
|
|
|
cmdConfig.Schema = "public"
|
|
|
|
}
|
|
|
|
|
2016-06-19 23:47:50 +02:00
|
|
|
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"),
|
2016-06-19 23:47:50 +02:00
|
|
|
).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" {
|
2017-01-14 04:38:40 +01:00
|
|
|
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"),
|
|
|
|
}
|
|
|
|
|
2017-01-02 06:16:08 +01:00
|
|
|
// 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)
|
|
|
|
}
|
|
|
|
|
2017-04-02 18:40:08 +02:00
|
|
|
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())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-14 04:38:40 +01:00
|
|
|
cmdState, err = boilingcore.New(cmdConfig)
|
2016-06-12 03:37:36 +02:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func run(cmd *cobra.Command, args []string) error {
|
2016-06-12 20:19:23 +02:00
|
|
|
return cmdState.Run(true)
|
2016-06-12 03:37:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func postRun(cmd *cobra.Command, args []string) error {
|
2016-06-12 20:19:23 +02:00
|
|
|
return cmdState.Cleanup()
|
2016-06-12 03:37:36 +02:00
|
|
|
}
|