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