<commit_before>package chunk

import (
	"testing"

	"github.com/jdkato/prose/tag"
	"github.com/jdkato/prose/tokenize"
)

func Test(t *testing.T) {
	text := `
Property surveyors are getting gloomier about the state of the housing market, according to the Royal Institution of Chartered Surveyors (Rics).
Its latest monthly survey shows that stock levels are at a new record low.
The number of people interested in buying a property - and the number of sales - were also "stagnant" in March, it said.
However, because of the shortage of housing, it said prices in many parts of the UK are continuing to accelerate.
While prices carry on falling in central London, Rics said that price rises in the North West were "particularly strong".
Most surveyors across the country still expect prices to rise over the next 12 months, but by a smaller majority than in February.
But on average, each estate agent has just 43 properties for sale on its books, the lowest number recorded since the methodology began in 1994.
"High-end sale properties in central London remain under pressure, while the wider residential market continues to be underpinned by a lack of stock," said Simon Rubinsohn, Rics chief economist.
"For the time being, it is hard to see any major impetus for change in the market, something also being reflected in the flat trend in transaction levels."
Earlier this week, the Office for National Statistics said house prices grew at 5.8% in the year to February, a small rise on the previous month.
However, both Nationwide and the Halifax have said that house price inflation is moderating.
Separate figures from the Bank of England suggested that lenders are offering fewer loans.
Banks reported a tightening of lending criteria, and a drop in loan approval rates.
A significant majority also reported falling demand.
Hansen Lu, property economist with Capital Economics, said that pointed to an "even more gloomy picture than the Rics survey".

The above articile was retrieved from the B.B.C. News website on 13 April 2017.
It was also reported on BBC Radio 4 and BBC Radio 5 Live.
`
	expected := []string{
		"Royal Institution of Chartered Surveyors",
		"Rics",
		"March",
		"UK",
		"central London",
		"Rics",
		"North West",
		"February",
		"central London",
		"Simon Rubinsohn",
		"Rics",
		"Office for National Statistics",
		"February",
		"Nationwide",
		"Halifax",
		"Bank of England",
		"Hansen Lu",
		"Capital Economics",
		"Rics",
		"B.B.C. News",
		"13 April 2017",
		"BBC Radio 4",
		"BBC Radio 5 Live",
	}

	words := tokenize.TextToWords(text)
	tagger := tag.NewPerceptronTagger()
	tagged := tagger.Tag(words)
	rs := Locate(tagged, TreebankNamedEntities)

	for r, loc := range rs {
		res := ""
		for t, tt := range tagged[loc[0]:loc[1]] {
			if t != 0 {
				res += " "
			}
			res += tt.Text
		}
		t.Log(res)
		if r >= len(expected) {
			t.Error("ERROR unexpected result: " + res)
		} else {
			if res != expected[r] {
				t.Error("ERROR", res, "!=", expected[r])
			}
		}
	}
}
<commit_msg>Don't log chunks<commit_after>package chunk

import (
	"testing"

	"github.com/jdkato/prose/tag"
	"github.com/jdkato/prose/tokenize"
)

func Test(t *testing.T) {
	text := `
Property surveyors are getting gloomier about the state of the housing market, according to the Royal Institution of Chartered Surveyors (Rics).
Its latest monthly survey shows that stock levels are at a new record low.
The number of people interested in buying a property - and the number of sales - were also "stagnant" in March, it said.
However, because of the shortage of housing, it said prices in many parts of the UK are continuing to accelerate.
While prices carry on falling in central London, Rics said that price rises in the North West were "particularly strong".
Most surveyors across the country still expect prices to rise over the next 12 months, but by a smaller majority than in February.
But on average, each estate agent has just 43 properties for sale on its books, the lowest number recorded since the methodology began in 1994.
"High-end sale properties in central London remain under pressure, while the wider residential market continues to be underpinned by a lack of stock," said Simon Rubinsohn, Rics chief economist.
"For the time being, it is hard to see any major impetus for change in the market, something also being reflected in the flat trend in transaction levels."
Earlier this week, the Office for National Statistics said house prices grew at 5.8% in the year to February, a small rise on the previous month.
However, both Nationwide and the Halifax have said that house price inflation is moderating.
Separate figures from the Bank of England suggested that lenders are offering fewer loans.
Banks reported a tightening of lending criteria, and a drop in loan approval rates.
A significant majority also reported falling demand.
Hansen Lu, property economist with Capital Economics, said that pointed to an "even more gloomy picture than the Rics survey".

The above articile was retrieved from the B.B.C. News website on 13 April 2017.
It was also reported on BBC Radio 4 and BBC Radio 5 Live.
`
	expected := []string{
		"Royal Institution of Chartered Surveyors",
		"Rics",
		"March",
		"UK",
		"central London",
		"Rics",
		"North West",
		"February",
		"central London",
		"Simon Rubinsohn",
		"Rics",
		"Office for National Statistics",
		"February",
		"Nationwide",
		"Halifax",
		"Bank of England",
		"Hansen Lu",
		"Capital Economics",
		"Rics",
		"B.B.C. News",
		"13 April 2017",
		"BBC Radio 4",
		"BBC Radio 5 Live",
	}

	words := tokenize.TextToWords(text)
	tagger := tag.NewPerceptronTagger()
	tagged := tagger.Tag(words)
	rs := Locate(tagged, TreebankNamedEntities)

	for r, loc := range rs {
		res := ""
		for t, tt := range tagged[loc[0]:loc[1]] {
			if t != 0 {
				res += " "
			}
			res += tt.Text
		}

		if r >= len(expected) {
			t.Error("ERROR unexpected result: " + res)
		} else {
			if res != expected[r] {
				t.Error("ERROR", res, "!=", expected[r])
			}
		}
	}
}
<|endoftext|>


<commit_before>package gorush

import (
	"errors"
	"net/http"

	"github.com/appleboy/gorush/storage/boltdb"
	"github.com/appleboy/gorush/storage/buntdb"
	"github.com/appleboy/gorush/storage/leveldb"
	"github.com/appleboy/gorush/storage/memory"
	"github.com/appleboy/gorush/storage/redis"
	"github.com/gin-gonic/gin"
	"github.com/thoas/stats"
)

// Stats provide response time, status code count, etc.
var Stats = stats.New()

// StatusApp is app status structure
type StatusApp struct {
	Version    string        `json:"version"`
	QueueMax   int           `json:"queue_max"`
	QueueUsage int           `json:"queue_usage"`
	TotalCount int64         `json:"total_count"`
	Ios        IosStatus     `json:"ios"`
	Android    AndroidStatus `json:"android"`
}

// AndroidStatus is android structure
type AndroidStatus struct {
	PushSuccess int64 `json:"push_success"`
	PushError   int64 `json:"push_error"`
}

// IosStatus is iOS structure
type IosStatus struct {
	PushSuccess int64 `json:"push_success"`
	PushError   int64 `json:"push_error"`
}

// InitAppStatus for initialize app status
func InitAppStatus() error {
	switch PushConf.Stat.Engine {
	case "memory":
		StatStorage = memory.New()
	case "redis":
		StatStorage = redis.New(PushConf)
	case "boltdb":
		StatStorage = boltdb.New(PushConf)
	case "buntdb":
		StatStorage = buntdb.New(PushConf)
	case "leveldb":
		StatStorage = leveldb.New(PushConf)
	default:
		err := errors.New("can't find storage driver")
		if err != nil {
			LogError.Error("storage error: " + err.Error())
			return err
		}
	}

	if err := StatStorage.Init(); err != nil {
		LogError.Error("storage error: " + err.Error())

		return err
	}

	return nil
}

func appStatusHandler(c *gin.Context) {
	result := StatusApp{}

	result.Version = GetVersion()
	result.QueueMax = cap(QueueNotification)
	result.QueueUsage = len(QueueNotification)
	result.TotalCount = StatStorage.GetTotalCount()
	result.Ios.PushSuccess = StatStorage.GetIosSuccess()
	result.Ios.PushError = StatStorage.GetIosError()
	result.Android.PushSuccess = StatStorage.GetAndroidSuccess()
	result.Android.PushError = StatStorage.GetAndroidError()

	c.JSON(http.StatusOK, result)
}

func sysStatsHandler(c *gin.Context) {
	c.JSON(http.StatusOK, Stats.Data())
}

// StatMiddleware response time, status code count, etc.
func StatMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		beginning, recorder := Stats.Begin(c.Writer)
		c.Next()
		Stats.End(beginning, recorder)
	}
}
<commit_msg>refactor: update status init func (#241)<commit_after>package gorush

import (
	"errors"
	"net/http"

	"github.com/appleboy/gorush/storage/boltdb"
	"github.com/appleboy/gorush/storage/buntdb"
	"github.com/appleboy/gorush/storage/leveldb"
	"github.com/appleboy/gorush/storage/memory"
	"github.com/appleboy/gorush/storage/redis"
	"github.com/gin-gonic/gin"
	"github.com/thoas/stats"
)

// Stats provide response time, status code count, etc.
var Stats = stats.New()

// StatusApp is app status structure
type StatusApp struct {
	Version    string        `json:"version"`
	QueueMax   int           `json:"queue_max"`
	QueueUsage int           `json:"queue_usage"`
	TotalCount int64         `json:"total_count"`
	Ios        IosStatus     `json:"ios"`
	Android    AndroidStatus `json:"android"`
}

// AndroidStatus is android structure
type AndroidStatus struct {
	PushSuccess int64 `json:"push_success"`
	PushError   int64 `json:"push_error"`
}

// IosStatus is iOS structure
type IosStatus struct {
	PushSuccess int64 `json:"push_success"`
	PushError   int64 `json:"push_error"`
}

// InitAppStatus for initialize app status
func InitAppStatus() error {
	switch PushConf.Stat.Engine {
	case "memory":
		StatStorage = memory.New()
	case "redis":
		StatStorage = redis.New(PushConf)
	case "boltdb":
		StatStorage = boltdb.New(PushConf)
	case "buntdb":
		StatStorage = buntdb.New(PushConf)
	case "leveldb":
		StatStorage = leveldb.New(PushConf)
	default:
		LogError.Error("storage error: can't find storage driver")
		return errors.New("can't find storage driver")
	}

	if err := StatStorage.Init(); err != nil {
		LogError.Error("storage error: " + err.Error())

		return err
	}

	return nil
}

func appStatusHandler(c *gin.Context) {
	result := StatusApp{}

	result.Version = GetVersion()
	result.QueueMax = cap(QueueNotification)
	result.QueueUsage = len(QueueNotification)
	result.TotalCount = StatStorage.GetTotalCount()
	result.Ios.PushSuccess = StatStorage.GetIosSuccess()
	result.Ios.PushError = StatStorage.GetIosError()
	result.Android.PushSuccess = StatStorage.GetAndroidSuccess()
	result.Android.PushError = StatStorage.GetAndroidError()

	c.JSON(http.StatusOK, result)
}

func sysStatsHandler(c *gin.Context) {
	c.JSON(http.StatusOK, Stats.Data())
}

// StatMiddleware response time, status code count, etc.
func StatMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		beginning, recorder := Stats.Begin(c.Writer)
		c.Next()
		Stats.End(beginning, recorder)
	}
}
<|endoftext|>


<commit_before>package gotermBox

import (
	"bytes"
	"io"

	"github.com/antongulenko/goterm"
)

// CliLogBox can display a box spanning over the entire command-line screen
// containing arbitrary content that can be updated from outside, and an additional
// section at the bottom containing log messages captured using a LogBuffer.
type CliLogBox struct {
	// LogBuffer provides the underlying functionality for capturing log messages.
	// CliLogBox acts like an extension of LogBuffer. After calling Init(),
	// the log capturing must be taken care of using RegisterMessageHooks(),
	// InterceptLogger() and RestoreLogger().
	*LogBuffer

	// NoUtf8 can be set to true to replace UTF8 border drawing characters with
	// regular ASCII characters.
	NoUtf8 bool

	// LogLines configures the minimum number of log entries that must remain visible
	// in the lower part of the console box. The log entries are appended directly
	// to the actual output and usually take the rest of the screen. If the box content
	// is so long, that it would leave less than LogLines log entries, the content is
	// truncated. The truncation is visualized by three dots in the separator line
	// between the content and the log entries.
	LogLines int

	// MessageBuffer configures the number of messages stored in the underlying LogBuffer.
	MessageBuffer int
}

// Init initializes the underlying LogBuffer and should be called before any other methods.
func (box *CliLogBox) Init() {
	box.LogBuffer = NewDefaultLogBuffer(box.MessageBuffer)
}

// Updates refreshes the entire display output. It can be called in arbitrary time intervals,
// but should never be called concurrently. The content must be written by the given function,
// which also receives the width of the screen. If it prints lines that are longer than the screen
// width, they will be cut off. It can produce an arbitrary number of lines.
func (box *CliLogBox) Update(writeContent func(out io.Writer, width int)) {
	gotermBox := &goterm.Box{
		Buf:      new(bytes.Buffer),
		Width:    goterm.Width(),
		Height:   goterm.Height() - 1, // Subtract 1 for the line with cursor
		PaddingX: 1,
		PaddingY: 0,
	}
	var separator, dots string
	if box.NoUtf8 {
		gotermBox.Border = "- | - - - -"
		separator = "-"
		dots = "... "
	} else {
		gotermBox.Border = "═ ║ ╔ ╗ ╚ ╝"
		separator = "═"
		dots = "··· "
	}
	lines := gotermBox.Height - 3 // borders + separator

	counter := newlineCounter{out: gotermBox}
	if box.LogLines > 0 {
		counter.max_lines = lines - box.LogLines
	}
	writeContent(&counter, gotermBox.Width)
	lines -= counter.num

	if counter.num > 0 {
		i := 0
		if counter.truncated {
			gotermBox.Write([]byte(dots))
			i += len(dots)
		}
		for i := 0; i < gotermBox.Width; i++ {
			gotermBox.Write([]byte(separator))
		}
		gotermBox.Write([]byte("\n"))
	}
	box.PrintMessages(gotermBox, lines)
	goterm.MoveCursor(1, 1)
	goterm.Print(gotermBox)
	goterm.Flush()
}

type newlineCounter struct {
	out       io.Writer
	num       int
	max_lines int
	truncated bool
}

func (counter *newlineCounter) Write(data []byte) (int, error) {
	total := len(data)
	if counter.max_lines <= 0 || counter.num < counter.max_lines {
		written := 0
		start := 0
		for i, char := range data {
			if char == '\n' {
				counter.num++
				num, err := counter.out.Write(data[start : i+1])
				written += num
				start = i + 1
				if err != nil {
					return written, err
				}
				if counter.max_lines > 0 && counter.num >= counter.max_lines {
					return total, err
				}
			}
		}
		num, err := counter.out.Write(data[start:])
		written += num
		if err != nil {
			return written, err
		}
	} else {
		counter.truncated = true
	}
	return total, nil
}
<commit_msg>fixing<commit_after>package gotermBox

import (
	"bytes"
	"io"

	"github.com/antongulenko/golib"
	"github.com/antongulenko/goterm"
)

// CliLogBox can display a box spanning over the entire command-line screen
// containing arbitrary content that can be updated from outside, and an additional
// section at the bottom containing log messages captured using a LogBuffer.
type CliLogBox struct {
	// LogBuffer provides the underlying functionality for capturing log messages.
	// CliLogBox acts like an extension of LogBuffer. After calling Init(),
	// the log capturing must be taken care of using RegisterMessageHooks(),
	// InterceptLogger() and RestoreLogger().
	*LogBuffer

	// NoUtf8 can be set to true to replace UTF8 border drawing characters with
	// regular ASCII characters.
	NoUtf8 bool

	// LogLines configures the minimum number of log entries that must remain visible
	// in the lower part of the console box. The log entries are appended directly
	// to the actual output and usually take the rest of the screen. If the box content
	// is so long, that it would leave less than LogLines log entries, the content is
	// truncated. The truncation is visualized by three dots in the separator line
	// between the content and the log entries.
	LogLines int

	// MessageBuffer configures the number of messages stored in the underlying LogBuffer.
	MessageBuffer int
}

// Init initializes the underlying LogBuffer and should be called before any other methods.
func (box *CliLogBox) Init() {
	box.LogBuffer = NewDefaultLogBuffer(box.MessageBuffer)
}

// Updates refreshes the entire display output. It can be called in arbitrary time intervals,
// but should never be called concurrently. The content must be written by the given function,
// which also receives the width of the screen. If it prints lines that are longer than the screen
// width, they will be cut off. It can produce an arbitrary number of lines.
func (box *CliLogBox) Update(writeContent func(out io.Writer, width int)) {
	termSize := golib.GetTerminalSize()
	gotermBox := &goterm.Box{
		Buf:      new(bytes.Buffer),
		Width:    int(termSize.Col),
		Height:   int(termSize.Row) - 1, // Subtract 1 for the line with cursor
		PaddingX: 1,
		PaddingY: 0,
	}
	var separator, dots string
	if box.NoUtf8 {
		gotermBox.Border = "- | - - - -"
		separator = "-"
		dots = "... "
	} else {
		gotermBox.Border = "═ ║ ╔ ╗ ╚ ╝"
		separator = "═"
		dots = "··· "
	}
	lines := gotermBox.Height - 3 // borders + separator

	counter := newlineCounter{out: gotermBox}
	if box.LogLines > 0 {
		counter.max_lines = lines - box.LogLines
	}
	writeContent(&counter, gotermBox.Width)
	lines -= counter.num

	if counter.num > 0 {
		i := 0
		if counter.truncated {
			gotermBox.Write([]byte(dots))
			i += len(dots)
		}
		for i := 0; i < gotermBox.Width; i++ {
			gotermBox.Write([]byte(separator))
		}
		gotermBox.Write([]byte("\n"))
	}
	box.PrintMessages(gotermBox, lines)
	goterm.MoveCursor(1, 1)
	goterm.Print(gotermBox)
	goterm.Flush()
}

type newlineCounter struct {
	out       io.Writer
	num       int
	max_lines int
	truncated bool
}

func (counter *newlineCounter) Write(data []byte) (int, error) {
	total := len(data)
	if counter.max_lines <= 0 || counter.num < counter.max_lines {
		written := 0
		start := 0
		for i, char := range data {
			if char == '\n' {
				counter.num++
				num, err := counter.out.Write(data[start : i+1])
				written += num
				start = i + 1
				if err != nil {
					return written, err
				}
				if counter.max_lines > 0 && counter.num >= counter.max_lines {
					return total, err
				}
			}
		}
		num, err := counter.out.Write(data[start:])
		written += num
		if err != nil {
			return written, err
		}
	} else {
		counter.truncated = true
	}
	return total, nil
}
<|endoftext|>


<commit_before>// A microservice that accepts HTTP requests, creates a Task from given
// parameters, and adds the Task to a Push TaskQueue.
package pushqueue

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"net/url"

	"github.com/m-lab/etl/etl"
	"github.com/m-lab/etl/storage"
	"google.golang.org/appengine"
	"google.golang.org/appengine/taskqueue"
)

const defaultMessage = "This is not the app you're looking for."

// Requests can only add tasks to one of these whitelisted queue names.
var queueForType = map[etl.DataType]string{
	etl.NDT: "etl-ndt-queue",
	etl.SS:  "etl-sidestream-queue",
	etl.PT:  "etl-traceroute-queue",
	etl.SW:  "etl-disco-queue",
}

func init() {
	http.HandleFunc("/", defaultHandler)
	http.HandleFunc("/receiver", receiver)
	http.HandleFunc("/stats", queueStats)
}

// A default handler for root path.
func defaultHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}
	fmt.Fprintf(w, defaultMessage)
}

// queueStats provides statistics for a given queue.
func queueStats(w http.ResponseWriter, r *http.Request) {
	queuename := r.FormValue("queuename")

	if queuename == "" {
		http.Error(w, `{"message": "Bad request parameters"}`, http.StatusBadRequest)
		return
	}

	// TODO(dev): maybe this should be made more efficient?
	validQueue := false
	for _, queue := range queueForType {
		validQueue = validQueue || (queuename == queue)
	}
	if !validQueue {
		// TODO(dev): return a list of valid queues
		http.Error(w, `{"message": "Given queue name is not acceptable"}`, http.StatusNotAcceptable)
		return
	}

	// Get stats.
	ctx := appengine.NewContext(r)
	stats, err := taskqueue.QueueStats(ctx, []string{queuename})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Return stats to client.
	b, err := json.Marshal(stats)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	fmt.Fprintf(w, string(b))
}

// receiver accepts a GET request, and transforms the given parameters into a TaskQueue Task.
func receiver(w http.ResponseWriter, r *http.Request) {
	// TODO(dev): require a POST instead of working with both POST and GET
	// after we update the Cloud Function to use POST.
	filename := r.FormValue("filename")
	if filename == "" {
		http.Error(w, `{"message": "No filename provided"}`, http.StatusBadRequest)
		return
	}

	decoded_filename, err := storage.GetFilename(filename)
	if err != nil {
		http.Error(w, `{"message": "Could not base64decode filename"}`, http.StatusBadRequest)
		return
	}

	// Validate filename.
	fn_data, err := etl.ValidateTestPath(decoded_filename)
	if err != nil {
		log.Println(err)
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, `{"message": "Invalid filename."}`)
	}
	// determine correct queue based on file name.
	queuename, ok := queueForType[fn_data.GetDataType()]

	// Lots of files will be archived that should not be enqueued. Pass
	// over those files without comment.
	// TODO(dev) count how many names we skip over using prometheus
	if ok {
		ctx := appengine.NewContext(r)
		params := url.Values{"filename": []string{filename}}
		t := taskqueue.NewPOSTTask("/worker", params)
		if _, err := taskqueue.Add(ctx, t, queuename); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}
}
<commit_msg>Add return after error to avoid panic<commit_after>// A microservice that accepts HTTP requests, creates a Task from given
// parameters, and adds the Task to a Push TaskQueue.
package pushqueue

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"net/url"

	"github.com/m-lab/etl/etl"
	"github.com/m-lab/etl/storage"
	"google.golang.org/appengine"
	"google.golang.org/appengine/taskqueue"
)

const defaultMessage = "This is not the app you're looking for."

// Requests can only add tasks to one of these whitelisted queue names.
var queueForType = map[etl.DataType]string{
	etl.NDT: "etl-ndt-queue",
	etl.SS:  "etl-sidestream-queue",
	etl.PT:  "etl-traceroute-queue",
	etl.SW:  "etl-disco-queue",
}

func init() {
	http.HandleFunc("/", defaultHandler)
	http.HandleFunc("/receiver", receiver)
	http.HandleFunc("/stats", queueStats)
}

// A default handler for root path.
func defaultHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}
	fmt.Fprintf(w, defaultMessage)
}

// queueStats provides statistics for a given queue.
func queueStats(w http.ResponseWriter, r *http.Request) {
	queuename := r.FormValue("queuename")

	if queuename == "" {
		http.Error(w, `{"message": "Bad request parameters"}`, http.StatusBadRequest)
		return
	}

	// TODO(dev): maybe this should be made more efficient?
	validQueue := false
	for _, queue := range queueForType {
		validQueue = validQueue || (queuename == queue)
	}
	if !validQueue {
		// TODO(dev): return a list of valid queues
		http.Error(w, `{"message": "Given queue name is not acceptable"}`, http.StatusNotAcceptable)
		return
	}

	// Get stats.
	ctx := appengine.NewContext(r)
	stats, err := taskqueue.QueueStats(ctx, []string{queuename})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Return stats to client.
	b, err := json.Marshal(stats)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	fmt.Fprintf(w, string(b))
}

// receiver accepts a GET request, and transforms the given parameters into a TaskQueue Task.
func receiver(w http.ResponseWriter, r *http.Request) {
	// TODO(dev): require a POST instead of working with both POST and GET
	// after we update the Cloud Function to use POST.
	filename := r.FormValue("filename")
	if filename == "" {
		http.Error(w, `{"message": "No filename provided"}`, http.StatusBadRequest)
		return
	}

	decoded_filename, err := storage.GetFilename(filename)
	if err != nil {
		http.Error(w, `{"message": "Could not base64decode filename"}`, http.StatusBadRequest)
		return
	}

	// Validate filename.
	fn_data, err := etl.ValidateTestPath(decoded_filename)
	if err != nil {
		log.Println(err)
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, `{"message": "Invalid filename."}`)
		return
	}
	// determine correct queue based on file name.
	queuename, ok := queueForType[fn_data.GetDataType()]

	// Lots of files will be archived that should not be enqueued. Pass
	// over those files without comment.
	// TODO(dev) count how many names we skip over using prometheus
	if ok {
		ctx := appengine.NewContext(r)
		params := url.Values{"filename": []string{filename}}
		t := taskqueue.NewPOSTTask("/worker", params)
		if _, err := taskqueue.Add(ctx, t, queuename); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"math/rand"
	"strings"
	"time"

	derpiSearch "github.com/PonyvilleFM/aura/cmd/aerial/derpi"
	"github.com/PonyvilleFM/aura/pvfm"
	"github.com/PonyvilleFM/aura/pvfm/pvl"
	pvfmschedule "github.com/PonyvilleFM/aura/pvfm/schedule"
	"github.com/PonyvilleFM/aura/pvfm/station"
	"github.com/bwmarrin/discordgo"
	"github.com/tebeka/strftime"
)

func init() {
	rand.Seed(time.Now().Unix())
}

// randomRange gives a random whole integer between the given integers [min, max)
func randomRange(min, max int) int {
	return rand.Intn(max-min) + min
}

func pesterLink(s *discordgo.Session, m *discordgo.MessageCreate) {
	if musicLinkRegex.Match([]byte(m.Content)) {
		i, err := pvfm.GetStats()
		if err != nil {
			log.Println(err)
			return
		}

		if i.IsDJLive() && m.ChannelID == youtubeSpamRoomID {
			s.ChannelMessageSend(m.ChannelID, "Please be mindful sharing links to music when a DJ is performing. Thanks!")
		}
	}
}

func np(s *discordgo.Session, m *discordgo.Message, parv []string) error {
	i, err := pvfm.GetStats()
	if err != nil {
		log.Printf("Can't get info: %v, failing over to plan b", err)
		return doStationRequest(s, m, parv)
	}

	result := []string{}

	if i.Main.Nowplaying == "Fetching info..." {
		log.Println("Main information was bad, fetching from station directly...")

		err := doStationRequest(s, m, parv)
		if err != nil {
			return err
		}

		return nil
	} else {
		result = append(result, "📻 **Now Playing on PVFM**\n")

		result = append(result, fmt.Sprintf(
			"Main 🎵 %s\n",
			i.Main.Nowplaying,
		))
		result = append(result, fmt.Sprintf(
			"Chill 🎵 %s\n",
			i.Secondary.Nowplaying,
		))
		result = append(result, fmt.Sprintf(
			"Free! 🎵 %s",
			i.MusicOnly.Nowplaying,
		))
	}

	s.ChannelMessageSend(m.ChannelID, strings.Join(result, "\n"))
	return nil
}

func dj(s *discordgo.Session, m *discordgo.Message, parv []string) error {
	cal, err := pvl.Get()
	if err != nil {
		return err
	}

	now := cal.Result[0]
	result := []string{}

	localTime := time.Now()
	thentime := time.Unix(now.StartTime, 0)
	if thentime.Unix() < localTime.Unix() {
		result = append(result, fmt.Sprintf("Currently live: %s\n", now.Title))
		now = cal.Result[1]
	}

	nowTime := time.Unix(now.StartTime, 0).UTC()
	zone, _ := nowTime.Zone()
	fmttime, _ := strftime.Format("%Y-%m-%d %H:%M:%S", nowTime)

	result = append(result, fmt.Sprintf("Next event: %s at %s \x02%s\x02",
		now.Title,
		fmttime,
		zone,
	))

	s.ChannelMessageSend(m.ChannelID, strings.Join(result, "\n"))
	return nil
}

func stats(s *discordgo.Session, m *discordgo.Message, parv []string) error {
	i, err := pvfm.GetStats()
	if err != nil {
		log.Printf("Error getting the station info: %v, falling back to plan b", err)
		return doStatsFromStation(s, m, parv)
	}

	st, err := station.GetStats()
	if err != nil {
		return err
	}

	var l int
	var peak int

	for _, source := range st.Icestats.Source {
		l = l + source.Listeners
		peak = peak + source.ListenerPeak
	}

	result := []string{
		fmt.Sprintf(
			"Current listeners across all streams: %d with a maximum of %d!",
			i.Listeners.Listeners, peak,
		),
		fmt.Sprintf(
			"Detailed: Main: %d listeners, Two: %d listeners, Free: %d listeners",
			i.Main.Listeners, i.Secondary.Listeners, i.MusicOnly.Listeners,
		),
	}

	s.ChannelMessageSend(m.ChannelID, strings.Join(result, "\n"))

	return nil
}

func schedule(s *discordgo.Session, m *discordgo.Message, parv []string) error {
	result := []string{}
	schEntries, err := pvfmschedule.Get()
	if err != nil {
		return err
	}

	for _, entry := range schEntries {
		result = append(result, entry.String())
	}

	s.ChannelMessageSend(m.ChannelID, strings.Join(result, "\n"))
	return nil
}

func doStationRequest(s *discordgo.Session, m *discordgo.Message, parv []string) error {
	stats, err := station.GetStats()
	if err != nil {
		return err
	}

	result := fmt.Sprintf(
		"Now playing: %s - %s on Ponyville FM!",
		stats.Icestats.Source[0].Title,
		stats.Icestats.Source[0].Artist,
	)

	s.ChannelMessageSend(m.ChannelID, result)
	return nil
}

func doStatsFromStation(s *discordgo.Session, m *discordgo.Message, parv []string) error {
	st, err := station.GetStats()
	if err != nil {
		return err
	}

	var l int
	var peak int

	for _, source := range st.Icestats.Source {
		l = l + source.Listeners
		peak = peak + source.ListenerPeak
	}

	result := []string{
		fmt.Sprintf("Current listeners: %d with a maximum of %d!", l, peak),
	}

	s.ChannelMessageSend(m.ChannelID, strings.Join(result, "\n"))
	return nil
}

func curTime(s *discordgo.Session, m *discordgo.Message, parv []string) error {
	s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("The time currently is %s", time.Now().UTC().Format("2006-01-02 15:04:05 UTC")))

	return nil
}

func streams(s *discordgo.Session, m *discordgo.Message, parv []string) error {
	currentMeta, metaErr := station.GetStats()
	if metaErr != nil {
		s.ChannelMessageSend(m.ChannelID, "Error receiving pvfm metadata")
		return metaErr
	}

	// start building custom embed
	outputEmbed := NewEmbed().
		SetTitle("Stream Links").
		SetDescription("These are direct feeds of the live streams; most browsers and media players can play them!")

		// this will dynamically build the list from station metadata
		pvfmList := ""
	for _, element := range currentMeta.Icestats.Source {
		pvfmList += ":musical_note: " + element.ServerDescription + ":\n<" + strings.Replace(element.Listenurl, "aerial", "dj.bronyradio.com", -1) + ">\n"
	}

	// PVFM
	outputEmbed.AddField("PVFM Servers", pvfmList)
	// Luna Radio
	outputEmbed.AddField("Luna Radio Servers", ":musical_note: Luna Radio MP3 128Kbps Stream:\n<http://radio.ponyvillelive.com:8002/stream.mp3>\n:musical_note: Luna Radio Mobile MP3 64Kbps Stream:\n<http://radio.ponyvillelive.com:8002/mobile?;stream.mp3>\n")
	// Recordings
	outputEmbed.AddField(":cd: DJ Recordings", "<https://pvfmsets.cf/var/93252527679639552/>")
	// Legacy Recordings
	outputEmbed.AddField(":cd: Legacy DJ Recordings", "<http://darkling.darkwizards.com/wang/BronyRadio/?M=D>")

	s.ChannelMessageSendEmbed(m.ChannelID, outputEmbed.MessageEmbed)

	// no errors yay!!!!
	return nil
}

func derpi(s *discordgo.Session, m *discordgo.Message, parv []string) error {
	searchResults, err := derpiSearch.SearchDerpi(m.Content[7:len(m.Content)]) // no api key needed, we only search safe images!
	if err != nil {
		s.ChannelMessageSend(m.ChannelID, "An error occured.")
		return err
	}
	if len(searchResults.Search) < 1 {
		s.ChannelMessageSend(m.ChannelID, "Error: No results")
		return nil
	}
	s.ChannelMessageSend(m.ChannelID, "http:"+searchResults.Search[randomRange(0, len(searchResults.Search))].Image)
	return nil
}
<commit_msg>reformat streams for consistency with new format<commit_after>package main

import (
	"fmt"
	"log"
	"math/rand"
	"strings"
	"time"

	derpiSearch "github.com/PonyvilleFM/aura/cmd/aerial/derpi"
	"github.com/PonyvilleFM/aura/pvfm"
	"github.com/PonyvilleFM/aura/pvfm/pvl"
	pvfmschedule "github.com/PonyvilleFM/aura/pvfm/schedule"
	"github.com/PonyvilleFM/aura/pvfm/station"
	"github.com/bwmarrin/discordgo"
	"github.com/tebeka/strftime"
)

func init() {
	rand.Seed(time.Now().Unix())
}

// randomRange gives a random whole integer between the given integers [min, max)
func randomRange(min, max int) int {
	return rand.Intn(max-min) + min
}

func pesterLink(s *discordgo.Session, m *discordgo.MessageCreate) {
	if musicLinkRegex.Match([]byte(m.Content)) {
		i, err := pvfm.GetStats()
		if err != nil {
			log.Println(err)
			return
		}

		if i.IsDJLive() && m.ChannelID == youtubeSpamRoomID {
			s.ChannelMessageSend(m.ChannelID, "Please be mindful sharing links to music when a DJ is performing. Thanks!")
		}
	}
}

func np(s *discordgo.Session, m *discordgo.Message, parv []string) error {
	i, err := pvfm.GetStats()
	if err != nil {
		log.Printf("Can't get info: %v, failing over to plan b", err)
		return doStationRequest(s, m, parv)
	}

	result := []string{}

	if i.Main.Nowplaying == "Fetching info..." {
		log.Println("Main information was bad, fetching from station directly...")

		err := doStationRequest(s, m, parv)
		if err != nil {
			return err
		}

		return nil
	} else {
		result = append(result, "📻 **Now Playing on PVFM**\n")

		result = append(result, fmt.Sprintf(
			"Main 🎵 %s\n",
			i.Main.Nowplaying,
		))
		result = append(result, fmt.Sprintf(
			"Chill 🎵 %s\n",
			i.Secondary.Nowplaying,
		))
		result = append(result, fmt.Sprintf(
			"Free! 🎵 %s",
			i.MusicOnly.Nowplaying,
		))
	}

	s.ChannelMessageSend(m.ChannelID, strings.Join(result, "\n"))
	return nil
}

func dj(s *discordgo.Session, m *discordgo.Message, parv []string) error {
	cal, err := pvl.Get()
	if err != nil {
		return err
	}

	now := cal.Result[0]
	result := []string{}

	localTime := time.Now()
	thentime := time.Unix(now.StartTime, 0)
	if thentime.Unix() < localTime.Unix() {
		result = append(result, fmt.Sprintf("Currently live: %s\n", now.Title))
		now = cal.Result[1]
	}

	nowTime := time.Unix(now.StartTime, 0).UTC()
	zone, _ := nowTime.Zone()
	fmttime, _ := strftime.Format("%Y-%m-%d %H:%M:%S", nowTime)

	result = append(result, fmt.Sprintf("Next event: %s at %s \x02%s\x02",
		now.Title,
		fmttime,
		zone,
	))

	s.ChannelMessageSend(m.ChannelID, strings.Join(result, "\n"))
	return nil
}

func stats(s *discordgo.Session, m *discordgo.Message, parv []string) error {
	i, err := pvfm.GetStats()
	if err != nil {
		log.Printf("Error getting the station info: %v, falling back to plan b", err)
		return doStatsFromStation(s, m, parv)
	}

	st, err := station.GetStats()
	if err != nil {
		return err
	}

	var l int
	var peak int

	for _, source := range st.Icestats.Source {
		l = l + source.Listeners
		peak = peak + source.ListenerPeak
	}

	result := []string{
		fmt.Sprintf(
			"Current listeners across all streams: %d with a maximum of %d!",
			i.Listeners.Listeners, peak,
		),
		fmt.Sprintf(
			"Detailed: Main: %d listeners, Two: %d listeners, Free: %d listeners",
			i.Main.Listeners, i.Secondary.Listeners, i.MusicOnly.Listeners,
		),
	}

	s.ChannelMessageSend(m.ChannelID, strings.Join(result, "\n"))

	return nil
}

func schedule(s *discordgo.Session, m *discordgo.Message, parv []string) error {
	result := []string{}
	schEntries, err := pvfmschedule.Get()
	if err != nil {
		return err
	}

	for _, entry := range schEntries {
		result = append(result, entry.String())
	}

	s.ChannelMessageSend(m.ChannelID, strings.Join(result, "\n"))
	return nil
}

func doStationRequest(s *discordgo.Session, m *discordgo.Message, parv []string) error {
	stats, err := station.GetStats()
	if err != nil {
		return err
	}

	result := fmt.Sprintf(
		"Now playing: %s - %s on Ponyville FM!",
		stats.Icestats.Source[0].Title,
		stats.Icestats.Source[0].Artist,
	)

	s.ChannelMessageSend(m.ChannelID, result)
	return nil
}

func doStatsFromStation(s *discordgo.Session, m *discordgo.Message, parv []string) error {
	st, err := station.GetStats()
	if err != nil {
		return err
	}

	var l int
	var peak int

	for _, source := range st.Icestats.Source {
		l = l + source.Listeners
		peak = peak + source.ListenerPeak
	}

	result := []string{
		fmt.Sprintf("Current listeners: %d with a maximum of %d!", l, peak),
	}

	s.ChannelMessageSend(m.ChannelID, strings.Join(result, "\n"))
	return nil
}

func curTime(s *discordgo.Session, m *discordgo.Message, parv []string) error {
	s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("The time currently is %s", time.Now().UTC().Format("2006-01-02 15:04:05 UTC")))

	return nil
}

func streams(s *discordgo.Session, m *discordgo.Message, parv []string) error {
	currentMeta, metaErr := station.GetStats()
	if metaErr != nil {
		s.ChannelMessageSend(m.ChannelID, "Error receiving pvfm metadata")
		return metaErr
	}

	// start building custom embed
	outputEmbed := NewEmbed().
		SetTitle("Stream Links").
		SetDescription("These are direct feeds of the live streams; most browsers and media players can play them!")

		// this will dynamically build the list from station metadata
		pvfmList := ""
	for _, element := range currentMeta.Icestats.Source {
		pvfmList += ":musical_note: " + element.ServerDescription + ":\n<" + strings.Replace(element.Listenurl, "aerial", "dj.bronyradio.com", -1) + ">\n"
	}

	// PVFM
	outputEmbed.AddField(":musical_note:  PVFM Servers", pvfmList)
	// Luna Radio
	outputEmbed.AddField(":musical_note:  Luna Radio Servers", "Luna Radio MP3 128Kbps Stream:\n<http://radio.ponyvillelive.com:8002/stream.mp3>\nLuna Radio Mobile MP3 64Kbps Stream:\n<http://radio.ponyvillelive.com:8002/mobile?;stream.mp3>\n")
	// Recordings
	outputEmbed.AddField(":cd:  DJ Recordings", "Archive\n<https://pvfmsets.cf/var/93252527679639552/>\nLegacy Archive\n<http://darkling.darkwizards.com/wang/BronyRadio/?M=D>")

	s.ChannelMessageSendEmbed(m.ChannelID, outputEmbed.MessageEmbed)

	// no errors yay!!!!
	return nil
}

func derpi(s *discordgo.Session, m *discordgo.Message, parv []string) error {
	searchResults, err := derpiSearch.SearchDerpi(m.Content[7:len(m.Content)]) // no api key needed, we only search safe images!
	if err != nil {
		s.ChannelMessageSend(m.ChannelID, "An error occured.")
		return err
	}
	if len(searchResults.Search) < 1 {
		s.ChannelMessageSend(m.ChannelID, "Error: No results")
		return nil
	}
	s.ChannelMessageSend(m.ChannelID, "http:"+searchResults.Search[randomRange(0, len(searchResults.Search))].Image)
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"

	"golang.org/x/tools/go/vcs"
)

// builderEnv represents the environment that a Builder will run tests in.
type builderEnv interface {
	// setup sets up the builder environment and returns the directory to run the buildCmd in.
	setup(repo *Repo, workpath, hash string, envv []string) (string, error)
}

// goEnv represents the builderEnv for the main Go repo.
type goEnv struct {
	goos, goarch string
}

func (b *Builder) envv() []string {
	if runtime.GOOS == "windows" {
		return b.envvWindows()
	}

	var e []string
	if *buildTool == "go" {
		e = []string{
			"GOOS=" + b.goos,
			"GOARCH=" + b.goarch,
		}
		switch b.goos {
		case "android", "nacl":
			// Cross compile.
		default:
			// If we are building, for example, linux/386 on a linux/amd64 machine we want to
			// make sure that the whole build is done as a if this were compiled on a real
			// linux/386 machine. In other words, we want to not do a cross compilation build.
			// To do this we set GOHOSTOS and GOHOSTARCH to override the detection in make.bash.
			//
			// The exception to this rule is when we are doing nacl/android builds. These are by
			// definition always cross compilation, and we have support built into cmd/go to be
			// able to handle this case.
			e = append(e, "GOHOSTOS="+b.goos, "GOHOSTARCH="+b.goarch)
		}
	}

	for _, k := range extraEnv() {
		if s, ok := getenvOk(k); ok {
			e = append(e, k+"="+s)
		}
	}
	return e
}

func (b *Builder) envvWindows() []string {
	var start map[string]string
	if *buildTool == "go" {
		start = map[string]string{
			"GOOS":        b.goos,
			"GOHOSTOS":    b.goos,
			"GOARCH":      b.goarch,
			"GOHOSTARCH":  b.goarch,
			"GOBUILDEXIT": "1", // exit all.bat with completion status.
		}
	}

	for _, name := range extraEnv() {
		if s, ok := getenvOk(name); ok {
			start[name] = s
		}
	}
	if b.goos == "windows" {
		switch b.goarch {
		case "amd64":
			start["PATH"] = `c:\TDM-GCC-64\bin;` + start["PATH"]
		case "386":
			start["PATH"] = `c:\TDM-GCC-32\bin;` + start["PATH"]
		}
	}
	skip := map[string]bool{
		"GOBIN":   true,
		"GOPATH":  true,
		"GOROOT":  true,
		"INCLUDE": true,
		"LIB":     true,
	}
	var e []string
	for name, v := range start {
		e = append(e, name+"="+v)
		skip[name] = true
	}
	for _, kv := range os.Environ() {
		s := strings.SplitN(kv, "=", 2)
		name := strings.ToUpper(s[0])
		switch {
		case name == "":
			// variables, like "=C:=C:\", just copy them
			e = append(e, kv)
		case !skip[name]:
			e = append(e, kv)
			skip[name] = true
		}
	}
	return e
}

// setup for a goEnv clones the main go repo to workpath/go at the provided hash
// and returns the path workpath/go/src, the location of all go build scripts.
func (env *goEnv) setup(repo *Repo, workpath, hash string, envv []string) (string, error) {
	goworkpath := filepath.Join(workpath, "go")
	if err := repo.Export(goworkpath, hash); err != nil {
		return "", fmt.Errorf("error exporting repository: %s", err)
	}
	return filepath.Join(goworkpath, "src"), nil
}

// gccgoEnv represents the builderEnv for the gccgo compiler.
type gccgoEnv struct{}

// setup for a gccgoEnv clones the gofrontend repo to workpath/go at the hash
// and clones the latest GCC branch to repo.Path/gcc. The gccgo sources are
// replaced with the updated sources in the gofrontend repo and gcc gets
// gets configured and built in workpath/gcc-objdir. The path to
// workpath/gcc-objdir is returned.
func (env *gccgoEnv) setup(repo *Repo, workpath, hash string, envv []string) (string, error) {
	gccpath := filepath.Join(repo.Path, "gcc")

	// get a handle to Git vcs.Cmd for pulling down GCC from the mirror.
	git := vcs.ByCmd("git")

	// only pull down gcc if we don't have a local copy.
	if _, err := os.Stat(gccpath); err != nil {
		if err := timeout(*cmdTimeout, func() error {
			// pull down a working copy of GCC.

			cloneCmd := []string{
				"clone",
				// This is just a guess since there are ~6000 commits to
				// GCC per year. It's likely there will be enough history
				// to cross-reference the Gofrontend commit against GCC.
				// The disadvantage would be if the commit being built is more than
				// a year old; in this case, the user should make a clone that has
				// the full history.
				"--depth", "6000",
				// We only care about the master branch.
				"--branch", "master", "--single-branch",
				*gccPath,
			}

			// Clone Kind			Clone Time(Dry run)	Clone Size
			// ---------------------------------------------------------------
			// Full Clone			10 - 15 min		2.2 GiB
			// Master Branch		2 - 3 min		1.5 GiB
			// Full Clone(shallow)		1 min			900 MiB
			// Master Branch(shallow)	40 sec			900 MiB
			//
			// The shallow clones have the same size, which is expected,
			// but the full shallow clone will only have 6000 commits
			// spread across all branches.  There are ~50 branches.
			return run(exec.Command("git", cloneCmd...), runEnv(envv), allOutput(os.Stdout), runDir(repo.Path))
		}); err != nil {
			return "", err
		}
	}

	if err := git.Download(gccpath); err != nil {
		return "", err
	}

	// get the modified files for this commit.

	var buf bytes.Buffer
	if err := run(exec.Command("hg", "status", "--no-status", "--change", hash),
		allOutput(&buf), runDir(repo.Path), runEnv(envv)); err != nil {
		return "", fmt.Errorf("Failed to find the modified files for %s: %s", hash, err)
	}
	modifiedFiles := strings.Split(buf.String(), "\n")
	var isMirrored bool
	for _, f := range modifiedFiles {
		if strings.HasPrefix(f, "go/") || strings.HasPrefix(f, "libgo/") {
			isMirrored = true
			break
		}
	}

	// use git log to find the corresponding commit to sync to in the gcc mirror.
	// If the files modified in the gofrontend are mirrored to gcc, we expect a
	// commit with a similar description in the gcc mirror. If the files modified are
	// not mirrored, e.g. in support/, we can sync to the most recent gcc commit that
	// occurred before those files were modified to verify gccgo's status at that point.
	logCmd := []string{
		"log",
		"-1",
		"--format=%H",
	}
	var errMsg string
	if isMirrored {
		commitDesc, err := repo.Master.VCS.LogAtRev(repo.Path, hash, "{desc|firstline|escape}")
		if err != nil {
			return "", err
		}

		quotedDesc := regexp.QuoteMeta(string(commitDesc))
		logCmd = append(logCmd, "--grep", quotedDesc, "--regexp-ignore-case", "--extended-regexp")
		errMsg = fmt.Sprintf("Failed to find a commit with a similar description to '%s'", string(commitDesc))
	} else {
		commitDate, err := repo.Master.VCS.LogAtRev(repo.Path, hash, "{date|rfc3339date}")
		if err != nil {
			return "", err
		}

		logCmd = append(logCmd, "--before", string(commitDate))
		errMsg = fmt.Sprintf("Failed to find a commit before '%s'", string(commitDate))
	}

	buf.Reset()
	if err := run(exec.Command("git", logCmd...), runEnv(envv), allOutput(&buf), runDir(gccpath)); err != nil {
		return "", fmt.Errorf("%s: %s", errMsg, err)
	}
	gccRev := buf.String()
	if gccRev == "" {
		return "", fmt.Errorf(errMsg)
	}

	// checkout gccRev
	// TODO(cmang): Fix this to work in parallel mode.
	if err := run(exec.Command("git", "reset", "--hard", strings.TrimSpace(gccRev)), runEnv(envv), runDir(gccpath)); err != nil {
		return "", fmt.Errorf("Failed to checkout commit at revision %s: %s", gccRev, err)
	}

	// make objdir to work in
	gccobjdir := filepath.Join(workpath, "gcc-objdir")
	if err := os.Mkdir(gccobjdir, mkdirPerm); err != nil {
		return "", err
	}

	// configure GCC with substituted gofrontend and libgo
	if err := run(exec.Command(filepath.Join(gccpath, "configure"),
		"--enable-languages=c,c++,go",
		"--disable-bootstrap",
		"--disable-multilib",
	), runEnv(envv), runDir(gccobjdir)); err != nil {
		return "", fmt.Errorf("Failed to configure GCC: %v", err)
	}

	// build gcc
	if err := run(exec.Command("make", *gccOpts), runTimeout(*buildTimeout), runEnv(envv), runDir(gccobjdir)); err != nil {
		return "", fmt.Errorf("Failed to build GCC: %s", err)
	}

	return gccobjdir, nil
}

func getenvOk(k string) (v string, ok bool) {
	v = os.Getenv(k)
	if v != "" {
		return v, true
	}
	keq := k + "="
	for _, kv := range os.Environ() {
		if kv == keq {
			return "", true
		}
	}
	return "", false
}

// extraEnv returns environment variables that need to be copied from
// the gobuilder's environment to the envv of its subprocesses.
func extraEnv() []string {
	extra := []string{
		"GOARM",
		"GO386",
		"GOROOT_BOOTSTRAP", // See https://golang.org/s/go15bootstrap
		"CGO_ENABLED",
		"CC",
		"CC_FOR_TARGET",
		"PATH",
		"TMPDIR",
		"USER",
	}
	if runtime.GOOS == "plan9" {
		extra = append(extra, "objtype", "cputype", "path")
	}
	return extra
}
<commit_msg>cmd/builder: cross compile darwin/arm<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"

	"golang.org/x/tools/go/vcs"
)

// builderEnv represents the environment that a Builder will run tests in.
type builderEnv interface {
	// setup sets up the builder environment and returns the directory to run the buildCmd in.
	setup(repo *Repo, workpath, hash string, envv []string) (string, error)
}

// goEnv represents the builderEnv for the main Go repo.
type goEnv struct {
	goos, goarch string
}

func (b *Builder) crossCompile() bool {
	switch b.goos {
	case "android", "nacl":
		return true
	case "darwin":
		return b.goarch == "arm" // iOS
	default:
		return false
	}
}

func (b *Builder) envv() []string {
	if runtime.GOOS == "windows" {
		return b.envvWindows()
	}

	var e []string
	if *buildTool == "go" {
		e = []string{
			"GOOS=" + b.goos,
			"GOARCH=" + b.goarch,
		}
		if !b.crossCompile() {
			// If we are building, for example, linux/386 on a linux/amd64 machine we want to
			// make sure that the whole build is done as a if this were compiled on a real
			// linux/386 machine. In other words, we want to not do a cross compilation build.
			// To do this we set GOHOSTOS and GOHOSTARCH to override the detection in make.bash.
			//
			// The exception to this rule is when we are doing nacl/android builds. These are by
			// definition always cross compilation, and we have support built into cmd/go to be
			// able to handle this case.
			e = append(e, "GOHOSTOS="+b.goos, "GOHOSTARCH="+b.goarch)
		}
	}

	for _, k := range extraEnv() {
		if s, ok := getenvOk(k); ok {
			e = append(e, k+"="+s)
		}
	}
	return e
}

func (b *Builder) envvWindows() []string {
	var start map[string]string
	if *buildTool == "go" {
		start = map[string]string{
			"GOOS":        b.goos,
			"GOHOSTOS":    b.goos,
			"GOARCH":      b.goarch,
			"GOHOSTARCH":  b.goarch,
			"GOBUILDEXIT": "1", // exit all.bat with completion status.
		}
	}

	for _, name := range extraEnv() {
		if s, ok := getenvOk(name); ok {
			start[name] = s
		}
	}
	if b.goos == "windows" {
		switch b.goarch {
		case "amd64":
			start["PATH"] = `c:\TDM-GCC-64\bin;` + start["PATH"]
		case "386":
			start["PATH"] = `c:\TDM-GCC-32\bin;` + start["PATH"]
		}
	}
	skip := map[string]bool{
		"GOBIN":   true,
		"GOPATH":  true,
		"GOROOT":  true,
		"INCLUDE": true,
		"LIB":     true,
	}
	var e []string
	for name, v := range start {
		e = append(e, name+"="+v)
		skip[name] = true
	}
	for _, kv := range os.Environ() {
		s := strings.SplitN(kv, "=", 2)
		name := strings.ToUpper(s[0])
		switch {
		case name == "":
			// variables, like "=C:=C:\", just copy them
			e = append(e, kv)
		case !skip[name]:
			e = append(e, kv)
			skip[name] = true
		}
	}
	return e
}

// setup for a goEnv clones the main go repo to workpath/go at the provided hash
// and returns the path workpath/go/src, the location of all go build scripts.
func (env *goEnv) setup(repo *Repo, workpath, hash string, envv []string) (string, error) {
	goworkpath := filepath.Join(workpath, "go")
	if err := repo.Export(goworkpath, hash); err != nil {
		return "", fmt.Errorf("error exporting repository: %s", err)
	}
	return filepath.Join(goworkpath, "src"), nil
}

// gccgoEnv represents the builderEnv for the gccgo compiler.
type gccgoEnv struct{}

// setup for a gccgoEnv clones the gofrontend repo to workpath/go at the hash
// and clones the latest GCC branch to repo.Path/gcc. The gccgo sources are
// replaced with the updated sources in the gofrontend repo and gcc gets
// gets configured and built in workpath/gcc-objdir. The path to
// workpath/gcc-objdir is returned.
func (env *gccgoEnv) setup(repo *Repo, workpath, hash string, envv []string) (string, error) {
	gccpath := filepath.Join(repo.Path, "gcc")

	// get a handle to Git vcs.Cmd for pulling down GCC from the mirror.
	git := vcs.ByCmd("git")

	// only pull down gcc if we don't have a local copy.
	if _, err := os.Stat(gccpath); err != nil {
		if err := timeout(*cmdTimeout, func() error {
			// pull down a working copy of GCC.

			cloneCmd := []string{
				"clone",
				// This is just a guess since there are ~6000 commits to
				// GCC per year. It's likely there will be enough history
				// to cross-reference the Gofrontend commit against GCC.
				// The disadvantage would be if the commit being built is more than
				// a year old; in this case, the user should make a clone that has
				// the full history.
				"--depth", "6000",
				// We only care about the master branch.
				"--branch", "master", "--single-branch",
				*gccPath,
			}

			// Clone Kind			Clone Time(Dry run)	Clone Size
			// ---------------------------------------------------------------
			// Full Clone			10 - 15 min		2.2 GiB
			// Master Branch		2 - 3 min		1.5 GiB
			// Full Clone(shallow)		1 min			900 MiB
			// Master Branch(shallow)	40 sec			900 MiB
			//
			// The shallow clones have the same size, which is expected,
			// but the full shallow clone will only have 6000 commits
			// spread across all branches.  There are ~50 branches.
			return run(exec.Command("git", cloneCmd...), runEnv(envv), allOutput(os.Stdout), runDir(repo.Path))
		}); err != nil {
			return "", err
		}
	}

	if err := git.Download(gccpath); err != nil {
		return "", err
	}

	// get the modified files for this commit.

	var buf bytes.Buffer
	if err := run(exec.Command("hg", "status", "--no-status", "--change", hash),
		allOutput(&buf), runDir(repo.Path), runEnv(envv)); err != nil {
		return "", fmt.Errorf("Failed to find the modified files for %s: %s", hash, err)
	}
	modifiedFiles := strings.Split(buf.String(), "\n")
	var isMirrored bool
	for _, f := range modifiedFiles {
		if strings.HasPrefix(f, "go/") || strings.HasPrefix(f, "libgo/") {
			isMirrored = true
			break
		}
	}

	// use git log to find the corresponding commit to sync to in the gcc mirror.
	// If the files modified in the gofrontend are mirrored to gcc, we expect a
	// commit with a similar description in the gcc mirror. If the files modified are
	// not mirrored, e.g. in support/, we can sync to the most recent gcc commit that
	// occurred before those files were modified to verify gccgo's status at that point.
	logCmd := []string{
		"log",
		"-1",
		"--format=%H",
	}
	var errMsg string
	if isMirrored {
		commitDesc, err := repo.Master.VCS.LogAtRev(repo.Path, hash, "{desc|firstline|escape}")
		if err != nil {
			return "", err
		}

		quotedDesc := regexp.QuoteMeta(string(commitDesc))
		logCmd = append(logCmd, "--grep", quotedDesc, "--regexp-ignore-case", "--extended-regexp")
		errMsg = fmt.Sprintf("Failed to find a commit with a similar description to '%s'", string(commitDesc))
	} else {
		commitDate, err := repo.Master.VCS.LogAtRev(repo.Path, hash, "{date|rfc3339date}")
		if err != nil {
			return "", err
		}

		logCmd = append(logCmd, "--before", string(commitDate))
		errMsg = fmt.Sprintf("Failed to find a commit before '%s'", string(commitDate))
	}

	buf.Reset()
	if err := run(exec.Command("git", logCmd...), runEnv(envv), allOutput(&buf), runDir(gccpath)); err != nil {
		return "", fmt.Errorf("%s: %s", errMsg, err)
	}
	gccRev := buf.String()
	if gccRev == "" {
		return "", fmt.Errorf(errMsg)
	}

	// checkout gccRev
	// TODO(cmang): Fix this to work in parallel mode.
	if err := run(exec.Command("git", "reset", "--hard", strings.TrimSpace(gccRev)), runEnv(envv), runDir(gccpath)); err != nil {
		return "", fmt.Errorf("Failed to checkout commit at revision %s: %s", gccRev, err)
	}

	// make objdir to work in
	gccobjdir := filepath.Join(workpath, "gcc-objdir")
	if err := os.Mkdir(gccobjdir, mkdirPerm); err != nil {
		return "", err
	}

	// configure GCC with substituted gofrontend and libgo
	if err := run(exec.Command(filepath.Join(gccpath, "configure"),
		"--enable-languages=c,c++,go",
		"--disable-bootstrap",
		"--disable-multilib",
	), runEnv(envv), runDir(gccobjdir)); err != nil {
		return "", fmt.Errorf("Failed to configure GCC: %v", err)
	}

	// build gcc
	if err := run(exec.Command("make", *gccOpts), runTimeout(*buildTimeout), runEnv(envv), runDir(gccobjdir)); err != nil {
		return "", fmt.Errorf("Failed to build GCC: %s", err)
	}

	return gccobjdir, nil
}

func getenvOk(k string) (v string, ok bool) {
	v = os.Getenv(k)
	if v != "" {
		return v, true
	}
	keq := k + "="
	for _, kv := range os.Environ() {
		if kv == keq {
			return "", true
		}
	}
	return "", false
}

// extraEnv returns environment variables that need to be copied from
// the gobuilder's environment to the envv of its subprocesses.
func extraEnv() []string {
	extra := []string{
		"GOARM",
		"GO386",
		"GOROOT_BOOTSTRAP", // See https://golang.org/s/go15bootstrap
		"CGO_ENABLED",
		"CC",
		"CC_FOR_TARGET",
		"PATH",
		"TMPDIR",
		"USER",
	}
	if runtime.GOOS == "plan9" {
		extra = append(extra, "objtype", "cputype", "path")
	}
	return extra
}
<|endoftext|>


<commit_before>package cmd

import (
	"testing"
)

func TestMergeConfigs(t *testing.T) {
	c1 := &config{ApiUser: "a", ApiKey: "abcd"}
	c2 := &config{ApiUser: "b", Verbose: true}
	merged, err := mergeConfigs(c1, c2)
	if err != nil {
		t.Error(err)
	}
	if merged.ApiUser != "a" {
		t.Fatal("ApiUser shouldn't have been overriden")
	}
	if !merged.Verbose {
		t.Fatal("Verbose should have been true")
	}
}
<commit_msg>test was broken after removing verbose<commit_after>package cmd

import (
	"testing"
)

func TestMergeConfigs(t *testing.T) {
	c1 := &config{ApiUser: "a", ApiKey: "abcd"}
	c2 := &config{ApiUser: "b"}
	merged, err := mergeConfigs(c1, c2)
	if err != nil {
		t.Error(err)
	}
	if merged.ApiUser != "a" {
		t.Fatal("ApiUser shouldn't have been overriden")
	}
}
<|endoftext|>


<commit_before>// estab exports elasticsearch fields as tab separated values
package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"os"
	"runtime/pprof"
	"strconv"
	"strings"

	"github.com/belogik/goes"
	"github.com/miku/estab"
)

func main() {

	host := flag.String("host", "localhost", "elasticsearch host")
	port := flag.String("port", "9200", "elasticsearch port")
	indicesString := flag.String("indices", "", "indices to search (or all)")
	fieldsString := flag.String("f", "_id _index", "field or fields space separated")
	timeout := flag.String("timeout", "10m", "scroll timeout")
	size := flag.Int("size", 10000, "scroll batch size")
	nullValue := flag.String("null", "NOT_AVAILABLE", "value for empty fields")
	separator := flag.String("separator", "|", "separator to use for multiple field values")
	delimiter := flag.String("delimiter", "\t", "column delimiter")
	limit := flag.Int("limit", 0, "maximum number of docs to return (return all by default)")
	version := flag.Bool("v", false, "prints current program version")
	cpuprofile := flag.String("cpuprofile", "", "write cpu profile to file")
	queryString := flag.String("query", "", "custom query to run")

	flag.Parse()

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	if *version {
		fmt.Println(estab.Version)
		os.Exit(0)
	}

	var indices []string
	trimmed := strings.TrimSpace(*indicesString)
	if len(trimmed) > 0 {
		indices = strings.Fields(trimmed)
	}

	fields := strings.Fields(*fieldsString)
	conn := goes.NewConnection(*host, *port)
	var query map[string]interface{}
	if *queryString == "" {
		query = map[string]interface{}{
			"query": map[string]interface{}{
				"match_all": map[string]interface{}{},
			},
			"fields": fields,
		}
	} else {
		err := json.Unmarshal([]byte(*queryString), &query)
		if err != nil {
			log.Fatalln(err)
		}
		query["fields"] = fields
	}

	scanResponse, err := conn.Scan(query, indices, []string{""}, *timeout, *size)
	if err != nil {
		log.Fatalln(err)
	}

	counter := 0

	for {
		scrollResponse, err := conn.Scroll(scanResponse.ScrollId, *timeout)
		if err != nil {
			log.Fatalln(err)
		}
		if len(scrollResponse.Hits.Hits) == 0 {
			break
		}
		for _, hit := range scrollResponse.Hits.Hits {
			if *limit > 0 && counter == *limit {
				return
			}
			var columns []string
			for _, f := range fields {
				var c []string
				switch f {
				case "_id":
					c = append(c, hit.Id)
				case "_index":
					c = append(c, hit.Index)
				case "_type":
					c = append(c, hit.Type)
				case "_score":
					c = append(c, strconv.FormatFloat(hit.Score, 'f', 6, 64))
				default:
					switch value := hit.Fields[f].(type) {
					case nil:
						c = []string{*nullValue}
					case []interface{}:
						for _, e := range value {
							c = append(c, e.(string))
						}
					default:
						log.Fatalf("unknown field type in response: %+v\n", hit.Fields[f])
					}
				}
				columns = append(columns, strings.Join(c, *separator))
			}
			fmt.Println(strings.Join(columns, *delimiter))
			counter++
		}
	}
}
<commit_msg>make limit check simpler<commit_after>// estab exports elasticsearch fields as tab separated values
package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"os"
	"runtime/pprof"
	"strconv"
	"strings"

	"github.com/belogik/goes"
	"github.com/miku/estab"
)

func main() {

	host := flag.String("host", "localhost", "elasticsearch host")
	port := flag.String("port", "9200", "elasticsearch port")
	indicesString := flag.String("indices", "", "indices to search (or all)")
	fieldsString := flag.String("f", "_id _index", "field or fields space separated")
	timeout := flag.String("timeout", "10m", "scroll timeout")
	size := flag.Int("size", 10000, "scroll batch size")
	nullValue := flag.String("null", "NOT_AVAILABLE", "value for empty fields")
	separator := flag.String("separator", "|", "separator to use for multiple field values")
	delimiter := flag.String("delimiter", "\t", "column delimiter")
	limit := flag.Int("limit", -1, "maximum number of docs to return (return all by default)")
	version := flag.Bool("v", false, "prints current program version")
	cpuprofile := flag.String("cpuprofile", "", "write cpu profile to file")
	queryString := flag.String("query", "", "custom query to run")

	flag.Parse()

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	if *version {
		fmt.Println(estab.Version)
		os.Exit(0)
	}

	var indices []string
	trimmed := strings.TrimSpace(*indicesString)
	if len(trimmed) > 0 {
		indices = strings.Fields(trimmed)
	}

	fields := strings.Fields(*fieldsString)
	conn := goes.NewConnection(*host, *port)
	var query map[string]interface{}
	if *queryString == "" {
		query = map[string]interface{}{
			"query": map[string]interface{}{
				"match_all": map[string]interface{}{},
			},
			"fields": fields,
		}
	} else {
		err := json.Unmarshal([]byte(*queryString), &query)
		if err != nil {
			log.Fatalln(err)
		}
		query["fields"] = fields
	}

	scanResponse, err := conn.Scan(query, indices, []string{""}, *timeout, *size)
	if err != nil {
		log.Fatalln(err)
	}

	i := 0

	for {
		scrollResponse, err := conn.Scroll(scanResponse.ScrollId, *timeout)
		if err != nil {
			log.Fatalln(err)
		}
		if len(scrollResponse.Hits.Hits) == 0 {
			break
		}
		for _, hit := range scrollResponse.Hits.Hits {
			if i == *limit {
				return
			}
			var columns []string
			for _, f := range fields {
				var c []string
				switch f {
				case "_id":
					c = append(c, hit.Id)
				case "_index":
					c = append(c, hit.Index)
				case "_type":
					c = append(c, hit.Type)
				case "_score":
					c = append(c, strconv.FormatFloat(hit.Score, 'f', 6, 64))
				default:
					switch value := hit.Fields[f].(type) {
					case nil:
						c = []string{*nullValue}
					case []interface{}:
						for _, e := range value {
							c = append(c, e.(string))
						}
					default:
						log.Fatalf("unknown field type in response: %+v\n", hit.Fields[f])
					}
				}
				columns = append(columns, strings.Join(c, *separator))
			}
			fmt.Println(strings.Join(columns, *delimiter))
			i++
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/influxdb/influxdb"
	"github.com/influxdb/influxdb/messaging"
)

// execRun runs the "run" command.
func execRun(args []string) {
	// Parse command flags.
	fs := flag.NewFlagSet("", flag.ExitOnError)
	var (
		configPath  = fs.String("config", configDefaultPath, "")
		pidPath     = fs.String("pidfile", "", "")
		role        = fs.String("role", "combined", "")
		hostname    = fs.String("hostname", "", "")
		seedServers = fs.String("seed-servers", "", "")
	)
	fs.Usage = printRunUsage
	fs.Parse(args)

	// Validate CLI flags.
	if *role != "combined" && *role != "broker" && *role != "data" {
		log.Fatalf("role must be 'combined', 'broker', or 'data'")
	}

	// Parse broker urls from seed servers.
	brokerURLs := parseSeedServers(*seedServers)

	// Print sweet InfluxDB logo and write the process id to file.
	log.Print(logo)
	writePIDFile(*pidPath)

	// Parse the configuration and determine if a broker and/or server exist.
	config := parseConfig(*configPath, *hostname)
	hasBroker := fileExists(config.Broker.Dir)
	hasServer := fileExists(config.Data.Dir)
	initializing := !hasBroker && !hasServer

	// Open broker if it exists or if we're initializing for the first time.
	var b *messaging.Broker
	var h *Handler
	if hasBroker || (initializing && (*role == "combined" || *role == "broker")) {
		b = openBroker(config.Broker.Dir, config.BrokerConnectionString())

		// If this is the first time running then initialize a broker.
		// Update the seed server so the server can connect locally.
		if initializing {
			if err := b.Initialize(); err != nil {
				log.Fatalf("initialize: %s", err)
			}
		}

		// Start the broker handler.
		h = &Handler{brokerHandler: messaging.NewHandler(b)}
		go func() { log.Fatal(http.ListenAndServe(config.BrokerListenAddr(), h)) }()
		log.Printf("Broker running on %s", config.BrokerListenAddr())
	}

	// Open server if it exists or we're initializing for the first time.
	var s *influxdb.Server
	if hasServer || (initializing && (*role == "combined" || *role == "data")) {
		s = openServer(config.Data.Dir)

		// If the server is uninitialized then initialize it with the broker.
		// Otherwise simply create a messaging client with the server id.
		if s.ID() == 0 {
			initServer(s, b)
		} else {
			openServerClient(s, brokerURLs)
		}

		// Start the server handler.
		// If it uses the same port as the broker then simply attach it.
		sh := influxdb.NewHandler(s)
		if config.BrokerListenAddr() == config.ApiHTTPListenAddr() {
			h.serverHandler = sh
		} else {
			go func() { log.Fatal(http.ListenAndServe(config.ApiHTTPListenAddr(), sh)) }()
		}
		log.Printf("DataNode#%d running on %s", s.ID(), config.ApiHTTPListenAddr())
	}

	// Wait indefinitely.
	<-(chan struct{})(nil)
}

// write the current process id to a file specified by path.
func writePIDFile(path string) {
	if path == "" {
		return
	}

	// Retrieve the PID and write it.
	pid := strconv.Itoa(os.Getpid())
	if err := ioutil.WriteFile(path, []byte(pid), 0644); err != nil {
		log.Fatal(err)
	}
}

// parses the configuration from a given path. Sets overrides as needed.
func parseConfig(path, hostname string) *Config {
	// Parse configuration.
	config, err := ParseConfigFile(path)
	if os.IsNotExist(err) {
		config = NewConfig()
	} else if err != nil {
		log.Fatalf("config: %s", err)
	}

	// Override config properties.
	if hostname != "" {
		config.Hostname = hostname
	}

	return config
}

// creates and initializes a broker at a given path.
func openBroker(path, addr string) *messaging.Broker {
	b := messaging.NewBroker()
	if err := b.Open(path, addr); err != nil {
		log.Fatalf("failed to open broker: %s", err)
	}
	return b
}

// creates and initializes a server at a given path.
func openServer(path string) *influxdb.Server {
	s := influxdb.NewServer()
	if err := s.Open(path); err != nil {
		log.Fatalf("failed to open data server", err.Error())
	}
	return s
}

// initializes a new server that does not yet have an ID.
func initServer(s *influxdb.Server, b *messaging.Broker) {
	// TODO: Change messaging client to not require a ReplicaID so we can create
	// a replica without already being a replica.

	// Create replica on broker.
	if err := b.CreateReplica(1); err != nil {
		log.Fatalf("replica creation error: %d", err)
	}

	// Initialize messaging client.
	c := messaging.NewClient(1)
	if err := c.Open(filepath.Join(s.Path(), messagingClientFile), []*url.URL{b.URL()}); err != nil {
		log.Fatalf("messaging client error: %s", err)
	}
	if err := s.SetClient(c); err != nil {
		log.Fatalf("set client error: %s", err)
	}

	// Initialize the server.
	if err := s.Initialize(b.URL()); err != nil {
		log.Fatalf("server initialization error: %s", err)
	}
}

// opens the messaging client and attaches it to the server.
func openServerClient(s *influxdb.Server, brokerURLs []*url.URL) {
	c := messaging.NewClient(s.ID())
	if err := c.Open(filepath.Join(s.Path(), messagingClientFile), brokerURLs); err != nil {
		log.Fatalf("messaging client error: %s", err)
	}
	if err := s.SetClient(c); err != nil {
		log.Fatalf("set client error: %s", err)
	}
}

// parses a comma-delimited list of URLs.
func parseSeedServers(s string) (a []*url.URL) {
	for _, s := range strings.Split(s, ",") {
		u, err := url.Parse(s)
		if err != nil {
			log.Fatalf("cannot parse seed servers: %s", err)
		}
		a = append(a, u)
	}
	return
}

// returns true if the file exists.
func fileExists(path string) bool {
	if _, err := os.Stat(path); os.IsNotExist(err) {
		return false
	}
	return true
}

func printRunUsage() {
	log.Printf(`usage: run [flags]

run starts the node with any existing cluster configuration. If no cluster configuration is
found, then the node runs in "local" mode. "Local" mode is a single-node mode that does not
use Distributed Consensus, but is otherwise fully-functional.

        -config <path>
                                Set the path to the configuration file. Defaults to %s.

        -role <role>
                                Set the role to be 'combined', 'broker' or 'data'. broker' means it will take
                                part in Raft Distributed Consensus. 'data' means it will store time-series data.
                                'combined' means it will do both. The default is 'combined'. In role other than
                                these three is invalid.

        -hostname <name>
                                Override the hostname, the 'hostname' configuration option will be overridden.

        -seed-servers <servers>
                                If joining a cluster, overrides any previously configured or discovered
                                Data node seed servers.

        -pidfile <path>
                                Write process ID to a file.
`, configDefaultPath)
}
<commit_msg>making go vet pass for cmd/influxd/run.go<commit_after>package main

import (
	"flag"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/influxdb/influxdb"
	"github.com/influxdb/influxdb/messaging"
)

// execRun runs the "run" command.
func execRun(args []string) {
	// Parse command flags.
	fs := flag.NewFlagSet("", flag.ExitOnError)
	var (
		configPath  = fs.String("config", configDefaultPath, "")
		pidPath     = fs.String("pidfile", "", "")
		role        = fs.String("role", "combined", "")
		hostname    = fs.String("hostname", "", "")
		seedServers = fs.String("seed-servers", "", "")
	)
	fs.Usage = printRunUsage
	fs.Parse(args)

	// Validate CLI flags.
	if *role != "combined" && *role != "broker" && *role != "data" {
		log.Fatalf("role must be 'combined', 'broker', or 'data'")
	}

	// Parse broker urls from seed servers.
	brokerURLs := parseSeedServers(*seedServers)

	// Print sweet InfluxDB logo and write the process id to file.
	log.Print(logo)
	writePIDFile(*pidPath)

	// Parse the configuration and determine if a broker and/or server exist.
	config := parseConfig(*configPath, *hostname)
	hasBroker := fileExists(config.Broker.Dir)
	hasServer := fileExists(config.Data.Dir)
	initializing := !hasBroker && !hasServer

	// Open broker if it exists or if we're initializing for the first time.
	var b *messaging.Broker
	var h *Handler
	if hasBroker || (initializing && (*role == "combined" || *role == "broker")) {
		b = openBroker(config.Broker.Dir, config.BrokerConnectionString())

		// If this is the first time running then initialize a broker.
		// Update the seed server so the server can connect locally.
		if initializing {
			if err := b.Initialize(); err != nil {
				log.Fatalf("initialize: %s", err)
			}
		}

		// Start the broker handler.
		h = &Handler{brokerHandler: messaging.NewHandler(b)}
		go func() { log.Fatal(http.ListenAndServe(config.BrokerListenAddr(), h)) }()
		log.Printf("Broker running on %s", config.BrokerListenAddr())
	}

	// Open server if it exists or we're initializing for the first time.
	var s *influxdb.Server
	if hasServer || (initializing && (*role == "combined" || *role == "data")) {
		s = openServer(config.Data.Dir)

		// If the server is uninitialized then initialize it with the broker.
		// Otherwise simply create a messaging client with the server id.
		if s.ID() == 0 {
			initServer(s, b)
		} else {
			openServerClient(s, brokerURLs)
		}

		// Start the server handler.
		// If it uses the same port as the broker then simply attach it.
		sh := influxdb.NewHandler(s)
		if config.BrokerListenAddr() == config.ApiHTTPListenAddr() {
			h.serverHandler = sh
		} else {
			go func() { log.Fatal(http.ListenAndServe(config.ApiHTTPListenAddr(), sh)) }()
		}
		log.Printf("DataNode#%d running on %s", s.ID(), config.ApiHTTPListenAddr())
	}

	// Wait indefinitely.
	<-(chan struct{})(nil)
}

// write the current process id to a file specified by path.
func writePIDFile(path string) {
	if path == "" {
		return
	}

	// Retrieve the PID and write it.
	pid := strconv.Itoa(os.Getpid())
	if err := ioutil.WriteFile(path, []byte(pid), 0644); err != nil {
		log.Fatal(err)
	}
}

// parses the configuration from a given path. Sets overrides as needed.
func parseConfig(path, hostname string) *Config {
	// Parse configuration.
	config, err := ParseConfigFile(path)
	if os.IsNotExist(err) {
		config = NewConfig()
	} else if err != nil {
		log.Fatalf("config: %s", err)
	}

	// Override config properties.
	if hostname != "" {
		config.Hostname = hostname
	}

	return config
}

// creates and initializes a broker at a given path.
func openBroker(path, addr string) *messaging.Broker {
	b := messaging.NewBroker()
	if err := b.Open(path, addr); err != nil {
		log.Fatalf("failed to open broker: %s", err)
	}
	return b
}

// creates and initializes a server at a given path.
func openServer(path string) *influxdb.Server {
	s := influxdb.NewServer()
	if err := s.Open(path); err != nil {
		log.Fatalf("failed to open data server", err.Error())
					log.Fatalf("seed server %v", err)
	}
	return s
}

// initializes a new server that does not yet have an ID.
func initServer(s *influxdb.Server, b *messaging.Broker) {
	// TODO: Change messaging client to not require a ReplicaID so we can create
	// a replica without already being a replica.

	// Create replica on broker.
	if err := b.CreateReplica(1); err != nil {
		log.Fatalf("replica creation error: %d", err)
	}

	// Initialize messaging client.
	c := messaging.NewClient(1)
	if err := c.Open(filepath.Join(s.Path(), messagingClientFile), []*url.URL{b.URL()}); err != nil {
		log.Fatalf("messaging client error: %s", err)
	}
	if err := s.SetClient(c); err != nil {
		log.Fatalf("set client error: %s", err)
	}

	// Initialize the server.
	if err := s.Initialize(b.URL()); err != nil {
		log.Fatalf("server initialization error: %s", err)
			log.Fatalf("failed to open data Server %v", err.Error())
	}
}

// opens the messaging client and attaches it to the server.
func openServerClient(s *influxdb.Server, brokerURLs []*url.URL) {
	c := messaging.NewClient(s.ID())
	if err := c.Open(filepath.Join(s.Path(), messagingClientFile), brokerURLs); err != nil {
		log.Fatalf("messaging client error: %s", err)
	}
	if err := s.SetClient(c); err != nil {
		log.Fatalf("set client error: %s", err)
	}
}

// parses a comma-delimited list of URLs.
func parseSeedServers(s string) (a []*url.URL) {
	for _, s := range strings.Split(s, ",") {
		u, err := url.Parse(s)
		if err != nil {
			log.Fatalf("cannot parse seed servers: %s", err)
		}
		a = append(a, u)
	}
	return
}

// returns true if the file exists.
func fileExists(path string) bool {
	if _, err := os.Stat(path); os.IsNotExist(err) {
		return false
	}
	return true
}

func printRunUsage() {
	log.Printf(`usage: run [flags]

run starts the node with any existing cluster configuration. If no cluster configuration is
found, then the node runs in "local" mode. "Local" mode is a single-node mode that does not
use Distributed Consensus, but is otherwise fully-functional.

        -config <path>
                                Set the path to the configuration file. Defaults to %s.

        -role <role>
                                Set the role to be 'combined', 'broker' or 'data'. broker' means it will take
                                part in Raft Distributed Consensus. 'data' means it will store time-series data.
                                'combined' means it will do both. The default is 'combined'. In role other than
                                these three is invalid.

        -hostname <name>
                                Override the hostname, the 'hostname' configuration option will be overridden.

        -seed-servers <servers>
                                If joining a cluster, overrides any previously configured or discovered
                                Data node seed servers.

        -pidfile <path>
                                Write process ID to a file.
`, configDefaultPath)
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"io/ioutil"
	"launchpad.net/gnuflag"
	"launchpad.net/juju-core/charm"
	"launchpad.net/juju-core/cmd"
	"launchpad.net/juju-core/constraints"
	"launchpad.net/juju-core/juju"
	"launchpad.net/juju-core/state"
	"os"
)

type DeployCommand struct {
	EnvCommandBase
	CharmName    string
	ServiceName  string
	Config       cmd.FileVar
	Constraints  constraints.Value
	NumUnits     int // defaults to 1
	BumpRevision bool
	RepoPath     string // defaults to JUJU_REPOSITORY
	MachineId    string
}

const deployDoc = `
<charm name> can be a charm URL, or an unambiguously condensed form of it;
assuming a current default series of "precise", the following forms will be
accepted.

For cs:precise/mysql
  mysql
  precise/mysql

For cs:~user/precise/mysql
  cs:~user/mysql

For local:precise/mysql
  local:mysql

In all cases, a versioned charm URL will be expanded as expected (for example,
mysql-33 becomes cs:precise/mysql-33).

<service name>, if omitted, will be derived from <charm name>.
`

func (c *DeployCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "deploy",
		Args:    "<charm name> [<service name>]",
		Purpose: "deploy a new service",
		Doc:     deployDoc,
	}
}

func (c *DeployCommand) SetFlags(f *gnuflag.FlagSet) {
	c.EnvCommandBase.SetFlags(f)
	f.IntVar(&c.NumUnits, "n", 1, "number of service units to deploy for principal charms")
	f.IntVar(&c.NumUnits, "num-units", 1, "")
	f.StringVar(&c.MachineId, "force-machine", "", "Machine to deploy initial unit")
	f.BoolVar(&c.BumpRevision, "u", false, "increment local charm directory revision")
	f.BoolVar(&c.BumpRevision, "upgrade", false, "")
	f.Var(&c.Config, "config", "path to yaml-formatted service config")
	f.Var(constraints.ConstraintsValue{&c.Constraints}, "constraints", "set service constraints")
	f.StringVar(&c.RepoPath, "repository", os.Getenv("JUJU_REPOSITORY"), "local charm repository")
}

func (c *DeployCommand) Init(args []string) error {
	// TODO --constraints
	switch len(args) {
	case 2:
		if !state.IsServiceName(args[1]) {
			return fmt.Errorf("invalid service name %q", args[1])
		}
		c.ServiceName = args[1]
		fallthrough
	case 1:
		if _, err := charm.InferURL(args[0], "fake"); err != nil {
			return fmt.Errorf("invalid charm name %q", args[0])
		}
		c.CharmName = args[0]
	case 0:
		return errors.New("no charm specified")
	default:
		return cmd.CheckEmpty(args[2:])
	}
	if c.NumUnits < 1 {
		// TODO improve/remove: this is misleading when deploying subordinates.
		return errors.New("must deploy at least one unit")
	}
	return nil
}

func (c *DeployCommand) Run(ctx *cmd.Context) error {
	conn, err := juju.NewConnFromName(c.EnvName)
	if err != nil {
		return err
	}
	defer conn.Close()
	conf, err := conn.State.EnvironConfig()
	if err != nil {
		return err
	}
	curl, err := charm.InferURL(c.CharmName, conf.DefaultSeries())
	if err != nil {
		return err
	}
	repo, err := charm.InferRepository(curl, ctx.AbsPath(c.RepoPath))
	if err != nil {
		return err
	}
	var configYAML []byte
	if c.Config.Path != "" {
		configYAML, err = ioutil.ReadFile(c.Config.Path)
		if err != nil {
			return err
		}
	}
	charm, err := conn.PutCharm(curl, repo, c.BumpRevision)
	if err != nil {
		return err
	}
	if charm.Meta().Subordinate {
		empty := constraints.Value{}
		if c.Constraints != empty {
			return state.ErrSubordinateConstraints
		}
	}
	serviceName := c.ServiceName
	if serviceName == "" {
		serviceName = curl.Name
	}
	args := juju.DeployServiceParams{
		Charm:       charm,
		ServiceName: serviceName,
		NumUnits:    c.NumUnits,
		// BUG(lp:1162122): --config has no tests.
		ConfigYAML:  string(configYAML),
		Constraints: c.Constraints,
		MachineId:   c.MachineId,
	}
	_, err = conn.DeployService(args)
	return err
}
<commit_msg>document that force-machine bypasses constraints<commit_after>package main

import (
	"errors"
	"fmt"
	"io/ioutil"
	"launchpad.net/gnuflag"
	"launchpad.net/juju-core/charm"
	"launchpad.net/juju-core/cmd"
	"launchpad.net/juju-core/constraints"
	"launchpad.net/juju-core/juju"
	"launchpad.net/juju-core/state"
	"os"
)

type DeployCommand struct {
	EnvCommandBase
	CharmName    string
	ServiceName  string
	Config       cmd.FileVar
	Constraints  constraints.Value
	NumUnits     int // defaults to 1
	BumpRevision bool
	RepoPath     string // defaults to JUJU_REPOSITORY
	MachineId    string
}

const deployDoc = `
<charm name> can be a charm URL, or an unambiguously condensed form of it;
assuming a current default series of "precise", the following forms will be
accepted.

For cs:precise/mysql
  mysql
  precise/mysql

For cs:~user/precise/mysql
  cs:~user/mysql

For local:precise/mysql
  local:mysql

In all cases, a versioned charm URL will be expanded as expected (for example,
mysql-33 becomes cs:precise/mysql-33).

<service name>, if omitted, will be derived from <charm name>.
`

func (c *DeployCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "deploy",
		Args:    "<charm name> [<service name>]",
		Purpose: "deploy a new service",
		Doc:     deployDoc,
	}
}

func (c *DeployCommand) SetFlags(f *gnuflag.FlagSet) {
	c.EnvCommandBase.SetFlags(f)
	f.IntVar(&c.NumUnits, "n", 1, "number of service units to deploy for principal charms")
	f.IntVar(&c.NumUnits, "num-units", 1, "")
	f.StringVar(&c.MachineId, "force-machine", "", "Machine to deploy initial unit, bypasses constraints")
	f.BoolVar(&c.BumpRevision, "u", false, "increment local charm directory revision")
	f.BoolVar(&c.BumpRevision, "upgrade", false, "")
	f.Var(&c.Config, "config", "path to yaml-formatted service config")
	f.Var(constraints.ConstraintsValue{&c.Constraints}, "constraints", "set service constraints")
	f.StringVar(&c.RepoPath, "repository", os.Getenv("JUJU_REPOSITORY"), "local charm repository")
}

func (c *DeployCommand) Init(args []string) error {
	// TODO --constraints
	switch len(args) {
	case 2:
		if !state.IsServiceName(args[1]) {
			return fmt.Errorf("invalid service name %q", args[1])
		}
		c.ServiceName = args[1]
		fallthrough
	case 1:
		if _, err := charm.InferURL(args[0], "fake"); err != nil {
			return fmt.Errorf("invalid charm name %q", args[0])
		}
		c.CharmName = args[0]
	case 0:
		return errors.New("no charm specified")
	default:
		return cmd.CheckEmpty(args[2:])
	}
	if c.NumUnits < 1 {
		// TODO improve/remove: this is misleading when deploying subordinates.
		return errors.New("must deploy at least one unit")
	}
	return nil
}

func (c *DeployCommand) Run(ctx *cmd.Context) error {
	conn, err := juju.NewConnFromName(c.EnvName)
	if err != nil {
		return err
	}
	defer conn.Close()
	conf, err := conn.State.EnvironConfig()
	if err != nil {
		return err
	}
	curl, err := charm.InferURL(c.CharmName, conf.DefaultSeries())
	if err != nil {
		return err
	}
	repo, err := charm.InferRepository(curl, ctx.AbsPath(c.RepoPath))
	if err != nil {
		return err
	}
	var configYAML []byte
	if c.Config.Path != "" {
		configYAML, err = ioutil.ReadFile(c.Config.Path)
		if err != nil {
			return err
		}
	}
	charm, err := conn.PutCharm(curl, repo, c.BumpRevision)
	if err != nil {
		return err
	}
	if charm.Meta().Subordinate {
		empty := constraints.Value{}
		if c.Constraints != empty {
			return state.ErrSubordinateConstraints
		}
	}
	serviceName := c.ServiceName
	if serviceName == "" {
		serviceName = curl.Name
	}
	args := juju.DeployServiceParams{
		Charm:       charm,
		ServiceName: serviceName,
		NumUnits:    c.NumUnits,
		// BUG(lp:1162122): --config has no tests.
		ConfigYAML:  string(configYAML),
		Constraints: c.Constraints,
		MachineId:   c.MachineId,
	}
	_, err = conn.DeployService(args)
	return err
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net/http"
	"strconv"

	"github.com/codegangsta/cli"
	"github.com/danmane/abalone/go/api"
	"github.com/danmane/abalone/go/api/router"
	"github.com/olekukonko/tablewriter"
)

var UsersCmd = cli.Command{
	Name:      "users",
	ShortName: "u",
	Usage:     "manage abalone users",
	Subcommands: []cli.Command{
		{
			Name:      "create",
			ShortName: "c",
			Usage:     "creates a user",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "name, n",
					Value: "",
				},
				cli.StringFlag{
					Name:  "email, e",
					Value: "",
				},
			},
			Action: func(c *cli.Context) {
				if err := CreateUsersHandler(c); err != nil {
					log.Fatal(err)
				}
			},
		},
		{
			Name:      "list",
			ShortName: "l",
			Usage:     "lists users",
			Action: func(c *cli.Context) {
				if err := ListUsersHandler(c); err != nil {
					log.Fatal(err)
				}
			},
		},
		{
			Name:      "delete",
			ShortName: "d",
			Usage:     "delete user by id",
			Action: func(c *cli.Context) {
				if err := DeleteUsersHandler(c); err != nil {
					log.Fatal(err)
				}
			},
		},
	},
}

func CreateUsersHandler(c *cli.Context) error {
	r := router.NewAPIRouter()
	path, err := r.Get(router.UsersCreate).URL()
	if err != nil {
		return err
	}

	if !c.IsSet("name") {
		return errors.New("name is required")
	}
	n := c.String("name")

	if !c.IsSet("email") {
		return errors.New("email is required")
	}
	e := c.String("email")

	req := api.User{
		Name:  n,
		Email: e,
	}
	var buf bytes.Buffer
	if err := json.NewEncoder(&buf).Encode(&req); err != nil {
		return err
	}
	url := fmt.Sprintf("http://%s%s", c.GlobalString("httpd"), path.String())
	resp, err := http.Post(url, "application/json", &buf)
	if err != nil {
		return err
	}
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("error: %s", resp.Status)
	}
	return nil
}

func ListUsersHandler(c *cli.Context) error {
	r := router.NewAPIRouter()
	path, err := r.Get(router.Users).URL()
	if err != nil {
		return err
	}
	url := fmt.Sprintf("http://%s%s", c.GlobalString("httpd"), path.String())
	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("error: %s", resp.Status)
	}
	var users []api.User
	if err := json.NewDecoder(resp.Body).Decode(&users); err != nil {
		return fmt.Errorf("error decoding json response: %s", err)
	}

	table := tablewriter.NewWriter(c.App.Writer)
	table.SetHeader([]string{"ID", "Name", "Email", "Created", "Updated"})
	for _, u := range users {
		row := []string{
			strconv.FormatInt(u.ID, 10),
			u.Name,
			u.Email,
			u.CreatedAt.Format("Mon Jan 2 15:04:05"),
			u.UpdatedAt.Format("Mon Jan 2 15:04:05"),
		}
		table.Append(row)
	}
	table.Render() // Send output
	return nil
}

func DeleteUsersHandler(c *cli.Context) error {
	r := router.NewAPIRouter()
	path, err := r.Get(router.UsersDelete).URL("id", c.Args().First())
	if err != nil {
		return fmt.Errorf("error parsing user id: %s", err)
	}
	url := fmt.Sprintf("http://%s%s", c.GlobalString("httpd"), path.String())
	req, err := http.NewRequest("DELETE", url, nil)
	if err != nil {
		return err
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("error: %s", resp.Status)
	}
	return nil
}
<commit_msg>feat(ctl) let 'users' execute users.list<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net/http"
	"strconv"

	"github.com/codegangsta/cli"
	"github.com/danmane/abalone/go/api"
	"github.com/danmane/abalone/go/api/router"
	"github.com/olekukonko/tablewriter"
)

var UsersCmd = cli.Command{
	Name:      "users",
	ShortName: "u",
	Usage:     "manage abalone users",
	Action: func(c *cli.Context) {
		if err := ListUsersHandler(c); err != nil {
			log.Fatal(err)
		}
	},
	Subcommands: []cli.Command{
		{
			Name:      "create",
			ShortName: "c",
			Usage:     "creates a user",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "name, n",
					Value: "",
				},
				cli.StringFlag{
					Name:  "email, e",
					Value: "",
				},
			},
			Action: func(c *cli.Context) {
				if err := CreateUsersHandler(c); err != nil {
					log.Fatal(err)
				}
			},
		},
		{
			Name:      "list",
			ShortName: "l",
			Usage:     "lists users",
			Action: func(c *cli.Context) {
				if err := ListUsersHandler(c); err != nil {
					log.Fatal(err)
				}
			},
		},
		{
			Name:      "delete",
			ShortName: "d",
			Usage:     "delete user by id",
			Action: func(c *cli.Context) {
				if err := DeleteUsersHandler(c); err != nil {
					log.Fatal(err)
				}
			},
		},
	},
}

func CreateUsersHandler(c *cli.Context) error {
	r := router.NewAPIRouter()
	path, err := r.Get(router.UsersCreate).URL()
	if err != nil {
		return err
	}

	if !c.IsSet("name") {
		return errors.New("name is required")
	}
	n := c.String("name")

	if !c.IsSet("email") {
		return errors.New("email is required")
	}
	e := c.String("email")

	req := api.User{
		Name:  n,
		Email: e,
	}
	var buf bytes.Buffer
	if err := json.NewEncoder(&buf).Encode(&req); err != nil {
		return err
	}
	url := fmt.Sprintf("http://%s%s", c.GlobalString("httpd"), path.String())
	resp, err := http.Post(url, "application/json", &buf)
	if err != nil {
		return err
	}
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("error: %s", resp.Status)
	}
	return nil
}

func ListUsersHandler(c *cli.Context) error {
	r := router.NewAPIRouter()
	path, err := r.Get(router.Users).URL()
	if err != nil {
		return err
	}
	url := fmt.Sprintf("http://%s%s", c.GlobalString("httpd"), path.String())
	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("error: %s", resp.Status)
	}
	var users []api.User
	if err := json.NewDecoder(resp.Body).Decode(&users); err != nil {
		return fmt.Errorf("error decoding json response: %s", err)
	}

	table := tablewriter.NewWriter(c.App.Writer)
	table.SetHeader([]string{"ID", "Name", "Email", "Created", "Updated"})
	for _, u := range users {
		row := []string{
			strconv.FormatInt(u.ID, 10),
			u.Name,
			u.Email,
			u.CreatedAt.Format("Mon Jan 2 15:04:05"),
			u.UpdatedAt.Format("Mon Jan 2 15:04:05"),
		}
		table.Append(row)
	}
	table.Render() // Send output
	return nil
}

func DeleteUsersHandler(c *cli.Context) error {
	r := router.NewAPIRouter()
	path, err := r.Get(router.UsersDelete).URL("id", c.Args().First())
	if err != nil {
		return fmt.Errorf("error parsing user id: %s", err)
	}
	url := fmt.Sprintf("http://%s%s", c.GlobalString("httpd"), path.String())
	req, err := http.NewRequest("DELETE", url, nil)
	if err != nil {
		return err
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("error: %s", resp.Status)
	}
	return nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"os"

	"github.com/loadimpact/k6/stats/cloud"
	"github.com/loadimpact/k6/ui"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

const (
        actionSetToken = iota
        actionShowToken
        actionLogin
)

// loginCloudCommand represents the 'login cloud' command
var loginCloudCommand = &cobra.Command{
	Use:   "cloud",
	Short: "Authenticate with Load Impact",
	Long: `Authenticate with Load Impact.

This will set the default token used when just "k6 run -o cloud" is passed.`,

	Example: `
  # Show the stored token.
  k6 login cloud -s

  # Set up the token.
  k6 login cloud -t YOUR_TOKEN

  # Ask for your Load Impact user email and password to automatically set up the token.
  k6 login cloud`[1:],

	Args: cobra.NoArgs,
	RunE: func(cmd *cobra.Command, args []string) error {

		printToken := func(conf cloud.Config) {
			fmt.Fprintf(stdout, "  token: %s\n", ui.ValueColor.Sprint(conf.Token))
		}

		config, cdir, err := readDiskConfig()
		if err != nil {
			return err
		}

		token := getNullString(cmd.Flags(), "token")
		show := getNullBool(cmd.Flags(), "show")

                cmdName := actionLogin
                if show.Valid {
                        cmdName = actionShowToken
                } else if token.Valid {
                        cmdName = actionSetToken
                }

		conf := config.Collectors.Cloud

                switch cmdName {
                case actionSetToken:
                        conf.Token = token.String
                case actionLogin:
                        printToken(conf)

                        form := ui.Form{
                                Fields: []ui.Field{
                                        ui.StringField{
                                                Key:   "Email",
                                                Label: "Email",
					},
                                        ui.StringField{
                                                Key:   "Password",
                                                Label: "Password",
                                        },
                                },
                        }

                        vals, err := form.Run(os.Stdin, stdout)
                        if err != nil {
                                return err
			}

                        email := vals["Email"].(string)
                        password := vals["Password"].(string)
                        client := cloud.NewClient("", conf.Host, Version)
                        response, err := client.Login(email, password)
                        if err != nil {
                                return err
                        }

                        if response.APIToken == "" {
                                return errors.New("Your account has no API token, please generate one: `https://app.loadimpact.com/account/token`.")
                        }

                        conf.Token = response.APIToken
                }

                if cmdName != actionShowToken {
			config.Collectors.Cloud = conf
			if err := writeDiskConfig(cdir, config); err != nil {
				return err
			}
		}

		printToken(conf)
		return nil
	},
}

func init() {
	loginCmd.AddCommand(loginCloudCommand)
	loginCloudCommand.Flags().StringP("token", "t", "", "specify `token` to use")
	loginCloudCommand.Flags().BoolP("show", "s", false, "display saved token and exit")
}
<commit_msg>Refactor `switch` statement<commit_after>package cmd

import (
	"fmt"
	"os"

	"github.com/loadimpact/k6/stats/cloud"
	"github.com/loadimpact/k6/ui"
	"github.com/pkg/errors"
        "github.com/spf13/cobra"
)

// loginCloudCommand represents the 'login cloud' command
var loginCloudCommand = &cobra.Command{
        Use:   "cloud",
	Short: "Authenticate with Load Impact",
	Long: `Authenticate with Load Impact.

This will set the default token used when just "k6 run -o cloud" is passed.`,

	Example: `
  # Show the stored token.
  k6 login cloud -s

  # Set up the token.
  k6 login cloud -t YOUR_TOKEN

  # Ask for your Load Impact user email and password to automatically set up the token.
  k6 login cloud`[1:],

	Args: cobra.NoArgs,
	RunE: func(cmd *cobra.Command, args []string) error {

		printToken := func(conf cloud.Config) {
			fmt.Fprintf(stdout, "  token: %s\n", ui.ValueColor.Sprint(conf.Token))
		}

		config, cdir, err := readDiskConfig()
		if err != nil {
                        return err
                }

                flags := cmd.Flags()
                show, err := flags.GetBool("show")
                if err != nil {
                        return err
                }
                token, err := flags.GetString("token")
                if err != nil {
                        return err
                }

                conf := config.Collectors.Cloud

                switch {
                case show:
                        printToken(conf)
                        return nil
                case token != "":
                        conf.Token = token
                default:
                        printToken(conf)

                        form := ui.Form{
                                Fields: []ui.Field{
                                        ui.StringField{
                                                Key:   "Email",
                                                Label: "Email",
					},
                                        ui.StringField{
                                                Key:   "Password",
                                                Label: "Password",
                                        },
                                },
                        }

                        vals, err := form.Run(os.Stdin, stdout)
                        if err != nil {
                                return err
			}

                        email := vals["Email"].(string)
                        password := vals["Password"].(string)
                        client := cloud.NewClient("", conf.Host, Version)
                        response, err := client.Login(email, password)
                        if err != nil {
                                return err
                        }

                        if response.APIToken == "" {
                                return errors.New("Your account has no API token, please generate one: `https://app.loadimpact.com/account/token`.")
                        }

                        conf.Token = response.APIToken
                }

                config.Collectors.Cloud = conf
                if err := writeDiskConfig(cdir, config); err != nil {
                        return err
                }

                printToken(conf)
		return nil
	},
}

func init() {
	loginCmd.AddCommand(loginCloudCommand)
	loginCloudCommand.Flags().StringP("token", "t", "", "specify `token` to use")
	loginCloudCommand.Flags().BoolP("show", "s", false, "display saved token and exit")
}
<|endoftext|>