<commit_before>// Copyright 2013 bee authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package main

import (
	"database/sql"
	"os"
	"os/exec"
	"path"
	"strconv"
	"strings"
	"time"
)

var cmdMigrate = &Command{
	UsageLine: "migrate [Command]",
	Short:     "run database migrations",
	Long: `
bee migrate
    run all outstanding migrations
    -driver: [mysql | postgresql | sqlite], the default is mysql
    -conn:   the connection string used by the driver, the default is root:@tcp(127.0.0.1:3306)/test

bee migrate rollback
    rollback the last migration operation
    -driver: [mysql | postgresql | sqlite], the default is mysql
    -conn:   the connection string used by the driver, the default is root:@tcp(127.0.0.1:3306)/test

bee migrate reset
    rollback all migrations
    -driver: [mysql | postgresql | sqlite], the default is mysql
    -conn:   the connection string used by the driver, the default is root:@tcp(127.0.0.1:3306)/test

bee migrate refresh
    rollback all migrations and run them all again
    -driver: [mysql | postgresql | sqlite], the default is mysql
    -conn:   the connection string used by the driver, the default is root:@tcp(127.0.0.1:3306)/test
`,
}

var mDriver docValue
var mConn docValue

func init() {
	cmdMigrate.Run = runMigration
	cmdMigrate.Flag.Var(&mDriver, "driver", "database driver: mysql, postgresql, etc.")
	cmdMigrate.Flag.Var(&mConn, "conn", "connection string used by the driver to connect to a database instance")
}

// runMigration is the entry point for starting a migration
func runMigration(cmd *Command, args []string) {
	crupath, _ := os.Getwd()

	gopath := os.Getenv("GOPATH")
	Debugf("gopath:%s", gopath)
	if gopath == "" {
		ColorLog("[ERRO] $GOPATH not found\n")
		ColorLog("[HINT] Set $GOPATH in your environment vairables\n")
		os.Exit(2)
	}
	// load config
	err := loadConfig()
	if err != nil {
		ColorLog("[ERRO] Fail to parse bee.json[ %s ]\n", err)
	}
	// getting command line arguments
	if len(args) != 0 {
		cmd.Flag.Parse(args[1:])
	}
	if mDriver == "" {
		mDriver = docValue(conf.Database.Driver)
		if mDriver == "" {
			mDriver = "mysql"
		}
	}
	if mConn == "" {
		mConn = docValue(conf.Database.Conn)
		if mConn == "" {
			mConn = "root:@tcp(127.0.0.1:3306)/test"
		}
	}
	ColorLog("[INFO] Using '%s' as 'driver'\n", mDriver)
	ColorLog("[INFO] Using '%s' as 'conn'\n", mConn)
	driverStr, connStr := string(mDriver), string(mConn)
	if len(args) == 0 {
		// run all outstanding migrations
		ColorLog("[INFO] Running all outstanding migrations\n")
		migrateUpdate(crupath, driverStr, connStr)
	} else {
		mcmd := args[0]
		switch mcmd {
		case "rollback":
			ColorLog("[INFO] Rolling back the last migration operation\n")
			migrateRollback(crupath, driverStr, connStr)
		case "reset":
			ColorLog("[INFO] Reseting all migrations\n")
			migrateReset(crupath, driverStr, connStr)
		case "refresh":
			ColorLog("[INFO] Refreshing all migrations\n")
			migrateReset(crupath, driverStr, connStr)
		default:
			ColorLog("[ERRO] Command is missing\n")
			os.Exit(2)
		}
	}
	ColorLog("[SUCC] Migration successful!\n")
}

// migrateUpdate does the schema update
func migrateUpdate(crupath, driver, connStr string) {
	migrate("upgrade", crupath, driver, connStr)
}

// migrateRollback rolls back the latest migration
func migrateRollback(crupath, driver, connStr string) {
	migrate("rollback", crupath, driver, connStr)
}

// migrateReset rolls back all migrations
func migrateReset(crupath, driver, connStr string) {
	migrate("reset", crupath, driver, connStr)
}

// migrationRefresh rolls back all migrations and start over again
func migrateRefresh(crupath, driver, connStr string) {
	migrate("refresh", crupath, driver, connStr)
}

// migrate generates source code, build it, and invoke the binary who does the actual migration
func migrate(goal, crupath, driver, connStr string) {
	dir := path.Join(crupath, "database", "migrations")
	binary := "m"
	source := binary + ".go"
	// connect to database
	db, err := sql.Open(driver, connStr)
	if err != nil {
		ColorLog("[ERRO] Could not connect to %s: %s\n", driver, connStr)
		os.Exit(2)
	}
	defer db.Close()
	checkForSchemaUpdateTable(db)
	latestName, latestTime := getLatestMigration(db)
	writeMigrationSourceFile(dir, source, driver, connStr, latestTime, latestName, goal)
	buildMigrationBinary(dir, binary)
	runMigrationBinary(dir, binary)
	removeTempFile(dir, source)
	removeTempFile(dir, binary)
}

// checkForSchemaUpdateTable checks the existence of migrations table.
// It checks for the proper table structures and creates the table using MYSQL_MIGRATION_DDL if it does not exist.
func checkForSchemaUpdateTable(db *sql.DB) {
	if rows, err := db.Query("SHOW TABLES LIKE 'migrations'"); err != nil {
		ColorLog("[ERRO] Could not show migrations table: %s\n", err)
		os.Exit(2)
	} else if !rows.Next() {
		// no migrations table, create anew
		ColorLog("[INFO] Creating 'migrations' table...\n")
		if _, err := db.Query(MYSQL_MIGRATION_DDL); err != nil {
			ColorLog("[ERRO] Could not create migrations table: %s\n", err)
			os.Exit(2)
		}
	}
	// checking that migrations table schema are expected
	if rows, err := db.Query("DESC migrations"); err != nil {
		ColorLog("[ERRO] Could not show columns of migrations table: %s\n", err)
		os.Exit(2)
	} else {
		for rows.Next() {
			var fieldBytes, typeBytes, nullBytes, keyBytes, defaultBytes, extraBytes []byte
			if err := rows.Scan(&fieldBytes, &typeBytes, &nullBytes, &keyBytes, &defaultBytes, &extraBytes); err != nil {
				ColorLog("[ERRO] Could not read column information: %s\n", err)
				os.Exit(2)
			}
			fieldStr, typeStr, nullStr, keyStr, defaultStr, extraStr :=
				string(fieldBytes), string(typeBytes), string(nullBytes), string(keyBytes), string(defaultBytes), string(extraBytes)
			if fieldStr == "id_migration" {
				if keyStr != "PRI" || extraStr != "auto_increment" {
					ColorLog("[ERRO] Column migration.id_migration type mismatch: KEY: %s, EXTRA: %s\n", keyStr, extraStr)
					ColorLog("[HINT] Expecting KEY: PRI, EXTRA: auto_increment\n")
					os.Exit(2)
				}
			} else if fieldStr == "name" {
				if !strings.HasPrefix(typeStr, "varchar") || nullStr != "YES" {
					ColorLog("[ERRO] Column migration.name type mismatch: TYPE: %s, NULL: %s\n", typeStr, nullStr)
					ColorLog("[HINT] Expecting TYPE: varchar, NULL: YES\n")
					os.Exit(2)
				}

			} else if fieldStr == "created_at" {
				if typeStr != "timestamp" || defaultStr != "CURRENT_TIMESTAMP" {
					ColorLog("[ERRO] Column migration.timestamp type mismatch: TYPE: %s, DEFAULT: %s\n", typeStr, defaultStr)
					ColorLog("[HINT] Expecting TYPE: timestamp, DEFAULT: CURRENT_TIMESTAMP\n")
					os.Exit(2)
				}
			}
		}
	}
}

// getLatestMigration retrives latest migration with status 'update'
func getLatestMigration(db *sql.DB) (file string, createdAt int64) {
	sql := "SELECT name, created_at FROM migrations where status = 'update' ORDER BY id_migration DESC LIMIT 1"
	if rows, err := db.Query(sql); err != nil {
		ColorLog("[ERRO] Could not retrieve migrations: %s\n", err)
		os.Exit(2)
	} else {
		var createdAtStr string
		if rows.Next() {
			if err := rows.Scan(&file, &createdAtStr); err != nil {
				ColorLog("[ERRO] Could not read migrations in database: %s\n", err)
				os.Exit(2)
			}
			if t, err := time.Parse("2006-01-02 15:04:05", createdAtStr); err != nil {
				ColorLog("[ERRO] Could not parse time: %s\n", err)
				os.Exit(2)
			} else {
				createdAt = t.Unix()
			}
		} else {
			file, createdAt = "", 0
		}
	}
	return
}

// writeMigrationSourceFile create the source file based on MIGRATION_MAIN_TPL
func writeMigrationSourceFile(dir, source, driver, connStr string, latestTime int64, latestName string, task string) {
	os.Chdir(dir)
	if f, err := os.OpenFile(source, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err != nil {
		ColorLog("[ERRO] Could not create file: %s\n", err)
		os.Exit(2)
	} else {
		content := strings.Replace(MIGRATION_MAIN_TPL, "{{DBDriver}}", driver, -1)
		content = strings.Replace(content, "{{ConnStr}}", connStr, -1)
		content = strings.Replace(content, "{{LatestTime}}", strconv.FormatInt(latestTime, 10), -1)
		content = strings.Replace(content, "{{LatestName}}", latestName, -1)
		content = strings.Replace(content, "{{Task}}", task, -1)
		if _, err := f.WriteString(content); err != nil {
			ColorLog("[ERRO] Could not write to file: %s\n", err)
			os.Exit(2)
		}
		f.Close()
	}
}

// buildMigrationBinary changes directory to database/migrations folder and go-build the source
func buildMigrationBinary(dir, binary string) {
	os.Chdir(dir)
	cmd := exec.Command("go", "build", "-o", binary)
	if out, err := cmd.CombinedOutput(); err != nil {
		ColorLog("[ERRO] Could not build migration binary: %s\n", err)
		formatShellErrOutput(string(out))
		os.Exit(2)
	}
}

// runMigrationBinary runs the migration program who does the actual work
func runMigrationBinary(dir, binary string) {
	os.Chdir(dir)
	cmd := exec.Command("./" + binary)
	if out, err := cmd.CombinedOutput(); err != nil {
		formatShellOutput(string(out))
		ColorLog("[ERRO] Could not run migration binary: %s\n", err)
		os.Exit(2)
	} else {
		formatShellOutput(string(out))
	}
}

// removeTempFile removes a file in dir
func removeTempFile(dir, file string) {
	os.Chdir(dir)
	if err := os.Remove(file); err != nil {
		ColorLog("[ERRO] Could not remove temporary migration files: %s\n", err)
		os.Exit(2)
	}
}

// formatShellErrOutput formats the error shell output
func formatShellErrOutput(o string) {
	for _, line := range strings.Split(o, "\n") {
		if line != "" {
			ColorLog("[ERRO] -| %s\n", line)
		}
	}
}

// formatShellOutput formats the normal shell output
func formatShellOutput(o string) {
	for _, line := range strings.Split(o, "\n") {
		if line != "" {
			ColorLog("[INFO] -| %s\n", line)
		}
	}
}

const (
	MIGRATION_MAIN_TPL = `package main

import(
	"os"
	"github.com/astaxie/beego/orm"
	"github.com/astaxie/beego/migration"

	_ "github.com/go-sql-driver/mysql"
)

func init(){
	orm.RegisterDataBase("default", "{{DBDriver}}","{{ConnStr}}")
}

func main(){
	task := "{{Task}}"
	switch task {
	case "upgrade":
		if err := migration.Upgrade({{LatestTime}}); err != nil {
			os.Exit(2)
		}
	case "rollback":
		if err := migration.Rollback("{{LatestName}}"); err != nil {
			os.Exit(2)
		}
	case "reset":
		if err := migration.Reset(); err != nil {
			os.Exit(2)
		}
	case "refresh":
		if err := migration.Refresh(); err != nil {
			os.Exit(2)
		}
	}
}

`
	MYSQL_MIGRATION_DDL = `
CREATE TABLE migrations (
	id_migration int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'surrogate key',
	name varchar(255) DEFAULT NULL COMMENT 'migration name, unique',
	created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'date migrated or rolled back',
	statements longtext COMMENT 'SQL statements for this migration',
	rollback_statements longtext COMMENT 'SQL statment for rolling back migration',
	status ENUM('update', 'rollback') COMMENT 'update indicates it is a normal migration while rollback means this migration is rolled back',
	PRIMARY KEY (id_migration),
	UNIQUE KEY (name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
`
)
<commit_msg>update template to be standard to gofmt<commit_after>// Copyright 2013 bee authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package main

import (
	"database/sql"
	"os"
	"os/exec"
	"path"
	"strconv"
	"strings"
	"time"
)

var cmdMigrate = &Command{
	UsageLine: "migrate [Command]",
	Short:     "run database migrations",
	Long: `
bee migrate
    run all outstanding migrations
    -driver: [mysql | postgresql | sqlite], the default is mysql
    -conn:   the connection string used by the driver, the default is root:@tcp(127.0.0.1:3306)/test

bee migrate rollback
    rollback the last migration operation
    -driver: [mysql | postgresql | sqlite], the default is mysql
    -conn:   the connection string used by the driver, the default is root:@tcp(127.0.0.1:3306)/test

bee migrate reset
    rollback all migrations
    -driver: [mysql | postgresql | sqlite], the default is mysql
    -conn:   the connection string used by the driver, the default is root:@tcp(127.0.0.1:3306)/test

bee migrate refresh
    rollback all migrations and run them all again
    -driver: [mysql | postgresql | sqlite], the default is mysql
    -conn:   the connection string used by the driver, the default is root:@tcp(127.0.0.1:3306)/test
`,
}

var mDriver docValue
var mConn docValue

func init() {
	cmdMigrate.Run = runMigration
	cmdMigrate.Flag.Var(&mDriver, "driver", "database driver: mysql, postgresql, etc.")
	cmdMigrate.Flag.Var(&mConn, "conn", "connection string used by the driver to connect to a database instance")
}

// runMigration is the entry point for starting a migration
func runMigration(cmd *Command, args []string) {
	crupath, _ := os.Getwd()

	gopath := os.Getenv("GOPATH")
	Debugf("gopath:%s", gopath)
	if gopath == "" {
		ColorLog("[ERRO] $GOPATH not found\n")
		ColorLog("[HINT] Set $GOPATH in your environment vairables\n")
		os.Exit(2)
	}
	// load config
	err := loadConfig()
	if err != nil {
		ColorLog("[ERRO] Fail to parse bee.json[ %s ]\n", err)
	}
	// getting command line arguments
	if len(args) != 0 {
		cmd.Flag.Parse(args[1:])
	}
	if mDriver == "" {
		mDriver = docValue(conf.Database.Driver)
		if mDriver == "" {
			mDriver = "mysql"
		}
	}
	if mConn == "" {
		mConn = docValue(conf.Database.Conn)
		if mConn == "" {
			mConn = "root:@tcp(127.0.0.1:3306)/test"
		}
	}
	ColorLog("[INFO] Using '%s' as 'driver'\n", mDriver)
	ColorLog("[INFO] Using '%s' as 'conn'\n", mConn)
	driverStr, connStr := string(mDriver), string(mConn)
	if len(args) == 0 {
		// run all outstanding migrations
		ColorLog("[INFO] Running all outstanding migrations\n")
		migrateUpdate(crupath, driverStr, connStr)
	} else {
		mcmd := args[0]
		switch mcmd {
		case "rollback":
			ColorLog("[INFO] Rolling back the last migration operation\n")
			migrateRollback(crupath, driverStr, connStr)
		case "reset":
			ColorLog("[INFO] Reseting all migrations\n")
			migrateReset(crupath, driverStr, connStr)
		case "refresh":
			ColorLog("[INFO] Refreshing all migrations\n")
			migrateReset(crupath, driverStr, connStr)
		default:
			ColorLog("[ERRO] Command is missing\n")
			os.Exit(2)
		}
	}
	ColorLog("[SUCC] Migration successful!\n")
}

// migrateUpdate does the schema update
func migrateUpdate(crupath, driver, connStr string) {
	migrate("upgrade", crupath, driver, connStr)
}

// migrateRollback rolls back the latest migration
func migrateRollback(crupath, driver, connStr string) {
	migrate("rollback", crupath, driver, connStr)
}

// migrateReset rolls back all migrations
func migrateReset(crupath, driver, connStr string) {
	migrate("reset", crupath, driver, connStr)
}

// migrationRefresh rolls back all migrations and start over again
func migrateRefresh(crupath, driver, connStr string) {
	migrate("refresh", crupath, driver, connStr)
}

// migrate generates source code, build it, and invoke the binary who does the actual migration
func migrate(goal, crupath, driver, connStr string) {
	dir := path.Join(crupath, "database", "migrations")
	binary := "m"
	source := binary + ".go"
	// connect to database
	db, err := sql.Open(driver, connStr)
	if err != nil {
		ColorLog("[ERRO] Could not connect to %s: %s\n", driver, connStr)
		os.Exit(2)
	}
	defer db.Close()
	checkForSchemaUpdateTable(db)
	latestName, latestTime := getLatestMigration(db)
	writeMigrationSourceFile(dir, source, driver, connStr, latestTime, latestName, goal)
	buildMigrationBinary(dir, binary)
	runMigrationBinary(dir, binary)
	removeTempFile(dir, source)
	removeTempFile(dir, binary)
}

// checkForSchemaUpdateTable checks the existence of migrations table.
// It checks for the proper table structures and creates the table using MYSQL_MIGRATION_DDL if it does not exist.
func checkForSchemaUpdateTable(db *sql.DB) {
	if rows, err := db.Query("SHOW TABLES LIKE 'migrations'"); err != nil {
		ColorLog("[ERRO] Could not show migrations table: %s\n", err)
		os.Exit(2)
	} else if !rows.Next() {
		// no migrations table, create anew
		ColorLog("[INFO] Creating 'migrations' table...\n")
		if _, err := db.Query(MYSQL_MIGRATION_DDL); err != nil {
			ColorLog("[ERRO] Could not create migrations table: %s\n", err)
			os.Exit(2)
		}
	}
	// checking that migrations table schema are expected
	if rows, err := db.Query("DESC migrations"); err != nil {
		ColorLog("[ERRO] Could not show columns of migrations table: %s\n", err)
		os.Exit(2)
	} else {
		for rows.Next() {
			var fieldBytes, typeBytes, nullBytes, keyBytes, defaultBytes, extraBytes []byte
			if err := rows.Scan(&fieldBytes, &typeBytes, &nullBytes, &keyBytes, &defaultBytes, &extraBytes); err != nil {
				ColorLog("[ERRO] Could not read column information: %s\n", err)
				os.Exit(2)
			}
			fieldStr, typeStr, nullStr, keyStr, defaultStr, extraStr :=
				string(fieldBytes), string(typeBytes), string(nullBytes), string(keyBytes), string(defaultBytes), string(extraBytes)
			if fieldStr == "id_migration" {
				if keyStr != "PRI" || extraStr != "auto_increment" {
					ColorLog("[ERRO] Column migration.id_migration type mismatch: KEY: %s, EXTRA: %s\n", keyStr, extraStr)
					ColorLog("[HINT] Expecting KEY: PRI, EXTRA: auto_increment\n")
					os.Exit(2)
				}
			} else if fieldStr == "name" {
				if !strings.HasPrefix(typeStr, "varchar") || nullStr != "YES" {
					ColorLog("[ERRO] Column migration.name type mismatch: TYPE: %s, NULL: %s\n", typeStr, nullStr)
					ColorLog("[HINT] Expecting TYPE: varchar, NULL: YES\n")
					os.Exit(2)
				}

			} else if fieldStr == "created_at" {
				if typeStr != "timestamp" || defaultStr != "CURRENT_TIMESTAMP" {
					ColorLog("[ERRO] Column migration.timestamp type mismatch: TYPE: %s, DEFAULT: %s\n", typeStr, defaultStr)
					ColorLog("[HINT] Expecting TYPE: timestamp, DEFAULT: CURRENT_TIMESTAMP\n")
					os.Exit(2)
				}
			}
		}
	}
}

// getLatestMigration retrives latest migration with status 'update'
func getLatestMigration(db *sql.DB) (file string, createdAt int64) {
	sql := "SELECT name, created_at FROM migrations where status = 'update' ORDER BY id_migration DESC LIMIT 1"
	if rows, err := db.Query(sql); err != nil {
		ColorLog("[ERRO] Could not retrieve migrations: %s\n", err)
		os.Exit(2)
	} else {
		var createdAtStr string
		if rows.Next() {
			if err := rows.Scan(&file, &createdAtStr); err != nil {
				ColorLog("[ERRO] Could not read migrations in database: %s\n", err)
				os.Exit(2)
			}
			if t, err := time.Parse("2006-01-02 15:04:05", createdAtStr); err != nil {
				ColorLog("[ERRO] Could not parse time: %s\n", err)
				os.Exit(2)
			} else {
				createdAt = t.Unix()
			}
		} else {
			file, createdAt = "", 0
		}
	}
	return
}

// writeMigrationSourceFile create the source file based on MIGRATION_MAIN_TPL
func writeMigrationSourceFile(dir, source, driver, connStr string, latestTime int64, latestName string, task string) {
	os.Chdir(dir)
	if f, err := os.OpenFile(source, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err != nil {
		ColorLog("[ERRO] Could not create file: %s\n", err)
		os.Exit(2)
	} else {
		content := strings.Replace(MIGRATION_MAIN_TPL, "{{DBDriver}}", driver, -1)
		content = strings.Replace(content, "{{ConnStr}}", connStr, -1)
		content = strings.Replace(content, "{{LatestTime}}", strconv.FormatInt(latestTime, 10), -1)
		content = strings.Replace(content, "{{LatestName}}", latestName, -1)
		content = strings.Replace(content, "{{Task}}", task, -1)
		if _, err := f.WriteString(content); err != nil {
			ColorLog("[ERRO] Could not write to file: %s\n", err)
			os.Exit(2)
		}
		f.Close()
	}
}

// buildMigrationBinary changes directory to database/migrations folder and go-build the source
func buildMigrationBinary(dir, binary string) {
	os.Chdir(dir)
	cmd := exec.Command("go", "build", "-o", binary)
	if out, err := cmd.CombinedOutput(); err != nil {
		ColorLog("[ERRO] Could not build migration binary: %s\n", err)
		formatShellErrOutput(string(out))
		os.Exit(2)
	}
}

// runMigrationBinary runs the migration program who does the actual work
func runMigrationBinary(dir, binary string) {
	os.Chdir(dir)
	cmd := exec.Command("./" + binary)
	if out, err := cmd.CombinedOutput(); err != nil {
		formatShellOutput(string(out))
		ColorLog("[ERRO] Could not run migration binary: %s\n", err)
		os.Exit(2)
	} else {
		formatShellOutput(string(out))
	}
}

// removeTempFile removes a file in dir
func removeTempFile(dir, file string) {
	os.Chdir(dir)
	if err := os.Remove(file); err != nil {
		ColorLog("[ERRO] Could not remove temporary migration files: %s\n", err)
		os.Exit(2)
	}
}

// formatShellErrOutput formats the error shell output
func formatShellErrOutput(o string) {
	for _, line := range strings.Split(o, "\n") {
		if line != "" {
			ColorLog("[ERRO] -| %s\n", line)
		}
	}
}

// formatShellOutput formats the normal shell output
func formatShellOutput(o string) {
	for _, line := range strings.Split(o, "\n") {
		if line != "" {
			ColorLog("[INFO] -| %s\n", line)
		}
	}
}

const (
	MIGRATION_MAIN_TPL = `package main

import(
	"os"

	"github.com/astaxie/beego/orm"
	"github.com/astaxie/beego/migration"

	_ "github.com/go-sql-driver/mysql"
)

func init(){
	orm.RegisterDataBase("default", "{{DBDriver}}","{{ConnStr}}")
}

func main(){
	task := "{{Task}}"
	switch task {
	case "upgrade":
		if err := migration.Upgrade({{LatestTime}}); err != nil {
			os.Exit(2)
		}
	case "rollback":
		if err := migration.Rollback("{{LatestName}}"); err != nil {
			os.Exit(2)
		}
	case "reset":
		if err := migration.Reset(); err != nil {
			os.Exit(2)
		}
	case "refresh":
		if err := migration.Refresh(); err != nil {
			os.Exit(2)
		}
	}
}

`
	MYSQL_MIGRATION_DDL = `
CREATE TABLE migrations (
	id_migration int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'surrogate key',
	name varchar(255) DEFAULT NULL COMMENT 'migration name, unique',
	created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'date migrated or rolled back',
	statements longtext COMMENT 'SQL statements for this migration',
	rollback_statements longtext COMMENT 'SQL statment for rolling back migration',
	status ENUM('update', 'rollback') COMMENT 'update indicates it is a normal migration while rollback means this migration is rolled back',
	PRIMARY KEY (id_migration),
	UNIQUE KEY (name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
`
)
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"github.com/4180122/distbayes/distmlMatlab"
	"github.com/arcaneiceman/GoVector/govec"
	//"github.com/gonum/matrix/mat64"
	//"io/ioutil"
	"net"
	"os"
	//"strconv"
	//"strings"
	"time"
)

const BUFFSIZE = 200000

//10485760

var (
	cnum      int = 0
	name      string
	inputargs []string
	myaddr    *net.TCPAddr
	svaddr    *net.TCPAddr
	model     distmlMatlab.MatModel
	logger    *govec.GoLog
	X         string
	Y         string
	Xt        string
	Yt        string
	l         *net.TCPListener
	gmodel    distmlMatlab.MatGlobalModel
	gempty    distmlMatlab.MatGlobalModel
	committed bool
)

type message struct {
	Id     int
	IpMe   string
	NameMe string
	Type   string
	Model  distmlMatlab.MatModel
	GModel distmlMatlab.MatGlobalModel
}

func main() {
	//Parsing inputargs
	parseArgs()

	//Hacky solution to the Matlab problem (Mathworks, please fix this!)
	// see: https://www.mathworks.com/matlabcentral/answers/305877-what-is-the-primary-message-table-for-module-77
	// and  https://github.com/JuliaInterop/MATLAB.jl/issues/47
	distmlMatlab.Hack()

	//Initialize stuff
	model = distmlMatlab.NewModel(X, Y)

	//Initialize TCP Connection and listener
	l, _ = net.ListenTCP("tcp", myaddr)
	fmt.Printf("Node initialized as %v.\n", name)
	go listener()
	requestJoin()

	committed = false

	//Main function of this server
	for {
		//parseUserInput()
		time.Sleep(time.Duration(5 * time.Second))
		if !committed {
			requestCommit()
		}
	}
}

func listener() {
	for {
		conn, err := l.AcceptTCP()
		checkError(err)
		go connHandler(conn)
	}
}

func connHandler(conn *net.TCPConn) {
	p := make([]byte, BUFFSIZE)
	conn.Read(p)
	var msg message
	logger.UnpackReceive("Received message", p, &msg)
	switch msg.Type {
	case "test_request":
		// server is asking me to test
		conn.Write([]byte("OK"))
		go testModel(msg.Id, msg.Model)
	case "global_grant":
		// server is sending global model
		conn.Write([]byte("OK"))
		gmodel = msg.GModel
		fmt.Printf("\n <-- Pulled global model from server.\nEnter command: ")
		//go testGlobal(msg.GModel)
	default:
		// respond to ping
		conn.Write([]byte("Unknown command"))
	}
	conn.Close()
}

func parseUserInput() {
	var ident string
	reader := bufio.NewReader(os.Stdin)
	fmt.Print("Enter command: ")
	text, _ := reader.ReadString('\n')
	//Windows adds its own strange carriage return, the following lines fix it
	if text[len(text)-2] == '\r' {
		ident = text[0 : len(text)-2]
	} else {
		ident = text[0 : len(text)-1]
	}
	switch ident {
	case "read":
		//x = readData(inputargs[3])
		//y = readData(inputargs[4])
		fmt.Printf(" --- Local data updated.\n")
	case "train":
		model = distmlMatlab.NewModel(X, Y) //GOOD
		fmt.Printf(" --- Local model error on local data is: %v.\n", model.Weight)
	case "push":
		requestCommit()
	case "pull":
		requestGlobal()
	case "valid":
		acc, _ := distmlMatlab.GetErrorGlobal(X, Y, gmodel)
		fmt.Printf(" --- Global model error on local data is: %v.\n", acc)
	case "test":
		acc := distmlMatlab.GetError(Xt, Yt, model)
		fmt.Printf(" --- Local model error on test data is: %v.\n", acc)
	case "testg":
		acc, _ := distmlMatlab.GetErrorGlobal(Xt, Yt, gmodel)
		fmt.Printf(" --- Global model error on test data is: %v.\n", acc)
	case "who":
		fmt.Printf("%v\n", name)
	default:
		fmt.Printf(" Command not recognized: %v.\n\n", ident)
		fmt.Printf("  Choose from the following commands\n")
		fmt.Printf("  read  -- Read data from disk\n")
		fmt.Printf("  push  -- Push trained model to server\n")
		fmt.Printf("  pull  -- Obtain global model from server\n")
		fmt.Printf("  train -- Train model from data (reports error)\n")
		fmt.Printf("  valid -- Validate global model with local data\n")
		fmt.Printf("  test  -- Test local model with test data\n")
		fmt.Printf("  testg -- Test global model with test data\n")
		fmt.Printf("  who   -- Print node name\n\n")
	}
}

func requestJoin() {
	msg := message{cnum, myaddr.String(), name, "join_request", model, gempty}
	fmt.Printf(" --> Asking server to join.")
	tcpSend(msg)
}

func requestCommit() {
	cnum++
	msg := message{cnum, myaddr.String(), name, "commit_request", model, gempty}
	fmt.Printf(" --> Pushing local model to server.")
	tcpSend(msg)
}

func requestGlobal() {
	msg := message{cnum, myaddr.String(), name, "global_request", model, gempty}
	fmt.Printf(" --> Requesting global model from server.")
	tcpSend(msg)
}

func testModel(id int, testmodel distmlMatlab.MatModel) {
	//func testModel(id int, testmodel bclass.Model) {
	fmt.Printf("\n <-- Received test requset.\nEnter command: ")
	distmlMatlab.TestModel(X, Y, &testmodel)
	msg := message{id, myaddr.String(), name, "test_complete", testmodel, gempty}
	fmt.Printf("\n --> Sending completed test requset.")
	tcpSend(msg)
	fmt.Printf("Enter command: ")
}

func tcpSend(msg message) {
	p := make([]byte, BUFFSIZE)
	conn, err := net.DialTCP("tcp", nil, svaddr)
	checkError(err)
	outbuf := logger.PrepareSend(msg.Type, msg)
	_, err = conn.Write(outbuf)
	checkError(err)
	n, _ := conn.Read(p)
	if string(p[:n]) == "OK" {
		fmt.Printf(" [OK]\n")
		if msg.Type == "commit_request" {
			committed = true
		}
	} else if string(p[:n]) == "OOPS!" {
		fmt.Println(msg.NameMe, msg.IpMe, msg.Type)
	} else {
		fmt.Printf(" [NO!]\n *** Request was denied by server: %v.\nEnter command: ", string(p[:n]))
	}
}

func parseArgs() {
	flag.Parse()
	inputargs = flag.Args()
	var err error
	if len(inputargs) < 2 {
		fmt.Printf("Not enough inputs.\n")
		return
	}
	name = inputargs[0]
	myaddr, err = net.ResolveTCPAddr("tcp", inputargs[1])
	checkError(err)
	svaddr, err = net.ResolveTCPAddr("tcp", inputargs[2])
	checkError(err)
	X = inputargs[3]
	Y = inputargs[4]
	Xt = "C:/work/src/github.com/4180122/distbayes/testdata/xv.txt"
	Yt = "C:/work/src/github.com/4180122/distbayes/testdata/yv.txt"
	logger = govec.Initialize(inputargs[0], inputargs[5])
}

func checkError(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
		os.Exit(1)
	}
}
<commit_msg>client problems<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"github.com/4180122/distbayes/distmlMatlab"
	"github.com/arcaneiceman/GoVector/govec"
	//"github.com/gonum/matrix/mat64"
	//"io/ioutil"
	"net"
	"os"
	//"strconv"
	//"strings"
	"time"
)

const BUFFSIZE = 200000

//10485760

var (
	cnum      int = 0
	name      string
	inputargs []string
	myaddr    *net.TCPAddr
	svaddr    *net.TCPAddr
	model     distmlMatlab.MatModel
	logger    *govec.GoLog
	X         string
	Y         string
	Xt        string
	Yt        string
	l         *net.TCPListener
	gmodel    distmlMatlab.MatGlobalModel
	gempty    distmlMatlab.MatGlobalModel
	committed bool
)

type message struct {
	Id     int
	IpMe   string
	NameMe string
	Type   string
	Model  distmlMatlab.MatModel
	GModel distmlMatlab.MatGlobalModel
}

func main() {
	//Parsing inputargs
	parseArgs()

	//Hacky solution to the Matlab problem (Mathworks, please fix this!)
	// see: https://www.mathworks.com/matlabcentral/answers/305877-what-is-the-primary-message-table-for-module-77
	// and  https://github.com/JuliaInterop/MATLAB.jl/issues/47
	distmlMatlab.Hack()

	//Initialize stuff
	model = distmlMatlab.NewModel(X, Y)

	//Initialize TCP Connection and listener
	l, _ = net.ListenTCP("tcp", myaddr)
	fmt.Printf("Node initialized as %v.\n", name)
	go listener()
	requestJoin()

	committed = false

	//Main function of this server
	for {
		//parseUserInput()
		time.Sleep(time.Duration(2 * time.Second))
		if !committed {
			requestCommit()
		}
	}
}

func listener() {
	for {
		conn, err := l.AcceptTCP()
		checkError(err)
		go connHandler(conn)
	}
}

func connHandler(conn *net.TCPConn) {
	p := make([]byte, BUFFSIZE)
	conn.Read(p)
	var msg message
	logger.UnpackReceive("Received message", p, &msg)
	switch msg.Type {
	case "test_request":
		// server is asking me to test
		conn.Write([]byte("OK"))
		go testModel(msg.Id, msg.Model)
	case "global_grant":
		// server is sending global model
		conn.Write([]byte("OK"))
		gmodel = msg.GModel
		fmt.Printf("\n <-- Pulled global model from server.\nEnter command: ")
		//go testGlobal(msg.GModel)
	default:
		// respond to ping
		conn.Write([]byte("Unknown command"))
	}
	conn.Close()
}

func parseUserInput() {
	var ident string
	reader := bufio.NewReader(os.Stdin)
	fmt.Print("Enter command: ")
	text, _ := reader.ReadString('\n')
	//Windows adds its own strange carriage return, the following lines fix it
	if text[len(text)-2] == '\r' {
		ident = text[0 : len(text)-2]
	} else {
		ident = text[0 : len(text)-1]
	}
	switch ident {
	case "read":
		//x = readData(inputargs[3])
		//y = readData(inputargs[4])
		fmt.Printf(" --- Local data updated.\n")
	case "train":
		model = distmlMatlab.NewModel(X, Y) //GOOD
		fmt.Printf(" --- Local model error on local data is: %v.\n", model.Weight)
	case "push":
		requestCommit()
	case "pull":
		requestGlobal()
	case "valid":
		acc, _ := distmlMatlab.GetErrorGlobal(X, Y, gmodel)
		fmt.Printf(" --- Global model error on local data is: %v.\n", acc)
	case "test":
		acc := distmlMatlab.GetError(Xt, Yt, model)
		fmt.Printf(" --- Local model error on test data is: %v.\n", acc)
	case "testg":
		acc, _ := distmlMatlab.GetErrorGlobal(Xt, Yt, gmodel)
		fmt.Printf(" --- Global model error on test data is: %v.\n", acc)
	case "who":
		fmt.Printf("%v\n", name)
	default:
		fmt.Printf(" Command not recognized: %v.\n\n", ident)
		fmt.Printf("  Choose from the following commands\n")
		fmt.Printf("  read  -- Read data from disk\n")
		fmt.Printf("  push  -- Push trained model to server\n")
		fmt.Printf("  pull  -- Obtain global model from server\n")
		fmt.Printf("  train -- Train model from data (reports error)\n")
		fmt.Printf("  valid -- Validate global model with local data\n")
		fmt.Printf("  test  -- Test local model with test data\n")
		fmt.Printf("  testg -- Test global model with test data\n")
		fmt.Printf("  who   -- Print node name\n\n")
	}
}

func requestJoin() {
	msg := message{cnum, myaddr.String(), name, "join_request", model, gempty}
	fmt.Printf(" --> Asking server to join.")
	tcpSend(msg)
}

func requestCommit() {
	cnum++
	msg := message{cnum, myaddr.String(), name, "commit_request", model, gempty}
	fmt.Printf(" --> Pushing local model to server.")
	tcpSend(msg)
}

func requestGlobal() {
	msg := message{cnum, myaddr.String(), name, "global_request", model, gempty}
	fmt.Printf(" --> Requesting global model from server.")
	tcpSend(msg)
}

func testModel(id int, testmodel distmlMatlab.MatModel) {
	//func testModel(id int, testmodel bclass.Model) {
	fmt.Printf("\n <-- Received test requset.\nEnter command: ")
	distmlMatlab.TestModel(X, Y, &testmodel)
	msg := message{id, myaddr.String(), name, "test_complete", testmodel, gempty}
	fmt.Printf("\n --> Sending completed test requset.")
	tcpSend(msg)
	fmt.Printf("Enter command: ")
}

func tcpSend(msg message) {
	p := make([]byte, BUFFSIZE)
	conn, err := net.DialTCP("tcp", nil, svaddr)
	checkError(err)
	outbuf := logger.PrepareSend(msg.Type, msg)
	_, err = conn.Write(outbuf)
	checkError(err)
	n, _ := conn.Read(p)
	if string(p[:n]) == "OK" {
		fmt.Printf(" [OK]\n")
		if msg.Type == "commit_request" {
			committed = true
		}
	} else if string(p[:n]) == "OOPS!" {
		fmt.Println(p[:n])
		fmt.Println(msg.NameMe, msg.IpMe, msg.Type)
		var msgwhat message
		logger.UnpackReceive("Received message", p, &msgwhat)
		fmt.Println(msgwhat.NameMe, msgwhat.IpMe, msgwhat.Type)
	} else {
		fmt.Printf(" [NO!]\n *** Request was denied by server: %v.\nEnter command: ", string(p[:n]))
	}
}

func parseArgs() {
	flag.Parse()
	inputargs = flag.Args()
	var err error
	if len(inputargs) < 2 {
		fmt.Printf("Not enough inputs.\n")
		return
	}
	name = inputargs[0]
	myaddr, err = net.ResolveTCPAddr("tcp", inputargs[1])
	checkError(err)
	svaddr, err = net.ResolveTCPAddr("tcp", inputargs[2])
	checkError(err)
	X = inputargs[3]
	Y = inputargs[4]
	Xt = "C:/work/src/github.com/4180122/distbayes/testdata/xv.txt"
	Yt = "C:/work/src/github.com/4180122/distbayes/testdata/yv.txt"
	logger = govec.Initialize(inputargs[0], inputargs[5])
}

func checkError(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package vm

import (
	"fmt"
	"regexp/syntax"
)

// checker holds data for a semantic checker
type checker struct {
	errors ErrorList

	// symtab contains the current scope search path
	symtab SymbolTable
}

// Check performs a semantic check of the ast node, and returns a boolean
// indicating OK; if ok is not true, then error is a list of errors found.
func Check(node node) error {
	c := &checker{}
	Walk(c, node)
	if len(c.errors) > 0 {
		return c.errors
	}
	return nil
}

func (c *checker) VisitBefore(node node) Visitor {
	switch n := node.(type) {

	case *stmtlistNode:
		c.symtab.EnterScope(nil)
		n.s = c.symtab.CurrentScope()

	case *caprefNode:
		if sym, ok := c.symtab.Lookup(n.name, CaprefSymbol); ok {
			n.sym = sym
		} else {
			c.errors.Add(n.Pos(), fmt.Sprintf("Capture group `$%s' was not defined by a regular expression in this or outer scopes.\n\tTry using `(?P<%s>...)' to name the capture group.", n.name, n.name))
			return nil
		}

	case *declNode:
		if sym, ok := c.symtab.Lookup(n.name, IDSymbol); ok {
			c.errors.Add(n.Pos(), fmt.Sprintf("Declaration of `%s' shadows the previous at %s", n.name, sym.loc))
			return nil
		}
		n.sym = c.symtab.Add(n.name, IDSymbol, &n.pos)

	case *defNode:
		n.sym = c.symtab.Add(n.name, DefSymbol, &n.pos)
		(*n.sym).binding = n

	case *decoNode:
		if sym, ok := c.symtab.Lookup(n.name, DefSymbol); ok {
			if sym.binding == nil {
				c.errors.Add(n.Pos(), fmt.Sprintf("Internal error: Decorator %q not bound to its definition.", n.name))
				return nil
			}
			n.def = sym.binding.(*defNode)
		} else {
			c.errors.Add(n.Pos(), fmt.Sprintf("Decorator `%s' not defined.\n\tTry adding a definition `def %s {}' earlier in the program.", n.name, n.name))
			return nil
		}

	case *idNode:
		if sym, ok := c.symtab.Lookup(n.name, IDSymbol); ok {
			n.sym = sym
		} else {
			c.errors.Add(n.Pos(), fmt.Sprintf("Identifier `%s' not declared.\n\tTry adding `counter %s' to the top of the program.", n.name, n.name))
			return nil
		}

	case *regexNode:
		if re, err := syntax.Parse(n.pattern, syntax.Perl); err != nil {
			c.errors.Add(n.Pos(), fmt.Sprintf(err.Error()))
			return nil
		} else {
			n.re_ast = re
			// We can reserve storage for these capturing groups, storing them in
			// the current scope, so that future CAPTUREGROUPs can retrieve their
			// value.  At parse time, we can warn about nonexistent names.
			for i := 1; i <= re.MaxCap(); i++ {
				sym := c.symtab.Add(fmt.Sprintf("%d", i),
					CaprefSymbol, n.Pos())
				sym.binding = n
				sym.addr = i - 1
			}
			for i, capref := range re.CapNames() {
				if capref != "" {
					sym := c.symtab.Add(capref, CaprefSymbol, n.Pos())
					sym.binding = n
					sym.addr = i
				}
			}
		}
	}
	return c
}

func (c *checker) VisitAfter(node node) {
	switch n := node.(type) {
	case *stmtlistNode:
		c.symtab.ExitScope()

	case *binaryExprNode:
		var rType Type
		Tl := n.lhs.Type()
		Tr := n.rhs.Type()
		switch n.op {
		//case DIV, MOD, MUL, MINUS, PLUS, POW:
		// Numeric
		// O ⊢ e1 : Tl, O ⊢ e2 : Tr
		// Tl <= Tr , Tr <= Tl
		// ⇒ O ⊢ e : lub(Tl, Tr)
		// case SHL, SHR, AND, OR, XOR, NOT:
		// 	//  integer
		// O ⊢ e1 :Int, O ⊢ e2 : Int
		// ⇒ O ⊢ e : Int
		// case LT, GT, LE, GE, EQ, NE:
		// 	// comparable
		// O ⊢ e1 : Tl, O ⊢ e2 : Tr
		// Tl <= Tr , Tr <= Tl
		// ⇒ O ⊢ e : lub(Tl, Tr)
		// case ASSIGN:
		// O ⊢ e1 : Tl, O ⊢ e2 : Tr
		// Tl <= Tr
		// ⇒ O ⊢ e : Tl
		default:
			if Tl != Tr {
				c.errors.Add(n.Pos(), fmt.Sprintf("Type mismatch between lhs (%s) and rhs (%s) for op %s", Tl, Tr, n.op))
			}
			rType = Tl
		}
		n.typ = rType

	case *unaryExprNode:
		n.typ = n.expr.Type()
	}
}
<commit_msg>Errors if a decorator is redefined.<commit_after>// Copyright 2016 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package vm

import (
	"fmt"
	"regexp/syntax"
)

// checker holds data for a semantic checker
type checker struct {
	errors ErrorList

	// symtab contains the current scope search path
	symtab SymbolTable
}

// Check performs a semantic check of the ast node, and returns a boolean
// indicating OK; if ok is not true, then error is a list of errors found.
func Check(node node) error {
	c := &checker{}
	Walk(c, node)
	if len(c.errors) > 0 {
		return c.errors
	}
	return nil
}

func (c *checker) VisitBefore(node node) Visitor {
	switch n := node.(type) {

	case *stmtlistNode:
		c.symtab.EnterScope(nil)
		n.s = c.symtab.CurrentScope()

	case *caprefNode:
		if sym, ok := c.symtab.Lookup(n.name, CaprefSymbol); ok {
			n.sym = sym
		} else {
			c.errors.Add(n.Pos(), fmt.Sprintf("Capture group `$%s' was not defined by a regular expression in this or outer scopes.\n\tTry using `(?P<%s>...)' to name the capture group.", n.name, n.name))
			return nil
		}

	case *declNode:
		if sym, ok := c.symtab.Lookup(n.name, IDSymbol); ok {
			c.errors.Add(n.Pos(), fmt.Sprintf("Declaration of `%s' shadows the previous at %s", n.name, sym.loc))
			return nil
		}
		n.sym = c.symtab.Add(n.name, IDSymbol, &n.pos)

	case *defNode:
		if sym, ok := c.symtab.Lookup(n.name, DefSymbol); ok {
			c.errors.Add(n.Pos(), fmt.Sprintf("Definition of decorator `%s' shadows the previous at %s", n.name, sym.loc))
			return nil
		}
		n.sym = c.symtab.Add(n.name, DefSymbol, &n.pos)
		(*n.sym).binding = n

	case *decoNode:
		if sym, ok := c.symtab.Lookup(n.name, DefSymbol); ok {
			if sym.binding == nil {
				c.errors.Add(n.Pos(), fmt.Sprintf("Internal error: Decorator %q not bound to its definition.", n.name))
				return nil
			}
			n.def = sym.binding.(*defNode)
		} else {
			c.errors.Add(n.Pos(), fmt.Sprintf("Decorator `%s' not defined.\n\tTry adding a definition `def %s {}' earlier in the program.", n.name, n.name))
			return nil
		}

	case *idNode:
		if sym, ok := c.symtab.Lookup(n.name, IDSymbol); ok {
			n.sym = sym
		} else {
			c.errors.Add(n.Pos(), fmt.Sprintf("Identifier `%s' not declared.\n\tTry adding `counter %s' to the top of the program.", n.name, n.name))
			return nil
		}

	case *regexNode:
		if re, err := syntax.Parse(n.pattern, syntax.Perl); err != nil {
			c.errors.Add(n.Pos(), fmt.Sprintf(err.Error()))
			return nil
		} else {
			n.re_ast = re
			// We can reserve storage for these capturing groups, storing them in
			// the current scope, so that future CAPTUREGROUPs can retrieve their
			// value.  At parse time, we can warn about nonexistent names.
			for i := 1; i <= re.MaxCap(); i++ {
				sym := c.symtab.Add(fmt.Sprintf("%d", i),
					CaprefSymbol, n.Pos())
				sym.binding = n
				sym.addr = i - 1
			}
			for i, capref := range re.CapNames() {
				if capref != "" {
					sym := c.symtab.Add(capref, CaprefSymbol, n.Pos())
					sym.binding = n
					sym.addr = i
				}
			}
		}
	}
	return c
}

func (c *checker) VisitAfter(node node) {
	switch n := node.(type) {
	case *stmtlistNode:
		c.symtab.ExitScope()

	case *binaryExprNode:
		var rType Type
		Tl := n.lhs.Type()
		Tr := n.rhs.Type()
		switch n.op {
		//case DIV, MOD, MUL, MINUS, PLUS, POW:
		// Numeric
		// O ⊢ e1 : Tl, O ⊢ e2 : Tr
		// Tl <= Tr , Tr <= Tl
		// ⇒ O ⊢ e : lub(Tl, Tr)
		// case SHL, SHR, AND, OR, XOR, NOT:
		// 	//  integer
		// O ⊢ e1 :Int, O ⊢ e2 : Int
		// ⇒ O ⊢ e : Int
		// case LT, GT, LE, GE, EQ, NE:
		// 	// comparable
		// O ⊢ e1 : Tl, O ⊢ e2 : Tr
		// Tl <= Tr , Tr <= Tl
		// ⇒ O ⊢ e : lub(Tl, Tr)
		// case ASSIGN:
		// O ⊢ e1 : Tl, O ⊢ e2 : Tr
		// Tl <= Tr
		// ⇒ O ⊢ e : Tl
		default:
			if Tl != Tr {
				c.errors.Add(n.Pos(), fmt.Sprintf("Type mismatch between lhs (%s) and rhs (%s) for op %s", Tl, Tr, n.op))
			}
			rType = Tl
		}
		n.typ = rType

	case *unaryExprNode:
		n.typ = n.expr.Type()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"
	"time"

	"github.com/coocood/qbs"

	"example.com/api/cms"
	"podipo.com/skellago/be"
)

var logger = log.New(os.Stdout, "[example-demo] ", 0)

func main() {
	err := be.InitDB()
	if err != nil {
		logger.Fatal("Could not init the db", err)
		return
	}

	db, err := qbs.GetQbs()
	if err != nil {
		logger.Fatal("Could not get the db", err)
		return
	}
	defer db.Close()

	err = cms.DeleteAllTags(db)
	if err != nil {
		logger.Fatal("Could not delete tags", err)
		return
	}
	err = cms.DeleteAllEntries(db)
	if err != nil {
		logger.Fatal("Could not delete entries", err)
		return
	}
	err = cms.DeleteAllLogs(db)
	if err != nil {
		logger.Fatal("Could not delete logs", err)
		return
	}

	log, err := cms.CreateLog("Blargh", "blargh", db)
	if err != nil {
		logger.Fatal("Could not create a log", err)
		return
	}
	log.Publish = true
	err = cms.UpdateLog(log, db)
	if err != nil {
		logger.Fatal("Could not publish the log", err)
		return
	}

	entry1, err := cms.CreateEntry(log, "First post", "first", "This is the first post.", db)
	if err != nil {
		logger.Fatal("Could not create an entry", err)
		return
	}
	entry1.Publish = true
	entry1.Issued = time.Now()
	err = cms.UpdateEntry(entry1, db)
	if err != nil {
		logger.Fatal("Could not update the entry", err)
		return
	}

	entry2, err := cms.CreateEntry(log, "Second post", "second", "This is the second post.", db)
	if err != nil {
		logger.Fatal("Could not create an entry", err)
		return
	}
	entry2.Publish = true
	entry2.Issued = time.Now()
	err = cms.UpdateEntry(entry2, db)
	if err != nil {
		logger.Fatal("Could not update the entry", err)
		return
	}
}
<commit_msg>Tweak the demo log.<commit_after>package main

import (
	"log"
	"os"
	"time"

	"github.com/coocood/qbs"

	"example.com/api/cms"
	"podipo.com/skellago/be"
)

var logger = log.New(os.Stdout, "[example-demo] ", 0)

func main() {
	err := be.InitDB()
	if err != nil {
		logger.Fatal("Could not init the db", err)
		return
	}

	db, err := qbs.GetQbs()
	if err != nil {
		logger.Fatal("Could not get the db", err)
		return
	}
	defer db.Close()

	err = cms.DeleteAllTags(db)
	if err != nil {
		logger.Fatal("Could not delete tags", err)
		return
	}
	err = cms.DeleteAllEntries(db)
	if err != nil {
		logger.Fatal("Could not delete entries", err)
		return
	}
	err = cms.DeleteAllLogs(db)
	if err != nil {
		logger.Fatal("Could not delete logs", err)
		return
	}

	log, err := cms.CreateLog("Blargh", "blargh", db)
	if err != nil {
		logger.Fatal("Could not create a log", err)
		return
	}
	log.Publish = true
	log.Tagline = "Stuff and thangs."
	err = cms.UpdateLog(log, db)
	if err != nil {
		logger.Fatal("Could not publish the log", err)
		return
	}

	entry1, err := cms.CreateEntry(log, "First post", "first", "This is the first post.", db)
	if err != nil {
		logger.Fatal("Could not create an entry", err)
		return
	}
	entry1.Publish = true
	entry1.Issued = time.Now()
	err = cms.UpdateEntry(entry1, db)
	if err != nil {
		logger.Fatal("Could not update the entry", err)
		return
	}

	entry2, err := cms.CreateEntry(log, "Second post", "second", "This is the second post.", db)
	if err != nil {
		logger.Fatal("Could not create an entry", err)
		return
	}
	entry2.Publish = true
	entry2.Issued = time.Now()
	err = cms.UpdateEntry(entry2, db)
	if err != nil {
		logger.Fatal("Could not update the entry", err)
		return
	}
}
<|endoftext|>


<commit_before>package volume

import (
	"log"
	"net/http"

	"github.com/docker/go-plugins-helpers/sdk"
)

const (
	// DefaultDockerRootDirectory is the default directory where volumes will be created.
	DefaultDockerRootDirectory = "/var/lib/docker-volumes"

	manifest         = `{"Implements": ["VolumeDriver"]}`
	createPath       = "/VolumeDriver.Create"
	getPath          = "/VolumeDriver.Get"
	listPath         = "/VolumeDriver.List"
	removePath       = "/VolumeDriver.Remove"
	hostVirtualPath  = "/VolumeDriver.Path"
	mountPath        = "/VolumeDriver.Mount"
	unmountPath      = "/VolumeDriver.Unmount"
	capabilitiesPath = "/VolumeDriver.Capabilities"
)

// CreateRequest is the structure that docker's requests are deserialized to.
type CreateRequest struct {
	Name    string
	Options map[string]string `json:"Opts,omitempty"`
}

// RemoveRequest structure for a volume remove request
type RemoveRequest struct {
	Name string
}

// MountRequest structure for a volume mount request
type MountRequest struct {
	Name string
	ID   string
}

// MountResponse structure for a volume mount response
type MountResponse struct {
	Mountpoint string
}

// UnmountRequest structure for a volume unmount request
type UnmountRequest struct {
	Name string
	ID   string
}

// PathRequest structure for a volume path request
type PathRequest struct {
	Name string
}

// PathResponse structure for a volume path response
type PathResponse struct {
	Mountpoint string
}

// GetRequest structure for a volume get request
type GetRequest struct {
	Name string
}

// GetResponse structure for a volume get response
type GetResponse struct {
	Volume *Volume
}

// ListResponse structure for a volume list response
type ListResponse struct {
	Volumes []*Volume
}

// CapabilitiesResponse structure for a volume capability response
type CapabilitiesResponse struct {
	Capabilities Capability
}

// Volume represents a volume object for use with `Get` and `List` requests
type Volume struct {
	Name       string
	Mountpoint string
	CreatedAt  string `json:",omitempty"`
	Status     map[string]interface{}
}

// Capability represents the list of capabilities a volume driver can return
type Capability struct {
	Scope string
}

// ErrorResponse is a formatted error message that docker can understand
type ErrorResponse struct {
	Err string
}

// NewErrorResponse creates an ErrorResponse with the provided message
func NewErrorResponse(msg string) *ErrorResponse {
	return &ErrorResponse{Err: msg}
}

// Driver represent the interface a driver must fulfill.
type Driver interface {
	Create(*CreateRequest) error
	List() (*ListResponse, error)
	Get(*GetRequest) (*GetResponse, error)
	Remove(*RemoveRequest) error
	Path(*PathRequest) (*PathResponse, error)
	Mount(*MountRequest) (*MountResponse, error)
	Unmount(*UnmountRequest) error
	Capabilities() *CapabilitiesResponse
}

// Handler forwards requests and responses between the docker daemon and the plugin.
type Handler struct {
	driver Driver
	sdk.Handler
}

// NewHandler initializes the request handler with a driver implementation.
func NewHandler(driver Driver) *Handler {
	h := &Handler{driver, sdk.NewHandler(manifest)}
	h.initMux()
	return h
}

func (h *Handler) initMux() {
	h.HandleFunc(createPath, func(w http.ResponseWriter, r *http.Request) {
		log.Println("Entering go-plugins-helpers createPath")
		req := &CreateRequest{}
		err := sdk.DecodeRequest(w, r, req)
		if err != nil {
			return
		}
		err = h.driver.Create(req)
		if err != nil {
			sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true)
			return
		}
		sdk.EncodeResponse(w, struct{}{}, false)
	})
	h.HandleFunc(removePath, func(w http.ResponseWriter, r *http.Request) {
		log.Println("Entering go-plugins-helpers removePath")
		req := &RemoveRequest{}
		err := sdk.DecodeRequest(w, r, req)
		if err != nil {
			return
		}
		err = h.driver.Remove(req)
		if err != nil {
			sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true)
			return
		}
		sdk.EncodeResponse(w, struct{}{}, false)
	})
	h.HandleFunc(mountPath, func(w http.ResponseWriter, r *http.Request) {
		log.Println("Entering go-plugins-helpers mountPath")
		req := &MountRequest{}
		err := sdk.DecodeRequest(w, r, req)
		if err != nil {
			return
		}
		res, err := h.driver.Mount(req)
		if err != nil {
			sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true)
			return
		}
		sdk.EncodeResponse(w, res, false)
	})
	h.HandleFunc(hostVirtualPath, func(w http.ResponseWriter, r *http.Request) {
		log.Println("Entering go-plugins-helpers hostVirtualPath")
		req := &PathRequest{}
		err := sdk.DecodeRequest(w, r, req)
		if err != nil {
			return
		}
		res, err := h.driver.Path(req)
		if err != nil {
			sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true)
			return
		}
		sdk.EncodeResponse(w, res, false)
	})
	h.HandleFunc(getPath, func(w http.ResponseWriter, r *http.Request) {
		log.Println("Entering go-plugins-helpers getPath")
		req := &GetRequest{}
		err := sdk.DecodeRequest(w, r, req)
		if err != nil {
			return
		}
		res, err := h.driver.Get(req)
		if err != nil {
			sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true)
			return
		}
		sdk.EncodeResponse(w, res, false)
	})
	h.HandleFunc(unmountPath, func(w http.ResponseWriter, r *http.Request) {
		log.Println("Entering go-plugins-helpers unmountPath")
		req := &UnmountRequest{}
		err := sdk.DecodeRequest(w, r, req)
		if err != nil {
			return
		}
		err = h.driver.Unmount(req)
		if err != nil {
			sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true)
			return
		}
		sdk.EncodeResponse(w, struct{}{}, false)
	})
	h.HandleFunc(listPath, func(w http.ResponseWriter, r *http.Request) {
		log.Println("Entering go-plugins-helpers listPath")
		res, err := h.driver.List()
		if err != nil {
			sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true)
			return
		}
		sdk.EncodeResponse(w, res, false)
	})

	h.HandleFunc(capabilitiesPath, func(w http.ResponseWriter, r *http.Request) {
		log.Println("Entering go-plugins-helpers capabilitiesPath")
		sdk.EncodeResponse(w, h.driver.Capabilities(), false)
	})
}
<commit_msg>Ignore empty volume status too<commit_after>package volume

import (
	"log"
	"net/http"

	"github.com/docker/go-plugins-helpers/sdk"
)

const (
	// DefaultDockerRootDirectory is the default directory where volumes will be created.
	DefaultDockerRootDirectory = "/var/lib/docker-volumes"

	manifest         = `{"Implements": ["VolumeDriver"]}`
	createPath       = "/VolumeDriver.Create"
	getPath          = "/VolumeDriver.Get"
	listPath         = "/VolumeDriver.List"
	removePath       = "/VolumeDriver.Remove"
	hostVirtualPath  = "/VolumeDriver.Path"
	mountPath        = "/VolumeDriver.Mount"
	unmountPath      = "/VolumeDriver.Unmount"
	capabilitiesPath = "/VolumeDriver.Capabilities"
)

// CreateRequest is the structure that docker's requests are deserialized to.
type CreateRequest struct {
	Name    string
	Options map[string]string `json:"Opts,omitempty"`
}

// RemoveRequest structure for a volume remove request
type RemoveRequest struct {
	Name string
}

// MountRequest structure for a volume mount request
type MountRequest struct {
	Name string
	ID   string
}

// MountResponse structure for a volume mount response
type MountResponse struct {
	Mountpoint string
}

// UnmountRequest structure for a volume unmount request
type UnmountRequest struct {
	Name string
	ID   string
}

// PathRequest structure for a volume path request
type PathRequest struct {
	Name string
}

// PathResponse structure for a volume path response
type PathResponse struct {
	Mountpoint string
}

// GetRequest structure for a volume get request
type GetRequest struct {
	Name string
}

// GetResponse structure for a volume get response
type GetResponse struct {
	Volume *Volume
}

// ListResponse structure for a volume list response
type ListResponse struct {
	Volumes []*Volume
}

// CapabilitiesResponse structure for a volume capability response
type CapabilitiesResponse struct {
	Capabilities Capability
}

// Volume represents a volume object for use with `Get` and `List` requests
type Volume struct {
	Name       string
	Mountpoint string
	CreatedAt  string `json:",omitempty"`
	Status     map[string]interface{} `json:",omitempty"`
}

// Capability represents the list of capabilities a volume driver can return
type Capability struct {
	Scope string
}

// ErrorResponse is a formatted error message that docker can understand
type ErrorResponse struct {
	Err string
}

// NewErrorResponse creates an ErrorResponse with the provided message
func NewErrorResponse(msg string) *ErrorResponse {
	return &ErrorResponse{Err: msg}
}

// Driver represent the interface a driver must fulfill.
type Driver interface {
	Create(*CreateRequest) error
	List() (*ListResponse, error)
	Get(*GetRequest) (*GetResponse, error)
	Remove(*RemoveRequest) error
	Path(*PathRequest) (*PathResponse, error)
	Mount(*MountRequest) (*MountResponse, error)
	Unmount(*UnmountRequest) error
	Capabilities() *CapabilitiesResponse
}

// Handler forwards requests and responses between the docker daemon and the plugin.
type Handler struct {
	driver Driver
	sdk.Handler
}

// NewHandler initializes the request handler with a driver implementation.
func NewHandler(driver Driver) *Handler {
	h := &Handler{driver, sdk.NewHandler(manifest)}
	h.initMux()
	return h
}

func (h *Handler) initMux() {
	h.HandleFunc(createPath, func(w http.ResponseWriter, r *http.Request) {
		log.Println("Entering go-plugins-helpers createPath")
		req := &CreateRequest{}
		err := sdk.DecodeRequest(w, r, req)
		if err != nil {
			return
		}
		err = h.driver.Create(req)
		if err != nil {
			sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true)
			return
		}
		sdk.EncodeResponse(w, struct{}{}, false)
	})
	h.HandleFunc(removePath, func(w http.ResponseWriter, r *http.Request) {
		log.Println("Entering go-plugins-helpers removePath")
		req := &RemoveRequest{}
		err := sdk.DecodeRequest(w, r, req)
		if err != nil {
			return
		}
		err = h.driver.Remove(req)
		if err != nil {
			sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true)
			return
		}
		sdk.EncodeResponse(w, struct{}{}, false)
	})
	h.HandleFunc(mountPath, func(w http.ResponseWriter, r *http.Request) {
		log.Println("Entering go-plugins-helpers mountPath")
		req := &MountRequest{}
		err := sdk.DecodeRequest(w, r, req)
		if err != nil {
			return
		}
		res, err := h.driver.Mount(req)
		if err != nil {
			sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true)
			return
		}
		sdk.EncodeResponse(w, res, false)
	})
	h.HandleFunc(hostVirtualPath, func(w http.ResponseWriter, r *http.Request) {
		log.Println("Entering go-plugins-helpers hostVirtualPath")
		req := &PathRequest{}
		err := sdk.DecodeRequest(w, r, req)
		if err != nil {
			return
		}
		res, err := h.driver.Path(req)
		if err != nil {
			sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true)
			return
		}
		sdk.EncodeResponse(w, res, false)
	})
	h.HandleFunc(getPath, func(w http.ResponseWriter, r *http.Request) {
		log.Println("Entering go-plugins-helpers getPath")
		req := &GetRequest{}
		err := sdk.DecodeRequest(w, r, req)
		if err != nil {
			return
		}
		res, err := h.driver.Get(req)
		if err != nil {
			sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true)
			return
		}
		sdk.EncodeResponse(w, res, false)
	})
	h.HandleFunc(unmountPath, func(w http.ResponseWriter, r *http.Request) {
		log.Println("Entering go-plugins-helpers unmountPath")
		req := &UnmountRequest{}
		err := sdk.DecodeRequest(w, r, req)
		if err != nil {
			return
		}
		err = h.driver.Unmount(req)
		if err != nil {
			sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true)
			return
		}
		sdk.EncodeResponse(w, struct{}{}, false)
	})
	h.HandleFunc(listPath, func(w http.ResponseWriter, r *http.Request) {
		log.Println("Entering go-plugins-helpers listPath")
		res, err := h.driver.List()
		if err != nil {
			sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true)
			return
		}
		sdk.EncodeResponse(w, res, false)
	})

	h.HandleFunc(capabilitiesPath, func(w http.ResponseWriter, r *http.Request) {
		log.Println("Entering go-plugins-helpers capabilitiesPath")
		sdk.EncodeResponse(w, h.driver.Capabilities(), false)
	})
}
<|endoftext|>


<commit_before>package lib

import (
	"errors"
	"net/http"
	"strings"
	"time"

	"github.com/clawio/clawiod/entities"
	"github.com/clawio/clawiod/keys"
	"github.com/dgrijalva/jwt-go"
)

// Authenticator represents the strategy to create authentication tokens.
type Authenticator struct {
	JWTKey           string
	JWTSigningMethod string
}

// NewAuthenticator returns a new Authenticator.
func NewAuthenticator(key, method string) *Authenticator {
	return &Authenticator{JWTKey: key, JWTSigningMethod: method}
}

// CreateToken returns an authentication token from an User.
func (a *Authenticator) CreateToken(user *entities.User) (string, error) {
	if user == nil {
		return "", errors.New("user is nil")
	}
	token := jwt.New(jwt.GetSigningMethod(a.JWTSigningMethod))
	token.Claims["username"] = user.Username
	token.Claims["email"] = user.Email
	token.Claims["display_name"] = user.DisplayName
	token.Claims["exp"] = time.Now().Add(time.Second * 3600).UnixNano()
	return token.SignedString([]byte(a.JWTKey))
}

// CreateUserFromToken parses an authentication token and returns the User contained in the token.
func (a *Authenticator) CreateUserFromToken(token string) (*entities.User, error) {
	rawToken, err := a.parseToken(token)
	if err != nil {
		return nil, err
	}
	return a.getUserFromRawToken(rawToken)
}

func (a *Authenticator) getUserFromRawToken(rawToken *jwt.Token) (*entities.User, error) {
	username, ok := rawToken.Claims["username"].(string)
	if !ok {
		return nil, errors.New("token username claim failed cast to string")
	}

	email, ok := rawToken.Claims["email"].(string)
	if !ok {
		return nil, errors.New("token email claim failed cast to string")
	}

	displayName, ok := rawToken.Claims["display_name"].(string)
	if !ok {
		return nil, errors.New("token display_name claim failed cast to string")
	}
	return &entities.User{
		Username:    username,
		Email:       email,
		DisplayName: displayName,
	}, nil
}
func (a *Authenticator) parseToken(token string) (*jwt.Token, error) {
	return jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
		return []byte(a.JWTKey), nil
	})
}

func (a *Authenticator) getTokenFromRequest(r *http.Request) string {
	if t := a.getTokenFromHeader(r); t != "" {
		return t
	}
	return a.getTokenFromQuery(r)
}
func (a *Authenticator) getTokenFromQuery(r *http.Request) string {
	return r.URL.Query().Get("access_token")
}
func (a *Authenticator) getTokenFromHeader(r *http.Request) string {
	header := r.Header.Get("Authorization")
	parts := strings.Split(header, " ")
	if len(parts) < 2 {
		return ""
	}
	if strings.ToLower(parts[0]) != "bearer" {
		return ""
	}
	return parts[1]
}

// JWTHandlerFunc is a middleware function to authenticate HTTP requests.
func (a *Authenticator) JWTHandlerFunc(handler http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		log := keys.MustGetLog(r)
		token := a.getTokenFromRequest(r)
		user, err := a.CreateUserFromToken(token)
		if err != nil {
			log.Warn("unauthorized")
			http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
			return
		}
		keys.SetUser(r, user)
		log.WithField("user", user.Username).Info("authenticated request")
		handler(w, r)
	}
}
<commit_msg>Adapt code to new JWT library version<commit_after>package lib

import (
	"errors"
	"net/http"
	"strings"
	"time"

	"github.com/clawio/clawiod/entities"
	"github.com/clawio/clawiod/keys"
	"github.com/dgrijalva/jwt-go"
)

// Authenticator represents the strategy to create authentication tokens.
type Authenticator struct {
	JWTKey           string
	JWTSigningMethod string
}

// NewAuthenticator returns a new Authenticator.
func NewAuthenticator(key, method string) *Authenticator {
	return &Authenticator{JWTKey: key, JWTSigningMethod: method}
}

// CreateToken returns an authentication token from an User.
func (a *Authenticator) CreateToken(user *entities.User) (string, error) {
	if user == nil {
		return "", errors.New("user is nil")
	}
	token := jwt.New(jwt.GetSigningMethod(a.JWTSigningMethod))
	claims := token.Claims.(jwt.MapClaims)
	claims["username"] = user.Username
	claims["email"] = user.Email
	claims["display_name"] = user.DisplayName
	claims["exp"] = time.Now().Add(time.Second * 3600).UnixNano()
	return token.SignedString([]byte(a.JWTKey))
}

// CreateUserFromToken parses an authentication token and returns the User contained in the token.
func (a *Authenticator) CreateUserFromToken(token string) (*entities.User, error) {
	rawToken, err := a.parseToken(token)
	if err != nil {
		return nil, err
	}
	return a.getUserFromRawToken(rawToken)
}

func (a *Authenticator) getUserFromRawToken(rawToken *jwt.Token) (*entities.User, error) {
	claims := rawToken.Claims.(jwt.MapClaims)
	username, ok := claims["username"].(string)
	if !ok {
		return nil, errors.New("token username claim failed cast to string")
	}

	email, ok := claims["email"].(string)
	if !ok {
		return nil, errors.New("token email claim failed cast to string")
	}

	displayName, ok := claims["display_name"].(string)
	if !ok {
		return nil, errors.New("token display_name claim failed cast to string")
	}
	return &entities.User{
		Username:    username,
		Email:       email,
		DisplayName: displayName,
	}, nil
}
func (a *Authenticator) parseToken(token string) (*jwt.Token, error) {
	return jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
		return []byte(a.JWTKey), nil
	})
}

func (a *Authenticator) getTokenFromRequest(r *http.Request) string {
	if t := a.getTokenFromHeader(r); t != "" {
		return t
	}
	return a.getTokenFromQuery(r)
}
func (a *Authenticator) getTokenFromQuery(r *http.Request) string {
	return r.URL.Query().Get("access_token")
}
func (a *Authenticator) getTokenFromHeader(r *http.Request) string {
	header := r.Header.Get("Authorization")
	parts := strings.Split(header, " ")
	if len(parts) < 2 {
		return ""
	}
	if strings.ToLower(parts[0]) != "bearer" {
		return ""
	}
	return parts[1]
}

// JWTHandlerFunc is a middleware function to authenticate HTTP requests.
func (a *Authenticator) JWTHandlerFunc(handler http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		log := keys.MustGetLog(r)
		token := a.getTokenFromRequest(r)
		user, err := a.CreateUserFromToken(token)
		if err != nil {
			log.Warn("unauthorized")
			http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
			return
		}
		keys.SetUser(r, user)
		log.WithField("user", user.Username).Info("authenticated request")
		handler(w, r)
	}
}
<|endoftext|>


<commit_before>package mafsa

import (
	"fmt"
	"sort"
	"strings"
)

type (
	// MinTree implements a simple prefix tree with read-only functionality.
	// It supports Minimal Perfect Hashing (MPH) so you can lookup entries
	// by their index in a slice.
	MinTree struct {
		Root *MinTreeNode
	}

	// MinTreeNode is a node in a MinTree.
	MinTreeNode struct {
		Edges  map[rune]*MinTreeNode
		Final  bool
		Number int
	}

	// Entry represents a value in the tree along with its
	// index number (minimal perfect hashing).
	Entry struct {
		// The actual entry that was added to the tree
		Value string

		// Represents how many entries were added to the tree before this one
		Index int
	}
)

// Contains returns true if word is found in the tree,
// false otherwise.
func (t *MinTree) Contains(word string) bool {
	result := t.Traverse([]rune(word))
	return result != nil && result.Final
}

// Traverse visits nodes according to word and returns the
// last node, if there was one. Note that returning a non-nil
// node is not indicative of membership; a node may be
// returned even if the word is not in the set. Traverse
// implements a fast traversal which does not count the
// index number of the last node.
func (t *MinTree) Traverse(word []rune) *MinTreeNode {
	node := t.Root
	for i := 0; i < len(word); i++ {
		if child, ok := node.Edges[word[i]]; ok {
			node = child
		} else {
			return nil
		}
	}
	return node
}

// IndexedTraverse visits nodes according to word and
// returns the last node, if there was one, along with
// its index number. The index number represents how
// many entries, including the returned node, are in the
// tree before entries beginning with the specified prefix.
// Such an indexed traversal is slightly slower than a
// regular traversal since this kind of traversal has to
// iterate more nodes and count the numbers on each node.
// Note that returning a non-nil node is not indicative of
// membership; a node may be be returned even if the word is
// not in the set. If last node is nil, the returned index
// is -1. The algorithm is adapted directly from the paper
// by Lucceshi and Kowaltowski, 1992 (section 5.2), with
// one slight modification for correctness because of a slight
// difference in the way our tree is implemented.
func (t *MinTree) IndexedTraverse(word []rune) (*MinTreeNode, int) {
	index := 0
	node := t.Root

	for i := 0; i < len(word); i++ {
		if child, ok := node.Edges[word[i]]; ok {
			for char, child := range node.Edges {
				if char < word[i] {
					index += child.Number

					// If a previous sibling is also a final
					// node, add 1, since that word appears before
					// any word through this node. This line is
					// a modification of the algorithm described
					// in the paper.
					if child.Final {
						index++
					}
				}
			}
			node = child
			if node.Final {
				index++
			}
		} else {
			return nil, -1
		}
	}

	return node, index
}

// String serializes the tree roughly as a human-readable string
// for debugging purposes. Don't try this on large trees.
func (t *MinTree) String() string {
	return t.recursiveString(t.Root, "", 0)
}

// recursiveString is used by String to visit each node
// and build a string representation of the tree.
func (t *MinTree) recursiveString(node *MinTreeNode, str string, level int) string {
	keys := node.OrderedEdges()
	for _, char := range keys {
		child := node.Edges[char]
		str += fmt.Sprintf("%s%s %p %d\n", strings.Repeat(" ", level), string(char), child, child.Number)
		str = t.recursiveString(child, str, level+1)
	}
	return str
}

// UnmarshalBinary decodes binary data into this MinTree. It implements the functionality
// described by the encoding.BinaryMarhsaler interface. The associated
// encoding.BinaryMarshaler type is BuildTree.
func (t *MinTree) UnmarshalBinary(data []byte) error {
	return new(Decoder).decodeMinTree(t, data)
}

// OrderedEdges returns the keys of the outgoing edges in
// lexigocraphical sorted order. It enables deterministic
// traversal of edges to child nodes.
func (n *MinTreeNode) OrderedEdges() []rune {
	keys := make(runeSlice, 0, len(n.Edges))
	for char := range n.Edges {
		keys = append(keys, char)
	}
	sort.Sort(keys)
	return []rune(keys)
}

// IterateDepthFirst returns an unbuffered channel which will be loaded with all items
// in the tree in lexicographical order. The caller need only range over the channel (which
// will be closed whan all items have been loaded).
func (t *MinTree) IterateDepthFirst() chan string {
	search := &depthFirst{tree: t, channel: make(chan string)}
	go search.start()
	return search.channel
}

// newMinTree constructs a new, empty MA-FSA that must be assembled
// manually (e.g. when decoding from binary), but is very memory
// efficient.
func newMinTree() *MinTree {
	t := new(MinTree)
	t.Root = new(MinTreeNode)
	t.Root.Edges = make(map[rune]*MinTreeNode)
	return t
}
<commit_msg>Use contructor function.<commit_after>package mafsa

import (
	"fmt"
	"sort"
	"strings"
)

type (
	// MinTree implements a simple prefix tree with read-only functionality.
	// It supports Minimal Perfect Hashing (MPH) so you can lookup entries
	// by their index in a slice.
	MinTree struct {
		Root *MinTreeNode
	}

	// MinTreeNode is a node in a MinTree.
	MinTreeNode struct {
		Edges  map[rune]*MinTreeNode
		Final  bool
		Number int
	}

	// Entry represents a value in the tree along with its
	// index number (minimal perfect hashing).
	Entry struct {
		// The actual entry that was added to the tree
		Value string

		// Represents how many entries were added to the tree before this one
		Index int
	}
)

// Contains returns true if word is found in the tree,
// false otherwise.
func (t *MinTree) Contains(word string) bool {
	result := t.Traverse([]rune(word))
	return result != nil && result.Final
}

// Traverse visits nodes according to word and returns the
// last node, if there was one. Note that returning a non-nil
// node is not indicative of membership; a node may be
// returned even if the word is not in the set. Traverse
// implements a fast traversal which does not count the
// index number of the last node.
func (t *MinTree) Traverse(word []rune) *MinTreeNode {
	node := t.Root
	for i := 0; i < len(word); i++ {
		if child, ok := node.Edges[word[i]]; ok {
			node = child
		} else {
			return nil
		}
	}
	return node
}

// IndexedTraverse visits nodes according to word and
// returns the last node, if there was one, along with
// its index number. The index number represents how
// many entries, including the returned node, are in the
// tree before entries beginning with the specified prefix.
// Such an indexed traversal is slightly slower than a
// regular traversal since this kind of traversal has to
// iterate more nodes and count the numbers on each node.
// Note that returning a non-nil node is not indicative of
// membership; a node may be be returned even if the word is
// not in the set. If last node is nil, the returned index
// is -1. The algorithm is adapted directly from the paper
// by Lucceshi and Kowaltowski, 1992 (section 5.2), with
// one slight modification for correctness because of a slight
// difference in the way our tree is implemented.
func (t *MinTree) IndexedTraverse(word []rune) (*MinTreeNode, int) {
	index := 0
	node := t.Root

	for i := 0; i < len(word); i++ {
		if child, ok := node.Edges[word[i]]; ok {
			for char, child := range node.Edges {
				if char < word[i] {
					index += child.Number

					// If a previous sibling is also a final
					// node, add 1, since that word appears before
					// any word through this node. This line is
					// a modification of the algorithm described
					// in the paper.
					if child.Final {
						index++
					}
				}
			}
			node = child
			if node.Final {
				index++
			}
		} else {
			return nil, -1
		}
	}

	return node, index
}

// String serializes the tree roughly as a human-readable string
// for debugging purposes. Don't try this on large trees.
func (t *MinTree) String() string {
	return t.recursiveString(t.Root, "", 0)
}

// recursiveString is used by String to visit each node
// and build a string representation of the tree.
func (t *MinTree) recursiveString(node *MinTreeNode, str string, level int) string {
	keys := node.OrderedEdges()
	for _, char := range keys {
		child := node.Edges[char]
		str += fmt.Sprintf("%s%s %p %d\n", strings.Repeat(" ", level), string(char), child, child.Number)
		str = t.recursiveString(child, str, level+1)
	}
	return str
}

// UnmarshalBinary decodes binary data into this MinTree. It implements the functionality
// described by the encoding.BinaryMarhsaler interface. The associated
// encoding.BinaryMarshaler type is BuildTree.
func (t *MinTree) UnmarshalBinary(data []byte) error {
	return new(Decoder).decodeMinTree(t, data)
}

// OrderedEdges returns the keys of the outgoing edges in
// lexigocraphical sorted order. It enables deterministic
// traversal of edges to child nodes.
func (n *MinTreeNode) OrderedEdges() []rune {
	keys := make(runeSlice, 0, len(n.Edges))
	for char := range n.Edges {
		keys = append(keys, char)
	}
	sort.Sort(keys)
	return []rune(keys)
}

// IterateDepthFirst returns an unbuffered channel which will be loaded with all items
// in the tree in lexicographical order. The caller need only range over the channel (which
// will be closed whan all items have been loaded).
func (t *MinTree) IterateDepthFirst() chan string {
	search := newDepthFirst(t)
	go search.start()
	return search.channel
}

// newMinTree constructs a new, empty MA-FSA that must be assembled
// manually (e.g. when decoding from binary), but is very memory
// efficient.
func newMinTree() *MinTree {
	t := new(MinTree)
	t.Root = new(MinTreeNode)
	t.Root.Edges = make(map[rune]*MinTreeNode)
	return t
}
<|endoftext|>


<commit_before>package crawl

import (
	"errors"
	"fmt"
	"testing"
	"vaddy/args"
	"vaddy/httpreq"
	"vaddy/test/mock/httpreqmock"
)

//Crawl検索で3件取得し、その中のItemの先頭のid:2が返ることを確認する
// total countが3件というのも確認する
func TestGetCrawlIdOkCrawlId2(t *testing.T) {
	var jsonResponse string = `{"total":3,"page":1,"limit":30,
	"items":[
		{"id":2, "label": "all-data", "start":"2016-03-12T11:11:11+0000", "end":"2016-03-12T12:00:00+0000"},
		{"id":1, "label": null, "start":"2016-03-12T11:11:11+0000", "end":"2016-03-12T12:00:00+0000"},
		{"id":3, "label": null, "start":"2016-03-12T11:11:11+0000", "end":"2016-03-12T12:00:00+0000"}
	]}`
	httpreqmock.HttpResponseMock = httpreq.HttpResponseData{200, []byte(jsonResponse), nil}
	httpreqmock.HttpResponseMockErr = nil

	httpRequestHandler = httpreqmock.HttpRequestData{} //search_crawl.go global var HttpRequestHander
	scanSetting := args.ScanSetting{}
	crawlId, count, err := GetCrawlId(scanSetting)
	if err != nil {
		t.Error("err is not nil")
	}
	if crawlId != "2" {
		t.Error("crawlId not 2")
	}
	if count != 3 {
		t.Error("crawl count not 3")
	}
}

//Crawl検索で0件だったためエラーとなるのをテスト
func TestGetCrawlIdNoItemError(t *testing.T) {
	var jsonResponse string = `{"total":0,"page":1,"limit":30,
	"items":[
	]}`
	httpreqmock.HttpResponseMock = httpreq.HttpResponseData{200, []byte(jsonResponse), nil}
	httpreqmock.HttpResponseMockErr = nil

	httpRequestHandler = httpreqmock.HttpRequestData{} //search_crawl.go global var HttpRequestHander
	scanSetting := args.ScanSetting{}
	_, _, err := GetCrawlId(scanSetting)
	if err == nil {
		t.Error("err is nil")
	}
	if err.Error() != `Can not find crawl id. using latest crawl id.` {
		t.Fatal("Expect no item error")
	}
}

//レスポンスのJSONがJSON形式ではないためJSON convert errorとなるかチェック
func TestGetCrawlIdNotJsonDataError(t *testing.T) {
	httpreqmock.HttpResponseMock = httpreq.HttpResponseData{200, []byte("not json data"), nil}
	httpreqmock.HttpResponseMockErr = nil

	httpRequestHandler = httpreqmock.HttpRequestData{} //search_crawl.go global var HttpRequestHander
	scanSetting := args.ScanSetting{}
	_, _, err := GetCrawlId(scanSetting)
	if err == nil {
		t.Error("err is nil")
	}
	if err.Error() != `Can not convert json response in crawl search.` {
		t.Fatal("Expect JSON convert error")
	}
}

// HTTPレスポンスがエラーとなっているのをテスト
func TestGetCrawlIdReturnError(t *testing.T) {
	httpreqmock.HttpResponseMock = httpreq.HttpResponseData{400, []byte("result body"), nil}
	httpreqmock.HttpResponseMockErr = errors.New("Error test")

	httpRequestHandler = httpreqmock.HttpRequestData{}
	scanSetting := args.ScanSetting{}
	result, _, err := GetCrawlId(scanSetting)
	fmt.Println(result)
	if err == nil {
		t.Error("Expect error response status.")
	}
}
<commit_msg>不要なprintを削除<commit_after>package crawl

import (
	"errors"
	"testing"
	"vaddy/args"
	"vaddy/httpreq"
	"vaddy/test/mock/httpreqmock"
)

//Crawl検索で3件取得し、その中のItemの先頭のid:2が返ることを確認する
// total countが3件というのも確認する
func TestGetCrawlIdOkCrawlId2(t *testing.T) {
	var jsonResponse string = `{"total":3,"page":1,"limit":30,
	"items":[
		{"id":2, "label": "all-data", "start":"2016-03-12T11:11:11+0000", "end":"2016-03-12T12:00:00+0000"},
		{"id":1, "label": null, "start":"2016-03-12T11:11:11+0000", "end":"2016-03-12T12:00:00+0000"},
		{"id":3, "label": null, "start":"2016-03-12T11:11:11+0000", "end":"2016-03-12T12:00:00+0000"}
	]}`
	httpreqmock.HttpResponseMock = httpreq.HttpResponseData{200, []byte(jsonResponse), nil}
	httpreqmock.HttpResponseMockErr = nil

	httpRequestHandler = httpreqmock.HttpRequestData{} //search_crawl.go global var HttpRequestHander
	scanSetting := args.ScanSetting{}
	crawlId, count, err := GetCrawlId(scanSetting)
	if err != nil {
		t.Error("err is not nil")
	}
	if crawlId != "2" {
		t.Error("crawlId not 2")
	}
	if count != 3 {
		t.Error("crawl count not 3")
	}
}

//Crawl検索で0件だったためエラーとなるのをテスト
func TestGetCrawlIdNoItemError(t *testing.T) {
	var jsonResponse string = `{"total":0,"page":1,"limit":30,
	"items":[
	]}`
	httpreqmock.HttpResponseMock = httpreq.HttpResponseData{200, []byte(jsonResponse), nil}
	httpreqmock.HttpResponseMockErr = nil

	httpRequestHandler = httpreqmock.HttpRequestData{} //search_crawl.go global var HttpRequestHander
	scanSetting := args.ScanSetting{}
	_, _, err := GetCrawlId(scanSetting)
	if err == nil {
		t.Error("err is nil")
	}
	if err.Error() != `Can not find crawl id. using latest crawl id.` {
		t.Fatal("Expect no item error")
	}
}

//レスポンスのJSONがJSON形式ではないためJSON convert errorとなるかチェック
func TestGetCrawlIdNotJsonDataError(t *testing.T) {
	httpreqmock.HttpResponseMock = httpreq.HttpResponseData{200, []byte("not json data"), nil}
	httpreqmock.HttpResponseMockErr = nil

	httpRequestHandler = httpreqmock.HttpRequestData{} //search_crawl.go global var HttpRequestHander
	scanSetting := args.ScanSetting{}
	_, _, err := GetCrawlId(scanSetting)
	if err == nil {
		t.Error("err is nil")
	}
	if err.Error() != `Can not convert json response in crawl search.` {
		t.Fatal("Expect JSON convert error")
	}
}

// HTTPレスポンスがエラーとなっているのをテスト
func TestGetCrawlIdReturnError(t *testing.T) {
	httpreqmock.HttpResponseMock = httpreq.HttpResponseData{400, []byte("result body"), nil}
	httpreqmock.HttpResponseMockErr = errors.New("Error test")

	httpRequestHandler = httpreqmock.HttpRequestData{}
	scanSetting := args.ScanSetting{}
	_, _, err := GetCrawlId(scanSetting)
	if err == nil {
		t.Error("Expect error response status.")
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package version

var (
	// Major is the current major version of master branch.
	Major = 0
	// Minor is the current minor version of master branch.
	Minor = 5
	// Patch is the current patched version of the master branch.
	Patch = 0
	// Release is the current release level of the master branch. Valid values
	// are dev (development unreleased), rcX (release candidate with current
	// iteration), stable (indicates a final released version).
	Release = "stable"
)
<commit_msg>Upgrade to 0.5.1 dev<commit_after>// Copyright 2016 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package version

var (
	// Major is the current major version of master branch.
	Major = 0
	// Minor is the current minor version of master branch.
	Minor = 5
	// Patch is the current patched version of the master branch.
	Patch = 1
	// Release is the current release level of the master branch. Valid values
	// are dev (development unreleased), rcX (release candidate with current
	// iteration), stable (indicates a final released version).
	Release = "dev"
)
<|endoftext|>


<commit_before>// Copyright (c) 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package sentry

import (
	"compress/zlib"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	raven "github.com/getsentry/raven-go"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"github.com/uber-go/zap"
)

type fakeClient raven.Client

func TestBadDSN(t *testing.T) {
	_, err := New("123http://whoops")
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "failed to create sentry client")
}

func TestEmptyDSN(t *testing.T) {
	l, err := New("")
	assert.NoError(t, err)
	assert.NotNil(t, l)
}

func TestWithLevels(t *testing.T) {
	l, err := New("", MinLevel(zap.InfoLevel))
	assert.NoError(t, err)
	assert.NotNil(t, l)
	assert.Equal(t, l.minLevel, zap.InfoLevel)
}

func TestExtra(t *testing.T) {
	f := map[string]interface{}{
		"requestID":         "123h2eor2039423",
		"someInt":           123,
		"arrayOfManyThings": []int{1, 2, 3},
	}
	s, err := New("", Fields(f))
	s.CheckAndFire(zap.ErrorLevel, "error log", "foo", "bar")
	assert.NoError(t, err)
	assert.Equal(t, f, s.Fields())
}

func TestWith(t *testing.T) {
	sh, err := New("", Fields(map[string]interface{}{
		"someInt": 123,
	}))
	assert.NoError(t, err)
	expected := map[string]interface{}{"someInt": 123, "someFloat": float64(10)}
	sh.AppendFields("someFloat", float64(10))
	assert.Equal(t, expected, sh.Fields())
}

func TestCopy(t *testing.T) {
	sh, err := New("", Fields(map[string]interface{}{
		"someInt": 123,
	}))
	assert.NoError(t, err)
	shCopy := sh.Copy()
	for k, v := range sh.Fields() {
		assert.Equal(t, v, shCopy.Fields()[k])
	}
	assert.Equal(t, sh.Capturer, shCopy.Capturer)
	assert.Equal(t, sh.minLevel, shCopy.minLevel)
	assert.Equal(t, sh.traceEnabled, shCopy.traceEnabled)
	assert.Equal(t, sh.traceSkipFrames, shCopy.traceSkipFrames)
	assert.Equal(t, sh.traceContextLines, shCopy.traceContextLines)
	assert.Equal(t, sh.traceAppPrefixes, shCopy.traceAppPrefixes)
}

func TestWithTraceDisabled(t *testing.T) {
	_, ps := capturePackets(func(sh *Hook) {
		sh.CheckAndFire(zap.ErrorLevel, "some error message", "foo", "bar")
		sh.CheckAndFire(zap.ErrorLevel, "another error message")
	}, DisableTraces())

	for _, p := range ps {
		assert.Empty(t, p.Interfaces)
	}
}

func TestTraceCfg(t *testing.T) {
	l, err := New(
		"",
		TraceSkipFrames(1),
		TraceContextLines(7),
		TraceAppPrefixes([]string{"github.com/uber-go/unicorns"}),
	)
	assert.NoError(t, err)
	assert.Equal(t, l.traceSkipFrames, 1)
	assert.Equal(t, l.traceContextLines, 7)
	assert.Equal(t, l.traceAppPrefixes, []string{"github.com/uber-go/unicorns"})
}

func TestLevels(t *testing.T) {
	_, ps := capturePackets(func(sh *Hook) {
		sh.CheckAndFire(zap.DebugLevel, "debug level log")
		sh.CheckAndFire(zap.InfoLevel, "info level log")
		sh.CheckAndFire(zap.WarnLevel, "warn level log")
		sh.CheckAndFire(zap.ErrorLevel, "error level log")
	}, MinLevel(zap.WarnLevel))

	assert.Equal(t, len(ps), 2, "only Warn and Error packets should be collected")
}

func TestErrorCapture(t *testing.T) {
	_, p := capturePacket(func(sh *Hook) {
		sh.CheckAndFire(zap.ErrorLevel, "some error message", "foo", "bar")
	})

	assert.Equal(t, p.Message, "some error message")
	assert.Equal(t, p.Extra, map[string]interface{}{"foo": "bar"})

	trace := p.Interfaces[0].(*raven.Stacktrace)
	assert.NotNil(t, trace.Frames)
}

func TestPacketSending(t *testing.T) {
	withTestSentry(func(dsn string, ch <-chan *raven.Packet) {
		sh, err := New(dsn)
		defer sh.Close()
		assert.NoError(t, err)

		sh.CheckAndFire(zap.ErrorLevel, "my error message", "mykey1", "myvalue1")
		sh.CheckAndFire(zap.ErrorLevel, "my error message", "mykey1", "myvalue1")
		p := <-ch

		assert.Equal(t, p.Message, "my error message")
		assert.Equal(t, map[string]interface{}{"mykey1": "myvalue1"}, p.Extra)
	})
}

func TestConfigure(t *testing.T) {
	one := 1
	two := 2
	debug := zap.DebugLevel.String()
	str := "random string"
	trace := struct {
		Disabled     bool
		SkipFrames   *int `yaml:"skip_frames"`
		ContextLines *int `yaml:"context_lines"`
	}{
		Disabled:     true,
		SkipFrames:   &one,
		ContextLines: &two,
	}

	testCases := []struct {
		name  string
		conf  Configuration
		res   *Hook
		isErr bool
	}{
		{"Empty",
			Configuration{},
			&Hook{
				traceEnabled:      true,
				minLevel:          zap.ErrorLevel,
				traceContextLines: _traceContextLines,
				traceSkipFrames:   _traceSkipFrames,
				fields:            map[string]interface{}{},
			}, false},
		{"SomeValues",
			Configuration{
				MinLevel: &debug,
				Trace:    &trace,
				Fields:   map[string]interface{}{"mickey": "mouse"},
			},
			&Hook{
				minLevel:          zap.DebugLevel,
				traceEnabled:      false,
				traceSkipFrames:   one,
				traceContextLines: two,
				fields:            map[string]interface{}{"mickey": "mouse"},
			}, false},
		{"ParseError", Configuration{MinLevel: &str}, nil, true},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			conf, err := Configure(tc.conf)
			if tc.isErr {
				assert.Error(t, err)
				return
			}

			require.NoError(t, err)
			r := tc.res
			assert.Equal(t, r.traceEnabled, conf.traceEnabled)
			assert.Equal(t, r.minLevel, conf.minLevel)
			assert.Equal(t, r.traceContextLines, conf.traceContextLines)
			assert.Equal(t, r.traceSkipFrames, conf.traceSkipFrames)
			assert.Equal(t, r.fields, conf.fields)
		})
	}
}

func capturePacket(f func(sh *Hook), options ...Option) (*Hook, *raven.Packet) {
	l, ps := capturePackets(f, options...)
	if len(ps) != 1 {
		panic("Expected to capture a packet, but didn't")
	}
	return l, ps[0]
}

func capturePackets(f func(sh *Hook), options ...Option) (*Hook, []*raven.Packet) {
	sh, err := New("", options...)
	if err != nil {
		panic("Failed to create the logger")
	}

	c := &MemCapturer{}
	sh.Capturer = c

	f(sh)

	return sh, c.Packets
}

func withTestSentry(f func(string, <-chan *raven.Packet)) {
	ch := make(chan *raven.Packet)
	h := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
		defer req.Body.Close()

		contentType := req.Header.Get("Content-Type")
		var bodyReader io.Reader = req.Body
		// underlying client will compress and encode payload above certain size
		if contentType == "application/octet-stream" {
			bodyReader = base64.NewDecoder(base64.StdEncoding, bodyReader)
			bodyReader, _ = zlib.NewReader(bodyReader)
		}

		d := json.NewDecoder(bodyReader)
		p := &raven.Packet{}
		err := d.Decode(p)
		if err != nil {
			ch <- nil
			panic(err.Error())
		}
		ch <- p
	})
	s := httptest.NewServer(h)
	defer s.Close()

	fragments := strings.SplitN(s.URL, "://", 2)
	dsn := fmt.Sprintf(
		"%s://public:secret@%s/sentry/project-id",
		fragments[0],
		fragments[1],
	)

	f(dsn, ch)
}
<commit_msg>Run sentry tests in parallel (#293)<commit_after>// Copyright (c) 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package sentry

import (
	"compress/zlib"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	raven "github.com/getsentry/raven-go"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"github.com/uber-go/zap"
)

type fakeClient raven.Client

func TestBadDSN(t *testing.T) {
	t.Parallel()
	_, err := New("123http://whoops")
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "failed to create sentry client")
}

func TestEmptyDSN(t *testing.T) {
	t.Parallel()
	l, err := New("")
	assert.NoError(t, err)
	assert.NotNil(t, l)
}

func TestWithLevels(t *testing.T) {
	t.Parallel()
	l, err := New("", MinLevel(zap.InfoLevel))
	assert.NoError(t, err)
	assert.NotNil(t, l)
	assert.Equal(t, l.minLevel, zap.InfoLevel)
}

func TestExtra(t *testing.T) {
	t.Parallel()
	f := map[string]interface{}{
		"requestID":         "123h2eor2039423",
		"someInt":           123,
		"arrayOfManyThings": []int{1, 2, 3},
	}
	s, err := New("", Fields(f))
	s.CheckAndFire(zap.ErrorLevel, "error log", "foo", "bar")
	assert.NoError(t, err)
	assert.Equal(t, f, s.Fields())
}

func TestWith(t *testing.T) {
	t.Parallel()
	sh, err := New("", Fields(map[string]interface{}{
		"someInt": 123,
	}))
	assert.NoError(t, err)
	expected := map[string]interface{}{"someInt": 123, "someFloat": float64(10)}
	sh.AppendFields("someFloat", float64(10))
	assert.Equal(t, expected, sh.Fields())
}

func TestCopy(t *testing.T) {
	t.Parallel()
	sh, err := New("", Fields(map[string]interface{}{
		"someInt": 123,
	}))
	assert.NoError(t, err)
	shCopy := sh.Copy()
	for k, v := range sh.Fields() {
		assert.Equal(t, v, shCopy.Fields()[k])
	}
	assert.Equal(t, sh.Capturer, shCopy.Capturer)
	assert.Equal(t, sh.minLevel, shCopy.minLevel)
	assert.Equal(t, sh.traceEnabled, shCopy.traceEnabled)
	assert.Equal(t, sh.traceSkipFrames, shCopy.traceSkipFrames)
	assert.Equal(t, sh.traceContextLines, shCopy.traceContextLines)
	assert.Equal(t, sh.traceAppPrefixes, shCopy.traceAppPrefixes)
}

func TestWithTraceDisabled(t *testing.T) {
	t.Parallel()
	_, ps := capturePackets(func(sh *Hook) {
		sh.CheckAndFire(zap.ErrorLevel, "some error message", "foo", "bar")
		sh.CheckAndFire(zap.ErrorLevel, "another error message")
	}, DisableTraces())

	for _, p := range ps {
		assert.Empty(t, p.Interfaces)
	}
}

func TestTraceCfg(t *testing.T) {
	t.Parallel()
	l, err := New(
		"",
		TraceSkipFrames(1),
		TraceContextLines(7),
		TraceAppPrefixes([]string{"github.com/uber-go/unicorns"}),
	)
	assert.NoError(t, err)
	assert.Equal(t, l.traceSkipFrames, 1)
	assert.Equal(t, l.traceContextLines, 7)
	assert.Equal(t, l.traceAppPrefixes, []string{"github.com/uber-go/unicorns"})
}

func TestLevels(t *testing.T) {
	t.Parallel()
	_, ps := capturePackets(func(sh *Hook) {
		sh.CheckAndFire(zap.DebugLevel, "debug level log")
		sh.CheckAndFire(zap.InfoLevel, "info level log")
		sh.CheckAndFire(zap.WarnLevel, "warn level log")
		sh.CheckAndFire(zap.ErrorLevel, "error level log")
	}, MinLevel(zap.WarnLevel))

	assert.Equal(t, len(ps), 2, "only Warn and Error packets should be collected")
}

func TestErrorCapture(t *testing.T) {
	t.Parallel()
	_, p := capturePacket(func(sh *Hook) {
		sh.CheckAndFire(zap.ErrorLevel, "some error message", "foo", "bar")
	})

	assert.Equal(t, p.Message, "some error message")
	assert.Equal(t, p.Extra, map[string]interface{}{"foo": "bar"})

	trace := p.Interfaces[0].(*raven.Stacktrace)
	assert.NotNil(t, trace.Frames)
}

func TestPacketSending(t *testing.T) {
	t.Parallel()
	withTestSentry(func(dsn string, ch <-chan *raven.Packet) {
		sh, err := New(dsn)
		defer sh.Close()
		assert.NoError(t, err)

		sh.CheckAndFire(zap.ErrorLevel, "my error message", "mykey1", "myvalue1")
		sh.CheckAndFire(zap.ErrorLevel, "my error message", "mykey1", "myvalue1")
		p := <-ch

		assert.Equal(t, p.Message, "my error message")
		assert.Equal(t, map[string]interface{}{"mykey1": "myvalue1"}, p.Extra)
	})
}

func TestConfigure(t *testing.T) {
	t.Parallel()
	one := 1
	two := 2
	debug := zap.DebugLevel.String()
	str := "random string"
	trace := struct {
		Disabled     bool
		SkipFrames   *int `yaml:"skip_frames"`
		ContextLines *int `yaml:"context_lines"`
	}{
		Disabled:     true,
		SkipFrames:   &one,
		ContextLines: &two,
	}

	testCases := []struct {
		name  string
		conf  Configuration
		res   *Hook
		isErr bool
	}{
		{"Empty",
			Configuration{},
			&Hook{
				traceEnabled:      true,
				minLevel:          zap.ErrorLevel,
				traceContextLines: _traceContextLines,
				traceSkipFrames:   _traceSkipFrames,
				fields:            map[string]interface{}{},
			}, false},
		{"SomeValues",
			Configuration{
				MinLevel: &debug,
				Trace:    &trace,
				Fields:   map[string]interface{}{"mickey": "mouse"},
			},
			&Hook{
				minLevel:          zap.DebugLevel,
				traceEnabled:      false,
				traceSkipFrames:   one,
				traceContextLines: two,
				fields:            map[string]interface{}{"mickey": "mouse"},
			}, false},
		{"ParseError", Configuration{MinLevel: &str}, nil, true},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			conf, err := Configure(tc.conf)
			if tc.isErr {
				assert.Error(t, err)
				return
			}

			require.NoError(t, err)
			r := tc.res
			assert.Equal(t, r.traceEnabled, conf.traceEnabled)
			assert.Equal(t, r.minLevel, conf.minLevel)
			assert.Equal(t, r.traceContextLines, conf.traceContextLines)
			assert.Equal(t, r.traceSkipFrames, conf.traceSkipFrames)
			assert.Equal(t, r.fields, conf.fields)
		})
	}
}

func capturePacket(f func(sh *Hook), options ...Option) (*Hook, *raven.Packet) {
	l, ps := capturePackets(f, options...)
	if len(ps) != 1 {
		panic("Expected to capture a packet, but didn't")
	}
	return l, ps[0]
}

func capturePackets(f func(sh *Hook), options ...Option) (*Hook, []*raven.Packet) {
	sh, err := New("", options...)
	if err != nil {
		panic("Failed to create the logger")
	}

	c := &MemCapturer{}
	sh.Capturer = c

	f(sh)

	return sh, c.Packets
}

func withTestSentry(f func(string, <-chan *raven.Packet)) {
	ch := make(chan *raven.Packet)
	h := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
		defer req.Body.Close()

		contentType := req.Header.Get("Content-Type")
		var bodyReader io.Reader = req.Body
		// underlying client will compress and encode payload above certain size
		if contentType == "application/octet-stream" {
			bodyReader = base64.NewDecoder(base64.StdEncoding, bodyReader)
			bodyReader, _ = zlib.NewReader(bodyReader)
		}

		d := json.NewDecoder(bodyReader)
		p := &raven.Packet{}
		err := d.Decode(p)
		if err != nil {
			ch <- nil
			panic(err.Error())
		}
		ch <- p
	})
	s := httptest.NewServer(h)
	defer s.Close()

	fragments := strings.SplitN(s.URL, "://", 2)
	dsn := fmt.Sprintf(
		"%s://public:secret@%s/sentry/project-id",
		fragments[0],
		fragments[1],
	)

	f(dsn, ch)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/jmoiron/sqlx"
	_ "github.com/lib/pq"
)

const (
	DBHOST   string = "localhost"
	DATABASE string = "lms2_development"
	DBUSER   string = "lms"
	DBPASS   string = ""
	SSLMODE  string = "disable"
)

var DBUrl string = fmt.Sprintf(
	"postgres://%s:%s@%s/%s?sslmode=%s",
	DBUSER, DBPASS, DBHOST, DATABASE, SSLMODE)

func NewDBConn() (db *sqlx.DB) {
	db, err := sqlx.Connect("postgres", DBUrl)
	if err != nil {
		fmt.Println(err)
		return nil
	}

	return
}
<commit_msg>Switch to builtin database/sql driver<commit_after>package main

import (
	"database/sql"
	"fmt"

	_ "github.com/lib/pq"
)

const (
	DBHOST   string = "localhost"
	DATABASE string = "lms2_db_dev"
	DBUSER   string = "lms2_db_user"
	DBPASS   string = "lms_2014"
	SSLMODE  string = "disable"
)

var DBUrl string = fmt.Sprintf(
	"postgres://%s:%s@%s/%s?sslmode=%s",
	DBUSER, DBPASS, DBHOST, DATABASE, SSLMODE)

func NewDBConn() (db *sql.DB) {
	db, err := sql.Open("postgres", DBUrl)
	if err != nil {
		fmt.Println(err)
		return nil
	}

	return
}
<|endoftext|>