From 51519b62dd9f77b18bce96b4c548558c0d445f3f Mon Sep 17 00:00:00 2001 From: Nurahmadie Date: Sat, 8 Mar 2014 12:19:28 +0700 Subject: [PATCH] Actually use --driver option to set database driver for drone. This includes refactoring database setup, and migration system. Remove setupDatabase from main and use `Init` method from database package. At database package, defines Init method which actually initiate database with options given from comand line flag. I think `--path` wont be used anywhere so I plan to remove it later. Both meddler and migration initiated here, then we call `Set` method to setup all the tables, etc. Here I think I want to separate database schema and turn it into migration script instead, later maybe. At migration package I made some tweak to `Operation` interface. Realized that it's ludicrous to let migration driver re-implement `Exec` and `Query`, I made migration script to receive The whole migrationDriver struct which contains both Operation implementor, and the Tx itself. This made possible thanks to Go struct being able to promote its member, now our migration is more transparent. There's also stub implementation for bot mysql and postgresql, will implement this really soon. --- Makefile | 2 + cmd/droned/drone.go | 27 +------ pkg/database/database.go | 41 ++++++++++ ...402200603_rename_privelege_to_privilege.go | 8 +- .../201402211147_github_enterprise_support.go | 14 ++-- pkg/database/migrate/migrate.go | 23 +++--- pkg/database/migrate/mysql.go | 41 ++++++++++ pkg/database/migrate/postgresql.go | 41 ++++++++++ pkg/database/migrate/sqlite.go | 37 ++++----- pkg/database/migrate/sqlite_test.go | 78 +++++++++---------- 10 files changed, 203 insertions(+), 109 deletions(-) create mode 100644 pkg/database/migrate/mysql.go create mode 100644 pkg/database/migrate/postgresql.go diff --git a/Makefile b/Makefile index a4058a5f1..23aaef08b 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,8 @@ deps: go get github.com/drone/go-bitbucket/bitbucket go get github.com/GeertJohan/go.rice go get github.com/GeertJohan/go.rice/rice + go get github.com/go-sql-driver/mysql + go get github.com/lib/pq go get github.com/mattn/go-sqlite3 go get github.com/russross/meddler diff --git a/cmd/droned/drone.go b/cmd/droned/drone.go index a2a9b86ab..3cad9032d 100644 --- a/cmd/droned/drone.go +++ b/cmd/droned/drone.go @@ -1,7 +1,6 @@ package main import ( - "database/sql" "flag" "log" "net/http" @@ -12,13 +11,10 @@ import ( "code.google.com/p/go.net/websocket" "github.com/GeertJohan/go.rice" "github.com/bmizerany/pat" - _ "github.com/mattn/go-sqlite3" - "github.com/russross/meddler" "github.com/drone/drone/pkg/build/docker" "github.com/drone/drone/pkg/channel" "github.com/drone/drone/pkg/database" - "github.com/drone/drone/pkg/database/migrate" "github.com/drone/drone/pkg/handler" "github.com/drone/drone/pkg/queue" ) @@ -66,7 +62,9 @@ func main() { checkTLSFlags() // setup database and handlers - setupDatabase() + if err := database.Init(driver, datasource); err != nil { + log.Fatal("Can't initialize database:", err) + } setupStatic() setupHandlers() @@ -92,25 +90,6 @@ func checkTLSFlags() { } -// setup the database connection and register with the -// global database package. -func setupDatabase() { - // inform meddler and migration we're using sqlite - meddler.Default = meddler.SQLite - migrate.Driver = migrate.SQLite - - // connect to the SQLite database - db, err := sql.Open(driver, datasource) - if err != nil { - log.Fatal(err) - } - - database.Set(db) - - migration := migrate.New(db) - migration.All().Migrate() -} - // setup routes for static assets. These assets may // be directly embedded inside the application using // the `rice embed` command, else they are served from disk. diff --git a/pkg/database/database.go b/pkg/database/database.go index 223405433..fcaa3521c 100644 --- a/pkg/database/database.go +++ b/pkg/database/database.go @@ -4,12 +4,53 @@ import ( "database/sql" "log" + "github.com/drone/drone/pkg/database/migrate" "github.com/drone/drone/pkg/database/schema" + + _ "github.com/go-sql-driver/mysql" + _ "github.com/lib/pq" + _ "github.com/mattn/go-sqlite3" + + "github.com/russross/meddler" ) // global instance of our database connection. var db *sql.DB +func Init(name, datasource string) error { + driver := map[string]struct { + Md *meddler.Database + Mg migrate.DriverFunction + }{ + "sqlite3": { + meddler.SQLite, + migrate.SQLite, + }, + "mysql": { + meddler.MySQL, + migrate.MySQL, + }, + "postgresql": { + meddler.PostgreSQL, + migrate.PostgreSQL, + }, + } + + meddler.Default = driver[name].Md + migrate.Driver = driver[name].Mg + + db, err := sql.Open(name, datasource) + if err != nil { + return err + } + + Set(db) + + migration := migrate.New(db) + migration.All().Migrate() + return nil +} + // Set sets the default database. func Set(database *sql.DB) { // set the global database diff --git a/pkg/database/migrate/201402200603_rename_privelege_to_privilege.go b/pkg/database/migrate/201402200603_rename_privelege_to_privilege.go index 379a6649e..eeb1cdb29 100644 --- a/pkg/database/migrate/201402200603_rename_privelege_to_privilege.go +++ b/pkg/database/migrate/201402200603_rename_privelege_to_privilege.go @@ -8,15 +8,15 @@ func (r *Rev1) Revision() int64 { return 201402200603 } -func (r *Rev1) Up(op Operation) error { - _, err := op.RenameColumns("repos", map[string]string{ +func (r *Rev1) Up(mg *MigrationDriver) error { + _, err := mg.RenameColumns("repos", map[string]string{ "priveleged": "privileged", }) return err } -func (r *Rev1) Down(op Operation) error { - _, err := op.RenameColumns("repos", map[string]string{ +func (r *Rev1) Down(mg *MigrationDriver) error { + _, err := mg.RenameColumns("repos", map[string]string{ "privileged": "priveleged", }) return err diff --git a/pkg/database/migrate/201402211147_github_enterprise_support.go b/pkg/database/migrate/201402211147_github_enterprise_support.go index dcdd5e8f1..8c252d782 100644 --- a/pkg/database/migrate/201402211147_github_enterprise_support.go +++ b/pkg/database/migrate/201402211147_github_enterprise_support.go @@ -8,19 +8,19 @@ func (r *Rev3) Revision() int64 { return 201402211147 } -func (r *Rev3) Up(op Operation) error { - _, err := op.AddColumn("settings", "github_domain VARCHAR(255)") +func (r *Rev3) Up(mg *MigrationDriver) error { + _, err := mg.AddColumn("settings", "github_domain VARCHAR(255)") if err != nil { return err } - _, err = op.AddColumn("settings", "github_apiurl VARCHAR(255)") + _, err = mg.AddColumn("settings", "github_apiurl VARCHAR(255)") - op.Exec("update settings set github_domain=?", "github.com") - op.Exec("update settings set github_apiurl=?", "https://api.github.com") + mg.Tx.Exec("update settings set github_domain=?", "github.com") + mg.Tx.Exec("update settings set github_apiurl=?", "https://api.github.com") return err } -func (r *Rev3) Down(op Operation) error { - _, err := op.DropColumns("settings", []string{"github_domain", "github_apiurl"}) +func (r *Rev3) Down(mg *MigrationDriver) error { + _, err := mg.DropColumns("settings", []string{"github_domain", "github_apiurl"}) return err } diff --git a/pkg/database/migrate/migrate.go b/pkg/database/migrate/migrate.go index 63cef3914..1b7cbf28c 100644 --- a/pkg/database/migrate/migrate.go +++ b/pkg/database/migrate/migrate.go @@ -64,22 +64,17 @@ type Operation interface { DropColumns(tableName string, columnsToDrop []string) (sql.Result, error) RenameColumns(tableName string, columnChanges map[string]string) (sql.Result, error) - - Exec(query string, args ...interface{}) (sql.Result, error) - - Query(query string, args ...interface{}) (*sql.Rows, error) - - QueryRow(query string, args ...interface{}) *sql.Row } type Revision interface { - Up(op Operation) error - Down(op Operation) error + Up(mg *MigrationDriver) error + Down(mg *MigrationDriver) error Revision() int64 } type MigrationDriver struct { Tx *sql.Tx + Operation } type Migration struct { @@ -87,7 +82,9 @@ type Migration struct { revs []Revision } -var Driver func(tx *sql.Tx) Operation +type DriverFunction func(tx *sql.Tx) *MigrationDriver + +var Driver DriverFunction func New(db *sql.DB) *Migration { return &Migration{db: db} @@ -148,14 +145,14 @@ func (m *Migration) up(target, current int64) error { return err } - op := Driver(tx) + mg := Driver(tx) // loop through and execute revisions for _, rev := range m.revs { if rev.Revision() > current && rev.Revision() <= target { current = rev.Revision() // execute the revision Upgrade. - if err := rev.Up(op); err != nil { + if err := rev.Up(mg); err != nil { log.Printf("Failed to upgrade to Revision Number %v\n", current) log.Println(err) return tx.Rollback() @@ -181,7 +178,7 @@ func (m *Migration) down(target, current int64) error { return err } - op := Driver(tx) + mg := Driver(tx) // reverse the list of revisions revs := []Revision{} @@ -195,7 +192,7 @@ func (m *Migration) down(target, current int64) error { if rev.Revision() > target { current = rev.Revision() // execute the revision Upgrade. - if err := rev.Down(op); err != nil { + if err := rev.Down(mg); err != nil { log.Printf("Failed to downgrade from Revision Number %v\n", current) log.Println(err) return tx.Rollback() diff --git a/pkg/database/migrate/mysql.go b/pkg/database/migrate/mysql.go new file mode 100644 index 000000000..151c063cf --- /dev/null +++ b/pkg/database/migrate/mysql.go @@ -0,0 +1,41 @@ +package migrate + +import ( + "database/sql" + "errors" +) + +type mysqlDriver struct { + Tx *sql.Tx +} + +func MySQL(tx *sql.Tx) *MigrationDriver { + return &MigrationDriver{ + Tx: tx, + Operation: &mysqlDriver{Tx: tx}, + } +} + +func (p *mysqlDriver) CreateTable(tableName string, args []string) (sql.Result, error) { + return nil, errors.New("not implemented yet") +} + +func (p *mysqlDriver) RenameTable(tableName, newName string) (sql.Result, error) { + return nil, errors.New("not implemented yet") +} + +func (p *mysqlDriver) DropTable(tableName string) (sql.Result, error) { + return nil, errors.New("not implemented yet") +} + +func (p *mysqlDriver) AddColumn(tableName, columnSpec string) (sql.Result, error) { + return nil, errors.New("not implemented yet") +} + +func (p *mysqlDriver) DropColumns(tableName string, columnsToDrop []string) (sql.Result, error) { + return nil, errors.New("not implemented yet") +} + +func (p *mysqlDriver) RenameColumns(tableName string, columnChanges map[string]string) (sql.Result, error) { + return nil, errors.New("not implemented yet") +} diff --git a/pkg/database/migrate/postgresql.go b/pkg/database/migrate/postgresql.go new file mode 100644 index 000000000..e3cff1ad9 --- /dev/null +++ b/pkg/database/migrate/postgresql.go @@ -0,0 +1,41 @@ +package migrate + +import ( + "database/sql" + "errors" +) + +type postgresqlDriver struct { + Tx *sql.Tx +} + +func PostgreSQL(tx *sql.Tx) *MigrationDriver { + return &MigrationDriver{ + Tx: tx, + Operation: &postgresqlDriver{Tx: tx}, + } +} + +func (p *postgresqlDriver) CreateTable(tableName string, args []string) (sql.Result, error) { + return nil, errors.New("not implemented yet") +} + +func (p *postgresqlDriver) RenameTable(tableName, newName string) (sql.Result, error) { + return nil, errors.New("not implemented yet") +} + +func (p *postgresqlDriver) DropTable(tableName string) (sql.Result, error) { + return nil, errors.New("not implemented yet") +} + +func (p *postgresqlDriver) AddColumn(tableName, columnSpec string) (sql.Result, error) { + return nil, errors.New("not implemented yet") +} + +func (p *postgresqlDriver) DropColumns(tableName string, columnsToDrop []string) (sql.Result, error) { + return nil, errors.New("not implemented yet") +} + +func (p *postgresqlDriver) RenameColumns(tableName string, columnChanges map[string]string) (sql.Result, error) { + return nil, errors.New("not implemented yet") +} diff --git a/pkg/database/migrate/sqlite.go b/pkg/database/migrate/sqlite.go index 2cec5a026..fe6ee2013 100644 --- a/pkg/database/migrate/sqlite.go +++ b/pkg/database/migrate/sqlite.go @@ -9,41 +9,34 @@ import ( _ "github.com/mattn/go-sqlite3" ) -type SQLiteDriver MigrationDriver - -func SQLite(tx *sql.Tx) Operation { - return &SQLiteDriver{Tx: tx} +type sqliteDriver struct { + Tx *sql.Tx } -func (s *SQLiteDriver) Exec(query string, args ...interface{}) (sql.Result, error) { - return s.Tx.Exec(query, args...) +func SQLite(tx *sql.Tx) *MigrationDriver { + return &MigrationDriver{ + Tx: tx, + Operation: &sqliteDriver{Tx: tx}, + } } -func (s *SQLiteDriver) Query(query string, args ...interface{}) (*sql.Rows, error) { - return s.Tx.Query(query, args...) -} - -func (s *SQLiteDriver) QueryRow(query string, args ...interface{}) *sql.Row { - return s.Tx.QueryRow(query, args...) -} - -func (s *SQLiteDriver) CreateTable(tableName string, args []string) (sql.Result, error) { +func (s *sqliteDriver) CreateTable(tableName string, args []string) (sql.Result, error) { return s.Tx.Exec(fmt.Sprintf("CREATE TABLE %s (%s);", tableName, strings.Join(args, ", "))) } -func (s *SQLiteDriver) RenameTable(tableName, newName string) (sql.Result, error) { +func (s *sqliteDriver) RenameTable(tableName, newName string) (sql.Result, error) { return s.Tx.Exec(fmt.Sprintf("ALTER TABLE %s RENAME TO %s;", tableName, newName)) } -func (s *SQLiteDriver) DropTable(tableName string) (sql.Result, error) { +func (s *sqliteDriver) DropTable(tableName string) (sql.Result, error) { return s.Tx.Exec(fmt.Sprintf("DROP TABLE IF EXISTS %s;", tableName)) } -func (s *SQLiteDriver) AddColumn(tableName, columnSpec string) (sql.Result, error) { +func (s *sqliteDriver) AddColumn(tableName, columnSpec string) (sql.Result, error) { return s.Tx.Exec(fmt.Sprintf("ALTER TABLE %s ADD COLUMN %s;", tableName, columnSpec)) } -func (s *SQLiteDriver) DropColumns(tableName string, columnsToDrop []string) (sql.Result, error) { +func (s *sqliteDriver) DropColumns(tableName string, columnsToDrop []string) (sql.Result, error) { var err error var result sql.Result @@ -144,7 +137,7 @@ func (s *SQLiteDriver) DropColumns(tableName string, columnsToDrop []string) (sq return result, err } -func (s *SQLiteDriver) RenameColumns(tableName string, columnChanges map[string]string) (sql.Result, error) { +func (s *sqliteDriver) RenameColumns(tableName string, columnChanges map[string]string) (sql.Result, error) { var err error var result sql.Result @@ -243,7 +236,7 @@ func (s *SQLiteDriver) RenameColumns(tableName string, columnChanges map[string] return result, err } -func (s *SQLiteDriver) getDDLFromTable(tableName string) (string, error) { +func (s *sqliteDriver) getDDLFromTable(tableName string) (string, error) { var sql string query := `SELECT sql FROM sqlite_master WHERE type='table' and name=?;` err := s.Tx.QueryRow(query, tableName).Scan(&sql) @@ -253,7 +246,7 @@ func (s *SQLiteDriver) getDDLFromTable(tableName string) (string, error) { return sql, nil } -func (s *SQLiteDriver) getDDLFromIndex(tableName string) ([]string, error) { +func (s *sqliteDriver) getDDLFromIndex(tableName string) ([]string, error) { var sqls []string query := `SELECT sql FROM sqlite_master WHERE type='index' and tbl_name=?;` diff --git a/pkg/database/migrate/sqlite_test.go b/pkg/database/migrate/sqlite_test.go index c26d5b9bf..17763efdb 100644 --- a/pkg/database/migrate/sqlite_test.go +++ b/pkg/database/migrate/sqlite_test.go @@ -33,8 +33,8 @@ type AddColumnSample struct { type revision1 struct{} -func (r *revision1) Up(op Operation) error { - _, err := op.CreateTable("samples", []string{ +func (r *revision1) Up(mg *MigrationDriver) error { + _, err := mg.CreateTable("samples", []string{ "id INTEGER PRIMARY KEY AUTOINCREMENT", "imel VARCHAR(255) UNIQUE", "name VARCHAR(255)", @@ -42,8 +42,8 @@ func (r *revision1) Up(op Operation) error { return err } -func (r *revision1) Down(op Operation) error { - _, err := op.DropTable("samples") +func (r *revision1) Down(mg *MigrationDriver) error { + _, err := mg.DropTable("samples") return err } @@ -57,13 +57,13 @@ func (r *revision1) Revision() int64 { type revision2 struct{} -func (r *revision2) Up(op Operation) error { - _, err := op.RenameTable("samples", "examples") +func (r *revision2) Up(mg *MigrationDriver) error { + _, err := mg.RenameTable("samples", "examples") return err } -func (r *revision2) Down(op Operation) error { - _, err := op.RenameTable("examples", "samples") +func (r *revision2) Down(mg *MigrationDriver) error { + _, err := mg.RenameTable("examples", "samples") return err } @@ -77,16 +77,16 @@ func (r *revision2) Revision() int64 { type revision3 struct{} -func (r *revision3) Up(op Operation) error { - if _, err := op.AddColumn("samples", "url VARCHAR(255)"); err != nil { +func (r *revision3) Up(mg *MigrationDriver) error { + if _, err := mg.AddColumn("samples", "url VARCHAR(255)"); err != nil { return err } - _, err := op.AddColumn("samples", "num INTEGER") + _, err := mg.AddColumn("samples", "num INTEGER") return err } -func (r *revision3) Down(op Operation) error { - _, err := op.DropColumns("samples", []string{"num", "url"}) +func (r *revision3) Down(mg *MigrationDriver) error { + _, err := mg.DropColumns("samples", []string{"num", "url"}) return err } @@ -100,15 +100,15 @@ func (r *revision3) Revision() int64 { type revision4 struct{} -func (r *revision4) Up(op Operation) error { - _, err := op.RenameColumns("samples", map[string]string{ +func (r *revision4) Up(mg *MigrationDriver) error { + _, err := mg.RenameColumns("samples", map[string]string{ "imel": "email", }) return err } -func (r *revision4) Down(op Operation) error { - _, err := op.RenameColumns("samples", map[string]string{ +func (r *revision4) Down(mg *MigrationDriver) error { + _, err := mg.RenameColumns("samples", map[string]string{ "email": "imel", }) return err @@ -124,13 +124,13 @@ func (r *revision4) Revision() int64 { type revision5 struct{} -func (r *revision5) Up(op Operation) error { - _, err := op.Exec(`CREATE INDEX samples_url_name_ix ON samples (url, name)`) +func (r *revision5) Up(mg *MigrationDriver) error { + _, err := mg.Tx.Exec(`CREATE INDEX samples_url_name_ix ON samples (url, name)`) return err } -func (r *revision5) Down(op Operation) error { - _, err := op.Exec(`DROP INDEX samples_url_name_ix`) +func (r *revision5) Down(mg *MigrationDriver) error { + _, err := mg.Tx.Exec(`DROP INDEX samples_url_name_ix`) return err } @@ -143,15 +143,15 @@ func (r *revision5) Revision() int64 { // ---------- revision 6 type revision6 struct{} -func (r *revision6) Up(op Operation) error { - _, err := op.RenameColumns("samples", map[string]string{ +func (r *revision6) Up(mg *MigrationDriver) error { + _, err := mg.RenameColumns("samples", map[string]string{ "url": "host", }) return err } -func (r *revision6) Down(op Operation) error { - _, err := op.RenameColumns("samples", map[string]string{ +func (r *revision6) Down(mg *MigrationDriver) error { + _, err := mg.RenameColumns("samples", map[string]string{ "host": "url", }) return err @@ -166,16 +166,16 @@ func (r *revision6) Revision() int64 { // ---------- revision 7 type revision7 struct{} -func (r *revision7) Up(op Operation) error { - _, err := op.DropColumns("samples", []string{"host", "num"}) +func (r *revision7) Up(mg *MigrationDriver) error { + _, err := mg.DropColumns("samples", []string{"host", "num"}) return err } -func (r *revision7) Down(op Operation) error { - if _, err := op.AddColumn("samples", "host VARCHAR(255)"); err != nil { +func (r *revision7) Down(mg *MigrationDriver) error { + if _, err := mg.AddColumn("samples", "host VARCHAR(255)"); err != nil { return err } - _, err := op.AddColumn("samples", "num INSTEGER") + _, err := mg.AddColumn("samples", "num INSTEGER") return err } @@ -188,16 +188,16 @@ func (r *revision7) Revision() int64 { // ---------- revision 8 type revision8 struct{} -func (r *revision8) Up(op Operation) error { - if _, err := op.AddColumn("samples", "repo_id INTEGER"); err != nil { +func (r *revision8) Up(mg *MigrationDriver) error { + if _, err := mg.AddColumn("samples", "repo_id INTEGER"); err != nil { return err } - _, err := op.AddColumn("samples", "repo VARCHAR(255)") + _, err := mg.AddColumn("samples", "repo VARCHAR(255)") return err } -func (r *revision8) Down(op Operation) error { - _, err := op.DropColumns("samples", []string{"repo", "repo_id"}) +func (r *revision8) Down(mg *MigrationDriver) error { + _, err := mg.DropColumns("samples", []string{"repo", "repo_id"}) return err } @@ -210,15 +210,15 @@ func (r *revision8) Revision() int64 { // ---------- revision 9 type revision9 struct{} -func (r *revision9) Up(op Operation) error { - _, err := op.RenameColumns("samples", map[string]string{ +func (r *revision9) Up(mg *MigrationDriver) error { + _, err := mg.RenameColumns("samples", map[string]string{ "repo": "repository", }) return err } -func (r *revision9) Down(op Operation) error { - _, err := op.RenameColumns("samples", map[string]string{ +func (r *revision9) Down(mg *MigrationDriver) error { + _, err := mg.RenameColumns("samples", map[string]string{ "repository": "repo", }) return err