Example #1
0
// CreateDSN creates a DSN (data source name) string out of hostname, username,
// password, and timeout. It validates the resulting DSN and returns an error
// if the DSN is invalid.
func CreateDSN(host, username, password string, timeout time.Duration) (string, error) {
	// Example: [username[:password]@][protocol[(address)]]/
	dsn := host

	if username != "" || password != "" {
		dsn = "@" + dsn
	}

	if password != "" {
		dsn = ":" + password + dsn
	}

	if username != "" {
		dsn = username + dsn
	}

	config, err := mysql.ParseDSN(dsn)
	if err != nil {
		return "", errors.Wrapf(err, "config error for host '%s'", host)
	}

	if timeout > 0 {
		// Add connection timeouts to the DSN.
		config.Timeout = timeout
		config.ReadTimeout = timeout
		config.WriteTimeout = timeout
	}

	return config.FormatDSN(), nil
}
Example #2
0
func getDSNTag(dsn string) string {
	conf, err := mysql.ParseDSN(dsn)
	if err != nil {
		return "127.0.0.1:3306"
	}
	return conf.Addr
}
Example #3
0
func dsnAddTimeout(dsn string) (string, error) {
	conf, err := mysql.ParseDSN(dsn)
	if err != nil {
		return "", err
	}

	if conf.Timeout == 0 {
		conf.Timeout = time.Second * 5
	}

	return conf.FormatDSN(), nil
}
Example #4
0
// NewDbMap creates the root gorp mapping object. Create one of these for each
// database schema you wish to map. Each DbMap contains a list of mapped
// tables. It automatically maps the tables for the primary parts of Boulder
// around the Storage Authority.
func NewDbMap(dbConnect string, maxOpenConns int) (*gorp.DbMap, error) {
	var err error
	var config *mysql.Config
	if strings.HasPrefix(dbConnect, "mysql+tcp://") {
		dbConnect, err = recombineCustomMySQLURL(dbConnect)
		if err != nil {
			return nil, err
		}
	}

	config, err = mysql.ParseDSN(dbConnect)
	if err != nil {
		return nil, err
	}

	return NewDbMapFromConfig(config, maxOpenConns)
}
Example #5
0
func init() {

	migrationsPath := ""
	mysql.Init(func(c *mysql.Config) {
		parse.Populate(c, config.Conf, "mysql")

		migrationsPath = c.MigrationsPath
		c2, err := mysqlReal.ParseDSN(c.ConnectString)
		if err == nil {
			Info.Printf("Attempting to connect to %s@%s\n", c2.User, c2.Addr)
		} else {
			Error.Println("Error parsing DSN:", c.ConnectString)
		}
	})

	if migrationsPath != "" {
		mysql.Migrate(migrationsPath)
	}
}
Example #6
0
// ParseDSN creates a DSN (data source name) string by parsing the host.
// It validates the resulting DSN and returns an error if the DSN is invalid.
//
//   Format:  [username[:password]@][protocol[(address)]]/
//   Example: root:test@tcp(127.0.0.1:3306)/
func ParseDSN(mod mb.Module, host string) (mb.HostData, error) {
	c := struct {
		Username string `config:"username"`
		Password string `config:"password"`
	}{}
	if err := mod.UnpackConfig(&c); err != nil {
		return mb.HostData{}, err
	}

	config, err := mysql.ParseDSN(host)
	if err != nil {
		return mb.HostData{}, errors.Wrapf(err, "error parsing mysql host")
	}

	if config.User == "" {
		config.User = c.Username
	}

	if config.Passwd == "" {
		config.Passwd = c.Password
	}

	// Add connection timeouts to the DSN.
	if timeout := mod.Config().Timeout; timeout > 0 {
		config.Timeout = timeout
		config.ReadTimeout = timeout
		config.WriteTimeout = timeout
	}

	noCredentialsConfig := *config
	noCredentialsConfig.User = ""
	noCredentialsConfig.Passwd = ""

	return mb.HostData{
		URI:          config.FormatDSN(),
		SanitizedURI: noCredentialsConfig.FormatDSN(),
		Host:         config.Addr,
		User:         config.User,
		Password:     config.Passwd,
	}, nil
}
Example #7
0
func openDB() *sql.DB {
	cfg, err := mysql.ParseDSN("")
	if err != nil {
		log.Printf("Error parsing null DSN: %s\n", err)
	}
	cfg.User = DBCreds.Username
	cfg.Passwd = DBCreds.Password
	cfg.Addr = DBCreds.Hostname + ":" + strconv.Itoa(DBCreds.Port)
	cfg.DBName = DBCreds.Name
	db, err := sql.Open("mysql", cfg.FormatDSN())
	if err != nil {
		log.Printf("Error opening DB connection: %s\n", err)
	}
	if err = db.Ping(); err != nil {
		log.Printf("Error pinging DB: %s\n", err)
	}
	_, err = db.Exec("CREATE TABLE puzzles (ident VARCHAR(50) UNIQUE NOT NULL, author TEXT, solution TEXT, clues MEDIUMTEXT)")
	if err != nil && !strings.Contains(err.Error(), "Table 'puzzles' already exists") {
		log.Printf("Error creating table: %s\n", err)
	}
	return db
}
Example #8
0
// SetUpMySQLDatabase connects mysql container with given $connectURL and also creates a new database named $databaseName
// A modified url used to connect the created database will be returned
func SetUpMySQLDatabase(databaseName, connectURL string) (url string, err error) {
	if databaseName == defaultMySQLDBName {
		return connectURL, nil
	}

	db, err := sql.Open("mysql", connectURL)
	if err != nil {
		return "", err
	}
	defer db.Close()
	_, err = db.Exec(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s", databaseName))
	if err != nil {
		return "", err
	}

	// parse dsn
	config, err := mysql.ParseDSN(connectURL)
	if err != nil {
		return "", err
	}
	config.DBName = databaseName // overwrite database name
	return config.FormatDSN(), nil
}
Example #9
0
func dsnValidator(v *validator.Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
	dsn, err := mysql.ParseDSN(field.String())
	return err == nil && dsn.ParseTime
}
Example #10
0
func main() {
	var origTargetDb, targetDb, tableNames, packageName string
	var tmplName string
	var driver, schemaName string
	var touchTimestamp, buildStruct, readPass, createTableMigration, requestVersion, rebuildAll bool
	var pCount int
	var structName string

	versionNum := "16.11.10"

	for _, arg := range os.Args {
		if arg == "--version" {
			fmt.Println("ModelQ Version", versionNum)
			return
		}
	}

	flag.StringVar(&origTargetDb, "db", "", "Target database source string: e.g. root@tcp(127.0.0.1:3306)/test?charset=utf-8")
	flag.StringVar(&tableNames, "tables", "", "You may specify which tables the models need to be created, e.g. \"user,article,blog\"")
	flag.StringVar(&packageName, "pkg", "models", "Go source code package for generated models")
	flag.StringVar(&driver, "driver", "mysql", "(default:mysql) Current supported drivers include mysql, postgres")
	flag.BoolVar(&rebuildAll, "rebuild-all", false, "rebuild everything with a _mq extension")
	flag.StringVar(&schemaName, "schema", "", "(default:detected from db string) Schema for postgresql, database name for mysql")
	flag.BoolVar(&touchTimestamp, "dont-touch-timestamp", false, "Should touch the datetime fields with default value or on update")
	flag.StringVar(&tmplName, "template", "", "Passing the template to generate code, or use the default one")
	flag.IntVar(&pCount, "p", 4, "Parallell running for code generator")
	flag.BoolVar(&gmq.Debug, "debug", false, "Debug on/off")
	flag.BoolVar(&buildStruct, "struct", false, "Generate the struct too")
	flag.BoolVar(&readPass, "pass", false, "Request db password from command line")
	flag.StringVar(&structName, "name", "", "Custom Struct name to use when generating structs. Only works on the first table")
	flag.BoolVar(&createTableMigration, "ct", false, "Create Table: Generate a migration file to create the table (requires mysqldump)")
	flag.BoolVar(&requestVersion, "-version", false, fmt.Sprintf("Version Number (matches release date) %s", versionNum))
	flag.Parse()

	targetDb = string(origTargetDb)
	runtime.GOMAXPROCS(pCount)

	if targetDb == "" {
		fmt.Println("Please provide the target database source.")
		fmt.Println("Usage:")
		flag.PrintDefaults()
		return
	}

	if readPass {
		// break down the database as follows:
		// root:@tcp(localhost:3306)/dd
		// dbUser = root
		// dbHostPort = tcp(localhost:3306)
		// dbDatabase = dd

		reader := bufio.NewReader(os.Stdin)
		fmt.Print("Enter db password: "******"Error parsing DSN.")
			log.Fatal(err)
		}

		cfg.Passwd = pass
		targetDb = cfg.FormatDSN()

		//		fmt.Println(targetDb)

		// This utilty doesn't work... dunno why.  -Jeff
		//	  fmt.Printf("Enter database password: "******"AUTO_INCREMENT=\\d+")

		// this part executes a "mysqldmp --no-data command" and puts it into ./db/migrations
		cfg, err := mysql.ParseDSN(targetDb)
		if err != nil {
			log.Println("Error parsing DSN.")
			log.Fatal(err)
		}

		dbPort := 3306
		dbHost := cfg.Addr
		if strings.Contains(cfg.Addr, ":") {
			dbHostPort := strings.Split(cfg.Addr, ":")
			dbHost = dbHostPort[0]
			var err error
			dbPort, err = strconv.Atoi(dbHostPort[1])
			if err != nil {
				log.Println("Cannot parse port:", cfg.Addr)
				log.Fatal(err)
				return
			}
		}

		if dbHost == "localhost" {
			dbHost = "127.0.0.1" // apparently mysqldump doesn't like the word "localhost" -Jeff
			cfg.Addr = "127.0.0.1"
		}

		//		targetDb2 := cfg.FormatDSN()

		// run mysqldump for each table
		for _, dbTable := range strings.Split(tableNames, ",") {
			//mySqlDumpCmd := fmt.Sprintf("mysqldump -u %s -p%s -h %s -P %d --no-data %s %s > db/migrations/%s.sql", cfg.User, cfg.Passwd, dbHost, dbPort, cfg.DBName, dbTable, dbTable)

			// this is the mysql string
			mySqlDumpCmd := fmt.Sprintf("mysqldump -u %s -p%s -h %s -P %d --no-data %s %s", cfg.User, cfg.Passwd, dbHost, dbPort, cfg.DBName, dbTable)

			//			mySqlDumpCmd = fmt.Sprintf("mysql -u %s -p%s -h %s -P %d --batch --silent -e SHOW CREATE TABLE %s.%s;", cfg.User, cfg.Passwd, dbHost, dbPort, cfg.DBName, dbTable)

			//			mySqlDumpCmd = fmt.Sprintf("mysql -u %s -p%s -h %s -P %d SHOW CREATE TABLE %s.%s;", cfg.User, cfg.Passwd, dbHost, dbPort, cfg.DBName, dbTable)
			mySqlDumpCmd = fmt.Sprintf("mysql -u %s -p%s -h %s -P %d --batch --silent -e", cfg.User, cfg.Passwd, dbHost, dbPort)
			mySqlDumpCmd2 := fmt.Sprintf("SHOW CREATE TABLE %s.%s;", cfg.DBName, dbTable)
			//mySqlDumpCmd2 := fmt.Sprintf("SHOW CREATE TABLE %s;", dbTable)

			//			fmt.Println(mySqlDumpCmd)

			// we have to break it up into args for golang
			args := strings.Split(mySqlDumpCmd, " ")
			args = append(args, mySqlDumpCmd2)
			// execute and save the output
			data, err := exec.Command(args[0], args[1:]...).Output()
			//			data, err := exec.Command("mysql" %s SHOW CREATE TABLE %s;", targetDb2, dbTable).Output()
			if err != nil {
				log.Println("Cannot run mysqldump:", mySqlDumpCmd)
				log.Fatal(err)
				return
			}

			// the newlines are shit, fix them
			s_data := strings.Replace(string(data), "\\n", "\n", -1)

			//			fmt.Println(s_data)

			// for some dumbass reason, it places the table name in front of the create command, this removes it
			s_data = s_data[len(dbTable)+1:]

			//			fmt.Println(s_data)

			dbTableWithHyphen := strings.Replace(dbTable, "_", "-", -1)
			dbTableWithoutUnderscores := strings.Replace(strings.Title(dbTable), "_", "", -1)

			// add the goose header and drop command
			header := `-- +goose Up
-- name: drop-` + dbTableWithHyphen + `-table
DROP TABLE IF EXISTS ` + "`" + dbTable + "`" + `;

-- name: create-` + dbTableWithHyphen + `-table
`
			s_data = fmt.Sprintf("%s%s;", header, s_data)

			s_data = re_autoinc.ReplaceAllString(s_data, "AUTO_INCREMENT=1")

			//			fmt.Println(s_data)

			filename := fmt.Sprintf("db/migrations/%s.sql", dbTableWithoutUnderscores)

			//
			files, err := ioutil.ReadDir("db/migrations")
			if err != nil {
				log.Fatal(err)
			}

			fnameMatches := strings.ToLower(fmt.Sprintf("Create%sTable.sql", dbTableWithoutUnderscores))
			//			fmt.Println(fnameMatches)
			for _, file := range files {
				//			  fmt.Println(strings.ToLower(file.Name()))
				if strings.Contains(strings.ToLower(file.Name()), fnameMatches) {
					filename = fmt.Sprintf("db/migrations/%s", file.Name())
					fmt.Println("found matching file name", filename)
					break
				}
			}

			// write the file
			f, err := os.Create(filename)
			if err != nil {
				log.Println("Cannot open output file:", filename)
				log.Fatal(err)
				return
			}
			defer f.Close()
			f.Write([]byte(s_data))

		}
	}

	if packageName == "" {
		printUsages("Please provide the go source code package name for generated models.")
		return
	}

	if driver != "mysql" && driver != "postgres" {
		printUsages("Current supported drivers include mysql, postgres.")
		return
	}
	if schemaName == "" {
		dbParts := strings.Split(targetDb, "/")
		suffexes := strings.Split(dbParts[len(dbParts)-1], "?")
		schemaName = suffexes[0]

		if schemaName == "" {
			printUsages("Please provide the schema namee.")
			return
		}
	}

	newOsArgs := append([]string{}, os.Args...)
	for idx, osArg := range newOsArgs {
		if len(osArg) > 3 && osArg[0:3] == "-db" {
			newOsArgs[idx] = `-db="` + origTargetDb + `"`
			break
		}
	}

	if rebuildAll {
		nameRegexp := regexp.MustCompile(`-name=(\S+)`)
		tablesRegexp := regexp.MustCompile(`-tables=(\S+)`)

		files, err := ioutil.ReadDir(packageName + "/")
		if err != nil {
			log.Fatal(err)
		}

		for _, fileInfo := range files {
			fnameLower := strings.ToLower(fileInfo.Name())
			if strings.Contains(fnameLower, "_mq.go") {
				modelNameFromFile := fnameLower[:len(fnameLower)-6] // peel off "_mq.go"
				fmt.Println(fileInfo.Name(), modelNameFromFile)

				// when table and model match, there's no "-name=" ... only "-tables="
				nameParam := ""
				tableParam := modelNameFromFile

				// let's pars the file to see if the modelq execution command has -name

				// open the file for reading; yes, FileInfo is retarded -- you can't open it directly
				file, err := os.Open(packageName + "/" + fileInfo.Name())
				if err != nil {
					log.Fatal(err)
				}
				defer file.Close()

				// read the lines
				scanner := bufio.NewScanner(file)
				for scanner.Scan() {
					line := scanner.Text()
					// find the modelq execution one (should say "modelq" and "-tabels" ... can add more for certainty
					if strings.Contains(line, "modelq") && strings.Contains(line, "-tables") {
						fmt.Println(line)
						// see if it has the -name param
						if strings.Contains(line, "-name") {
							fmt.Println("nameee", nameParam)
							// get the part with the name
							nameParam = nameRegexp.FindStringSubmatch(line)[1]

							// see model matches the -name; otherwise it's a different table in the same run
							if nameParam == modelNameFromFile {
								// by rule, if using -name, then table param is required to be the first one
								tableParam = strings.Split(tablesRegexp.FindStringSubmatch(line)[1], ",")[0] // the first table name
							} else {
								// nope, disregard the name param, it's the wrong model
								nameParam = ""
							}
						}
						break
					}
				}
				var executionString string
				if len(nameParam) > 0 {
					executionString = fmt.Sprintf("modelq -db=%s -tables=%s -name=%s -struct=%t", origTargetDb, tableParam, nameParam, buildStruct)
				} else {
					executionString = fmt.Sprintf("modelq -db=%s -tables=%s -struct=%t", origTargetDb, tableParam, buildStruct)
				}
				fmt.Println("  " + executionString)

				// do the work
				dbSchema, err := drivers.LoadDatabaseSchema(driver, targetDb, schemaName, tableParam)
				if err != nil {
					log.Println("Cannot load table schemas from database.")
					log.Fatal(err)
				}

				codeConfig := &CodeConfig{
					packageName:     packageName,
					touchTimestamp:  touchTimestamp,
					template:        tmplName,
					buildStuct:      buildStruct,
					ExecutionString: executionString,
					ExecutionDate:   time.Now(),
				}
				codeConfig.MustCompileTemplate()
				generateModels(schemaName, dbSchema, *codeConfig, nameParam)
				formatCodes(packageName)
			}
		}
	} else {
		dbSchema, err := drivers.LoadDatabaseSchema(driver, targetDb, schemaName, tableNames)
		if err != nil {
			log.Println("Cannot load table schemas from database.")
			log.Fatal(err)
		}

		executionString := fmt.Sprintf("modelq %s", strings.Join(newOsArgs[1:], " "))
		codeConfig := &CodeConfig{
			packageName:     packageName,
			touchTimestamp:  touchTimestamp,
			template:        tmplName,
			buildStuct:      buildStruct,
			ExecutionString: executionString,
			ExecutionDate:   time.Now(),
		}
		codeConfig.MustCompileTemplate()
		generateModels(schemaName, dbSchema, *codeConfig, structName)
		formatCodes(packageName)
	}
}