<commit_before>package main

import (
	"flag"
	"github.com/owulveryck/gautomator"
	"log"
	"net/http"
	"sync"
)

func cleanup() {
	log.Println("cleanup")
}

func main() {

	//Parsing the dot
	var dotFiles []string
	var nodesFileJson = flag.String("nodes", "", "json file for node definition")
	flag.Parse()
	dotFiles = flag.Args()
	log.Println("Server mode")
	proto := "tcp"
	socket := "localhost:4546"
	go gautomator.Rserver(&proto, &socket)

	if len(dotFiles) != 0 {
		log.Println("Client mode")

		taskStructure := gautomator.ParseDotFiles(dotFiles)
		// Parse the nodes.json and adapt the tasks
		nodeStructure := gautomator.ParseNode(nodesFileJson)
		//var allSubTasks []*gautomator.TaskGraphStructure
		allSubTasks := make(map[int]*gautomator.TaskGraphStructure, 0)
		index := 0
		for _, nodeDef := range nodeStructure {
			for _, node := range nodeDef.Hosts {
				subTasks := taskStructure.GetSubstructure(nodeDef.Taskname)
				// If there is subtask
				if subTasks != nil {
					for i, _ := range subTasks.Tasks {
						subTasks.Tasks[i].Node = node
					}
					allSubTasks[index] = subTasks
					index += 1
				} else {
					// TODO Duplicate a single task
				}
			}
		}

		for _, subTask := range allSubTasks {
			//subTask.PrintAdjacencyMatrix()
			taskStructure = taskStructure.AugmentTaskStructure(subTask)
		}
		taskStructure.Relink()

		//taskStructure.PrintAdjacencyMatrix()
		// Entering the workers area
		taskStructure.PrintDot()
		var wg sync.WaitGroup
		doneChan := make(chan *gautomator.Task)

		// For each task, launch a goroutine
		for taskIndex, _ := range taskStructure.Tasks {
			go gautomator.Runner(taskStructure.Tasks[taskIndex], doneChan, &wg)
			wg.Add(1)
		}
		go gautomator.Advertize(taskStructure, doneChan)

		// This is the web displa
		router := gautomator.NewRouter(taskStructure)

		go log.Fatal(http.ListenAndServe(":8080", router))

		// Wait for all the runner(s) to be finished
		wg.Wait()
	}
}
<commit_msg>No more PrintDot here, it has been embedded in the web display http://localhost:8080/svg<commit_after>package main

import (
	"flag"
	"github.com/owulveryck/gautomator"
	"log"
	"net/http"
	"sync"
)

func cleanup() {
	log.Println("cleanup")
}

func main() {

	//Parsing the dot
	var dotFiles []string
	var nodesFileJson = flag.String("nodes", "", "json file for node definition")
	flag.Parse()
	dotFiles = flag.Args()
	log.Println("Server mode")
	proto := "tcp"
	socket := "localhost:4546"
	go gautomator.Rserver(&proto, &socket)

	if len(dotFiles) != 0 {
		log.Println("Client mode")

		taskStructure := gautomator.ParseDotFiles(dotFiles)
		// Parse the nodes.json and adapt the tasks
		nodeStructure := gautomator.ParseNode(nodesFileJson)
		//var allSubTasks []*gautomator.TaskGraphStructure
		allSubTasks := make(map[int]*gautomator.TaskGraphStructure, 0)
		index := 0
		for _, nodeDef := range nodeStructure {
			for _, node := range nodeDef.Hosts {
				subTasks := taskStructure.GetSubstructure(nodeDef.Taskname)
				// If there is subtask
				if subTasks != nil {
					for i, _ := range subTasks.Tasks {
						subTasks.Tasks[i].Node = node
					}
					allSubTasks[index] = subTasks
					index += 1
				} else {
					// TODO Duplicate a single task
				}
			}
		}

		for _, subTask := range allSubTasks {
			//subTask.PrintAdjacencyMatrix()
			taskStructure = taskStructure.AugmentTaskStructure(subTask)
		}
		taskStructure.Relink()

		//taskStructure.PrintAdjacencyMatrix()
		// Entering the workers area
		var wg sync.WaitGroup
		doneChan := make(chan *gautomator.Task)

		// For each task, launch a goroutine
		for taskIndex, _ := range taskStructure.Tasks {
			go gautomator.Runner(taskStructure.Tasks[taskIndex], doneChan, &wg)
			wg.Add(1)
		}
		go gautomator.Advertize(taskStructure, doneChan)

		// This is the web displa
		router := gautomator.NewRouter(taskStructure)

		go log.Fatal(http.ListenAndServe(":8080", router))

		// Wait for all the runner(s) to be finished
		wg.Wait()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"io"
	"time"
)

type NodeType int
type NodeMap [][]NodeType

const (
	T21Node NodeType = iota
	T30Node
	T31Node
)

type Tis100 struct {
	clock <-chan time.Time
	nodes [][]*T21 // TODO: Need to support other node types
}

func NewTis100(nodes NodeMap) *Tis100 {
	// All rows need to be the same length
	l := len(nodes[0])
	for i := 1; i < len(nodes); i++ {
		if len(nodes[i]) != l {
			panic("all rows must be the same length")
		}
	}

	t := &Tis100{
		clock: time.Tick(time.Millisecond * 10),
	}

	for _, list := range nodes {
		var cnodes []*T21

		for _, node := range list {
			switch node {
			case T21Node:
				cnodes = append(cnodes, NewT21())
			default:
				panic("uknown node type")
			}
		}

		t.nodes = append(t.nodes, cnodes)
	}

	// Connect nodes
	for r, row := range t.nodes {
		for i := 0; i < len(row)-1; i++ {
			row[i].ConnectRight(row[i+1])
		}

		for i := 0; i < len(row); i++ {
			if r < len(t.nodes)-1 {
				row[i].ConnectDown(t.nodes[r+1][i])
			}
		}
	}

	return t
}

func (t *Tis100) Input(in chan int, node int) {
	row, col := t.nodeOffsets(node)
	t.nodes[row][col].up = in
}

func (t *Tis100) Output(node int) chan int {
	row, col := t.nodeOffsets(node)

	out := make(chan int)
	t.nodes[row][col].down = out
	return out
}

func (t *Tis100) Program(r io.Reader) {
	p := NewParser(r)

	curNode := 0
	programs := make(map[int][]Statement, 0)

	for {
		stmt, err := p.Parse()
		if err != nil {
			panic(err)
		}
		if stmt.Op == EOF {
			break
		} else if stmt.Op == COMMENT {
			continue
		} else if stmt.Op == NODE {
			curNode = int(stmt.Src)
		} else {
			programs[curNode] = append(programs[curNode], stmt)
		}
	}

	for idx, program := range programs {
		row, col := t.nodeOffsets(idx)
		t.nodes[row][col].Program(program)
	}
}

func (t *Tis100) Run() {
	for _, nodes := range t.nodes {
		for _, node := range nodes {
			node.Run()
		}
	}

	go func() {
		for {
			<-t.clock
			for _, nodes := range t.nodes {
				for _, node := range nodes {
					node.tick()
				}
			}
		}
	}()
}

func (t *Tis100) nodeOffsets(node int) (int, int) {
	row := node / len(t.nodes[0])
	col := node % len(t.nodes[0])
	return row, col
}
<commit_msg>go faster<commit_after>package main

import (
	"io"
	"time"
)

type NodeType int
type NodeMap [][]NodeType

const (
	T21Node NodeType = iota
	T30Node
	T31Node
)

type Tis100 struct {
	clock <-chan time.Time
	nodes [][]*T21 // TODO: Need to support other node types
}

func NewTis100(nodes NodeMap) *Tis100 {
	// All rows need to be the same length
	l := len(nodes[0])
	for i := 1; i < len(nodes); i++ {
		if len(nodes[i]) != l {
			panic("all rows must be the same length")
		}
	}

	t := &Tis100{
		clock: time.Tick(time.Millisecond),
	}

	for _, list := range nodes {
		var cnodes []*T21

		for _, node := range list {
			switch node {
			case T21Node:
				cnodes = append(cnodes, NewT21())
			default:
				panic("uknown node type")
			}
		}

		t.nodes = append(t.nodes, cnodes)
	}

	// Connect nodes
	for r, row := range t.nodes {
		for i := 0; i < len(row)-1; i++ {
			row[i].ConnectRight(row[i+1])
		}

		for i := 0; i < len(row); i++ {
			if r < len(t.nodes)-1 {
				row[i].ConnectDown(t.nodes[r+1][i])
			}
		}
	}

	return t
}

func (t *Tis100) Input(in chan int, node int) {
	row, col := t.nodeOffsets(node)
	t.nodes[row][col].up = in
}

func (t *Tis100) Output(node int) chan int {
	row, col := t.nodeOffsets(node)

	out := make(chan int)
	t.nodes[row][col].down = out
	return out
}

func (t *Tis100) Program(r io.Reader) {
	p := NewParser(r)

	curNode := 0
	programs := make(map[int][]Statement, 0)

	for {
		stmt, err := p.Parse()
		if err != nil {
			panic(err)
		}
		if stmt.Op == EOF {
			break
		} else if stmt.Op == COMMENT {
			continue
		} else if stmt.Op == NODE {
			curNode = int(stmt.Src)
		} else {
			programs[curNode] = append(programs[curNode], stmt)
		}
	}

	for idx, program := range programs {
		row, col := t.nodeOffsets(idx)
		t.nodes[row][col].Program(program)
	}
}

func (t *Tis100) Run() {
	for _, nodes := range t.nodes {
		for _, node := range nodes {
			node.Run()
		}
	}

	go func() {
		for {
			<-t.clock
			for _, nodes := range t.nodes {
				for _, node := range nodes {
					node.tick()
				}
			}
		}
	}()
}

func (t *Tis100) nodeOffsets(node int) (int, int) {
	row := node / len(t.nodes[0])
	col := node % len(t.nodes[0])
	return row, col
}
<|endoftext|>


<commit_before>package models

import (
	"database/sql"
	"errors"
	"fmt"
	"github.com/sendgrid/sendgrid-go"
	"github.com/sendgrid/sendgrid-go/helpers/mail"
	"net/http"
	"os"
)

const (
	DEFAULT_LISTING_SUBJECT = "I am interested in buying an item from you: %s"
	DEFAULT_SEEK_SUBJECT    = "I am interested in selling an item to you: %s"
)

type emailInput struct {
	Sender    string
	Recepient string
	Subject   string
	Body      string `json:"body"`
}

func NewEmailInput(db *sql.DB, id string, isSeek bool) (*emailInput, error, int) {
	i := new(emailInput)

	var title string
	var ownerId int
	if isSeek {
		seek, err, code := ReadSeek(db, id)
		if err != nil {
			return nil, err, code
		}
		title = seek.Title
		ownerId = seek.UserID
	} else {
		listing, err, code := ReadListing(db, id)
		if err != nil {
			return nil, err, code
		}
		title = listing.Title
		ownerId = listing.UserID
	}

	if isSeek {
		i.Subject = fmt.Sprintf(DEFAULT_SEEK_SUBJECT, title)
	} else {
		i.Subject = fmt.Sprintf(DEFAULT_LISTING_SUBJECT, title)
	}

	if owner, err := GetUserByID(db, ownerId); err != nil {
		return nil, err, http.StatusInternalServerError
	} else {
		i.Recepient = owner.NetID
	}

	return i, nil, http.StatusOK
}

func getEmail(netId string) *mail.Email {
	addr := netId + "@princeton.edu" // TODO WARNING We can't assume this.
	return mail.NewEmail(netId, addr)
}

func SendEmail(input *emailInput) (error, int) {

	if input.Sender == input.Recepient {
		return errors.New("To and From fields cannot be the same."), http.StatusBadRequest
	}

	// Get email addresses
	from := getEmail(input.Sender)
	to := getEmail(input.Recepient)
	content := mail.NewContent("text/plain", input.Body)

	// Create email
	m := mail.NewV3Mail()
	m.SetFrom(from)
	p := mail.NewPersonalization()
	p.AddTos(to)
	p.AddCCs(from) // So that the sender still gets a copy in their inbox.
	p.Subject = input.Subject
	m.AddPersonalizations(p)
	m.AddContent(content)

	// Send email, hope for the best
	request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com")
	request.Method = "POST"
	request.Body = mail.GetRequestBody(m)
	response, err := sendgrid.API(request)
	if err != nil {
		return err, http.StatusInternalServerError
	}

	if response.StatusCode != 202 {
		err = errors.New(fmt.Sprint("Response not queued for sending. Status code: ", response.StatusCode))
	}

	return err, response.StatusCode
}
<commit_msg>add transactional templates<commit_after>package models

import (
	"database/sql"
	"errors"
	"fmt"
	"github.com/sendgrid/sendgrid-go"
	"github.com/sendgrid/sendgrid-go/helpers/mail"
	"net/http"
	"os"
)

const (
	DEFAULT_LISTING_SUBJECT = "I am interested in buying an item from you: %s"
	DEFAULT_SEEK_SUBJECT    = "I am interested in selling an item to you: %s"
)

type emailInput struct {
	Sender    string
	Recepient string
	Subject   string
	Body      string `json:"body"`
}

func NewEmailInput(db *sql.DB, id string, isSeek bool) (*emailInput, error, int) {
	i := new(emailInput)

	var title string
	var ownerId int
	if isSeek {
		seek, err, code := ReadSeek(db, id)
		if err != nil {
			return nil, err, code
		}
		title = seek.Title
		ownerId = seek.UserID
	} else {
		listing, err, code := ReadListing(db, id)
		if err != nil {
			return nil, err, code
		}
		title = listing.Title
		ownerId = listing.UserID
	}

	if isSeek {
		i.Subject = fmt.Sprintf(DEFAULT_SEEK_SUBJECT, title)
	} else {
		i.Subject = fmt.Sprintf(DEFAULT_LISTING_SUBJECT, title)
	}

	if owner, err := GetUserByID(db, ownerId); err != nil {
		return nil, err, http.StatusInternalServerError
	} else {
		i.Recepient = owner.NetID
	}

	return i, nil, http.StatusOK
}

func getEmail(netId string) *mail.Email {
	addr := netId + "@princeton.edu" // TODO WARNING We can't assume this.
	return mail.NewEmail(netId, addr)
}

func SendEmail(input *emailInput) (error, int) {

	if input.Sender == input.Recepient {
		return errors.New("To and From fields cannot be the same."), http.StatusBadRequest
	}

	// Get email addresses
	from := getEmail(input.Sender)
	to := getEmail(input.Recepient)
	content := mail.NewContent("text/plain", input.Body)

	// Create email
	m := mail.NewV3Mail()
	m.SetFrom(from)
	p := mail.NewPersonalization()
	p.AddTos(to)
	p.AddCCs(from) // So that the sender still gets a copy in their inbox.
	p.Subject = input.Subject
	m.AddPersonalizations(p)
	m.AddContent(content)
	m.SetTemplateID("f74e9873-ae64-4dde-b61b-20861f9fd645")

	// Send email, hope for the best
	request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com")
	request.Method = "POST"
	request.Body = mail.GetRequestBody(m)
	response, err := sendgrid.API(request)
	if err != nil {
		return err, http.StatusInternalServerError
	}

	if response.StatusCode != 202 {
		err = errors.New(fmt.Sprint("Response not queued for sending. Status code: ", response.StatusCode))
	}

	return err, response.StatusCode
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"

	"bitbucket.org/smartystreets/smartystreets-go-sdk/us-street-api"
)

func main() {
	log.SetFlags(log.Ltime)

	client, err := us_street.NewClientBuilder().
		WithSecretKeyCredential(os.Getenv("SMARTY_AUTH_ID"), os.Getenv("SMARTY_AUTH_TOKEN")).
		Build()

	if err != nil {
		log.Fatal("Error building client:", err)
	}

	batch := us_street.NewBatch()
	for batch.Append(&us_street.Lookup{Street: "3214 N University ave", LastLine: "Provo UT 84604"}) {
		fmt.Print(".")
	}
	fmt.Println("\nBatch full, preparing to send inputs:", batch.Length())

	if err = client.SendBatch(batch); err != nil {
		log.Fatal("Error sending batch:", err)
	}

	for i, input := range batch.Records() {
		fmt.Println("Input:", i)
		for j, candidate := range input.Results {
			fmt.Println("Candidate:", j)
			fmt.Println(candidate.DeliveryLine1)
			fmt.Println(candidate.LastLine)
			fmt.Println()
		}
	}
}
<commit_msg>Compilation.<commit_after>package main

import (
	"fmt"
	"log"
	"os"

	"bitbucket.org/smartystreets/smartystreets-go-sdk/us-street-api"
)

func main() {
	log.SetFlags(log.Ltime)

	client := us_street.NewClientBuilder().
		WithSecretKeyCredential(os.Getenv("SMARTY_AUTH_ID"), os.Getenv("SMARTY_AUTH_TOKEN")).
		Build()

	batch := us_street.NewBatch()
	for batch.Append(&us_street.Lookup{Street: "3214 N University ave", LastLine: "Provo UT 84604"}) {
		fmt.Print(".")
	}
	fmt.Println("\nBatch full, preparing to send inputs:", batch.Length())

	if err := client.SendBatch(batch); err != nil {
		log.Fatal("Error sending batch:", err)
	}

	for i, input := range batch.Records() {
		fmt.Println("Input:", i)
		for j, candidate := range input.Results {
			fmt.Println("Candidate:", j)
			fmt.Println(candidate.DeliveryLine1)
			fmt.Println(candidate.LastLine)
			fmt.Println()
		}
	}
}
<|endoftext|>


<commit_before>package pgmgr

import (
	"bytes"
	"database/sql"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/lib/pq"
)

// Migration directions
const (
	DOWN = iota
	UP
)

const datetimeFormat = "20060102130405"

// Migration directions used for error message building
const (
	MIGRATION = "migration"
	ROLLBACK  = "rollback"
)

// Migration stores a single migration's version and filename.
type Migration struct {
	Filename string
	Version  int64
}

// WrapInTransaction returns whether the migration should be run within
// a transaction.
func (m Migration) WrapInTransaction() bool {
	return !strings.Contains(m.Filename, ".no_txn.")
}

// Create creates the database specified by the configuration.
func Create(c *Config) error {
	return sh("createdb", []string{c.Database})
}

// Drop drops the database specified by the configuration.
func Drop(c *Config) error {
	return sh("dropdb", []string{c.Database})
}

// Dump dumps the schema and contents of the database to the dump file.
func Dump(c *Config) error {
	// dump schema first...
	schema, err := shRead("pg_dump", []string{"--schema-only", c.Database})
	if err != nil {
		return err
	}

	// then selected data...
	args := []string{c.Database, "--data-only"}
	if len(c.SeedTables) > 0 {
		for _, table := range c.SeedTables {
			println("pulling data for", table)
			args = append(args, "-t", table)
		}
	}
	println(strings.Join(args, ""))

	seeds, err := shRead("pg_dump", args)
	if err != nil {
		return err
	}

	// and combine into one file.
	file, err := os.OpenFile(c.DumpFile, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0600)
	if err != nil {
		return err
	}

	file.Write(*schema)
	file.Write(*seeds)
	file.Close()

	return nil
}

// Load loads the database from the dump file using psql.
func Load(c *Config) error {
	return sh("psql", []string{"-d", c.Database, "-f", c.DumpFile})
}

// Migrate applies un-applied migrations in the specified MigrationFolder.
func Migrate(c *Config) error {
	migrations, err := migrations(c, "up")
	if err != nil {
		return err
	}

	// ensure the version table is created
	if err := Initialize(c); err != nil {
		return err
	}

	appliedAny := false
	for _, m := range migrations {
		if applied, _ := migrationIsApplied(c, m.Version); !applied {
			fmt.Println("== Applying", m.Filename, "==")
			t0 := time.Now()

			if err = applyMigration(c, m, UP); err != nil { // halt the migration process and return the error.
				printFailedMigrationMessage(err, MIGRATION)
				return err
			}

			fmt.Println("== Completed in", time.Now().Sub(t0).Nanoseconds()/1e6, "ms ==")
			appliedAny = true
		}
	}

	if !appliedAny {
		fmt.Println("Nothing to do; all migrations already applied.")
	}

	return nil
}

// Rollback un-applies the latest migration, if possible.
func Rollback(c *Config) error {
	migrations, err := migrations(c, "down")
	if err != nil {
		return err
	}

	v, _ := Version(c)
	var toRollback *Migration
	for _, m := range migrations {
		if m.Version == v {
			toRollback = &m
			break
		}
	}

	if toRollback == nil {
		return nil
	}

	// rollback only the last migration
	fmt.Println("== Reverting", toRollback.Filename, "==")
	t0 := time.Now()

	if err = applyMigration(c, *toRollback, DOWN); err != nil {
		printFailedMigrationMessage(err, ROLLBACK)
		return err
	}

	fmt.Println("== Completed in", time.Now().Sub(t0).Nanoseconds()/1e6, "ms ==")

	return nil
}

// Version returns the highest version number stored in the database. This is not
// necessarily enough info to uniquely identify the version, since there may
// be backdated migrations which have not yet applied.
func Version(c *Config) (int64, error) {
	db, err := openConnection(c)
	defer db.Close()

	if err != nil {
		return -1, err
	}

	exists, err := migrationTableExists(c, db)
	if err != nil {
		return -1, err
	}

	if !exists {
		return -1, nil
	}

	var version int64
	err = db.QueryRow(fmt.Sprintf(
		`SELECT COALESCE(MAX(version)::text, '-1') FROM %s`,
		c.quotedMigrationTable(),
	)).Scan(&version)

	return version, err
}

// Initialize creates the schema_migrations table if necessary.
func Initialize(c *Config) error {
	db, err := openConnection(c)
	defer db.Close()
	if err != nil {
		return err
	}

	if err := createSchemaUnlessExists(c, db); err != nil {
		return err
	}

	tableExists, err := migrationTableExists(c, db)
	if err != nil {
		return err
	}

	if tableExists {
		return nil
	}

	_, err = db.Exec(fmt.Sprintf(
		"CREATE TABLE %s (version %s NOT NULL UNIQUE);",
		c.quotedMigrationTable(),
		c.versionColumnType(),
	))

	if err != nil {
		return err
	}

	return nil
}

// CreateMigration generates new, empty migration files.
func CreateMigration(c *Config, name string, noTransaction bool) error {
	version := generateVersion(c)
	prefix := fmt.Sprint(version, "_", name)

	if noTransaction {
		prefix += ".no_txn"
	}

	upFilepath := filepath.Join(c.MigrationFolder, prefix+".up.sql")
	downFilepath := filepath.Join(c.MigrationFolder, prefix+".down.sql")

	err := ioutil.WriteFile(upFilepath, []byte(`-- Migration goes here.`), 0644)
	if err != nil {
		return err
	}
	fmt.Println("Created", upFilepath)

	err = ioutil.WriteFile(downFilepath, []byte(`-- Rollback of migration goes here. If you don't want to write it, delete this file.`), 0644)
	if err != nil {
		return err
	}
	fmt.Println("Created", downFilepath)

	return nil
}

func generateVersion(c *Config) string {
	// TODO: guarantee no conflicts by incrementing if there is a conflict
	t := time.Now()

	if c.Format == "datetime" {
		return t.Format(datetimeFormat)
	}

	return strconv.FormatInt(t.Unix(), 10)
}

// need access to the original query contents in order to print it out properly,
// unfortunately.
func formatPgErr(contents *[]byte, pgerr *pq.Error) string {
	pos, _ := strconv.Atoi(pgerr.Position)
	lineNo := bytes.Count((*contents)[:pos], []byte("\n")) + 1
	columnNo := pos - bytes.LastIndex((*contents)[:pos], []byte("\n")) - 1

	return fmt.Sprint("PGERROR: line ", lineNo, " pos ", columnNo, ": ", pgerr.Message, ". ", pgerr.Detail)
}

type execer interface {
	Exec(query string, args ...interface{}) (sql.Result, error)
}

func applyMigration(c *Config, m Migration, direction int) error {
	var tx *sql.Tx
	var exec execer

	rollback := func() {
		if tx != nil {
			tx.Rollback()
		}
	}

	contents, err := ioutil.ReadFile(filepath.Join(c.MigrationFolder, m.Filename))
	if err != nil {
		return err
	}

	db, err := openConnection(c)
	defer db.Close()
	if err != nil {
		return err
	}
	exec = db

	if m.WrapInTransaction() {
		tx, err = db.Begin()
		if err != nil {
			return err
		}
		exec = tx
	}

	if _, err = exec.Exec(string(contents)); err != nil {
		rollback()
		return errors.New(formatPgErr(&contents, err.(*pq.Error)))
	}

	if direction == UP {
		if err = insertSchemaVersion(c, exec, m.Version); err != nil {
			rollback()
			return errors.New(formatPgErr(&contents, err.(*pq.Error)))
		}
	} else {
		if err = deleteSchemaVersion(c, exec, m.Version); err != nil {
			rollback()
			return errors.New(formatPgErr(&contents, err.(*pq.Error)))
		}
	}

	if tx != nil {
		err = tx.Commit()
		if err != nil {
			return err
		}
	}

	return nil
}

func createSchemaUnlessExists(c *Config, db *sql.DB) error {
	// If there's no schema name in the config, we don't need to create the schema.
	if !strings.Contains(c.MigrationTable, ".") {
		return nil
	}

	var exists bool

	schema := strings.SplitN(c.MigrationTable, ".", 2)[0]
	err := db.QueryRow(
		`SELECT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace WHERE nspname = $1)`,
		schema,
	).Scan(&exists)

	if err != nil {
		return err
	}

	if exists {
		return nil
	}

	_, err = db.Exec(fmt.Sprintf(
		"CREATE SCHEMA %s;",
		pq.QuoteIdentifier(schema),
	))
	return err
}

func insertSchemaVersion(c *Config, tx execer, version int64) error {
	_, err := tx.Exec(
		fmt.Sprintf(`INSERT INTO %s (version) VALUES ($1) RETURNING version;`, c.quotedMigrationTable()),
		typedVersion(c, version),
	)
	return err
}

func deleteSchemaVersion(c *Config, tx execer, version int64) error {
	_, err := tx.Exec(
		fmt.Sprintf(`DELETE FROM %s WHERE version = $1`, c.quotedMigrationTable()),
		typedVersion(c, version),
	)
	return err
}

func typedVersion(c *Config, version int64) interface{} {
	if c.ColumnType == "string" {
		return strconv.FormatInt(version, 10)
	}
	return version
}

func migrationTableExists(c *Config, db *sql.DB) (bool, error) {
	var hasTable bool
	var err error

	if strings.Contains(c.MigrationTable, ".") {
		tokens := strings.SplitN(c.MigrationTable, ".", 2)
		err = db.QueryRow(
			`SELECT EXISTS(SELECT 1 FROM pg_catalog.pg_tables WHERE schemaname = $1 AND tablename = $2)`,
			tokens[0], tokens[1],
		).Scan(&hasTable)
	} else {
		err = db.QueryRow(
			`SELECT EXISTS(SELECT 1 FROM pg_catalog.pg_tables WHERE tablename = $1)`,
			c.MigrationTable,
		).Scan(&hasTable)
	}

	return hasTable, err
}

func migrationIsApplied(c *Config, version int64) (bool, error) {
	db, err := openConnection(c)
	defer db.Close()
	if err != nil {
		return false, err
	}

	var applied bool
	err = db.QueryRow(
		fmt.Sprintf(`SELECT EXISTS(SELECT 1 FROM %s WHERE version = $1)`, c.quotedMigrationTable()),
		version,
	).Scan(&applied)

	if err != nil {
		return false, err
	}

	return applied, nil
}

func openConnection(c *Config) (*sql.DB, error) {
	db, err := sql.Open("postgres", sqlConnectionString(c))
	return db, err
}

func sqlConnectionString(c *Config) string {
	return fmt.Sprint(
		" user='", c.Username, "'",
		" dbname='", c.Database, "'",
		" password='", c.Password, "'",
		" host='", c.Host, "'",
		" port=", c.Port,
		" sslmode=", c.SslMode)
}

func migrations(c *Config, direction string) ([]Migration, error) {
	re := regexp.MustCompile("^[0-9]+")

	migrations := []Migration{}
	files, err := ioutil.ReadDir(c.MigrationFolder)
	if err != nil {
		return migrations, err
	}

	for _, file := range files {
		if match, _ := regexp.MatchString("^[0-9]+_.+\\."+direction+"\\.sql$", file.Name()); match {
			version, _ := strconv.ParseInt(re.FindString(file.Name()), 10, 64)
			migrations = append(migrations, Migration{Filename: file.Name(), Version: version})
		}
	}

	return migrations, nil
}

func sh(command string, args []string) error {
	c := exec.Command(command, args...)
	output, err := c.CombinedOutput()
	fmt.Println(string(output))
	if err != nil {
		return err
	}

	return nil
}

func shRead(command string, args []string) (*[]byte, error) {
	c := exec.Command(command, args...)
	output, err := c.CombinedOutput()
	return &output, err
}

func printFailedMigrationMessage(err error, migrationType string) {
	fmt.Fprintf(os.Stderr, err.Error())
	fmt.Fprintf(os.Stderr, "\n\n")
	fmt.Fprintf(os.Stderr, "ERROR! Aborting the "+migrationType+" process.\n")
}
<commit_msg>Build the connection string with only known values (#34)<commit_after>package pgmgr

import (
	"bytes"
	"database/sql"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/lib/pq"
)

// Migration directions
const (
	DOWN = iota
	UP
)

const datetimeFormat = "20060102130405"

// Migration directions used for error message building
const (
	MIGRATION = "migration"
	ROLLBACK  = "rollback"
)

// Migration stores a single migration's version and filename.
type Migration struct {
	Filename string
	Version  int64
}

// WrapInTransaction returns whether the migration should be run within
// a transaction.
func (m Migration) WrapInTransaction() bool {
	return !strings.Contains(m.Filename, ".no_txn.")
}

// Create creates the database specified by the configuration.
func Create(c *Config) error {
	return sh("createdb", []string{c.Database})
}

// Drop drops the database specified by the configuration.
func Drop(c *Config) error {
	return sh("dropdb", []string{c.Database})
}

// Dump dumps the schema and contents of the database to the dump file.
func Dump(c *Config) error {
	// dump schema first...
	schema, err := shRead("pg_dump", []string{"--schema-only", c.Database})
	if err != nil {
		return err
	}

	// then selected data...
	args := []string{c.Database, "--data-only"}
	if len(c.SeedTables) > 0 {
		for _, table := range c.SeedTables {
			println("pulling data for", table)
			args = append(args, "-t", table)
		}
	}
	println(strings.Join(args, ""))

	seeds, err := shRead("pg_dump", args)
	if err != nil {
		return err
	}

	// and combine into one file.
	file, err := os.OpenFile(c.DumpFile, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0600)
	if err != nil {
		return err
	}

	file.Write(*schema)
	file.Write(*seeds)
	file.Close()

	return nil
}

// Load loads the database from the dump file using psql.
func Load(c *Config) error {
	return sh("psql", []string{"-d", c.Database, "-f", c.DumpFile})
}

// Migrate applies un-applied migrations in the specified MigrationFolder.
func Migrate(c *Config) error {
	migrations, err := migrations(c, "up")
	if err != nil {
		return err
	}

	// ensure the version table is created
	if err := Initialize(c); err != nil {
		return err
	}

	appliedAny := false
	for _, m := range migrations {
		if applied, _ := migrationIsApplied(c, m.Version); !applied {
			fmt.Println("== Applying", m.Filename, "==")
			t0 := time.Now()

			if err = applyMigration(c, m, UP); err != nil { // halt the migration process and return the error.
				printFailedMigrationMessage(err, MIGRATION)
				return err
			}

			fmt.Println("== Completed in", time.Now().Sub(t0).Nanoseconds()/1e6, "ms ==")
			appliedAny = true
		}
	}

	if !appliedAny {
		fmt.Println("Nothing to do; all migrations already applied.")
	}

	return nil
}

// Rollback un-applies the latest migration, if possible.
func Rollback(c *Config) error {
	migrations, err := migrations(c, "down")
	if err != nil {
		return err
	}

	v, _ := Version(c)
	var toRollback *Migration
	for _, m := range migrations {
		if m.Version == v {
			toRollback = &m
			break
		}
	}

	if toRollback == nil {
		return nil
	}

	// rollback only the last migration
	fmt.Println("== Reverting", toRollback.Filename, "==")
	t0 := time.Now()

	if err = applyMigration(c, *toRollback, DOWN); err != nil {
		printFailedMigrationMessage(err, ROLLBACK)
		return err
	}

	fmt.Println("== Completed in", time.Now().Sub(t0).Nanoseconds()/1e6, "ms ==")

	return nil
}

// Version returns the highest version number stored in the database. This is not
// necessarily enough info to uniquely identify the version, since there may
// be backdated migrations which have not yet applied.
func Version(c *Config) (int64, error) {
	db, err := openConnection(c)
	defer db.Close()

	if err != nil {
		return -1, err
	}

	exists, err := migrationTableExists(c, db)
	if err != nil {
		return -1, err
	}

	if !exists {
		return -1, nil
	}

	var version int64
	err = db.QueryRow(fmt.Sprintf(
		`SELECT COALESCE(MAX(version)::text, '-1') FROM %s`,
		c.quotedMigrationTable(),
	)).Scan(&version)

	return version, err
}

// Initialize creates the schema_migrations table if necessary.
func Initialize(c *Config) error {
	db, err := openConnection(c)
	defer db.Close()
	if err != nil {
		return err
	}

	if err := createSchemaUnlessExists(c, db); err != nil {
		return err
	}

	tableExists, err := migrationTableExists(c, db)
	if err != nil {
		return err
	}

	if tableExists {
		return nil
	}

	_, err = db.Exec(fmt.Sprintf(
		"CREATE TABLE %s (version %s NOT NULL UNIQUE);",
		c.quotedMigrationTable(),
		c.versionColumnType(),
	))

	if err != nil {
		return err
	}

	return nil
}

// CreateMigration generates new, empty migration files.
func CreateMigration(c *Config, name string, noTransaction bool) error {
	version := generateVersion(c)
	prefix := fmt.Sprint(version, "_", name)

	if noTransaction {
		prefix += ".no_txn"
	}

	upFilepath := filepath.Join(c.MigrationFolder, prefix+".up.sql")
	downFilepath := filepath.Join(c.MigrationFolder, prefix+".down.sql")

	err := ioutil.WriteFile(upFilepath, []byte(`-- Migration goes here.`), 0644)
	if err != nil {
		return err
	}
	fmt.Println("Created", upFilepath)

	err = ioutil.WriteFile(downFilepath, []byte(`-- Rollback of migration goes here. If you don't want to write it, delete this file.`), 0644)
	if err != nil {
		return err
	}
	fmt.Println("Created", downFilepath)

	return nil
}

func generateVersion(c *Config) string {
	// TODO: guarantee no conflicts by incrementing if there is a conflict
	t := time.Now()

	if c.Format == "datetime" {
		return t.Format(datetimeFormat)
	}

	return strconv.FormatInt(t.Unix(), 10)
}

// need access to the original query contents in order to print it out properly,
// unfortunately.
func formatPgErr(contents *[]byte, pgerr *pq.Error) string {
	pos, _ := strconv.Atoi(pgerr.Position)
	lineNo := bytes.Count((*contents)[:pos], []byte("\n")) + 1
	columnNo := pos - bytes.LastIndex((*contents)[:pos], []byte("\n")) - 1

	return fmt.Sprint("PGERROR: line ", lineNo, " pos ", columnNo, ": ", pgerr.Message, ". ", pgerr.Detail)
}

type execer interface {
	Exec(query string, args ...interface{}) (sql.Result, error)
}

func applyMigration(c *Config, m Migration, direction int) error {
	var tx *sql.Tx
	var exec execer

	rollback := func() {
		if tx != nil {
			tx.Rollback()
		}
	}

	contents, err := ioutil.ReadFile(filepath.Join(c.MigrationFolder, m.Filename))
	if err != nil {
		return err
	}

	db, err := openConnection(c)
	defer db.Close()
	if err != nil {
		return err
	}
	exec = db

	if m.WrapInTransaction() {
		tx, err = db.Begin()
		if err != nil {
			return err
		}
		exec = tx
	}

	if _, err = exec.Exec(string(contents)); err != nil {
		rollback()
		return errors.New(formatPgErr(&contents, err.(*pq.Error)))
	}

	if direction == UP {
		if err = insertSchemaVersion(c, exec, m.Version); err != nil {
			rollback()
			return errors.New(formatPgErr(&contents, err.(*pq.Error)))
		}
	} else {
		if err = deleteSchemaVersion(c, exec, m.Version); err != nil {
			rollback()
			return errors.New(formatPgErr(&contents, err.(*pq.Error)))
		}
	}

	if tx != nil {
		err = tx.Commit()
		if err != nil {
			return err
		}
	}

	return nil
}

func createSchemaUnlessExists(c *Config, db *sql.DB) error {
	// If there's no schema name in the config, we don't need to create the schema.
	if !strings.Contains(c.MigrationTable, ".") {
		return nil
	}

	var exists bool

	schema := strings.SplitN(c.MigrationTable, ".", 2)[0]
	err := db.QueryRow(
		`SELECT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace WHERE nspname = $1)`,
		schema,
	).Scan(&exists)

	if err != nil {
		return err
	}

	if exists {
		return nil
	}

	_, err = db.Exec(fmt.Sprintf(
		"CREATE SCHEMA %s;",
		pq.QuoteIdentifier(schema),
	))
	return err
}

func insertSchemaVersion(c *Config, tx execer, version int64) error {
	_, err := tx.Exec(
		fmt.Sprintf(`INSERT INTO %s (version) VALUES ($1) RETURNING version;`, c.quotedMigrationTable()),
		typedVersion(c, version),
	)
	return err
}

func deleteSchemaVersion(c *Config, tx execer, version int64) error {
	_, err := tx.Exec(
		fmt.Sprintf(`DELETE FROM %s WHERE version = $1`, c.quotedMigrationTable()),
		typedVersion(c, version),
	)
	return err
}

func typedVersion(c *Config, version int64) interface{} {
	if c.ColumnType == "string" {
		return strconv.FormatInt(version, 10)
	}
	return version
}

func migrationTableExists(c *Config, db *sql.DB) (bool, error) {
	var hasTable bool
	var err error

	if strings.Contains(c.MigrationTable, ".") {
		tokens := strings.SplitN(c.MigrationTable, ".", 2)
		err = db.QueryRow(
			`SELECT EXISTS(SELECT 1 FROM pg_catalog.pg_tables WHERE schemaname = $1 AND tablename = $2)`,
			tokens[0], tokens[1],
		).Scan(&hasTable)
	} else {
		err = db.QueryRow(
			`SELECT EXISTS(SELECT 1 FROM pg_catalog.pg_tables WHERE tablename = $1)`,
			c.MigrationTable,
		).Scan(&hasTable)
	}

	return hasTable, err
}

func migrationIsApplied(c *Config, version int64) (bool, error) {
	db, err := openConnection(c)
	defer db.Close()
	if err != nil {
		return false, err
	}

	var applied bool
	err = db.QueryRow(
		fmt.Sprintf(`SELECT EXISTS(SELECT 1 FROM %s WHERE version = $1)`, c.quotedMigrationTable()),
		version,
	).Scan(&applied)

	if err != nil {
		return false, err
	}

	return applied, nil
}

func openConnection(c *Config) (*sql.DB, error) {
	db, err := sql.Open("postgres", sqlConnectionString(c))
	return db, err
}

func sqlConnectionString(c *Config) string {
	args := make([]interface{}, 0)

	if c.Database != "" {
		args = append(args, " dbname='", c.Database, "'")
	}

	if c.Password != "" {
		args = append(args, " password='", c.Password, "'")
	}

	args = append(args,
		" host='", c.Host, "'",
		" port=", c.Port,
		" sslmode=", c.SslMode)

	return fmt.Sprint(args...)
}

func migrations(c *Config, direction string) ([]Migration, error) {
	re := regexp.MustCompile("^[0-9]+")

	migrations := []Migration{}
	files, err := ioutil.ReadDir(c.MigrationFolder)
	if err != nil {
		return migrations, err
	}

	for _, file := range files {
		if match, _ := regexp.MatchString("^[0-9]+_.+\\."+direction+"\\.sql$", file.Name()); match {
			version, _ := strconv.ParseInt(re.FindString(file.Name()), 10, 64)
			migrations = append(migrations, Migration{Filename: file.Name(), Version: version})
		}
	}

	return migrations, nil
}

func sh(command string, args []string) error {
	c := exec.Command(command, args...)
	output, err := c.CombinedOutput()
	fmt.Println(string(output))
	if err != nil {
		return err
	}

	return nil
}

func shRead(command string, args []string) (*[]byte, error) {
	c := exec.Command(command, args...)
	output, err := c.CombinedOutput()
	return &output, err
}

func printFailedMigrationMessage(err error, migrationType string) {
	fmt.Fprintf(os.Stderr, err.Error())
	fmt.Fprintf(os.Stderr, "\n\n")
	fmt.Fprintf(os.Stderr, "ERROR! Aborting the "+migrationType+" process.\n")
}
<|endoftext|>


<commit_before>// Copyright 2016 The Serviced 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 utils

// #include <sys/types.h>
// #include <sys/sysctl.h>
import "C"

import (
	"fmt"
	"unsafe"
)

// getMemorySize attempts to get the size of the installed RAM.
func getMemorySize() (size uint64, err error) {
	var mib []C.int = []C.int{ C.CTL_HW, C.HW_MEMSIZE }
	var value C.int64_t = 0
	var length C.size_t = 8
	var unused unsafe.Pointer

	if -1 == C.sysctl(&mib[0], 2, unsafe.Pointer(&value), &length, unused, 0) {
		return 0, fmt.Errorf("oops")
	}

	return uint64(value), nil
}

//func getExecPath() (string, error) {
//	var bufferSize C.uint32_t = 1024
//	buffer := make([]C.char, bufferSize)
//
//	result := C._NSGetExecutablePath(&buffer[0], &bufferSize)
//	if result == -1 {
//		buffer := make([]C.char, bufferSize)
//		result = C._NSGetExecutablePath(&buffer[0], &bufferSize)
//		if result == -1 {
//			return "", fmt.Errorf("Unable to determine path")
//		}
//	}
//	return C.GoStringN(&buffer[0], C.int(bufferSize)), nil
//}<commit_msg>OSX Port: Remove dead code and cleanup error handling<commit_after>// Copyright 2016 The Serviced 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 utils

// #include <sys/types.h>
// #include <sys/sysctl.h>
import "C"

import (
	"fmt"
	"unsafe"
)

// getMemorySize attempts to get the size of the installed RAM.
func getMemorySize() (size uint64, err error) {
	var mib []C.int = []C.int{ C.CTL_HW, C.HW_MEMSIZE }
	var value C.int64_t = 0
	var length C.size_t = 8
	var unused unsafe.Pointer

	if rc, errno := C.sysctl(&mib[0], 2, unsafe.Pointer(&value), &length, unused, 0); rc == -1 {
		return 0, fmt.Errorf("unable to get memory size: errno=%d", errno)
	}

	return uint64(value), nil
}
<|endoftext|>


<commit_before>package panichandler

import (
	"fmt"
	"html/template"
	"os"
	"runtime"
	"strings"

	"code.cloudfoundry.org/cli/cf"
)

// HandlePanic will recover from any panics and display a friendly error
// message with additional information used for debugging the panic.
func HandlePanic() {
	if err := recover(); err != nil {
		formattedString := `
		Something unexpected happened. This is a bug in {{.Binary}}.

		Please re-run the command that caused this exception with the environment
		variable CF_TRACE set to true.

		Also, please update to the latest cli and try the command again:
		https://code.cloudfoundry.org/cli/releases

		Please create an issue at: https://code.cloudfoundry.org/cli/issues

		Include the below information when creating the issue:

		Command
		{{.Command}}

		CLI Version
		{{.Version}}

		Error
		{{.Error}}

		Stack Trace
		{{.StackTrace}}

		Your Platform Details
		e.g. Mac OS X 10.11, Windows 8.1 64-bit, Ubuntu 14.04.3 64-bit

		Shell
		e.g. Terminal, iTerm, Powershell, Cygwin, gnome-terminal, terminator
		`
		formattedTemplate := template.Must(template.New("Panic Template").Parse(formattedString))
		backtrace := generateBacktrace()
		templateErr := formattedTemplate.Execute(os.Stderr, map[string]interface{}{
			"Binary":     os.Args[0],
			"Command":    strings.Join(os.Args, " "),
			"Version":    cf.Version,
			"StackTrace": backtrace,
			"Error":      err,
		})
		if templateErr != nil {
			fmt.Fprintf(os.Stderr,
				"Unable to format panic response: %s\n",
				templateErr.Error(),
			)

			fmt.Fprintf(os.Stderr,
				"Version:%s\nCommand:%s\nOriginal Stack Trace:%s\nOriginal Error:%s\n",
				cf.Version,
				strings.Join(os.Args, " "),
				backtrace,
				err,
			)
		}
		os.Exit(1)
	}
}

func generateBacktrace() string {
	stackByteCount := 0
	stackSizeLimit := 1024 * 1024
	var bytes []byte
	for stackSize := 1024; (stackByteCount == 0 || stackByteCount == stackSize) && stackSize < stackSizeLimit; stackSize = 2 * stackSize {
		bytes = make([]byte, stackSize)
		stackByteCount = runtime.Stack(bytes, true)
	}
	stackTrace := "\t" + strings.Replace(string(bytes), "\n", "\n\t", -1)
	return stackTrace
}
<commit_msg>display full stack trace for panics<commit_after>package panichandler

import (
	"fmt"
	"os"
	"runtime"
	"strings"
	"text/template"

	"code.cloudfoundry.org/cli/cf"
)

const maxStackSizeLimit = 1024 * 1024

// HandlePanic will recover from any panics and display a friendly error
// message with additional information used for debugging the panic.
func HandlePanic() {
	stackTraceBytes := make([]byte, maxStackSizeLimit)
	runtime.Stack(stackTraceBytes, true)
	stackTrace := "\t" + strings.Replace(string(stackTraceBytes), "\n", "\n\t", -1)
	if err := recover(); err != nil {
		formattedString := `
		Something unexpected happened. This is a bug in {{.Binary}}.

		Please re-run the command that caused this exception with the environment
		variable CF_TRACE set to true.

		Also, please update to the latest cli and try the command again:
		https://code.cloudfoundry.org/cli/releases

		Please create an issue at: https://code.cloudfoundry.org/cli/issues

		Include the below information when creating the issue:

		Command
		{{.Command}}

		CLI Version
		{{.Version}}

		Error
		{{.Error}}

		Stack Trace
		{{.StackTrace}}

		Your Platform Details
		e.g. Mac OS X 10.11, Windows 8.1 64-bit, Ubuntu 14.04.3 64-bit

		Shell
		e.g. Terminal, iTerm, Powershell, Cygwin, gnome-terminal, terminator
		`
		formattedTemplate := template.Must(template.New("Panic Template").Parse(formattedString))
		templateErr := formattedTemplate.Execute(os.Stderr, map[string]interface{}{
			"Binary":     os.Args[0],
			"Command":    strings.Join(os.Args, " "),
			"Version":    cf.Version,
			"StackTrace": stackTrace,
			"Error":      err,
		})
		if templateErr != nil {
			fmt.Fprintf(os.Stderr,
				"Unable to format panic response: %s\n",
				templateErr.Error(),
			)

			fmt.Fprintf(os.Stderr,
				"Version:%s\nCommand:%s\nOriginal Stack Trace:%s\nOriginal Error:%s\n",
				cf.Version,
				strings.Join(os.Args, " "),
				stackTrace,
				err,
			)
		}
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package geocode

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
)

const (
	geoipURI string = "http://www.telize.com/geoip"
)

// Geocode response from www.telize.com/geoip
// comes back like:
// {
//     timezone: "America/New_York",
//     isp: "Road Runner HoldCo LLC",
//     region_code: "NY",
//     country: "United States",
//     dma_code: "0",
//     area_code: "0",
//     region: "New York",
//     ip: "74.71.83.142",
//     asn: "AS11351",
//     continent_code: "NA",
//     city: "New York",
//     postal_code: "10128",
//     longitude: -73.9512,
//     latitude: 40.7805,
//     country_code: "US",
//     country_code3: "USA"
// }
type Geocode struct {
	AreaCode      string  `json:"area_code"`
	Asn           string  `json:"asn"`
	City          string  `json:"city"`
	ContinentCode string  `json:"continent_code"`
	Country       string  `json:"country"`
	CountryCode   string  `json:"country_code"`
	CountryCode3  string  `json:"country_code3"`
	DMACode       string  `json:"dma_code"`
	Error         string  `json:"error"`
	IP            string  `json:"ip"`
	Isp           string  `json:"isp"`
	Latitude      float64 `json:"latitude"`
	Longitude     float64 `json:"longitude"`
	PostalCode    string  `json:"postal_code"`
	Region        string  `json:"region"`
	RegionCode    string  `json:"region_code"`
	Timezone      string  `json:"timezone"`
}

// Request describes the request posted to the geocode api.
type Request struct {
	Location string `json:"location"`
}

// Response is the response from the  Google Geocoding API
// it comes back like the following:
// {
//   "results" : [
//      {
//         "address_components" : [
//            {
//               "long_name" : "Manhattan Beach",
//               "short_name" : "Manhattan Beach",
//               "types" : [ "locality", "political" ]
//            },
//            {
//               "long_name" : "Los Angeles County",
//               "short_name" : "Los Angeles County",
//               "types" : [ "administrative_area_level_2", "political" ]
//            },
//            {
//               "long_name" : "California",
//               "short_name" : "CA",
//               "types" : [ "administrative_area_level_1", "political" ]
//            },
//            {
//               "long_name" : "United States",
//               "short_name" : "US",
//               "types" : [ "country", "political" ]
//            }
//         ],
//         "formatted_address" : "Manhattan Beach, CA, USA",
//         "geometry" : {
//            "bounds" : {
//               "northeast" : {
//                  "lat" : 33.906185,
//                  "lng" : -118.3785991
//               },
//               "southwest" : {
//                  "lat" : 33.8728038,
//                  "lng" : -118.4234639
//               }
//            },
//            "location" : {
//               "lat" : 33.8847361,
//               "lng" : -118.4109089
//            },
//            "location_type" : "APPROXIMATE",
//            "viewport" : {
//               "northeast" : {
//                  "lat" : 33.906185,
//                  "lng" : -118.3785991
//               },
//               "southwest" : {
//                  "lat" : 33.8728038,
//                  "lng" : -118.4234639
//               }
//            }
//         },
//         "place_id" : "ChIJL2Ow4sWzwoARIEUV9NRRAwc",
//         "types" : [ "locality", "political" ]
//      }
//   ],
//   "status" : "OK"
// }
type Response struct {
	Results      []Result `json:"results"`
	Status       string   `json:"status"`
	ErrorMessage string   `json:"error_message"`
}

// Result is the result from the Google geocoding API.
type Result struct {
	AddressComponents []Address `json:"address_components"`
	FormattedAddress  string    `json:"formatted_address"`
	Geometry          Geometry  `json:"geometry"`
	PlaceID           string    `json:"place_id"`
	Types             []string  `json:"types"`
}

// Address contains details of a place.
type Address struct {
	LongName  string   `json:"long_name"`
	ShortName string   `json:"short_name"`
	Types     []string `json:"types"`
}

// Geometry contains location data.
type Geometry struct {
	Bounds       map[string]Location `json:"bounds"`
	Location     Location            `json:"location"`
	LocationType string              `json:"location_type"`
	Viewport     map[string]Location `json:"viewport"`
}

// Location contains lat and lng.
type Location struct {
	Latitude  float64 `json:"lat"`
	Longitude float64 `json:"lng"`
}

// Autolocate gets the requesters geocode response based off their IP address.
func Autolocate() (geocode Geocode, err error) {
	// send the request
	resp, err := http.Get(geoipURI)
	if err != nil {
		return geocode, err
	}
	defer resp.Body.Close()

	// decode the body
	dec := json.NewDecoder(resp.Body)
	if err := dec.Decode(&geocode); err != nil {
		return geocode, fmt.Errorf("Decoding autolocate response failed: %v", err)
	}

	return geocode, nil
}

// Locate gets the geocode data of a location that is passed as a string.
func Locate(location, server string) (geocode Geocode, err error) {
	// create json data
	jsonByte, err := json.Marshal(Request{Location: location})
	if err != nil {
		return geocode, fmt.Errorf("Marshaling location json failed: %v", err)
	}

	// send the request
	req, err := http.NewRequest("POST", fmt.Sprintf("%s/geocode", server), bytes.NewReader(jsonByte))
	if err != nil {
		return geocode, err
	}
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return geocode, err
	}
	defer resp.Body.Close()

	// decode the body
	dec := json.NewDecoder(resp.Body)
	if err := dec.Decode(&geocode); err != nil {
		return geocode, fmt.Errorf("Decoding geocode response failed: %v", err)
	}

	// These messages come from our API server
	if geocode.Error != "" {
		return geocode, fmt.Errorf("Geocode API response error: %s", geocode.Error)
	}

	return geocode, nil
}
<commit_msg>fix telize url to hosted instance<commit_after>package geocode

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
)

const (
	geoipURI string = "https://telize.j3ss.co/geoip"
)

// Geocode response from www.telize.com/geoip
// comes back like:
// {
//     timezone: "America/New_York",
//     isp: "Road Runner HoldCo LLC",
//     region_code: "NY",
//     country: "United States",
//     dma_code: "0",
//     area_code: "0",
//     region: "New York",
//     ip: "74.71.83.142",
//     asn: "AS11351",
//     continent_code: "NA",
//     city: "New York",
//     postal_code: "10128",
//     longitude: -73.9512,
//     latitude: 40.7805,
//     country_code: "US",
//     country_code3: "USA"
// }
type Geocode struct {
	AreaCode      string  `json:"area_code"`
	Asn           string  `json:"asn"`
	City          string  `json:"city"`
	ContinentCode string  `json:"continent_code"`
	Country       string  `json:"country"`
	CountryCode   string  `json:"country_code"`
	CountryCode3  string  `json:"country_code3"`
	DMACode       string  `json:"dma_code"`
	Error         string  `json:"error"`
	IP            string  `json:"ip"`
	Isp           string  `json:"isp"`
	Latitude      float64 `json:"latitude"`
	Longitude     float64 `json:"longitude"`
	PostalCode    string  `json:"postal_code"`
	Region        string  `json:"region"`
	RegionCode    string  `json:"region_code"`
	Timezone      string  `json:"timezone"`
}

// Request describes the request posted to the geocode api.
type Request struct {
	Location string `json:"location"`
}

// Response is the response from the  Google Geocoding API
// it comes back like the following:
// {
//   "results" : [
//      {
//         "address_components" : [
//            {
//               "long_name" : "Manhattan Beach",
//               "short_name" : "Manhattan Beach",
//               "types" : [ "locality", "political" ]
//            },
//            {
//               "long_name" : "Los Angeles County",
//               "short_name" : "Los Angeles County",
//               "types" : [ "administrative_area_level_2", "political" ]
//            },
//            {
//               "long_name" : "California",
//               "short_name" : "CA",
//               "types" : [ "administrative_area_level_1", "political" ]
//            },
//            {
//               "long_name" : "United States",
//               "short_name" : "US",
//               "types" : [ "country", "political" ]
//            }
//         ],
//         "formatted_address" : "Manhattan Beach, CA, USA",
//         "geometry" : {
//            "bounds" : {
//               "northeast" : {
//                  "lat" : 33.906185,
//                  "lng" : -118.3785991
//               },
//               "southwest" : {
//                  "lat" : 33.8728038,
//                  "lng" : -118.4234639
//               }
//            },
//            "location" : {
//               "lat" : 33.8847361,
//               "lng" : -118.4109089
//            },
//            "location_type" : "APPROXIMATE",
//            "viewport" : {
//               "northeast" : {
//                  "lat" : 33.906185,
//                  "lng" : -118.3785991
//               },
//               "southwest" : {
//                  "lat" : 33.8728038,
//                  "lng" : -118.4234639
//               }
//            }
//         },
//         "place_id" : "ChIJL2Ow4sWzwoARIEUV9NRRAwc",
//         "types" : [ "locality", "political" ]
//      }
//   ],
//   "status" : "OK"
// }
type Response struct {
	Results      []Result `json:"results"`
	Status       string   `json:"status"`
	ErrorMessage string   `json:"error_message"`
}

// Result is the result from the Google geocoding API.
type Result struct {
	AddressComponents []Address `json:"address_components"`
	FormattedAddress  string    `json:"formatted_address"`
	Geometry          Geometry  `json:"geometry"`
	PlaceID           string    `json:"place_id"`
	Types             []string  `json:"types"`
}

// Address contains details of a place.
type Address struct {
	LongName  string   `json:"long_name"`
	ShortName string   `json:"short_name"`
	Types     []string `json:"types"`
}

// Geometry contains location data.
type Geometry struct {
	Bounds       map[string]Location `json:"bounds"`
	Location     Location            `json:"location"`
	LocationType string              `json:"location_type"`
	Viewport     map[string]Location `json:"viewport"`
}

// Location contains lat and lng.
type Location struct {
	Latitude  float64 `json:"lat"`
	Longitude float64 `json:"lng"`
}

// Autolocate gets the requesters geocode response based off their IP address.
func Autolocate() (geocode Geocode, err error) {
	// send the request
	resp, err := http.Get(geoipURI)
	if err != nil {
		return geocode, err
	}
	defer resp.Body.Close()

	// decode the body
	dec := json.NewDecoder(resp.Body)
	if err := dec.Decode(&geocode); err != nil {
		return geocode, fmt.Errorf("Decoding autolocate response failed: %v", err)
	}

	return geocode, nil
}

// Locate gets the geocode data of a location that is passed as a string.
func Locate(location, server string) (geocode Geocode, err error) {
	// create json data
	jsonByte, err := json.Marshal(Request{Location: location})
	if err != nil {
		return geocode, fmt.Errorf("Marshaling location json failed: %v", err)
	}

	// send the request
	req, err := http.NewRequest("POST", fmt.Sprintf("%s/geocode", server), bytes.NewReader(jsonByte))
	if err != nil {
		return geocode, err
	}
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return geocode, err
	}
	defer resp.Body.Close()

	// decode the body
	dec := json.NewDecoder(resp.Body)
	if err := dec.Decode(&geocode); err != nil {
		return geocode, fmt.Errorf("Decoding geocode response failed: %v", err)
	}

	// These messages come from our API server
	if geocode.Error != "" {
		return geocode, fmt.Errorf("Geocode API response error: %s", geocode.Error)
	}

	return geocode, nil
}
<|endoftext|>


<commit_before>package get

import (
	"crypto"
	"io"
	"log"
	"os"
	"path"

	"github.com/moio/minima/util"
)

// FileStorage allows to store data in a local directory
type FileStorage struct {
	directory      string
	checksumBuffer []byte
}

// NewFileStorage returns a new Storage given a local directory
func NewFileStorage(directory string) Storage {
	return &FileStorage{directory, make([]byte, 4*1024*1024)}
}

// NewReader returns a Reader for a file in a location, returns ErrFileNotFound
// if the requested path was not found at all
func (s *FileStorage) NewReader(filename string, location Location) (reader io.ReadCloser, err error) {
	var prefix string
	if location == Permanent {
		prefix = ""
	} else {
		prefix = "-in-progress"
	}
	fullPath := path.Join(s.directory+prefix, filename)
	stat, err := os.Stat(fullPath)
	if os.IsNotExist(err) || stat == nil {
		err = ErrFileNotFound
		return
	}

	f, err := os.Open(fullPath)
	if err != nil {
		log.Fatal(err)
	}

	return f, err
}

// StoringMapper returns a mapper that will store read data to a temporary location specified by filename
func (s *FileStorage) StoringMapper(filename string, checksum string, hash crypto.Hash) util.ReaderMapper {
	return func(reader io.ReadCloser) (result io.ReadCloser, err error) {
		fullPath := path.Join(s.directory+"-in-progress", filename)
		// attempt to create any missing directories in the full path
		err = os.MkdirAll(path.Dir(fullPath), os.ModePerm)
		if err != nil {
			return
		}

		file, err := os.Create(fullPath)
		if err != nil {
			return
		}

		result = util.NewTeeReadCloser(reader, util.NewChecksummingWriter(file, checksum, hash))
		return
	}
}

// Recycle will copy a file from the permanent to the temporary location
func (s *FileStorage) Recycle(filename string) (err error) {
	newPath := path.Join(s.directory+"-in-progress", filename)
	err = os.MkdirAll(path.Dir(newPath), os.ModePerm)
	if err != nil {
		return
	}

	return os.Link(path.Join(s.directory, filename), newPath)
}

// Commit moves any temporary file accumulated so far to the permanent location
func (s *FileStorage) Commit() (err error) {
	err = os.RemoveAll(s.directory + "-old")
	if err != nil {
		return
	}
	err = os.Rename(s.directory, s.directory+"-old")
	if err != nil && !os.IsNotExist(err) {
		return
	}
	err = os.Rename(s.directory+"-in-progress", s.directory)
	if err != nil {
		return
	}
	return os.RemoveAll(s.directory + "-old")
}
<commit_msg>Refactoring: remove unused field<commit_after>package get

import (
	"crypto"
	"io"
	"log"
	"os"
	"path"

	"github.com/moio/minima/util"
)

// FileStorage allows to store data in a local directory
type FileStorage struct {
	directory string
}

// NewFileStorage returns a new Storage given a local directory
func NewFileStorage(directory string) Storage {
	return &FileStorage{directory}
}

// NewReader returns a Reader for a file in a location, returns ErrFileNotFound
// if the requested path was not found at all
func (s *FileStorage) NewReader(filename string, location Location) (reader io.ReadCloser, err error) {
	var prefix string
	if location == Permanent {
		prefix = ""
	} else {
		prefix = "-in-progress"
	}
	fullPath := path.Join(s.directory+prefix, filename)
	stat, err := os.Stat(fullPath)
	if os.IsNotExist(err) || stat == nil {
		err = ErrFileNotFound
		return
	}

	f, err := os.Open(fullPath)
	if err != nil {
		log.Fatal(err)
	}

	return f, err
}

// StoringMapper returns a mapper that will store read data to a temporary location specified by filename
func (s *FileStorage) StoringMapper(filename string, checksum string, hash crypto.Hash) util.ReaderMapper {
	return func(reader io.ReadCloser) (result io.ReadCloser, err error) {
		fullPath := path.Join(s.directory+"-in-progress", filename)
		// attempt to create any missing directories in the full path
		err = os.MkdirAll(path.Dir(fullPath), os.ModePerm)
		if err != nil {
			return
		}

		file, err := os.Create(fullPath)
		if err != nil {
			return
		}

		result = util.NewTeeReadCloser(reader, util.NewChecksummingWriter(file, checksum, hash))
		return
	}
}

// Recycle will copy a file from the permanent to the temporary location
func (s *FileStorage) Recycle(filename string) (err error) {
	newPath := path.Join(s.directory+"-in-progress", filename)
	err = os.MkdirAll(path.Dir(newPath), os.ModePerm)
	if err != nil {
		return
	}

	return os.Link(path.Join(s.directory, filename), newPath)
}

// Commit moves any temporary file accumulated so far to the permanent location
func (s *FileStorage) Commit() (err error) {
	err = os.RemoveAll(s.directory + "-old")
	if err != nil {
		return
	}
	err = os.Rename(s.directory, s.directory+"-old")
	if err != nil && !os.IsNotExist(err) {
		return
	}
	err = os.Rename(s.directory+"-in-progress", s.directory)
	if err != nil {
		return
	}
	return os.RemoveAll(s.directory + "-old")
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/sha1"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/heroku/heroku-cli/Godeps/_workspace/src/github.com/dickeyxxx/golock"
	"github.com/heroku/heroku-cli/Godeps/_workspace/src/github.com/franela/goreq"
	"github.com/heroku/heroku-cli/Godeps/_workspace/src/github.com/kardianos/osext"
	"github.com/heroku/heroku-cli/gode"
)

var updateTopic = &Topic{
	Name:        "update",
	Description: "update heroku-cli",
}

var updateCmd = &Command{
	Topic:       "update",
	Hidden:      true,
	Description: "updates heroku-cli",
	Args:        []Arg{{Name: "channel", Optional: true}},
	Flags:       []Flag{{Name: "background", Hidden: true}},
	Run: func(ctx *Context) {
		channel := ctx.Args.(map[string]string)["channel"]
		if channel == "" {
			channel = Channel
		}
		t := "foreground"
		if ctx.Flags["background"] == true {
			t = "background"
		}
		Update(channel, t)
	},
}

var binPath string
var updateLockPath = filepath.Join(AppDir(), "updating.lock")
var autoupdateFile = filepath.Join(AppDir(), "autoupdate")
var tmpPath = filepath.Join(AppDir(), "tmp")

func init() {
	binPath, _ = osext.Executable()
}

// Update updates the CLI and plugins
func Update(channel string, t string) {
	if !IsUpdateNeeded(t) {
		return
	}
	done := make(chan bool)
	go func() {
		touchAutoupdateFile()
		updateCLI(channel)
		updateNode()
		updatePlugins()
		truncateErrorLog()
		cleanTmpDir()
		done <- true
	}()
	select {
	case <-time.After(time.Second * 300):
		Errln("Timed out while updating")
	case <-done:
	}
}

func updatePlugins() {
	plugins := PluginNamesNotSymlinked()
	if len(plugins) == 0 {
		return
	}
	Err("Updating plugins... ")
	packages, err := gode.OutdatedPackages(plugins...)
	PrintError(err, true)
	if len(packages) > 0 {
		for name, version := range packages {
			lockPlugin(name)
			PrintError(gode.InstallPackages(name+"@"+version), true)
			plugin, err := ParsePlugin(name)
			PrintError(err, true)
			AddPluginsToCache(plugin)
			unlockPlugin(name)
		}
		Errf("done. Updated %d %s.\n", len(packages), plural("package", len(packages)))
	} else {
		Errln("no plugins to update.")
	}
}

func updateCLI(channel string) {
	if channel == "?" {
		// do not update dev version
		return
	}
	manifest, err := getUpdateManifest(channel)
	if err != nil {
		Warn("Error updating CLI")
		PrintError(err, false)
		return
	}
	if manifest.Version == Version && manifest.Channel == Channel {
		return
	}
	LogIfError(golock.Lock(updateLockPath))
	unlock := func() {
		golock.Unlock(updateLockPath)
	}
	defer unlock()
	Errf("Updating Heroku v4 CLI to %s (%s)... ", manifest.Version, manifest.Channel)
	build := manifest.Builds[runtime.GOOS][runtime.GOARCH]
	// on windows we can't remove an existing file or remove the running binary
	// so we download the file to binName.new
	// move the running binary to binName.old (deleting any existing file first)
	// rename the downloaded file to binName
	if err := downloadBin(binPath+".new", build.URL); err != nil {
		panic(err)
	}
	if fileSha1(binPath+".new") != build.Sha1 {
		panic("SHA mismatch")
	}
	os.Remove(binPath + ".old")
	os.Rename(binPath, binPath+".old")
	if err := os.Rename(binPath+".new", binPath); err != nil {
		panic(err)
	}
	os.Remove(binPath + ".old")
	Errln("done")
	unlock()
	clearAutoupdateFile() // force full update
	reexec()              // reexec to finish updating with new code
}

// IsUpdateNeeded checks if an update is available
func IsUpdateNeeded(t string) bool {
	f, err := os.Stat(autoupdateFile)
	if err != nil {
		return true
	}
	if t == "background" {
		return time.Since(f.ModTime()) > 4*time.Hour
	} else if t == "block" {
		return time.Since(f.ModTime()) > 2160*time.Hour // 90 days
	}
	return true
}

func touchAutoupdateFile() {
	out, err := os.OpenFile(autoupdateFile, os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		panic(err)
	}
	out.WriteString(time.Now().String())
	out.Close()
}

// forces a full update on the next run
func clearAutoupdateFile() {
	PrintError(os.Remove(autoupdateFile), true)
}

type manifest struct {
	Channel, Version string
	Builds           map[string]map[string]struct {
		URL, Sha1 string
	}
}

func getUpdateManifest(channel string) (*manifest, error) {
	res, err := goreq.Request{
		Uri:       "https://cli-assets.heroku.com/" + channel + "/manifest.json",
		ShowDebug: debugging,
	}.Do()
	if err != nil {
		return nil, err
	}
	var m manifest
	res.Body.FromJsonTo(&m)
	return &m, nil
}

func downloadBin(path, url string) error {
	out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
	if err != nil {
		return err
	}
	defer out.Close()
	res, err := goreq.Request{
		Uri:       url + ".gz",
		ShowDebug: debugging,
	}.Do()
	if err != nil {
		return err
	}
	if res.StatusCode != 200 {
		b, _ := res.Body.ToString()
		return errors.New(b)
	}
	defer res.Body.Close()
	_, err = io.Copy(out, res.Body)
	return err
}

func fileSha1(path string) string {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		panic(err)
	}
	return fmt.Sprintf("%x", sha1.Sum(data))
}

// TriggerBackgroundUpdate will trigger an update to the client in the background
func TriggerBackgroundUpdate() {
	if IsUpdateNeeded("background") {
		exec.Command(binPath, "update", "--background").Start()
	}
}

// restarts the CLI with the same arguments
func reexec() {
	Debugln("reexecing new CLI...")
	cmd := exec.Command(binPath, os.Args[1:]...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	os.Exit(getExitCode(cmd.Run()))
}

func truncateErrorLog() {
	Debugln("truncating error log...")
	body, err := ioutil.ReadFile(ErrLogPath)
	if err != nil {
		PrintError(err, false)
		return
	}
	lines := strings.Split(string(body), "\n")
	lines = lines[maxint(len(lines)-1000, 0) : len(lines)-1]
	err = ioutil.WriteFile(ErrLogPath, []byte(strings.Join(lines, "\n")+"\n"), 0644)
	PrintError(err, false)
}

func maxint(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func cleanTmpDir() {
	Debugln("cleaning up tmp dirs...")
	dirs, err := ioutil.ReadDir(tmpPath)
	if err != nil {
		PrintError(err, false)
		return
	}
	for _, dir := range dirs {
		if time.Since(dir.ModTime()) > 24*time.Hour {
			path := filepath.Join(tmpPath, dir.Name())
			Debugln("deleting " + path)
			PrintError(os.RemoveAll(path), false)
		}
	}
}
<commit_msg>add updating output prefix<commit_after>package main

import (
	"crypto/sha1"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/heroku/heroku-cli/Godeps/_workspace/src/github.com/dickeyxxx/golock"
	"github.com/heroku/heroku-cli/Godeps/_workspace/src/github.com/franela/goreq"
	"github.com/heroku/heroku-cli/Godeps/_workspace/src/github.com/kardianos/osext"
	"github.com/heroku/heroku-cli/gode"
)

var updateTopic = &Topic{
	Name:        "update",
	Description: "update heroku-cli",
}

var updateCmd = &Command{
	Topic:       "update",
	Hidden:      true,
	Description: "updates heroku-cli",
	Args:        []Arg{{Name: "channel", Optional: true}},
	Flags:       []Flag{{Name: "background", Hidden: true}},
	Run: func(ctx *Context) {
		channel := ctx.Args.(map[string]string)["channel"]
		if channel == "" {
			channel = Channel
		}
		t := "foreground"
		if ctx.Flags["background"] == true {
			t = "background"
		}
		Update(channel, t)
	},
}

var binPath string
var updateLockPath = filepath.Join(AppDir(), "updating.lock")
var autoupdateFile = filepath.Join(AppDir(), "autoupdate")
var tmpPath = filepath.Join(AppDir(), "tmp")

func init() {
	binPath, _ = osext.Executable()
}

// Update updates the CLI and plugins
func Update(channel string, t string) {
	if !IsUpdateNeeded(t) {
		return
	}
	done := make(chan bool)
	go func() {
		touchAutoupdateFile()
		updateCLI(channel)
		updateNode()
		updatePlugins()
		truncateErrorLog()
		cleanTmpDir()
		done <- true
	}()
	select {
	case <-time.After(time.Second * 300):
		Errln("Timed out while updating")
	case <-done:
	}
}

func updatePlugins() {
	plugins := PluginNamesNotSymlinked()
	if len(plugins) == 0 {
		return
	}
	Err("heroku-cli: Updating plugins... ")
	packages, err := gode.OutdatedPackages(plugins...)
	PrintError(err, true)
	if len(packages) > 0 {
		for name, version := range packages {
			lockPlugin(name)
			PrintError(gode.InstallPackages(name+"@"+version), true)
			plugin, err := ParsePlugin(name)
			PrintError(err, true)
			AddPluginsToCache(plugin)
			unlockPlugin(name)
		}
		Errf("done. Updated %d %s.\n", len(packages), plural("package", len(packages)))
	} else {
		Errln("no plugins to update.")
	}
}

func updateCLI(channel string) {
	if channel == "?" {
		// do not update dev version
		return
	}
	manifest, err := getUpdateManifest(channel)
	if err != nil {
		Warn("Error updating CLI")
		PrintError(err, false)
		return
	}
	if manifest.Version == Version && manifest.Channel == Channel {
		return
	}
	LogIfError(golock.Lock(updateLockPath))
	unlock := func() {
		golock.Unlock(updateLockPath)
	}
	defer unlock()
	if manifest.Channel == "master" {
		Errf("heroku-cli: Updating to %s... ", manifest.Version)
	} else {
		Errf("heroku-cli: Updating to %s (%s)... ", manifest.Version, manifest.Channel)
	}
	build := manifest.Builds[runtime.GOOS][runtime.GOARCH]
	// on windows we can't remove an existing file or remove the running binary
	// so we download the file to binName.new
	// move the running binary to binName.old (deleting any existing file first)
	// rename the downloaded file to binName
	if err := downloadBin(binPath+".new", build.URL); err != nil {
		panic(err)
	}
	if fileSha1(binPath+".new") != build.Sha1 {
		panic("SHA mismatch")
	}
	os.Remove(binPath + ".old")
	os.Rename(binPath, binPath+".old")
	if err := os.Rename(binPath+".new", binPath); err != nil {
		panic(err)
	}
	os.Remove(binPath + ".old")
	Errln("done")
	unlock()
	clearAutoupdateFile() // force full update
	reexec()              // reexec to finish updating with new code
}

// IsUpdateNeeded checks if an update is available
func IsUpdateNeeded(t string) bool {
	f, err := os.Stat(autoupdateFile)
	if err != nil {
		return true
	}
	if t == "background" {
		return time.Since(f.ModTime()) > 4*time.Hour
	} else if t == "block" {
		return time.Since(f.ModTime()) > 2160*time.Hour // 90 days
	}
	return true
}

func touchAutoupdateFile() {
	out, err := os.OpenFile(autoupdateFile, os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		panic(err)
	}
	out.WriteString(time.Now().String())
	out.Close()
}

// forces a full update on the next run
func clearAutoupdateFile() {
	PrintError(os.Remove(autoupdateFile), true)
}

type manifest struct {
	Channel, Version string
	Builds           map[string]map[string]struct {
		URL, Sha1 string
	}
}

func getUpdateManifest(channel string) (*manifest, error) {
	res, err := goreq.Request{
		Uri:       "https://cli-assets.heroku.com/" + channel + "/manifest.json",
		ShowDebug: debugging,
	}.Do()
	if err != nil {
		return nil, err
	}
	var m manifest
	res.Body.FromJsonTo(&m)
	return &m, nil
}

func downloadBin(path, url string) error {
	out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
	if err != nil {
		return err
	}
	defer out.Close()
	res, err := goreq.Request{
		Uri:       url + ".gz",
		ShowDebug: debugging,
	}.Do()
	if err != nil {
		return err
	}
	if res.StatusCode != 200 {
		b, _ := res.Body.ToString()
		return errors.New(b)
	}
	defer res.Body.Close()
	_, err = io.Copy(out, res.Body)
	return err
}

func fileSha1(path string) string {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		panic(err)
	}
	return fmt.Sprintf("%x", sha1.Sum(data))
}

// TriggerBackgroundUpdate will trigger an update to the client in the background
func TriggerBackgroundUpdate() {
	if IsUpdateNeeded("background") {
		exec.Command(binPath, "update", "--background").Start()
	}
}

// restarts the CLI with the same arguments
func reexec() {
	Debugln("reexecing new CLI...")
	cmd := exec.Command(binPath, os.Args[1:]...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	os.Exit(getExitCode(cmd.Run()))
}

func truncateErrorLog() {
	Debugln("truncating error log...")
	body, err := ioutil.ReadFile(ErrLogPath)
	if err != nil {
		PrintError(err, false)
		return
	}
	lines := strings.Split(string(body), "\n")
	lines = lines[maxint(len(lines)-1000, 0) : len(lines)-1]
	err = ioutil.WriteFile(ErrLogPath, []byte(strings.Join(lines, "\n")+"\n"), 0644)
	PrintError(err, false)
}

func maxint(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func cleanTmpDir() {
	Debugln("cleaning up tmp dirs...")
	dirs, err := ioutil.ReadDir(tmpPath)
	if err != nil {
		PrintError(err, false)
		return
	}
	for _, dir := range dirs {
		if time.Since(dir.ModTime()) > 24*time.Hour {
			path := filepath.Join(tmpPath, dir.Name())
			Debugln("deleting " + path)
			PrintError(os.RemoveAll(path), false)
		}
	}
}
<|endoftext|>


<commit_before>//  Copyright (c) 2014 Couchbase, Inc.
//  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 (
	"io/ioutil"
	"os"
	"testing"
)

func TestOpenPIndex(t *testing.T) {
	pindex, err := OpenPIndex(nil, "not-a-bleve-file")
	if pindex != nil || err == nil {
		t.Errorf("expected OpenPIndex to fail on a bad file")
	}
}

func TestNewPIndex(t *testing.T) {
	emptyDir, _ := ioutil.TempDir("./tmp", "test")
	defer os.RemoveAll(emptyDir)

	// TODO: Should have a blackhole index implementation for testing.

	pindex, err := NewPIndex(nil, "fake", "uuid",
		"bleve", "indexName", "indexUUID", "",
		"sourceType", "sourceName", "sourceUUID", "sourcePartitions",
		PIndexPath(emptyDir, "fake"))
	if pindex == nil || err != nil {
		t.Errorf("expected NewPIndex to work")
	}
	close(pindex.Stream)

	pindex, err = NewPIndex(nil, "fake", "uuid",
		"bleve", "indexName", "indexUUID", "{}",
		"sourceType", "sourceName", "sourceUUID", "sourcePartitions",
		PIndexPath(emptyDir, "fake"))
	if pindex != nil || err == nil {
		t.Errorf("expected NewPIndex to fail with empty json map")
	}

	pindex, err = NewPIndex(nil, "fake", "uuid",
		"bleve", "indexName", "indexUUID", "} hey this isn't json :-(",
		"sourceType", "sourceName", "sourceUUID", "sourcePartitions",
		PIndexPath(emptyDir, "fake"))
	if pindex != nil || err == nil {
		t.Errorf("expected NewPIndex to fail with bad json")
	}
}

func TestNewPIndexImpl(t *testing.T) {
	emptyDir, _ := ioutil.TempDir("./tmp", "test")
	defer os.RemoveAll(emptyDir)

	pindexImpl, err := NewPIndexImpl("AN UNKNOWN PINDEX IMPL TYPE", "", emptyDir)
	if err == nil || pindexImpl != nil {
		t.Errorf("expected err on unknown impl type")
	}

	pindexImpl, err = OpenPIndexImpl("AN UNKNOWN PINDEX IMPL TYPE", emptyDir)
	if err == nil || pindexImpl != nil {
		t.Errorf("expected err on unknown impl type")
	}
}
<commit_msg>bleve accepts an empty JSON {} mapping<commit_after>//  Copyright (c) 2014 Couchbase, Inc.
//  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 (
	"io/ioutil"
	"os"
	"testing"
)

func TestOpenPIndex(t *testing.T) {
	pindex, err := OpenPIndex(nil, "not-a-bleve-file")
	if pindex != nil || err == nil {
		t.Errorf("expected OpenPIndex to fail on a bad file")
	}
}

func TestNewPIndex(t *testing.T) {
	emptyDir, _ := ioutil.TempDir("./tmp", "test")
	defer os.RemoveAll(emptyDir)

	// TODO: Should have a blackhole index implementation for testing.

	pindex, err := NewPIndex(nil, "fake", "uuid",
		"bleve", "indexName", "indexUUID", "",
		"sourceType", "sourceName", "sourceUUID", "sourcePartitions",
		PIndexPath(emptyDir, "fake"))
	if pindex == nil || err != nil {
		t.Errorf("expected NewPIndex to work")
	}
	close(pindex.Stream)
}

func TestNewPIndexEmptyJSON(t *testing.T) {
	emptyDir, _ := ioutil.TempDir("./tmp", "test")
	defer os.RemoveAll(emptyDir)

	pindex, err := NewPIndex(nil, "fake", "uuid",
		"bleve", "indexName", "indexUUID", "{}",
		"sourceType", "sourceName", "sourceUUID", "sourcePartitions",
		PIndexPath(emptyDir, "fake"))
	if pindex == nil || err != nil {
		t.Errorf("expected NewPIndex to fail with empty json map")
	}
}

func TestNewPIndexBadMapping(t *testing.T) {
	emptyDir, _ := ioutil.TempDir("./tmp", "test")
	defer os.RemoveAll(emptyDir)

	pindex, err := NewPIndex(nil, "fake", "uuid",
		"bleve", "indexName", "indexUUID", "} hey this isn't json :-(",
		"sourceType", "sourceName", "sourceUUID", "sourcePartitions",
		PIndexPath(emptyDir, "fake"))
	if pindex != nil || err == nil {
		t.Errorf("expected NewPIndex to fail with bad json")
	}
}

func TestNewPIndexImpl(t *testing.T) {
	emptyDir, _ := ioutil.TempDir("./tmp", "test")
	defer os.RemoveAll(emptyDir)

	pindexImpl, err := NewPIndexImpl("AN UNKNOWN PINDEX IMPL TYPE", "", emptyDir)
	if err == nil || pindexImpl != nil {
		t.Errorf("expected err on unknown impl type")
	}

	pindexImpl, err = OpenPIndexImpl("AN UNKNOWN PINDEX IMPL TYPE", emptyDir)
	if err == nil || pindexImpl != nil {
		t.Errorf("expected err on unknown impl type")
	}
}
<|endoftext|>


<commit_before>//  Copyright (c) 2014 Couchbase, Inc.
//  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 cbgt

import (
	"bytes"
	"io/ioutil"
	"os"
	"testing"
)

func TestOpenPIndex(t *testing.T) {
	pindex, err := OpenPIndex(nil, "not-a-real-file")
	if pindex != nil || err == nil {
		t.Errorf("expected OpenPIndex to fail on a bad file")
	}
}

func TestNewPIndex(t *testing.T) {
	emptyDir, _ := ioutil.TempDir("./tmp", "test")
	defer os.RemoveAll(emptyDir)

	pindex, err := NewPIndex(nil, "fake", "uuid",
		"blackhole", "indexName", "indexUUID", "",
		"sourceType", "sourceName", "sourceUUID",
		"sourceParams", "sourcePartitions",
		PIndexPath(emptyDir, "fake"))
	if pindex == nil || err != nil {
		t.Errorf("expected NewPIndex to work")
	}
	err = pindex.Close(true)
	if err != nil {
		t.Errorf("expected Close to work")
	}
}

func TestNewPIndexImpl(t *testing.T) {
	emptyDir, _ := ioutil.TempDir("./tmp", "test")
	defer os.RemoveAll(emptyDir)

	restart := func() {
		t.Errorf("not expecting a restart")
	}

	indexParams := ""

	pindexImpl, dest, err :=
		NewPIndexImpl("AN UNKNOWN PINDEX IMPL TYPE",
			indexParams, emptyDir, restart)
	if err == nil || pindexImpl != nil || dest != nil {
		t.Errorf("expected err on unknown impl type")
	}

	pindexImpl, dest, err =
		OpenPIndexImpl("AN UNKNOWN PINDEX IMPL TYPE", emptyDir, restart)
	if err == nil || pindexImpl != nil || dest != nil {
		t.Errorf("expected err on unknown impl type")
	}
}

func TestBlackholePIndexImpl(t *testing.T) {
	emptyDir, _ := ioutil.TempDir("./tmp", "test")
	defer os.RemoveAll(emptyDir)

	restart := func() {
		t.Errorf("not expecting a restart")
	}

	pindex, dest, err :=
		OpenBlackHolePIndexImpl("blackhole", emptyDir, restart)
	if err == nil || pindex != nil || dest != nil {
		t.Errorf("expected OpenBlackHolePIndexImpl to error on emptyDir")
	}

	pindex, dest, err =
		NewBlackHolePIndexImpl("blackhole", "", emptyDir, restart)
	if err != nil || pindex == nil || dest == nil {
		t.Errorf("expected NewBlackHolePIndexImpl to work")
	}

	pindex, dest, err =
		OpenBlackHolePIndexImpl("blackhole", emptyDir, restart)
	if err != nil || pindex == nil || dest == nil {
		t.Errorf("expected OpenBlackHolePIndexImpl to work")
	}

	if dest.Close() != nil ||
		dest.DataUpdate("", nil, 0, nil,
			0, DEST_EXTRAS_TYPE_NIL, nil) != nil ||
		dest.DataDelete("", nil, 0,
			0, DEST_EXTRAS_TYPE_NIL, nil) != nil ||
		dest.SnapshotStart("", 0, 0) != nil ||
		dest.OpaqueSet("", nil) != nil ||
		dest.Rollback("", 0) != nil ||
		dest.ConsistencyWait("", "", "", 0, nil) != nil ||
		dest.Query(nil, nil, nil, nil) != nil {
		t.Errorf("expected no errors from a blackhole pindex impl")
	}

	c, err := dest.Count(nil, nil)
	if err != nil || c != 0 {
		t.Errorf("expected 0, no err")
	}

	b := &bytes.Buffer{}
	err = dest.Stats(b)
	if err != nil {
		t.Errorf("expected 0, no err")
	}
	if string(b.Bytes()) != "null" {
		t.Errorf("expected null")
	}

	v, lastSeq, err := dest.OpaqueGet("")
	if err != nil || v != nil || lastSeq != 0 {
		t.Errorf("expected nothing from blackhole.OpaqueGet()")
	}

	bt := PIndexImplTypes["blackhole"]
	if bt == nil {
		t.Errorf("expected blackhole in PIndexImplTypes")
	}
	if bt.New == nil || bt.Open == nil {
		t.Errorf("blackhole should have open and new funcs")
	}
	if bt.Count != nil {
		t.Errorf("expected blackhole count nil")
	}
	if bt.Query != nil {
		t.Errorf("expected blackhole query nil")
	}
}

func TestErrorConsistencyWait(t *testing.T) {
	e := &ErrorConsistencyWait{}
	if e.Error() == "" {
		t.Errorf("expected err")
	}
}
<commit_msg>TestErrorConsistencyWaitDone<commit_after>//  Copyright (c) 2014 Couchbase, Inc.
//  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 cbgt

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"testing"
)

func TestOpenPIndex(t *testing.T) {
	pindex, err := OpenPIndex(nil, "not-a-real-file")
	if pindex != nil || err == nil {
		t.Errorf("expected OpenPIndex to fail on a bad file")
	}
}

func TestNewPIndex(t *testing.T) {
	emptyDir, _ := ioutil.TempDir("./tmp", "test")
	defer os.RemoveAll(emptyDir)

	pindex, err := NewPIndex(nil, "fake", "uuid",
		"blackhole", "indexName", "indexUUID", "",
		"sourceType", "sourceName", "sourceUUID",
		"sourceParams", "sourcePartitions",
		PIndexPath(emptyDir, "fake"))
	if pindex == nil || err != nil {
		t.Errorf("expected NewPIndex to work")
	}
	err = pindex.Close(true)
	if err != nil {
		t.Errorf("expected Close to work")
	}
}

func TestNewPIndexImpl(t *testing.T) {
	emptyDir, _ := ioutil.TempDir("./tmp", "test")
	defer os.RemoveAll(emptyDir)

	restart := func() {
		t.Errorf("not expecting a restart")
	}

	indexParams := ""

	pindexImpl, dest, err :=
		NewPIndexImpl("AN UNKNOWN PINDEX IMPL TYPE",
			indexParams, emptyDir, restart)
	if err == nil || pindexImpl != nil || dest != nil {
		t.Errorf("expected err on unknown impl type")
	}

	pindexImpl, dest, err =
		OpenPIndexImpl("AN UNKNOWN PINDEX IMPL TYPE", emptyDir, restart)
	if err == nil || pindexImpl != nil || dest != nil {
		t.Errorf("expected err on unknown impl type")
	}
}

func TestBlackholePIndexImpl(t *testing.T) {
	emptyDir, _ := ioutil.TempDir("./tmp", "test")
	defer os.RemoveAll(emptyDir)

	restart := func() {
		t.Errorf("not expecting a restart")
	}

	pindex, dest, err :=
		OpenBlackHolePIndexImpl("blackhole", emptyDir, restart)
	if err == nil || pindex != nil || dest != nil {
		t.Errorf("expected OpenBlackHolePIndexImpl to error on emptyDir")
	}

	pindex, dest, err =
		NewBlackHolePIndexImpl("blackhole", "", emptyDir, restart)
	if err != nil || pindex == nil || dest == nil {
		t.Errorf("expected NewBlackHolePIndexImpl to work")
	}

	pindex, dest, err =
		OpenBlackHolePIndexImpl("blackhole", emptyDir, restart)
	if err != nil || pindex == nil || dest == nil {
		t.Errorf("expected OpenBlackHolePIndexImpl to work")
	}

	if dest.Close() != nil ||
		dest.DataUpdate("", nil, 0, nil,
			0, DEST_EXTRAS_TYPE_NIL, nil) != nil ||
		dest.DataDelete("", nil, 0,
			0, DEST_EXTRAS_TYPE_NIL, nil) != nil ||
		dest.SnapshotStart("", 0, 0) != nil ||
		dest.OpaqueSet("", nil) != nil ||
		dest.Rollback("", 0) != nil ||
		dest.ConsistencyWait("", "", "", 0, nil) != nil ||
		dest.Query(nil, nil, nil, nil) != nil {
		t.Errorf("expected no errors from a blackhole pindex impl")
	}

	c, err := dest.Count(nil, nil)
	if err != nil || c != 0 {
		t.Errorf("expected 0, no err")
	}

	b := &bytes.Buffer{}
	err = dest.Stats(b)
	if err != nil {
		t.Errorf("expected 0, no err")
	}
	if string(b.Bytes()) != "null" {
		t.Errorf("expected null")
	}

	v, lastSeq, err := dest.OpaqueGet("")
	if err != nil || v != nil || lastSeq != 0 {
		t.Errorf("expected nothing from blackhole.OpaqueGet()")
	}

	bt := PIndexImplTypes["blackhole"]
	if bt == nil {
		t.Errorf("expected blackhole in PIndexImplTypes")
	}
	if bt.New == nil || bt.Open == nil {
		t.Errorf("blackhole should have open and new funcs")
	}
	if bt.Count != nil {
		t.Errorf("expected blackhole count nil")
	}
	if bt.Query != nil {
		t.Errorf("expected blackhole query nil")
	}
}

func TestErrorConsistencyWait(t *testing.T) {
	e := &ErrorConsistencyWait{}
	if e.Error() == "" {
		t.Errorf("expected err")
	}
}

func TestErrorConsistencyWaitDone(t *testing.T) {
	currSeqFunc := func() uint64 {
		return 101
	}

	cancelCh := make(chan bool)
	doneCh := make(chan error)

	var cwdErr error
	endCh := make(chan struct{})

	go func() {
		cwdErr = ConsistencyWaitDone("partition",
			cancelCh,
			doneCh,
			currSeqFunc)
		close(endCh)
	}()

	close(cancelCh)

	<-endCh

	if cwdErr == nil {
		t.Errorf("expected err")
	}

	// --------------------------

	cancelCh = make(chan bool)
	doneCh = make(chan error)

	cwdErr = nil
	endCh = make(chan struct{})

	go func() {
		cwdErr = ConsistencyWaitDone("partition",
			cancelCh,
			doneCh,
			currSeqFunc)
		close(endCh)
	}()

	doneErr := fmt.Errorf("doneErr")
	doneCh <- doneErr

	<-endCh

	if cwdErr != doneErr {
		t.Errorf("expected doneErr")
	}
}
<|endoftext|>


<commit_before>package api

import (
	"os/exec"
	"strconv"

	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
	"github.com/labstack/gommon/log"
	"github.com/nu7hatch/gouuid"
	"github.com/taku-k/xtralab/pkg/config"
	"github.com/taku-k/xtralab/pkg/storage"
)

// App struct.
// There is no singleton anti-pattern,
// all variables defined locally inside
// this struct.
type App struct {
	Engine *echo.Echo
	Conf   *config.Config
	API    *API
}

// NewApp returns initialized struct
// of main server application.
func NewApp(conf *config.Config) (*App, error) {
	// Make an engine
	engine := echo.New()

	// Set up echo debug level
	engine.Debug = conf.Debug

	// Regular middlewares
	engine.Use(middleware.Recover())

	engine.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
		Format: `${method} | ${status} | ${uri} -> ${latency_human}` + "\n",
	}))

	// FIXME: use option to choose a backup storage
	s, err := storage.NewLocalBackupStorage(conf)
	if err != nil {
		return nil, err
	}
	bm := NewBackupManager(conf)
	p := NewNCPool(conf)

	// Initialize the application
	app := &App{
		Conf:   conf,
		Engine: engine,
		API: &API{
			storage: s,
			bm:      bm,
			pool:    p,
		},
	}

	// Map app and uuid for every requests
	app.Engine.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			c.Set("app", app)
			id, _ := uuid.NewV4()
			c.Set("uuid", id)
			return next(c)
		}
	})

	// Bind api handling for URL api.prefix
	app.API.Bind(
		app.Engine.Group(
			conf.ApiPrefix,
		),
	)

	engine.Logger.SetLevel(log.DEBUG)

	return app, nil
}

func ensureExistXtrabackup() error {
	return exec.Command("which", "xtrabackup").Run()
}

// Run runs the app
func (app *App) Run() {
	//if err := ensureExistXtrabackup(); err != nil {
	//	log.Error("xtrabackup command not found")
	//	panic(err)
	//}
	err := app.Engine.Start(":" + strconv.Itoa(app.Conf.Port))
	if err != nil {
		panic(err)
	}
}
<commit_msg>Comment out<commit_after>package api

import (
	"os/exec"
	"strconv"

	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
	"github.com/labstack/gommon/log"
	"github.com/nu7hatch/gouuid"
	"github.com/taku-k/xtralab/pkg/config"
	"github.com/taku-k/xtralab/pkg/storage"
)

// App struct.
// There is no singleton anti-pattern,
// all variables defined locally inside
// this struct.
type App struct {
	Engine *echo.Echo
	Conf   *config.Config
	API    *API
}

// NewApp returns initialized struct
// of main server application.
func NewApp(conf *config.Config) (*App, error) {
	// Make an engine
	engine := echo.New()

	// Set up echo debug level
	engine.Debug = conf.Debug

	// Regular middlewares
	engine.Use(middleware.Recover())

	engine.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
		Format: `${method} | ${status} | ${uri} -> ${latency_human}` + "\n",
	}))

	// FIXME: use option to choose a backup storage
	s, err := storage.NewLocalBackupStorage(conf)
	if err != nil {
		return nil, err
	}
	bm := NewBackupManager(conf)
	//p := NewNCPool(conf)

	// Initialize the application
	app := &App{
		Conf:   conf,
		Engine: engine,
		API: &API{
			storage: s,
			bm:      bm,
			//pool:    p,
		},
	}

	// Map app and uuid for every requests
	app.Engine.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			c.Set("app", app)
			id, _ := uuid.NewV4()
			c.Set("uuid", id)
			return next(c)
		}
	})

	// Bind api handling for URL api.prefix
	app.API.Bind(
		app.Engine.Group(
			conf.ApiPrefix,
		),
	)

	engine.Logger.SetLevel(log.DEBUG)

	return app, nil
}

func ensureExistXtrabackup() error {
	return exec.Command("which", "xtrabackup").Run()
}

// Run runs the app
func (app *App) Run() {
	//if err := ensureExistXtrabackup(); err != nil {
	//	log.Error("xtrabackup command not found")
	//	panic(err)
	//}
	err := app.Engine.Start(":" + strconv.Itoa(app.Conf.Port))
	if err != nil {
		panic(err)
	}
}
<|endoftext|>