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

// Package mem gets and processes /proc/meminfo, returning the data in the
// appropriate format.
package mem

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strconv"
	"time"

	fb "github.com/google/flatbuffers/go"
	joe "github.com/mohae/joefriday"
)

type Info struct {
	Timestamp    int64
	MemTotal     int
	MemFree      int
	MemAvailable int
	Buffers      int
	Cached       int
	SwapCached   int
	Active       int
	Inactive     int
	SwapTotal    int
	SwapFree     int
}

// Serialize serializes the Info using flatbuffers.
func (i *Info) Serialize() []byte {
	builder := fb.NewBuilder(0)
	DataStart(builder)
	DataAddTimestamp(builder, int64(i.Timestamp))
	DataAddMemTotal(builder, int64(i.MemTotal))
	DataAddMemFree(builder, int64(i.MemFree))
	DataAddMemAvailable(builder, int64(i.MemAvailable))
	DataAddBuffers(builder, int64(i.Buffers))
	DataAddCached(builder, int64(i.Cached))
	DataAddSwapCached(builder, int64(i.SwapCached))
	DataAddActive(builder, int64(i.Active))
	DataAddInactive(builder, int64(i.Inactive))
	DataAddSwapTotal(builder, int64(i.SwapTotal))
	DataAddSwapFree(builder, int64(i.SwapFree))
	builder.Finish(DataEnd(builder))
	return builder.Bytes[builder.Head():]
}

// Deserialize deserializes bytes representing flatbuffers serialized Data
// into *Info.  If the bytes are not from flatbuffers serialization of
// Data, it is a programmer error and a panic will occur.
func Deserialize(p []byte) *Info {
	data := GetRootAsData(p, 0)
	info := &Info{}
	info.Timestamp = data.Timestamp()
	info.MemTotal = int(data.MemTotal())
	info.MemFree = int(data.MemFree())
	info.MemAvailable = int(data.MemAvailable())
	info.Buffers = int(data.Buffers())
	info.Cached = int(data.Cached())
	info.SwapCached = int(data.SwapCached())
	info.Active = int(data.Active())
	info.Inactive = int(data.Inactive())
	info.SwapTotal = int(data.SwapTotal())
	info.SwapFree = int(data.SwapFree())
	return info
}

// GetInfo returns some of the results of /proc/meminfo.
func GetInfo() (*Info, error) {
	var l, i int
	var name string
	var err error
	var v byte
	t := time.Now().UTC().UnixNano()
	f, err := os.Open("/proc/meminfo")
	if err != nil {
		return nil, err
	}
	defer f.Close()
	buf := bufio.NewReader(f)
	inf := &Info{Timestamp: t}
	var pos int
	line := make([]byte, 0, 50)
	val := make([]byte, 0, 32)
	for {
		if l == 16 {
			break
		}
		line, err = buf.ReadSlice('\n')
		if err != nil {
			if err == io.EOF {
				break
			}
			return nil, fmt.Errorf("error reading output bytes: %s", err)
		}
		l++
		if l > 8 && l < 15 {
			continue
		}
		// first grab the key name (everything up to the ':')
		for i, v = range line {
			if v == 0x3A {
				pos = i + 1
				break
			}
			val = append(val, v)
		}
		name = string(val[:])
		val = val[:0]
		// skip all spaces
		for i, v = range line[pos:] {
			if v != 0x20 {
				pos += i
				break
			}
		}

		// grab the numbers
		for _, v = range line[pos:] {
			if v == 0x20 || v == '\r' {
				break
			}
			val = append(val, v)
		}
		// any conversion error results in 0
		i, err = strconv.Atoi(string(val[:]))
		if err != nil {
			return nil, fmt.Errorf("%s: %s", name, err)
		}
		val = val[:0]
		if name == "MemTotal" {
			inf.MemTotal = i
			continue
		}
		if name == "MemFree" {
			inf.MemFree = i
			continue
		}
		if name == "MemAvailable" {
			inf.MemAvailable = i
			continue
		}
		if name == "Buffers" {
			inf.Buffers = i
			continue
		}
		if name == "Cached" {
			inf.MemAvailable = i
			continue
		}
		if name == "SwapCached" {
			inf.SwapCached = i
			continue
		}
		if name == "Active" {
			inf.Active = i
			continue
		}
		if name == "Inactive" {
			inf.Inactive = i
			continue
		}
		if name == "SwapTotal" {
			inf.SwapTotal = i
			continue
		}
		if name == "SwapFree" {
			inf.SwapFree = i
			continue
		}
	}
	return inf, nil
}

// GetData returns the current meminfo as flatbuffer serialized bytes.
func GetData() ([]byte, error) {
	inf, err := GetInfo()
	if err != nil {
		return nil, err
	}
	return inf.Serialize(), nil
}

// DataTicker gathers the meminfo on a ticker, whose interval is defined by
// the received duration, and sends the results to the channel.  The output
// is Flatbuffers serialized Data.  Any error encountered during processing
// is sent to the error channel.  Processing will continue
//
// Either closing the done channel or sending struct{} to the done channel
// will result in function exit.  The out channel is closed on exit.
//
// This pre-allocates the builder and everything other than the []byte that
// gets sent to the out channel to reduce allocations, as this is expected
// to be both a frequent and a long-running process.  Doing so reduces
// byte allocations per tick just ~ 42%.
func DataTicker(interval time.Duration, outCh chan []byte, done chan struct{}, errCh chan error) {
	ticker := time.NewTicker(interval)
	defer ticker.Stop()
	defer close(outCh)
	// predeclare some vars
	var l, i, pos int
	var t int64
	var v byte
	var name string
	// premake some temp slices
	line := make([]byte, 0, 64)
	val := make([]byte, 0, 32)
	// just reset the bldr at the end of every ticker
	bldr := fb.NewBuilder(0)
	var buf bufio.Reader
	// ticker
	for {
		select {
		case <-done:
			return
		case <-ticker.C:
			d, _ := ioutil.ReadFile("/proc/meminfo")
			fmt.Println(string(d))
			// The current timestamp is always in UTC
			t = time.Now().UTC().UnixNano()
			f, err := os.Open("/proc/meminfo")
			if err != nil {
				errCh <- joe.Error{Type: "mem", Op: "open /proc/meminfo", Err: err}
				continue
			}
			buf.Reset(f)
			DataStart(bldr)
			DataAddTimestamp(bldr, t)
			for {
				if l == 16 {
					break
				}
				fmt.Println(l)
				line, _, err = buf.ReadLine()
				if err != nil {
					if err == io.EOF {
						fmt.Println(err)
						break
					}
					errCh <- joe.Error{Type: "mem", Op: "read command results", Err: err}
					fmt.Println(line)
					break
				}
				fmt.Println(line)
				l++
				if l > 8 && l < 15 {
					continue
				}
				// first grab the key name (everything up to the ':')
				for i, v = range line {
					if v == 0x3A {
						pos = i + 1
						break
					}
					val = append(val, v)
				}
				name = string(val[:])
				val = val[:0]
				// skip all spaces
				for i, v = range line[pos:] {
					if v != 0x20 {
						pos += i
						break
					}
				}

				// grab the numbers
				for _, v = range line[pos:] {
					if v == 0x20 || v == '\r' {
						break
					}
					val = append(val, v)
				}
				// any conversion error results in 0
				i, err = strconv.Atoi(string(val[:]))
				if err != nil {
					errCh <- joe.Error{Type: "mem", Op: "convert to int", Err: err}
					continue
				}
				val = val[:0]
				if name == "MemTotal" {
					DataAddMemTotal(bldr, int64(i))
					continue
				}
				if name == "MemFree" {
					DataAddMemFree(bldr, int64(i))
					continue
				}
				if name == "MemAvailable" {
					DataAddMemAvailable(bldr, int64(i))
					continue
				}
				if name == "Buffers" {
					DataAddBuffers(bldr, int64(i))
					continue
				}
				if name == "Cached" {
					DataAddMemAvailable(bldr, int64(i))
					continue
				}
				if name == "SwapCached" {
					DataAddSwapCached(bldr, int64(i))
					continue
				}
				if name == "Active" {
					DataAddActive(bldr, int64(i))
					continue
				}
				if name == "Inactive" {
					DataAddInactive(bldr, int64(i))
					continue
				}
				if name == "SwapTotal" {
					DataAddSwapTotal(bldr, int64(i))
					continue
				}
				if name == "SwapFree" {
					DataAddSwapFree(bldr, int64(i))
					continue
				}
			}
			f.Close()
			bldr.Finish(DataEnd(bldr))
			data := bldr.Bytes[bldr.Head():]
			outCh <- data
			bldr.Reset()
			fmt.Println("meminfo")
			time.Sleep(time.Second)
			l = 0
		}
	}
}

func (d *Data) String() string {
	return fmt.Sprintf("Timestamp: %v\nMemTotal:\t%d\tMemFree:\t%d\tMemAvailable:\t%d\tActive:\t%d\tInactive:\t%d\nCached:\t\t%d\tBuffers\t:%d\nSwapTotal:\t%d\tSwapCached:\t%d\tSwapFree:\t%d\n", time.Unix(0, d.Timestamp()).UTC(), d.MemTotal(), d.MemFree(), d.MemAvailable(), d.Active(), d.Inactive(), d.Cached(), d.Buffers(), d.SwapTotal(), d.SwapCached(), d.SwapFree())
}
<commit_msg>add Stringer implementation to mem.Info<commit_after>// Copyright 2016 The JoeFriday authors.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package mem gets and processes /proc/meminfo, returning the data in the
// appropriate format.
package mem

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strconv"
	"time"

	fb "github.com/google/flatbuffers/go"
	joe "github.com/mohae/joefriday"
)

type Info struct {
	Timestamp    int64
	MemTotal     int
	MemFree      int
	MemAvailable int
	Buffers      int
	Cached       int
	SwapCached   int
	Active       int
	Inactive     int
	SwapTotal    int
	SwapFree     int
}

// Serialize serializes the Info using flatbuffers.
func (i *Info) Serialize() []byte {
	builder := fb.NewBuilder(0)
	DataStart(builder)
	DataAddTimestamp(builder, int64(i.Timestamp))
	DataAddMemTotal(builder, int64(i.MemTotal))
	DataAddMemFree(builder, int64(i.MemFree))
	DataAddMemAvailable(builder, int64(i.MemAvailable))
	DataAddBuffers(builder, int64(i.Buffers))
	DataAddCached(builder, int64(i.Cached))
	DataAddSwapCached(builder, int64(i.SwapCached))
	DataAddActive(builder, int64(i.Active))
	DataAddInactive(builder, int64(i.Inactive))
	DataAddSwapTotal(builder, int64(i.SwapTotal))
	DataAddSwapFree(builder, int64(i.SwapFree))
	builder.Finish(DataEnd(builder))
	return builder.Bytes[builder.Head():]
}

// Deserialize deserializes bytes representing flatbuffers serialized Data
// into *Info.  If the bytes are not from flatbuffers serialization of
// Data, it is a programmer error and a panic will occur.
func Deserialize(p []byte) *Info {
	data := GetRootAsData(p, 0)
	info := &Info{}
	info.Timestamp = data.Timestamp()
	info.MemTotal = int(data.MemTotal())
	info.MemFree = int(data.MemFree())
	info.MemAvailable = int(data.MemAvailable())
	info.Buffers = int(data.Buffers())
	info.Cached = int(data.Cached())
	info.SwapCached = int(data.SwapCached())
	info.Active = int(data.Active())
	info.Inactive = int(data.Inactive())
	info.SwapTotal = int(data.SwapTotal())
	info.SwapFree = int(data.SwapFree())
	return info
}

func (d *Info) String() string {
	return fmt.Sprintf("Timestamp: %v\nMemTotal:\t%d\tMemFree:\t%d\tMemAvailable:\t%d\tActive:\t%d\tInactive:\t%d\nCached:\t\t%d\tBuffers\t:%d\nSwapTotal:\t%d\tSwapCached:\t%d\tSwapFree:\t%d\n", time.Unix(0, d.Timestamp).UTC(), d.MemTotal, d.MemFree, d.MemAvailable, d.Active, d.Inactive, d.Cached, d.Buffers, d.SwapTotal, d.SwapCached, d.SwapFree)
}

// GetInfo returns some of the results of /proc/meminfo.
func GetInfo() (*Info, error) {
	var l, i int
	var name string
	var err error
	var v byte
	t := time.Now().UTC().UnixNano()
	f, err := os.Open("/proc/meminfo")
	if err != nil {
		return nil, err
	}
	defer f.Close()
	buf := bufio.NewReader(f)
	inf := &Info{Timestamp: t}
	var pos int
	line := make([]byte, 0, 50)
	val := make([]byte, 0, 32)
	for {
		if l == 16 {
			break
		}
		line, err = buf.ReadSlice('\n')
		if err != nil {
			if err == io.EOF {
				break
			}
			return nil, fmt.Errorf("error reading output bytes: %s", err)
		}
		l++
		if l > 8 && l < 15 {
			continue
		}
		// first grab the key name (everything up to the ':')
		for i, v = range line {
			if v == 0x3A {
				pos = i + 1
				break
			}
			val = append(val, v)
		}
		name = string(val[:])
		val = val[:0]
		// skip all spaces
		for i, v = range line[pos:] {
			if v != 0x20 {
				pos += i
				break
			}
		}

		// grab the numbers
		for _, v = range line[pos:] {
			if v == 0x20 || v == '\r' {
				break
			}
			val = append(val, v)
		}
		// any conversion error results in 0
		i, err = strconv.Atoi(string(val[:]))
		if err != nil {
			return nil, fmt.Errorf("%s: %s", name, err)
		}
		val = val[:0]
		if name == "MemTotal" {
			inf.MemTotal = i
			continue
		}
		if name == "MemFree" {
			inf.MemFree = i
			continue
		}
		if name == "MemAvailable" {
			inf.MemAvailable = i
			continue
		}
		if name == "Buffers" {
			inf.Buffers = i
			continue
		}
		if name == "Cached" {
			inf.MemAvailable = i
			continue
		}
		if name == "SwapCached" {
			inf.SwapCached = i
			continue
		}
		if name == "Active" {
			inf.Active = i
			continue
		}
		if name == "Inactive" {
			inf.Inactive = i
			continue
		}
		if name == "SwapTotal" {
			inf.SwapTotal = i
			continue
		}
		if name == "SwapFree" {
			inf.SwapFree = i
			continue
		}
	}
	return inf, nil
}

// GetData returns the current meminfo as flatbuffer serialized bytes.
func GetData() ([]byte, error) {
	inf, err := GetInfo()
	if err != nil {
		return nil, err
	}
	return inf.Serialize(), nil
}

// DataTicker gathers the meminfo on a ticker, whose interval is defined by
// the received duration, and sends the results to the channel.  The output
// is Flatbuffers serialized Data.  Any error encountered during processing
// is sent to the error channel.  Processing will continue
//
// Either closing the done channel or sending struct{} to the done channel
// will result in function exit.  The out channel is closed on exit.
//
// This pre-allocates the builder and everything other than the []byte that
// gets sent to the out channel to reduce allocations, as this is expected
// to be both a frequent and a long-running process.  Doing so reduces
// byte allocations per tick just ~ 42%.
func DataTicker(interval time.Duration, outCh chan []byte, done chan struct{}, errCh chan error) {
	ticker := time.NewTicker(interval)
	defer ticker.Stop()
	defer close(outCh)
	// predeclare some vars
	var l, i, pos int
	var t int64
	var v byte
	var name string
	// premake some temp slices
	line := make([]byte, 0, 64)
	val := make([]byte, 0, 32)
	// just reset the bldr at the end of every ticker
	bldr := fb.NewBuilder(0)
	var buf bufio.Reader
	// ticker
	for {
		select {
		case <-done:
			return
		case <-ticker.C:
			d, _ := ioutil.ReadFile("/proc/meminfo")
			fmt.Println(string(d))
			// The current timestamp is always in UTC
			t = time.Now().UTC().UnixNano()
			f, err := os.Open("/proc/meminfo")
			if err != nil {
				errCh <- joe.Error{Type: "mem", Op: "open /proc/meminfo", Err: err}
				continue
			}
			buf.Reset(f)
			DataStart(bldr)
			DataAddTimestamp(bldr, t)
			for {
				if l == 16 {
					break
				}
				fmt.Println(l)
				line, _, err = buf.ReadLine()
				if err != nil {
					if err == io.EOF {
						fmt.Println(err)
						break
					}
					errCh <- joe.Error{Type: "mem", Op: "read command results", Err: err}
					fmt.Println(line)
					break
				}
				fmt.Println(line)
				l++
				if l > 8 && l < 15 {
					continue
				}
				// first grab the key name (everything up to the ':')
				for i, v = range line {
					if v == 0x3A {
						pos = i + 1
						break
					}
					val = append(val, v)
				}
				name = string(val[:])
				val = val[:0]
				// skip all spaces
				for i, v = range line[pos:] {
					if v != 0x20 {
						pos += i
						break
					}
				}

				// grab the numbers
				for _, v = range line[pos:] {
					if v == 0x20 || v == '\r' {
						break
					}
					val = append(val, v)
				}
				// any conversion error results in 0
				i, err = strconv.Atoi(string(val[:]))
				if err != nil {
					errCh <- joe.Error{Type: "mem", Op: "convert to int", Err: err}
					continue
				}
				val = val[:0]
				if name == "MemTotal" {
					DataAddMemTotal(bldr, int64(i))
					continue
				}
				if name == "MemFree" {
					DataAddMemFree(bldr, int64(i))
					continue
				}
				if name == "MemAvailable" {
					DataAddMemAvailable(bldr, int64(i))
					continue
				}
				if name == "Buffers" {
					DataAddBuffers(bldr, int64(i))
					continue
				}
				if name == "Cached" {
					DataAddMemAvailable(bldr, int64(i))
					continue
				}
				if name == "SwapCached" {
					DataAddSwapCached(bldr, int64(i))
					continue
				}
				if name == "Active" {
					DataAddActive(bldr, int64(i))
					continue
				}
				if name == "Inactive" {
					DataAddInactive(bldr, int64(i))
					continue
				}
				if name == "SwapTotal" {
					DataAddSwapTotal(bldr, int64(i))
					continue
				}
				if name == "SwapFree" {
					DataAddSwapFree(bldr, int64(i))
					continue
				}
			}
			f.Close()
			bldr.Finish(DataEnd(bldr))
			data := bldr.Bytes[bldr.Head():]
			outCh <- data
			bldr.Reset()
			fmt.Println("meminfo")
			time.Sleep(time.Second)
			l = 0
		}
	}
}

func (d *Data) String() string {
	return fmt.Sprintf("Timestamp: %v\nMemTotal:\t%d\tMemFree:\t%d\tMemAvailable:\t%d\tActive:\t%d\tInactive:\t%d\nCached:\t\t%d\tBuffers\t:%d\nSwapTotal:\t%d\tSwapCached:\t%d\tSwapFree:\t%d\n", time.Unix(0, d.Timestamp()).UTC(), d.MemTotal(), d.MemFree(), d.MemAvailable(), d.Active(), d.Inactive(), d.Cached(), d.Buffers(), d.SwapTotal(), d.SwapCached(), d.SwapFree())
}
<|endoftext|>


<commit_before>package api

import (
	"reflect"

	"github.com/STNS/STNS/attribute"
	"github.com/STNS/STNS/config"
	"github.com/ant0ine/go-json-rest/rest"
)

type Query struct {
	resource string
	column   string
}

func (q Query) Get(value string) attribute.UserGroups {
	var attr attribute.UserGroups
	var resource attribute.UserGroups

	if q.resource == "user" {
		resource = config.All.Users
	} else if q.resource == "group" {
		resource = config.All.Groups
	}
	if q.column == "id" {
		attr = resource.GetById(value)
	} else if q.column == "name" {
		attr = resource.GetByName(value)
	} else if q.column == "list" {
		attr = resource
	}
	return attr
}

func Get(w rest.ResponseWriter, r *rest.Request) {
	value := r.PathParam("value")
	column := r.PathParam("column")
	resource_name := r.PathParam("resource_name")
	query := Query{resource_name, column}

	attr := query.Get(value)
	if attr == nil || reflect.ValueOf(attr).IsNil() {
		rest.NotFound(w, r)
		return
	}
	w.WriteJson(attr)
}
func GetList(w rest.ResponseWriter, r *rest.Request) {
	resource_name := r.PathParam("resource_name")

	query := Query{resource_name, "list"}
	resource := query.Get("")

	if resource == nil || reflect.ValueOf(resource).IsNil() {
		rest.NotFound(w, r)
		return
	}

	w.WriteJson(resource)
}

func HealthChech(w rest.ResponseWriter, r *rest.Request) {
	w.WriteJson("success")
}
<commit_msg>refact api<commit_after>package api

import (
	"reflect"

	"github.com/STNS/STNS/attribute"
	"github.com/STNS/STNS/config"
	"github.com/ant0ine/go-json-rest/rest"
)

type Query struct {
	resource string
	column   string
	value    string
}

func (q Query) Get(value string) attribute.UserGroups {
	var attr attribute.UserGroups
	var resource attribute.UserGroups

	if q.resource == "user" {
		resource = config.All.Users
	} else if q.resource == "group" {
		resource = config.All.Groups
	}
	if q.column == "id" {
		attr = resource.GetById(q.value)
	} else if q.column == "name" {
		attr = resource.GetByName(q.value)
	} else if q.column == "list" {
		attr = resource
	}
	return attr
}

func Get(w rest.ResponseWriter, r *rest.Request) {
	value := r.PathParam("value")
	column := r.PathParam("column")
	resource_name := r.PathParam("resource_name")
	query := Query{resource_name, column, value}
	query.Response(w, r)
}
func GetList(w rest.ResponseWriter, r *rest.Request) {
	resource_name := r.PathParam("resource_name")
	query := Query{resource_name, "list", ""}
	query.Response(w, r)
}

func (q Query) Response(w rest.ResponseWriter, r *rest.Request) {
	resource := query.Get()
	if resource == nil || reflect.ValueOf(resource).IsNil() {
		rest.NotFound(w, r)
		return
	}
	w.WriteJson(resource)
}

func HealthChech(w rest.ResponseWriter, r *rest.Request) {
	w.WriteJson("success")
}
<|endoftext|>


<commit_before>package api

// TODO: Start documenting the error codes to the frontend.

import (
	"hnews/services"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strconv"

	"github.com/gin-gonic/gin"
)

const (
	debug = true
)

// StartAPI sets up the API and starts it on Heroku port or :8080
func StartAPI() {
	r := gin.Default()
	if debug {
		gin.SetMode(gin.DebugMode)
	} else {
		gin.SetMode(gin.ReleaseMode)
	}

	// GET News from index :from: to index :to:
	r.GET("/v1/news", func(c *gin.Context) {
		from, err0 := strconv.Atoi(c.Query("from"))
		to, err1 := strconv.Atoi(c.Query("to"))
		if err0 != nil || err1 != nil || from <= 0 {
			c.String(http.StatusBadRequest, "Bad index")
			return
		}

		news := services.ReadNews(from, to)
		c.JSON(http.StatusOK, gin.H{"values": news})
	})

	/** Comment Endpoint **/
	// Gives the comments from a i to j given the provided news id.
	r.GET("/v1/comments", func(c *gin.Context) {
		from, err0 := strconv.Atoi(c.Query("from"))
		to, err1 := strconv.Atoi(c.Query("to"))
		if err0 != nil || err1 != nil || from <= 0 {
			c.String(http.StatusBadRequest, "Bad index")
			return
		}

		id, err := strconv.Atoi(c.Query("newsid"))
		if err != nil {
			c.String(http.StatusBadRequest, "Not a valid item id")
			return
		}

		comments := services.ReadComments(id, from, to)
		c.JSON(http.StatusOK, gin.H{"values": comments})
	})

	/** Login wrapper for login-service **/
	r.POST("/v1/login", func(c *gin.Context) {
		username := c.Query("username")
		password := c.Query("password")

		url := "http://localhost:3000/v1/login"
		req, _ := http.NewRequest("POST", url, nil)

		values := req.URL.Query()
		values.Add("username", username)
		values.Add("password", password)
		req.URL.RawQuery = values.Encode()

		resp, err := http.DefaultClient.Do(req)
		if err == nil {
			defer resp.Body.Close()
			content, _ := ioutil.ReadAll(resp.Body)
			c.String(resp.StatusCode, string(content))
		}
	})

	/** Entry wrapper for login-service **/
	r.POST("/v1/login/entry/upvote", func(c *gin.Context) {
		id := c.Query("id")
		apikey := c.Query("apikey")

		url := "http://localhost:3000/v1/login/entry/upvote"
		req, _ := http.NewRequest("POST", url, nil)

		values := req.URL.Query()
		values.Add("id", id)
		values.Add("apikey", apikey)
		req.URL.RawQuery = values.Encode()

		resp, err := http.DefaultClient.Do(req)
		if err == nil {
			defer resp.Body.Close()
			content, _ := ioutil.ReadAll(resp.Body)
			c.String(resp.StatusCode, string(content))
		}
	})

	r.POST("/v1/login/entry/comment", func(c *gin.Context) {
		id := c.Query("id")
		comment := c.Query("comment")
		apikey := c.Query("apikey")

		url := "http://localhost:3000/v1/login/entry/comment"
		req, _ := http.NewRequest("POST", url, nil)

		values := req.URL.Query()
		values.Add("id", id)
		values.Add("comment", comment)
		values.Add("apikey", apikey)
		req.URL.RawQuery = values.Encode()

		resp, err := http.DefaultClient.Do(req)
		if err == nil {
			defer resp.Body.Close()
			content, _ := ioutil.ReadAll(resp.Body)
			c.String(resp.StatusCode, string(content))
		}
	})

	/** Comment wrapper for login-service **/
	r.POST("/v1/login/comment/upvote", func(c *gin.Context) {
		id := c.Query("id")
		apikey := c.Query("apikey")

		url := "http://localhost:3000/v1/login/comment/upvote"
		req, _ := http.NewRequest("POST", url, nil)

		values := req.URL.Query()
		values.Add("id", id)
		values.Add("apikey", apikey)
		req.URL.RawQuery = values.Encode()

		resp, err := http.DefaultClient.Do(req)
		if err == nil {
			defer resp.Body.Close()
			content, _ := ioutil.ReadAll(resp.Body)
			c.String(resp.StatusCode, string(content))
		}
	})

	r.POST("/v1/login/commment/reply", func(c *gin.Context) {
		id := c.Query("id")
		reply := c.Query("reply")
		apikey := c.Query("apikey")

		url := "http://localhost:3000/v1/login/comment/reply"
		req, _ := http.NewRequest("POST", url, nil)

		values := req.URL.Query()
		values.Add("id", id)
		values.Add("reply", reply)
		values.Add("apikey", apikey)
		req.URL.RawQuery = values.Encode()

		resp, err := http.DefaultClient.Do(req)
		if err == nil {
			defer resp.Body.Close()
			content, _ := ioutil.ReadAll(resp.Body)
			c.String(resp.StatusCode, string(content))
		}
	})

	r.Run(":" + getPort()) // listen and serve on 0.0.0.0:8080
}

// Tries to get Heroku port otherwise return default 8080
func getPort() string {
	port := os.Getenv("PORT")
	log.Println(port)
	if port != "" {
		return port
	}
	return "8080"
}
<commit_msg>Changed login to return JSON, not string.<commit_after>package api

// TODO: Start documenting the error codes to the frontend.
// TODO: Disable debug mode in Gin
// TODO: Disable debug mode in Sinatra

import (
	"hnews/services"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strconv"

	"github.com/gin-gonic/gin"
)

const (
	debug = true
)

// StartAPI sets up the API and starts it on Heroku port or :8080
func StartAPI() {
	r := gin.Default()
	if debug {
		gin.SetMode(gin.DebugMode)
	} else {
		gin.SetMode(gin.ReleaseMode)
	}

	// GET News from index :from: to index :to:
	r.GET("/v1/news", func(c *gin.Context) {
		from, err0 := strconv.Atoi(c.Query("from"))
		to, err1 := strconv.Atoi(c.Query("to"))
		if err0 != nil || err1 != nil || from <= 0 {
			c.String(http.StatusBadRequest, "Bad index")
			return
		}

		news := services.ReadNews(from, to)
		c.JSON(http.StatusOK, gin.H{"values": news})
	})

	/** Comment Endpoint **/
	// Gives the comments from a i to j given the provided news id.
	r.GET("/v1/comments", func(c *gin.Context) {
		from, err0 := strconv.Atoi(c.Query("from"))
		to, err1 := strconv.Atoi(c.Query("to"))
		if err0 != nil || err1 != nil || from <= 0 {
			c.String(http.StatusBadRequest, "Bad index")
			return
		}

		id, err := strconv.Atoi(c.Query("newsid"))
		if err != nil {
			c.String(http.StatusBadRequest, "Not a valid item id")
			return
		}

		comments := services.ReadComments(id, from, to)
		c.JSON(http.StatusOK, gin.H{"values": comments})
	})

	/** Login wrapper for login-service **/
	r.POST("/v1/login", func(c *gin.Context) {
		username := c.Query("username")
		password := c.Query("password")

		url := "http://localhost:3000/v1/login"
		req, _ := http.NewRequest("POST", url, nil)

		values := req.URL.Query()
		values.Add("username", username)
		values.Add("password", password)
		req.URL.RawQuery = values.Encode()

		resp, err := http.DefaultClient.Do(req)
		if err == nil {
			defer resp.Body.Close()
			content, _ := ioutil.ReadAll(resp.Body)
			c.JSON(resp.StatusCode, string(content))
		}
	})

	/** Entry wrapper for login-service **/
	r.POST("/v1/login/entry/upvote", func(c *gin.Context) {
		id := c.Query("id")
		apikey := c.Query("apikey")

		url := "http://localhost:3000/v1/login/entry/upvote"
		req, _ := http.NewRequest("POST", url, nil)

		values := req.URL.Query()
		values.Add("id", id)
		values.Add("apikey", apikey)
		req.URL.RawQuery = values.Encode()

		resp, err := http.DefaultClient.Do(req)
		if err == nil {
			defer resp.Body.Close()
			content, _ := ioutil.ReadAll(resp.Body)
			c.JSON(resp.StatusCode, string(content))
		}
	})

	r.POST("/v1/login/entry/comment", func(c *gin.Context) {
		id := c.Query("id")
		comment := c.Query("comment")
		apikey := c.Query("apikey")

		url := "http://localhost:3000/v1/login/entry/comment"
		req, _ := http.NewRequest("POST", url, nil)

		values := req.URL.Query()
		values.Add("id", id)
		values.Add("comment", comment)
		values.Add("apikey", apikey)
		req.URL.RawQuery = values.Encode()

		resp, err := http.DefaultClient.Do(req)
		if err == nil {
			defer resp.Body.Close()
			content, _ := ioutil.ReadAll(resp.Body)
			c.JSON(resp.StatusCode, string(content))
		}
	})

	/** Comment wrapper for login-service **/
	r.POST("/v1/login/comment/upvote", func(c *gin.Context) {
		id := c.Query("id")
		apikey := c.Query("apikey")

		url := "http://localhost:3000/v1/login/comment/upvote"
		req, _ := http.NewRequest("POST", url, nil)

		values := req.URL.Query()
		values.Add("id", id)
		values.Add("apikey", apikey)
		req.URL.RawQuery = values.Encode()

		resp, err := http.DefaultClient.Do(req)
		if err == nil {
			defer resp.Body.Close()
			content, _ := ioutil.ReadAll(resp.Body)
			c.JSON(resp.StatusCode, string(content))
		}
	})

	r.POST("/v1/login/commment/reply", func(c *gin.Context) {
		id := c.Query("id")
		reply := c.Query("reply")
		apikey := c.Query("apikey")

		url := "http://localhost:3000/v1/login/comment/reply"
		req, _ := http.NewRequest("POST", url, nil)

		values := req.URL.Query()
		values.Add("id", id)
		values.Add("reply", reply)
		values.Add("apikey", apikey)
		req.URL.RawQuery = values.Encode()

		resp, err := http.DefaultClient.Do(req)
		if err == nil {
			defer resp.Body.Close()
			content, _ := ioutil.ReadAll(resp.Body)
			c.JSON(resp.StatusCode, string(content))
		}
	})

	r.Run(":" + getPort()) // listen and serve on 0.0.0.0:8080
}

// Tries to get Heroku port otherwise return default 8080
func getPort() string {
	port := os.Getenv("PORT")
	log.Println(port)
	if port != "" {
		return port
	}
	return "8080"
}
<|endoftext|>


<commit_before>package cache

import (
	"strconv"
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func TestCacheMemory1(t *testing.T) {
	Convey("cache memory", t, func() {
		c := New(Options{
			Name:    "test",
			Adapter: "memory",
			Config: map[string]interface{}{
				"bytesLimit": int64(1024), // 1KB
			},
		})

		Convey("set", func() {
			err := c.Set("test", "1", 6)
			So(err, ShouldBeNil)
		})

		Convey("get", func() {
			v := c.Get("test")
			So(v, ShouldEqual, "1")
		})

		Convey("gc", func() {
			for i := 0; i <= 100; i++ {
				key := "test" + strconv.Itoa(i)
				err := c.Set(key, i, 6)
				So(err, ShouldBeNil)
			}
			v := c.Get("test100")
			So(v, ShouldEqual, 100)
			v = c.Get("test1")
			So(v, ShouldBeNil)
		})
	})
}
<commit_msg>add benchmark test<commit_after>package cache

import (
	"fmt"
	"strconv"
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

// init a global cacher
var testCache Cacher

func TestCacheMemory1(t *testing.T) {
	Convey("cache memory", t, func() {
		c := New(Options{
			Name:    "test2",
			Adapter: "memory",
			Config: map[string]interface{}{
				"bytesLimit": int64(1024), // 1KB
			},
		})

		Convey("set", func() {
			err := c.Set("test", "1", 6)
			So(err, ShouldBeNil)
		})

		Convey("get", func() {
			v := c.Get("test")
			So(v, ShouldEqual, "1")
		})

		Convey("gc", func() {
			for i := 0; i <= 100; i++ {
				key := "test" + strconv.Itoa(i)
				err := c.Set(key, i, 6)
				So(err, ShouldBeNil)
			}
			v := c.Get("test100")
			So(v, ShouldEqual, 100)
			v = c.Get("test1")
			So(v, ShouldBeNil)
		})
	})
}

func BenchmarkCacheMemorySet(b *testing.B) {
	for i := 0; i < b.N; i++ {
		testCache.Set(fmt.Sprintf("test%d", i), 1, 1800)
	}
}

func BenchmarkCacheMemoryGet(b *testing.B) {
	for i := 0; i < b.N; i++ {
		testCache.Get(fmt.Sprintf("test%d", i))
	}
}

func init() {
	testCache = New(Options{
		Name:    "test",
		Adapter: "memory",
		Config: map[string]interface{}{
			"bytesLimit": int64(1024 * 1024), // 1MB
		},
	})
}
<|endoftext|>


<commit_before>// Package api provide the server side Goed API
// via RPC over local socket.
// See client/ for the client implementation.
package api

import (
	"log"
	"net"
	"net/http"
	"net/rpc"
	"time"

	"github.com/tcolar/goed/actions"
	"github.com/tcolar/goed/core"
)

type Api struct {
}

func (a *Api) Start() {
	r := new(GoedRpc)
	rpc.Register(r)
	rpc.HandleHTTP()
	l, err := net.Listen("unix", core.Socket)
	if err != nil {
		log.Fatalf("Socket listen error %s : \n", core.Socket, err.Error())
	}

	go func() {
		err = http.Serve(l, nil)
		if err != nil {
			panic(err)
		}
	}()
}

// Goed RPC functions holder
type GoedRpc struct{}

type RpcStruct struct {
	Data []string
}

func (r *GoedRpc) Action(args RpcStruct, res *RpcStruct) error {
	results, err := actions.Exec(args.Data[0], args.Data[1:])
	for _, r := range results {
		res.Data = append(res.Data, r)
	}
	return err
}

func (r *GoedRpc) Open(args []interface{}, _ *struct{}) error {
	vid := actions.Ar.EdOpen(args[1].(string), -1, args[0].(string), true)
	actions.Ar.EdActivateView(vid)
	actions.Ar.EdRender()
	return nil
}

func (r *GoedRpc) Edit(args []interface{}, _ *struct{}) error {
	curView := actions.Ar.EdCurView()
	vid := actions.Ar.EdOpen(args[1].(string), -1, args[0].(string), true)
	actions.Ar.EdActivateView(vid)
	actions.Ar.EdRender()
	// Wait til file closed
	for {
		v := core.Ed.ViewById(vid)
		if v.Terminated() {
			actions.Ar.EdActivateView(curView)
			actions.Ar.EdRender()
			return nil
		}
		time.Sleep(250 * time.Millisecond)
	}
}
<commit_msg>Fix edit action<commit_after>// Package api provide the server side Goed API
// via RPC over local socket.
// See client/ for the client implementation.
package api

import (
	"log"
	"net"
	"net/http"
	"net/rpc"
	"time"

	"github.com/tcolar/goed/actions"
	"github.com/tcolar/goed/core"
)

type Api struct {
}

func (a *Api) Start() {
	r := new(GoedRpc)
	rpc.Register(r)
	rpc.HandleHTTP()
	l, err := net.Listen("unix", core.Socket)
	if err != nil {
		log.Fatalf("Socket listen error %s : \n", core.Socket, err.Error())
	}

	go func() {
		err = http.Serve(l, nil)
		if err != nil {
			panic(err)
		}
	}()
}

// Goed RPC functions holder
type GoedRpc struct{}

type RpcStruct struct {
	Data []string
}

func (r *GoedRpc) Action(args RpcStruct, res *RpcStruct) error {
	results, err := actions.Exec(args.Data[0], args.Data[1:])
	for _, r := range results {
		res.Data = append(res.Data, r)
	}
	return err
}

func (r *GoedRpc) Open(args []interface{}, _ *struct{}) error {
	vid := actions.Ar.EdOpen(args[1].(string), -1, args[0].(string), true)
	actions.Ar.EdActivateView(vid)
	actions.Ar.EdRender()
	return nil
}

func (r *GoedRpc) Edit(args []interface{}, _ *struct{}) error {
	prevView := actions.Ar.EdCurView()
	vid := actions.Ar.EdOpen(args[1].(string), -1, args[0].(string), true)
	actions.Ar.EdActivateView(vid)
	actions.Ar.EdRender()
	// Wait til file closed
	for {
		v := core.Ed.ViewById(vid)
		if v == nil {
			// switch back to the original view
			actions.Ar.EdActivateView(prevView)
			actions.Ar.EdRender()
			return nil
		}
		time.Sleep(250 * time.Millisecond)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"strings"
	"syscall"

	"github.com/ianremmler/clac"
	"golang.org/x/crypto/ssh/terminal"
	"robpike.io/ivy/value"
)

type runMode int

const (
	cliMode runMode = iota
	tuiMode
	dmenuMode
)

var (
	// flags
	doDmenu          = false
	doInitStack      = false
	doHexOut         = false
	cliPrec     uint = 12

	cl      = clac.New()
	lastErr error
)

var cmdMap = map[string]func() error{
	"neg":    cl.Neg,
	"n":      cl.Neg,
	"abs":    cl.Abs,
	"a":      cl.Abs,
	"inv":    cl.Inv,
	"i":      cl.Inv,
	"+":      cl.Add,
	"-":      cl.Sub,
	"*":      cl.Mul,
	"x":      cl.Mul,
	"/":      cl.Div,
	"div":    cl.IntDiv,
	"%":      cl.Mod,
	"exp":    cl.Exp,
	"^":      cl.Pow,
	"2^":     cl.Pow2,
	"10^":    cl.Pow10,
	"logn":   cl.LogN,
	"ln":     cl.Ln,
	"log":    cl.Log,
	"lg":     cl.Lg,
	"sqrt":   cl.Sqrt,
	"!":      cl.Factorial,
	"comb":   cl.Comb,
	"perm":   cl.Perm,
	"sin":    cl.Sin,
	"cos":    cl.Cos,
	"tan":    cl.Tan,
	"asin":   cl.Asin,
	"acos":   cl.Acos,
	"atan":   cl.Atan,
	"atan2":  cl.Atan2,
	"dtor":   cl.DegToRad,
	"rtod":   cl.RadToDeg,
	"rtop":   cl.RectToPolar,
	"ptor":   cl.PolarToRect,
	"floor":  cl.Floor,
	"ceil":   cl.Ceil,
	"trunc":  cl.Trunc,
	"and":    cl.And,
	"or":     cl.Or,
	"xor":    cl.Xor,
	"not":    cl.Not,
	"andn":   cl.AndN,
	"orn":    cl.OrN,
	"xorn":   cl.XorN,
	"sum":    cl.Sum,
	"avg":    cl.Avg,
	"drop":   cl.Drop,
	"k":      cl.Drop,
	"dropn":  cl.DropN,
	"dropr":  cl.DropR,
	"dup":    cl.Dup,
	"d":      cl.Dup,
	"dupn":   cl.DupN,
	"dupr":   cl.DupR,
	"pick":   cl.Pick,
	"p":      cl.Pick,
	"swap":   cl.Swap,
	"s":      cl.Swap,
	"depth":  cl.Depth,
	"min":    cl.Min,
	"max":    cl.Max,
	"minn":   cl.MinN,
	"maxn":   cl.MaxN,
	"rot":    cl.Rot,
	"rotr":   cl.RotR,
	"unrot":  cl.Unrot,
	"unrotr": cl.UnrotR,
	"mag":    cl.Mag,
	"hyp":    cl.Hypot,
	"dot":    cl.Dot,
	"dot3":   cl.Dot3,
	"cross":  cl.Cross,
	"pi":     constant(clac.Pi),
	"e":      constant(clac.E),
	"phi":    constant(clac.Phi),
}

var uiCmdMap = map[string]func() error{
	"undo":  cl.Undo,
	"u":     cl.Undo,
	"redo":  cl.Redo,
	"r":     cl.Redo,
	"clear": cl.Clear,
	"c":     cl.Clear,
	"reset": cl.Reset,
	"quit":  quit,
	"q":     quit,
}

type term struct {
	io.Reader
	io.Writer
}

func init() {
	log.SetFlags(0)
	log.SetPrefix("clac: ")
	flag.BoolVar(&doDmenu, "d", doDmenu, "dmenu mode")
	flag.BoolVar(&doHexOut, "x", doHexOut, "hexidecimal output")
	flag.UintVar(&cliPrec, "p", cliPrec, "output precision")
	flag.BoolVar(&doInitStack, "i", doInitStack, "initialize stack")
}

func main() {
	flag.Parse()
	var mode runMode
	mode, lastErr = processCmdLine()
	switch mode {
	case cliMode:
		cliRun()
	case tuiMode:
		tuiRun()
	case dmenuMode:
		dmenuRun()
	}
}

func constant(v value.Value) func() error {
	return func() error { return cl.Push(v) }
}

func cliRun() {
	fmt.Println(stackStr(cl.Stack()))
	if lastErr != nil {
		log.Fatal(lastErr)
	}
}

func uiSetup() {
	for cmd, fn := range uiCmdMap {
		cmdMap[cmd] = fn
	}
	uiCmdMap = nil
}

func tuiRun() {
	uiSetup()
	if !terminal.IsTerminal(syscall.Stdin) {
		log.Fatalln("this doesn't look like an interactive terminal")
	}
	oldTrmState, err := terminal.MakeRaw(syscall.Stdin)
	if err != nil {
		log.Fatalln(err)
	}
	trm := terminal.NewTerminal(term{os.Stdin, os.Stdout}, "")
	for lastErr != io.EOF {
		tuiPrintStack(cl.Stack())
		var input string
		input, lastErr = trm.ReadLine()
		if lastErr == nil {
			lastErr = processInput(input)
		}
	}
	terminal.Restore(syscall.Stdin, oldTrmState)
}

func dmenuSetup() {
	uiSetup()
	cmdMap["hex"] = func() error { doHexOut = true; return nil }
	cmdMap["dec"] = func() error { doHexOut = false; return nil }
	cmdMap["conv"] = dmenuConv
}

func dmenuRun() {
	dmenuSetup()
	for {
		stack := stackStr(cl.Stack())
		if len(stack) > 0 {
			stack = " " + stack
		}
		out, err := exec.Command("dmenu", "-p", "clac:"+stack).Output()
		if err != nil {
			return
		}
		if err := processInput(string(out)); err != nil {
			exec.Command("dmenu", "-p", "clac: "+err.Error()).Run()
		}
	}
}

func dmenuConv() error {
	val, err := cl.Pop()
	if err != nil {
		return err
	}
	valStr := stackStr(clac.Stack{val})
	have, err := exec.Command("dmenu", "-p", "clac: conv: have: "+valStr).Output()
	if err != nil {
		return errors.New("abort")
	}
	want, err := exec.Command("dmenu", "-p", "clac: conv: want:").Output()
	if err != nil {
		return errors.New("abort")
	}
	haveStr := valStr + " " + strings.TrimSpace(string(have))
	wantStr := strings.TrimSpace(string(want))
	out, err := exec.Command("units", "-t", haveStr, wantStr).Output()
	if err != nil {
		errStr := strings.SplitN(string(out), "\n", 2)[0]
		if errStr != "" {
			return errors.New(errStr)
		}
		return err
	}
	num, err := clac.ParseNum(strings.TrimSpace(string(out)))
	if err != nil {
		return err
	}
	return cl.Push(num)
}

func processCmdLine() (runMode, error) {
	input := ""
	if stat, err := os.Stdin.Stat(); err == nil && stat.Mode()&os.ModeNamedPipe != 0 {
		if pipeInput, err := ioutil.ReadAll(os.Stdin); err == nil {
			input = string(pipeInput)
		}
	}
	if len(flag.Args()) > 0 {
		input += " " + strings.Join(flag.Args(), " ")
	}
	mode := cliMode
	switch {
	case doDmenu:
		mode = dmenuMode
	case doInitStack || input == "":
		mode = tuiMode
	}
	cl.EnableHistory(mode != cliMode)
	err := processInput(string(input))
	return mode, err
}

func stackStr(stack clac.Stack) string {
	out := ""
	if doHexOut {
		clac.SetFormat("%#x")
	} else {
		clac.SetFormat(fmt.Sprintf("%%.%dg", cliPrec))
	}
	for i := range stack {
		val := stack[len(stack)-i-1]
		var err error
		if doHexOut {
			val, err = clac.Trunc(val)
		}
		if err != nil {
			out += err.Error()
		} else {
			out += clac.Sprint(val)
		}
		if i < len(stack)-1 {
			out += " "
		}
	}
	return out
}

func quit() error {
	os.Exit(0)
	return nil
}

func processInput(input string) error {
	scanner := bufio.NewScanner(strings.NewReader(input))
	scanner.Split(bufio.ScanWords)
	for scanner.Scan() {
		tok := scanner.Text()
		if num, err := clac.ParseNum(tok); err == nil {
			if err = cl.Exec(func() error { return cl.Push(num) }); err != nil {
				return fmt.Errorf("push: %s", err)
			}
		} else if cmd, ok := cmdMap[tok]; ok {
			if err := cl.Exec(cmd); err != nil {
				return fmt.Errorf("%s: %s", tok, err)
			}
		} else {
			return fmt.Errorf("invalid input: \"%s\"", tok)
		}
	}
	if err := scanner.Err(); err != nil {
		return err
	}
	return nil
}

func tuiPrintStack(stack clac.Stack) {
	cols, rows, err := terminal.GetSize(syscall.Stdout)
	if err != nil {
		rows = len(stack) + 1
	}
	// ensure sane width
	if cols < 20 {
		cols = 20
	}
	clearScreen()

	dataCols := cols - 4
	hexCols := dataCols / 2
	floatCols := dataCols - hexCols
	floatFmt := fmt.Sprintf("%%%d.%dg", floatCols-1, floatCols-8)
	hexFmt := fmt.Sprintf("%%#%dx", hexCols-3)
	for i := rows - 3; i >= 0; i-- {
		line := fmt.Sprintf("%02d:", i)
		if i < len(stack) {
			clac.SetFormat(floatFmt)
			line += fmt.Sprintf(fmt.Sprintf(" %%%ds", floatCols), clac.Sprint(stack[i]))
			if val, err := clac.Trunc(stack[i]); err == nil {
				clac.SetFormat(hexFmt)
				hexStr := fmt.Sprintf(fmt.Sprintf(" %%%ds", hexCols-1), clac.Sprint(val))
				if len(hexStr) > hexCols {
					hexStr = hexStr[:hexCols-1] + "…"
				}
				line += hexStr
			}
		}
		fmt.Println(line + "\r")
	}
	info := ""
	if lastErr != nil {
		info = fmt.Sprintf("[ %s ]", lastErr)
	}
	fmt.Println(info + strings.Repeat("-", cols-len(info)))
	fmt.Print("\r")
}

func clearScreen() {
	fmt.Print("\033[2J\033[H")
}
<commit_msg>Be quiet when canceling unit conversion.<commit_after>package main

import (
	"bufio"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"strings"
	"syscall"

	"github.com/ianremmler/clac"
	"golang.org/x/crypto/ssh/terminal"
	"robpike.io/ivy/value"
)

type runMode int

const (
	cliMode runMode = iota
	tuiMode
	dmenuMode
)

var (
	// flags
	doDmenu          = false
	doInitStack      = false
	doHexOut         = false
	cliPrec     uint = 12

	cl      = clac.New()
	lastErr error
)

var cmdMap = map[string]func() error{
	"neg":    cl.Neg,
	"n":      cl.Neg,
	"abs":    cl.Abs,
	"a":      cl.Abs,
	"inv":    cl.Inv,
	"i":      cl.Inv,
	"+":      cl.Add,
	"-":      cl.Sub,
	"*":      cl.Mul,
	"x":      cl.Mul,
	"/":      cl.Div,
	"div":    cl.IntDiv,
	"%":      cl.Mod,
	"exp":    cl.Exp,
	"^":      cl.Pow,
	"2^":     cl.Pow2,
	"10^":    cl.Pow10,
	"logn":   cl.LogN,
	"ln":     cl.Ln,
	"log":    cl.Log,
	"lg":     cl.Lg,
	"sqrt":   cl.Sqrt,
	"!":      cl.Factorial,
	"comb":   cl.Comb,
	"perm":   cl.Perm,
	"sin":    cl.Sin,
	"cos":    cl.Cos,
	"tan":    cl.Tan,
	"asin":   cl.Asin,
	"acos":   cl.Acos,
	"atan":   cl.Atan,
	"atan2":  cl.Atan2,
	"dtor":   cl.DegToRad,
	"rtod":   cl.RadToDeg,
	"rtop":   cl.RectToPolar,
	"ptor":   cl.PolarToRect,
	"floor":  cl.Floor,
	"ceil":   cl.Ceil,
	"trunc":  cl.Trunc,
	"and":    cl.And,
	"or":     cl.Or,
	"xor":    cl.Xor,
	"not":    cl.Not,
	"andn":   cl.AndN,
	"orn":    cl.OrN,
	"xorn":   cl.XorN,
	"sum":    cl.Sum,
	"avg":    cl.Avg,
	"drop":   cl.Drop,
	"k":      cl.Drop,
	"dropn":  cl.DropN,
	"dropr":  cl.DropR,
	"dup":    cl.Dup,
	"d":      cl.Dup,
	"dupn":   cl.DupN,
	"dupr":   cl.DupR,
	"pick":   cl.Pick,
	"p":      cl.Pick,
	"swap":   cl.Swap,
	"s":      cl.Swap,
	"depth":  cl.Depth,
	"min":    cl.Min,
	"max":    cl.Max,
	"minn":   cl.MinN,
	"maxn":   cl.MaxN,
	"rot":    cl.Rot,
	"rotr":   cl.RotR,
	"unrot":  cl.Unrot,
	"unrotr": cl.UnrotR,
	"mag":    cl.Mag,
	"hyp":    cl.Hypot,
	"dot":    cl.Dot,
	"dot3":   cl.Dot3,
	"cross":  cl.Cross,
	"pi":     constant(clac.Pi),
	"e":      constant(clac.E),
	"phi":    constant(clac.Phi),
}

var uiCmdMap = map[string]func() error{
	"undo":  cl.Undo,
	"u":     cl.Undo,
	"redo":  cl.Redo,
	"r":     cl.Redo,
	"clear": cl.Clear,
	"c":     cl.Clear,
	"reset": cl.Reset,
	"quit":  quit,
	"q":     quit,
}

type term struct {
	io.Reader
	io.Writer
}

func init() {
	log.SetFlags(0)
	log.SetPrefix("clac: ")
	flag.BoolVar(&doDmenu, "d", doDmenu, "dmenu mode")
	flag.BoolVar(&doHexOut, "x", doHexOut, "hexidecimal output")
	flag.UintVar(&cliPrec, "p", cliPrec, "output precision")
	flag.BoolVar(&doInitStack, "i", doInitStack, "initialize stack")
}

func main() {
	flag.Parse()
	var mode runMode
	mode, lastErr = processCmdLine()
	switch mode {
	case cliMode:
		cliRun()
	case tuiMode:
		tuiRun()
	case dmenuMode:
		dmenuRun()
	}
}

func constant(v value.Value) func() error {
	return func() error { return cl.Push(v) }
}

func cliRun() {
	fmt.Println(stackStr(cl.Stack()))
	if lastErr != nil {
		log.Fatal(lastErr)
	}
}

func uiSetup() {
	for cmd, fn := range uiCmdMap {
		cmdMap[cmd] = fn
	}
	uiCmdMap = nil
}

func tuiRun() {
	uiSetup()
	if !terminal.IsTerminal(syscall.Stdin) {
		log.Fatalln("this doesn't look like an interactive terminal")
	}
	oldTrmState, err := terminal.MakeRaw(syscall.Stdin)
	if err != nil {
		log.Fatalln(err)
	}
	trm := terminal.NewTerminal(term{os.Stdin, os.Stdout}, "")
	for lastErr != io.EOF {
		tuiPrintStack(cl.Stack())
		var input string
		input, lastErr = trm.ReadLine()
		if lastErr == nil {
			lastErr = processInput(input)
		}
	}
	terminal.Restore(syscall.Stdin, oldTrmState)
}

func dmenuSetup() {
	uiSetup()
	cmdMap["hex"] = func() error { doHexOut = true; return nil }
	cmdMap["dec"] = func() error { doHexOut = false; return nil }
	cmdMap["conv"] = dmenuConv
}

func dmenuRun() {
	dmenuSetup()
	for {
		stack := stackStr(cl.Stack())
		if len(stack) > 0 {
			stack = " " + stack
		}
		out, err := exec.Command("dmenu", "-p", "clac:"+stack).Output()
		if err != nil {
			return
		}
		if err := processInput(string(out)); err != nil {
			exec.Command("dmenu", "-p", "clac: "+err.Error()).Run()
		}
	}
}

func dmenuConv() error {
	val, err := cl.Pop()
	if err != nil {
		return err
	}
	valStr := stackStr(clac.Stack{val})
	have, err := exec.Command("dmenu", "-p", "clac: conv: have: "+valStr).Output()
	if err != nil {
		return clac.ErrNoHistUpdate
	}
	want, err := exec.Command("dmenu", "-p", "clac: conv: want:").Output()
	if err != nil {
		return clac.ErrNoHistUpdate
	}
	haveStr := valStr + " " + strings.TrimSpace(string(have))
	wantStr := strings.TrimSpace(string(want))
	out, err := exec.Command("units", "-t", haveStr, wantStr).Output()
	if err != nil {
		errStr := strings.SplitN(string(out), "\n", 2)[0]
		if errStr != "" {
			return errors.New(errStr)
		}
		return err
	}
	num, err := clac.ParseNum(strings.TrimSpace(string(out)))
	if err != nil {
		return err
	}
	return cl.Push(num)
}

func processCmdLine() (runMode, error) {
	input := ""
	if stat, err := os.Stdin.Stat(); err == nil && stat.Mode()&os.ModeNamedPipe != 0 {
		if pipeInput, err := ioutil.ReadAll(os.Stdin); err == nil {
			input = string(pipeInput)
		}
	}
	if len(flag.Args()) > 0 {
		input += " " + strings.Join(flag.Args(), " ")
	}
	mode := cliMode
	switch {
	case doDmenu:
		mode = dmenuMode
	case doInitStack || input == "":
		mode = tuiMode
	}
	cl.EnableHistory(mode != cliMode)
	err := processInput(string(input))
	return mode, err
}

func stackStr(stack clac.Stack) string {
	out := ""
	if doHexOut {
		clac.SetFormat("%#x")
	} else {
		clac.SetFormat(fmt.Sprintf("%%.%dg", cliPrec))
	}
	for i := range stack {
		val := stack[len(stack)-i-1]
		var err error
		if doHexOut {
			val, err = clac.Trunc(val)
		}
		if err != nil {
			out += err.Error()
		} else {
			out += clac.Sprint(val)
		}
		if i < len(stack)-1 {
			out += " "
		}
	}
	return out
}

func quit() error {
	os.Exit(0)
	return nil
}

func processInput(input string) error {
	scanner := bufio.NewScanner(strings.NewReader(input))
	scanner.Split(bufio.ScanWords)
	for scanner.Scan() {
		tok := scanner.Text()
		if num, err := clac.ParseNum(tok); err == nil {
			if err = cl.Exec(func() error { return cl.Push(num) }); err != nil {
				return fmt.Errorf("push: %s", err)
			}
		} else if cmd, ok := cmdMap[tok]; ok {
			if err := cl.Exec(cmd); err != nil {
				return fmt.Errorf("%s: %s", tok, err)
			}
		} else {
			return fmt.Errorf("invalid input: \"%s\"", tok)
		}
	}
	if err := scanner.Err(); err != nil {
		return err
	}
	return nil
}

func tuiPrintStack(stack clac.Stack) {
	cols, rows, err := terminal.GetSize(syscall.Stdout)
	if err != nil {
		rows = len(stack) + 1
	}
	// ensure sane width
	if cols < 20 {
		cols = 20
	}
	clearScreen()

	dataCols := cols - 4
	hexCols := dataCols / 2
	floatCols := dataCols - hexCols
	floatFmt := fmt.Sprintf("%%%d.%dg", floatCols-1, floatCols-8)
	hexFmt := fmt.Sprintf("%%#%dx", hexCols-3)
	for i := rows - 3; i >= 0; i-- {
		line := fmt.Sprintf("%02d:", i)
		if i < len(stack) {
			clac.SetFormat(floatFmt)
			line += fmt.Sprintf(fmt.Sprintf(" %%%ds", floatCols), clac.Sprint(stack[i]))
			if val, err := clac.Trunc(stack[i]); err == nil {
				clac.SetFormat(hexFmt)
				hexStr := fmt.Sprintf(fmt.Sprintf(" %%%ds", hexCols-1), clac.Sprint(val))
				if len(hexStr) > hexCols {
					hexStr = hexStr[:hexCols-1] + "…"
				}
				line += hexStr
			}
		}
		fmt.Println(line + "\r")
	}
	info := ""
	if lastErr != nil {
		info = fmt.Sprintf("[ %s ]", lastErr)
	}
	fmt.Println(info + strings.Repeat("-", cols-len(info)))
	fmt.Print("\r")
}

func clearScreen() {
	fmt.Print("\033[2J\033[H")
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/base64"
	"errors"
	"os"

	"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag"
	"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander"
	config "github.com/jbenet/go-ipfs/config"
	ci "github.com/jbenet/go-ipfs/crypto"
	spipe "github.com/jbenet/go-ipfs/crypto/spipe"
	u "github.com/jbenet/go-ipfs/util"
)

var cmdIpfsInit = &commander.Command{
	UsageLine: "init",
	Short:     "Initialize ipfs local configuration",
	Long: `ipfs init

	Initializes ipfs configuration files and generates a
	new keypair.
`,
	Run:  initCmd,
	Flag: *flag.NewFlagSet("ipfs-init", flag.ExitOnError),
}

func init() {
	cmdIpfsInit.Flag.Int("b", 4096, "number of bits for keypair")
	cmdIpfsInit.Flag.String("p", "", "passphrase for encrypting keys")
	cmdIpfsInit.Flag.Bool("f", false, "force overwrite of existing config")
}

func initCmd(c *commander.Command, inp []string) error {
	configpath, err := getConfigDir(c.Parent)
	if err != nil {
		return err
	}
	if configpath == "" {
		configpath, err = u.TildeExpansion("~/.go-ipfs")
		if err != nil {
			return err
		}
	}

	u.POut("initializing ipfs node at %s\n", configpath)
	filename, err := config.Filename(configpath + "/config")
	if err != nil {
		return errors.New("Couldn't get home directory path")
	}

	fi, err := os.Lstat(filename)
	force, ok := c.Flag.Lookup("f").Value.Get().(bool)
	if !ok {
		return errors.New("failed to parse force flag")
	}
	if fi != nil || (err != nil && !os.IsNotExist(err)) {
		if !force {
			return errors.New("ipfs configuration file already exists!\nReinitializing would overwrite your keys.\n(use -f to force overwrite)")
		}
	}
	cfg := new(config.Config)

	cfg.Datastore = config.Datastore{}
	dspath, err := u.TildeExpansion("~/.go-ipfs/datastore")
	if err != nil {
		return err
	}
	cfg.Datastore.Path = dspath
	cfg.Datastore.Type = "leveldb"

	cfg.Identity = config.Identity{}

	// setup the node addresses.
	cfg.Addresses = config.Addresses{
		Swarm: "/ip4/0.0.0.0/tcp/4001",
		API:   "/ip4/127.0.0.1/tcp/5001",
	}

	nbits, ok := c.Flag.Lookup("b").Value.Get().(int)
	if !ok {
		return errors.New("failed to get bits flag")
	}
	if nbits < 1024 {
		return errors.New("Bitsize less than 1024 is considered unsafe.")
	}

	u.POut("generating key pair\n")
	sk, pk, err := ci.GenerateKeyPair(ci.RSA, nbits)
	if err != nil {
		return err
	}

	// currently storing key unencrypted. in the future we need to encrypt it.
	// TODO(security)
	skbytes, err := sk.Bytes()
	if err != nil {
		return err
	}
	cfg.Identity.PrivKey = base64.StdEncoding.EncodeToString(skbytes)

	id, err := spipe.IDFromPubKey(pk)
	if err != nil {
		return err
	}
	cfg.Identity.PeerID = id.Pretty()

	// Use these hardcoded bootstrap peers for now.
	cfg.Bootstrap = []*config.BootstrapPeer{
		&config.BootstrapPeer{
			// mars.i.ipfs.io
			PeerID:  "QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
			Address: "/ip4/104.131.131.82/tcp/4001",
		},
	}

	path, err := u.TildeExpansion(config.DefaultConfigFilePath)
	if err != nil {
		return err
	}

	err = config.WriteConfigFile(path, cfg)
	if err != nil {
		return err
	}
	return nil
}
<commit_msg>Implement ipfs init -d (change datastore location)<commit_after>package main

import (
	"encoding/base64"
	"errors"
	"os"

	"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag"
	"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander"
	config "github.com/jbenet/go-ipfs/config"
	ci "github.com/jbenet/go-ipfs/crypto"
	spipe "github.com/jbenet/go-ipfs/crypto/spipe"
	u "github.com/jbenet/go-ipfs/util"
)

var cmdIpfsInit = &commander.Command{
	UsageLine: "init",
	Short:     "Initialize ipfs local configuration",
	Long: `ipfs init

	Initializes ipfs configuration files and generates a
	new keypair.
`,
	Run:  initCmd,
	Flag: *flag.NewFlagSet("ipfs-init", flag.ExitOnError),
}

func init() {
	cmdIpfsInit.Flag.Int("b", 4096, "number of bits for keypair")
	cmdIpfsInit.Flag.String("p", "", "passphrase for encrypting keys")
	cmdIpfsInit.Flag.Bool("f", false, "force overwrite of existing config")
	cmdIpfsInit.Flag.String("d", "", "Change default datastore location")
}

func initCmd(c *commander.Command, inp []string) error {
	configpath, err := getConfigDir(c.Parent)
	if err != nil {
		return err
	}
	if configpath == "" {
		configpath, err = u.TildeExpansion("~/.go-ipfs")
		if err != nil {
			return err
		}
	}

	u.POut("initializing ipfs node at %s\n", configpath)
	filename, err := config.Filename(configpath + "/config")
	if err != nil {
		return errors.New("Couldn't get home directory path")
	}

	dspath, ok := c.Flag.Lookup("d").Value.Get().(string)
	if !ok {
		return errors.New("failed to parse datastore flag")
	}

	fi, err := os.Lstat(filename)
	force, ok := c.Flag.Lookup("f").Value.Get().(bool)
	if !ok {
		return errors.New("failed to parse force flag")
	}
	if fi != nil || (err != nil && !os.IsNotExist(err)) {
		if !force {
			return errors.New("ipfs configuration file already exists!\nReinitializing would overwrite your keys.\n(use -f to force overwrite)")
		}
	}
	cfg := new(config.Config)

	cfg.Datastore = config.Datastore{}
	if len(dspath) == 0 {
		dspath, err = u.TildeExpansion("~/.go-ipfs/datastore")
		if err != nil {
			return err
		}
	}
	cfg.Datastore.Path = dspath
	cfg.Datastore.Type = "leveldb"

	cfg.Identity = config.Identity{}

	// setup the node addresses.
	cfg.Addresses = config.Addresses{
		Swarm: "/ip4/0.0.0.0/tcp/4001",
		API:   "/ip4/127.0.0.1/tcp/5001",
	}

	nbits, ok := c.Flag.Lookup("b").Value.Get().(int)
	if !ok {
		return errors.New("failed to get bits flag")
	}
	if nbits < 1024 {
		return errors.New("Bitsize less than 1024 is considered unsafe.")
	}

	u.POut("generating key pair\n")
	sk, pk, err := ci.GenerateKeyPair(ci.RSA, nbits)
	if err != nil {
		return err
	}

	// currently storing key unencrypted. in the future we need to encrypt it.
	// TODO(security)
	skbytes, err := sk.Bytes()
	if err != nil {
		return err
	}
	cfg.Identity.PrivKey = base64.StdEncoding.EncodeToString(skbytes)

	id, err := spipe.IDFromPubKey(pk)
	if err != nil {
		return err
	}
	cfg.Identity.PeerID = id.Pretty()

	// Use these hardcoded bootstrap peers for now.
	cfg.Bootstrap = []*config.BootstrapPeer{
		&config.BootstrapPeer{
			// mars.i.ipfs.io
			PeerID:  "QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
			Address: "/ip4/104.131.131.82/tcp/4001",
		},
	}

	path, err := u.TildeExpansion(config.DefaultConfigFilePath)
	if err != nil {
		return err
	}

	err = config.WriteConfigFile(path, cfg)
	if err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/go-kit/kit/log/level"
	"github.com/grafana/loki/pkg/helpers"
	"github.com/grafana/loki/pkg/loki"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/common/version"
	"github.com/weaveworks/common/tracing"

	"github.com/cortexproject/cortex/pkg/util"
	"github.com/cortexproject/cortex/pkg/util/flagext"
	"github.com/cortexproject/cortex/pkg/util/validation"
)

func init() {
	prometheus.MustRegister(version.NewCollector("loki"))
}

func main() {
	var (
		cfg        loki.Config
		configFile = ""
	)
	flag.StringVar(&configFile, "config.file", "", "Configuration file to load.")
	flagext.RegisterFlags(&cfg)
	flag.Parse()

	// LimitsConfig has a customer UnmarshalYAML that will set the defaults to a global.
	// This global is set to the config passed into the last call to `NewOverrides`. If we don't
	// call it atleast once, the defaults are set to an empty struct.
	// We call it with the flag values so that the config file unmarshalling only overrides the values set in the config.
	if _, err := validation.NewOverrides(cfg.LimitsConfig); err != nil {
		level.Error(util.Logger).Log("msg", "error loading limits", "err", err)
		os.Exit(1)
	}

	util.InitLogger(&cfg.Server)

	if configFile != "" {
		if err := helpers.LoadConfig(configFile, &cfg); err != nil {
			level.Error(util.Logger).Log("msg", "error loading config", "filename", configFile, "err", err)
			os.Exit(1)
		}
	}

	// Setting the environment variable JAEGER_AGENT_HOST enables tracing
	trace := tracing.NewFromEnv(fmt.Sprintf("loki-%s", cfg.Target))
	defer func() {
		if err := trace.Close(); err != nil {
			level.Error(util.Logger).Log("msg", "error closing tracing", "err", err)
			os.Exit(1)
		}
	}()

	t, err := loki.New(cfg)
	if err != nil {
		level.Error(util.Logger).Log("msg", "error initialising loki", "err", err)
		os.Exit(1)
	}

	level.Info(util.Logger).Log("msg", "Starting Loki", "version", version.Info())

	if err := t.Run(); err != nil {
		level.Error(util.Logger).Log("msg", "error running loki", "err", err)
	}

	if err := t.Stop(); err != nil {
		level.Error(util.Logger).Log("msg", "error stopping loki", "err", err)
		os.Exit(1)
	}
}
<commit_msg>fix(loki): honor log level from config file (#657)<commit_after>package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/go-kit/kit/log/level"
	"github.com/grafana/loki/pkg/helpers"
	"github.com/grafana/loki/pkg/loki"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/common/version"
	"github.com/weaveworks/common/tracing"

	"github.com/cortexproject/cortex/pkg/util"
	"github.com/cortexproject/cortex/pkg/util/flagext"
	"github.com/cortexproject/cortex/pkg/util/validation"
)

func init() {
	prometheus.MustRegister(version.NewCollector("loki"))
}

func main() {
	var (
		cfg        loki.Config
		configFile = ""
	)
	flag.StringVar(&configFile, "config.file", "", "Configuration file to load.")
	flagext.RegisterFlags(&cfg)
	flag.Parse()

	// LimitsConfig has a customer UnmarshalYAML that will set the defaults to a global.
	// This global is set to the config passed into the last call to `NewOverrides`. If we don't
	// call it atleast once, the defaults are set to an empty struct.
	// We call it with the flag values so that the config file unmarshalling only overrides the values set in the config.
	if _, err := validation.NewOverrides(cfg.LimitsConfig); err != nil {
		level.Error(util.Logger).Log("msg", "error loading limits", "err", err)
		os.Exit(1)
	}

	util.InitLogger(&cfg.Server)

	if configFile != "" {
		if err := helpers.LoadConfig(configFile, &cfg); err != nil {
			level.Error(util.Logger).Log("msg", "error loading config", "filename", configFile, "err", err)
			os.Exit(1)
		}
	}

	// Re-init the logger which will now honor a different log level set in cfg.Server
	util.InitLogger(&cfg.Server)

	// Setting the environment variable JAEGER_AGENT_HOST enables tracing
	trace := tracing.NewFromEnv(fmt.Sprintf("loki-%s", cfg.Target))
	defer func() {
		if err := trace.Close(); err != nil {
			level.Error(util.Logger).Log("msg", "error closing tracing", "err", err)
			os.Exit(1)
		}
	}()

	t, err := loki.New(cfg)
	if err != nil {
		level.Error(util.Logger).Log("msg", "error initialising loki", "err", err)
		os.Exit(1)
	}

	level.Info(util.Logger).Log("msg", "Starting Loki", "version", version.Info())

	if err := t.Run(); err != nil {
		level.Error(util.Logger).Log("msg", "error running loki", "err", err)
	}

	if err := t.Stop(); err != nil {
		level.Error(util.Logger).Log("msg", "error stopping loki", "err", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/tatsushid/go-fastping"
	"net"
	"os"
	"os/signal"
	"syscall"
	"time"
)

type response struct {
	addr *net.IPAddr
	rtt  time.Duration
}

func main() {
	if len(os.Args) != 2 {
		fmt.Fprintf(os.Stderr, "Usage: %s {hostname}\n", os.Args[0])
		os.Exit(1)
	}
	p := fastping.NewPinger()
	ra, err := net.ResolveIPAddr("ip4:icmp", os.Args[1])
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	results := make(map[string]*response)
	results[ra.String()] = nil
	p.AddIPAddr(ra)

	onRecv, onIdle := make(chan *response), make(chan bool)
	p.AddHandler("receive", func(addr *net.IPAddr, t time.Duration) {
		onRecv <- &response{addr: addr, rtt: t}
	})
	p.AddHandler("idle", func() {
		onIdle <- true
	})

	p.MaxRTT = time.Second
	p.RunLoop()

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	signal.Notify(c, syscall.SIGTERM)

loop:
	for {
		select {
		case <-c:
			fmt.Println("get interrupted")
			break loop
		case res := <-onRecv:
			if _, ok := results[res.addr.String()]; ok {
				results[res.addr.String()] = res
			}
		case <-onIdle:
			for host, r := range results {
				if r == nil {
					fmt.Printf("%s : unreachable %v\n", host, time.Now())
				} else {
					fmt.Printf("%s : %v %v\n", host, r.rtt, time.Now())
				}
				results[host] = nil
			}
		case <-p.Done():
			if err = p.Err(); err != nil {
				fmt.Println("Ping failed:", err)
			}
			break loop
		}
	}
	signal.Stop(c)
	p.Stop()
}
<commit_msg>Add error handlings<commit_after>package main

import (
	"fmt"
	"github.com/tatsushid/go-fastping"
	"net"
	"os"
	"os/signal"
	"syscall"
	"time"
)

type response struct {
	addr *net.IPAddr
	rtt  time.Duration
}

func main() {
	if len(os.Args) != 2 {
		fmt.Fprintf(os.Stderr, "Usage: %s {hostname}\n", os.Args[0])
		os.Exit(1)
	}
	p := fastping.NewPinger()
	ra, err := net.ResolveIPAddr("ip4:icmp", os.Args[1])
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	results := make(map[string]*response)
	results[ra.String()] = nil
	p.AddIPAddr(ra)

	onRecv, onIdle := make(chan *response), make(chan bool)
	err = p.AddHandler("receive", func(addr *net.IPAddr, t time.Duration) {
		onRecv <- &response{addr: addr, rtt: t}
	})
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	err = p.AddHandler("idle", func() {
		onIdle <- true
	})
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	p.MaxRTT = time.Second
	p.RunLoop()

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	signal.Notify(c, syscall.SIGTERM)

loop:
	for {
		select {
		case <-c:
			fmt.Println("get interrupted")
			break loop
		case res := <-onRecv:
			if _, ok := results[res.addr.String()]; ok {
				results[res.addr.String()] = res
			}
		case <-onIdle:
			for host, r := range results {
				if r == nil {
					fmt.Printf("%s : unreachable %v\n", host, time.Now())
				} else {
					fmt.Printf("%s : %v %v\n", host, r.rtt, time.Now())
				}
				results[host] = nil
			}
		case <-p.Done():
			if err = p.Err(); err != nil {
				fmt.Println("Ping failed:", err)
			}
			break loop
		}
	}
	signal.Stop(c)
	p.Stop()
}
<|endoftext|>


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

package cmd

import (
	"log"
	"sync"

	"github.com/benjdewan/pachelbel/config"
	"github.com/benjdewan/pachelbel/connection"
	"github.com/golang-collections/go-datastructures/queue"
	"github.com/gosuri/uiprogress"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

// provisionCmd represents the provision command
var provisionCmd = &cobra.Command{
	Use:   "provision",
	Short: "Idempotent provisioner of compose deployments",
	Long: `pachelbel provision reads in YAML configuration(s) describing a list of
deployments that should exist in a list of clusters of specified sizes,
and ensures they do.

If the deployments do not exist, they are created. If they exist, but are
the wrong size they are scaled. If they are deployed as specified in the
configuration no actions are taken.`,
	Run: doProvision,
}

func doProvision(cmd *cobra.Command, args []string) {
	if len(args) == 0 {
		log.Fatal("The 'provision' command requires at least one configuration file or directory as input")
	}
	config.BuildClusterFilter(viper.GetStringSlice("cluster"))
	config.BuildDatacenterFilter(viper.GetStringSlice("datacenter"))

	verbose := viper.GetBool("verbose")
	deployments, err := config.ReadFiles(args, verbose)
	if err != nil {
		log.Fatal(err)
	}

	cxn, err := connection.Init(viper.GetString("api-key"),
		viper.GetInt("polling-interval"))
	if err != nil {
		log.Fatal(err)
	}
	cxn.MaxNameLength = config.MaxNameLength(deployments)

	errQueue := queue.New(int64(len(deployments)))
	var wg sync.WaitGroup
	wg.Add(len(deployments))
	uiprogress.Start()
	for _, deployment := range deployments {
		go connection.Provision(cxn, deployment, errQueue, &wg)
	}
	wg.Wait()
	flush(errQueue)
	uiprogress.Stop()

	errQueue = queue.New(0)
	cxn.ConnectionStringsYAML(viper.GetString("output"), errQueue)
	flush(errQueue)
}

func init() {
	RootCmd.AddCommand(provisionCmd)
	provisionCmd.Flags().StringSliceP("cluster", "c", []string{},
		`By default pachelbel provision will provision every deployment
			provided. Use this flag to limit pachelbel to only
			process deployments to the specified cluster.

			This flag can be repeated to specify multiple clusters`)
	provisionCmd.Flags().StringSliceP("datacenter", "d", []string{},
		`By default pachelbel provision will provision every
			deployment provided. Use this flat to limit pachelbel
			to only process deployments to the specified
			datacenter.

			This flag can be repeated to specify multiple datacenters.`)
	provisionCmd.Flags().StringP("output", "o", "./connection-strings.yml",
		`The file to write connection string information to.`)
	provisionCmd.Flags().IntP("polling-interval", "p", 5,
		`The polling interval, in seconds, to use when
			waiting for a provisioning recipe to complete`)

	viper.BindPFlag("cluster", provisionCmd.Flags().Lookup("cluster"))
	viper.BindPFlag("datacenter", provisionCmd.Flags().Lookup("datacenter"))
	viper.BindPFlag("output", provisionCmd.Flags().Lookup("output"))
	viper.BindPFlag("polling-interval", provisionCmd.Flags().Lookup("polling-interval"))
}

func flush(errQueue *queue.Queue) {
	if !errQueue.Empty() {
		items, qErr := errQueue.Get(errQueue.Len())
		if qErr != nil {
			// Get() only returns an error if Dispose() has already
			// been called on the queue.
			panic(qErr)
		}
		for _, unknown := range items {
			switch item := unknown.(type) {
			case error:
				log.Printf("Error: %v", item)
			default:
				log.Fatalf("Only errors should be in the error queue. Found %v", item)
			}
		}
	}
	errQueue.Dispose()
}
<commit_msg>Ensure we fail on error<commit_after>// Copyright © 2017 ben dewan <benj.dewan@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package cmd

import (
	"log"
	"os"
	"sync"

	"github.com/benjdewan/pachelbel/config"
	"github.com/benjdewan/pachelbel/connection"
	"github.com/golang-collections/go-datastructures/queue"
	"github.com/gosuri/uiprogress"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

// provisionCmd represents the provision command
var provisionCmd = &cobra.Command{
	Use:   "provision",
	Short: "Idempotent provisioner of compose deployments",
	Long: `pachelbel provision reads in YAML configuration(s) describing a list of
deployments that should exist in a list of clusters of specified sizes,
and ensures they do.

If the deployments do not exist, they are created. If they exist, but are
the wrong size they are scaled. If they are deployed as specified in the
configuration no actions are taken.`,
	Run: doProvision,
}

func doProvision(cmd *cobra.Command, args []string) {
	if len(args) == 0 {
		log.Fatal("The 'provision' command requires at least one configuration file or directory as input")
	}
	config.BuildClusterFilter(viper.GetStringSlice("cluster"))
	config.BuildDatacenterFilter(viper.GetStringSlice("datacenter"))

	verbose := viper.GetBool("verbose")
	deployments, err := config.ReadFiles(args, verbose)
	if err != nil {
		log.Fatal(err)
	}

	cxn, err := connection.Init(viper.GetString("api-key"),
		viper.GetInt("polling-interval"))
	if err != nil {
		log.Fatal(err)
	}
	cxn.MaxNameLength = config.MaxNameLength(deployments)

	errQueue := queue.New(int64(len(deployments)))
	var wg sync.WaitGroup
	wg.Add(len(deployments))
	uiprogress.Start()
	for _, deployment := range deployments {
		go connection.Provision(cxn, deployment, errQueue, &wg)
	}
	wg.Wait()
	flush(errQueue)
	uiprogress.Stop()

	errQueue = queue.New(0)
	cxn.ConnectionStringsYAML(viper.GetString("output"), errQueue)
	flush(errQueue)
}

func init() {
	RootCmd.AddCommand(provisionCmd)
	provisionCmd.Flags().StringSliceP("cluster", "c", []string{},
		`By default pachelbel provision will provision every deployment
			provided. Use this flag to limit pachelbel to only
			process deployments to the specified cluster.

			This flag can be repeated to specify multiple clusters`)
	provisionCmd.Flags().StringSliceP("datacenter", "d", []string{},
		`By default pachelbel provision will provision every
			deployment provided. Use this flat to limit pachelbel
			to only process deployments to the specified
			datacenter.

			This flag can be repeated to specify multiple datacenters.`)
	provisionCmd.Flags().StringP("output", "o", "./connection-strings.yml",
		`The file to write connection string information to.`)
	provisionCmd.Flags().IntP("polling-interval", "p", 5,
		`The polling interval, in seconds, to use when
			waiting for a provisioning recipe to complete`)

	viper.BindPFlag("cluster", provisionCmd.Flags().Lookup("cluster"))
	viper.BindPFlag("datacenter", provisionCmd.Flags().Lookup("datacenter"))
	viper.BindPFlag("output", provisionCmd.Flags().Lookup("output"))
	viper.BindPFlag("polling-interval", provisionCmd.Flags().Lookup("polling-interval"))
}

func flush(errQueue *queue.Queue) {
	if !errQueue.Empty() {
		items, qErr := errQueue.Get(errQueue.Len())
		if qErr != nil {
			// Get() only returns an error if Dispose() has already
			// been called on the queue.
			panic(qErr)
		}
		for _, unknown := range items {
			switch item := unknown.(type) {
			case error:
				log.Printf("Error: %v", item)
			default:
				log.Fatalf("Only errors should be in the error queue. Found %v", item)
			}
		}
		os.Exit(1)
	}
	errQueue.Dispose()
}
<|endoftext|>


<commit_before>// Copyright 2017 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

// push cross compiles one or multiple executables and pushes them to a micro
// computer over ssh.
package main

import (
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
)

// run is a shorthand for exec.Command().Run().
func run(name string, arg ...string) error {
	c := exec.Command(name, arg...)
	c.Stdout = os.Stdout
	c.Stderr = os.Stderr
	return c.Run()
}

type tool int

const (
	none tool = iota
	rsync
	pscp
	scp
)
const toolName = "nonersyncpscpscp"

var toolIndex = [...]uint8{0, 4, 9, 13, 16}

func (i tool) String() string {
	if i < 0 || i >= tool(len(toolIndex)-1) {
		return fmt.Sprintf("tool(%d)", i)
	}
	return toolName[toolIndex[i]:toolIndex[i+1]]
}

func (t tool) push(verbose bool, src string, pkgs []string, host, rel string) error {
	dst := fmt.Sprintf("%s:%s", host, rel)
	var args []string
	switch t {
	case rsync:
		// Push all files via rsync. This is the fastest method.
		args = []string{"--archive", "--info=progress2", "--compress", src + "/", dst}
		if verbose {
			args = append([]string{"-v"}, args...)
		}
	case pscp, scp:
		// Push all files via pscp/scp, provided by PuTTY/OpenSSH.
		//
		// It is slower than rsync and will fail if one of the destination
		// executable is under use, but it is a reasonable fallback.
		// TODO(maruel): pscp/scp with an alternate name, then plink/ssh in to
		// rename the files.
		args = []string{"-C", "-p", "-r"}
		for _, pkg := range pkgs {
			args = append(args, filepath.Join(src, filepath.Base(pkg)))
		}
		if verbose {
			args = append([]string{"-v"}, args...)
		}
		args = append(args, dst)
	default:
		return errors.New("please make sure at least one of rsync, scp or pscp is in PATH")
	}
	if err := run(t.String(), args...); err != nil {
		return err
	}
	if runtime.GOOS == "windows" {
		// On Windows, the +x bit is lost, so we are required to ssh in to change
		// the file mode.
		args = []string{host, "chmod", "+x"}
		for _, pkg := range pkgs {
			args = append(args, filepath.Join(rel, filepath.Base(pkg)))
		}
		switch t {
		case rsync, scp:
			return run("ssh", args...)
		case pscp:
			return run("plink", args...)
		}
	}
	return nil

}

// detect returns which tool to use.
func detect() tool {
	if _, err := exec.Command("rsync", "--version").CombinedOutput(); err == nil {
		return rsync
	}
	if runtime.GOOS == "windows" {
		if _, err := exec.Command("pscp", "-V").CombinedOutput(); err == nil {
			return pscp
		}
	}
	_, err := exec.Command("scp", "-V").CombinedOutput()
	if err2, ok := err.(*exec.Error); ok && err2.Err == exec.ErrNotFound {
		return none
	}
	return scp
}

// toPkg returns one or multiple packages matching the relpath.
func toPkg(item string) ([]string, error) {
	out, err := exec.Command("go", "list", item).CombinedOutput()
	s := strings.TrimSpace(string(out))
	if err != nil {
		return nil, fmt.Errorf("failed to list package %q: %v\n%s", item, err, s)
	}
	return strings.Split(s, "\n"), nil
}

// pushInner does the actual work: build then push.
func pushInner(verbose bool, t tool, pkgs []string, tags string, host, rel, d string) error {
	// First build everything.
	for _, pkg := range pkgs {
		fmt.Printf("- Building %s\n", pkg)
		args := []string{"build", "-v", "-o", filepath.Join(d, filepath.Base(pkg))}
		if tags != "" {
			args = append(args, "-tags", tags)
		}
		args = append(args, pkg)
		if err := run("go", args...); err != nil {
			fmt.Fprintf(os.Stderr, "Failed to build %s\n", pkg)
			return err
		}
	}

	// Then push it all as one swoop.
	fmt.Printf("- Pushing %d executables to %s in %s via %s\n", len(pkgs), rel, host, t)
	return t.push(verbose, d, pkgs, host, rel)
}

// push wraps pushInner with a temporary directory.
func push(verbose bool, t tool, items []string, tags string, host, rel string) error {
	// First convert the passed strings into real package names.
	var pkgs []string
	for _, item := range items {
		i, err := toPkg(item)
		if err != nil {
			return err
		}
		pkgs = append(pkgs, i...)
	}

	d, err := ioutil.TempDir("", "push")
	if err != nil {
		return err
	}
	err = pushInner(verbose, t, pkgs, tags, host, rel, d)
	if err1 := os.RemoveAll(d); err == nil {
		err = err1
	}
	return err
}

func mainImpl() error {
	goarch := flag.String("goarch", "arm", "GOARCH value to use")
	goarm := flag.String("goarm", "6", "GOARM value to use")
	goos := flag.String("goos", "linux", "GOOS value to use")
	tags := flag.String("tags", "", "build tags to pass")
	rel := flag.String("rel", ".", "directory on remote host to push files into")
	host := flag.String("host", os.Getenv("PUSH_HOST"), "host to push to; defaults to content of environment variable PUSH_HOST")
	verbose := flag.Bool("v", false, "verbose output")
	flag.Parse()
	pkgs := flag.Args()
	if len(pkgs) == 0 {
		fmt.Printf("Note: No argument provided, defaulting to the current directory.\n")
		pkgs = []string{"."}
	}
	if !*verbose {
		log.SetOutput(ioutil.Discard)
	}

	t := detect()
	if t == none {
		return errors.New("Please make sure at least one of rsync, scp or pscp is in PATH")
	}

	// Simplify our life and just set it process wide.
	os.Setenv("GOARCH", *goarch)
	os.Setenv("GOARM", *goarm)
	os.Setenv("GOOS", *goos)
	return push(*verbose, t, pkgs, *tags, *host, *rel)
}

func main() {
	if err := mainImpl(); err != nil {
		fmt.Fprintf(os.Stderr, "push: %s\n\nVisit https://github.com/periph/bootstrap#troubleshooting-push for help.\n", err)
		os.Exit(1)
	}
}
<commit_msg>push: don't push if -host is not provided<commit_after>// Copyright 2017 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

// push cross compiles one or multiple executables and pushes them to a micro
// computer over ssh.
package main

import (
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
)

// run is a shorthand for exec.Command().Run().
func run(name string, arg ...string) error {
	c := exec.Command(name, arg...)
	c.Stdout = os.Stdout
	c.Stderr = os.Stderr
	return c.Run()
}

type tool int

const (
	none tool = iota
	rsync
	pscp
	scp
)
const toolName = "nonersyncpscpscp"

var toolIndex = [...]uint8{0, 4, 9, 13, 16}

func (i tool) String() string {
	if i < 0 || i >= tool(len(toolIndex)-1) {
		return fmt.Sprintf("tool(%d)", i)
	}
	return toolName[toolIndex[i]:toolIndex[i+1]]
}

func (t tool) push(verbose bool, src string, pkgs []string, host, rel string) error {
	dst := fmt.Sprintf("%s:%s", host, rel)
	var args []string
	switch t {
	case rsync:
		// Push all files via rsync. This is the fastest method.
		args = []string{"--archive", "--info=progress2", "--compress", src + "/", dst}
		if verbose {
			args = append([]string{"-v"}, args...)
		}
	case pscp, scp:
		// Push all files via pscp/scp, provided by PuTTY/OpenSSH.
		//
		// It is slower than rsync and will fail if one of the destination
		// executable is under use, but it is a reasonable fallback.
		// TODO(maruel): pscp/scp with an alternate name, then plink/ssh in to
		// rename the files.
		args = []string{"-C", "-p", "-r"}
		for _, pkg := range pkgs {
			args = append(args, filepath.Join(src, filepath.Base(pkg)))
		}
		if verbose {
			args = append([]string{"-v"}, args...)
		}
		args = append(args, dst)
	default:
		return errors.New("please make sure at least one of rsync, scp or pscp is in PATH")
	}
	if err := run(t.String(), args...); err != nil {
		return err
	}
	if runtime.GOOS == "windows" {
		// On Windows, the +x bit is lost, so we are required to ssh in to change
		// the file mode.
		args = []string{host, "chmod", "+x"}
		for _, pkg := range pkgs {
			args = append(args, filepath.Join(rel, filepath.Base(pkg)))
		}
		switch t {
		case rsync, scp:
			return run("ssh", args...)
		case pscp:
			return run("plink", args...)
		}
	}
	return nil

}

// detect returns which tool to use.
func detect() tool {
	if _, err := exec.Command("rsync", "--version").CombinedOutput(); err == nil {
		return rsync
	}
	if runtime.GOOS == "windows" {
		if _, err := exec.Command("pscp", "-V").CombinedOutput(); err == nil {
			return pscp
		}
	}
	_, err := exec.Command("scp", "-V").CombinedOutput()
	if err2, ok := err.(*exec.Error); ok && err2.Err == exec.ErrNotFound {
		return none
	}
	return scp
}

// toPkg returns one or multiple packages matching the relpath.
func toPkg(item string) ([]string, error) {
	out, err := exec.Command("go", "list", item).CombinedOutput()
	s := strings.TrimSpace(string(out))
	if err != nil {
		return nil, fmt.Errorf("failed to list package %q: %v\n%s", item, err, s)
	}
	return strings.Split(s, "\n"), nil
}

// pushInner does the actual work: build then push.
func pushInner(verbose bool, t tool, pkgs []string, tags string, host, rel, d string) error {
	// First build everything.
	for _, pkg := range pkgs {
		fmt.Printf("- Building %s\n", pkg)
		args := []string{"build", "-v", "-o", filepath.Join(d, filepath.Base(pkg))}
		if tags != "" {
			args = append(args, "-tags", tags)
		}
		args = append(args, pkg)
		if err := run("go", args...); err != nil {
			fmt.Fprintf(os.Stderr, "Failed to build %s\n", pkg)
			return err
		}
	}

	if host == "" {
		fmt.Printf("Note: -host not provided, not pushing.\n")
		return nil
	}
	// Then push it all as one swoop.
	fmt.Printf("- Pushing %d executables to %s in %s via %s\n", len(pkgs), rel, host, t)
	return t.push(verbose, d, pkgs, host, rel)
}

// push wraps pushInner with a temporary directory.
func push(verbose bool, t tool, items []string, tags string, host, rel string) error {
	// First convert the passed strings into real package names.
	var pkgs []string
	for _, item := range items {
		i, err := toPkg(item)
		if err != nil {
			return err
		}
		pkgs = append(pkgs, i...)
	}

	d, err := ioutil.TempDir("", "push")
	if err != nil {
		return err
	}
	err = pushInner(verbose, t, pkgs, tags, host, rel, d)
	if err1 := os.RemoveAll(d); err == nil {
		err = err1
	}
	return err
}

func mainImpl() error {
	goarch := flag.String("goarch", "arm", "GOARCH value to use")
	goarm := flag.String("goarm", "6", "GOARM value to use")
	goos := flag.String("goos", "linux", "GOOS value to use")
	tags := flag.String("tags", "", "build tags to pass")
	rel := flag.String("rel", ".", "directory on remote host to push files into")
	host := flag.String("host", os.Getenv("PUSH_HOST"), "host to push to; defaults to content of environment variable PUSH_HOST")
	verbose := flag.Bool("v", false, "verbose output")
	flag.Parse()
	pkgs := flag.Args()
	if len(pkgs) == 0 {
		fmt.Printf("Note: No argument provided, defaulting to the current directory.\n")
		pkgs = []string{"."}
	}
	if !*verbose {
		log.SetOutput(ioutil.Discard)
	}

	t := detect()
	if t == none {
		return errors.New("Please make sure at least one of rsync, scp or pscp is in PATH")
	}

	// Simplify our life and just set it process wide.
	os.Setenv("GOARCH", *goarch)
	os.Setenv("GOARM", *goarm)
	os.Setenv("GOOS", *goos)
	return push(*verbose, t, pkgs, *tags, *host, *rel)
}

func main() {
	if err := mainImpl(); err != nil {
		fmt.Fprintf(os.Stderr, "push: %s\n\nVisit https://github.com/periph/bootstrap#troubleshooting-push for help.\n", err)
		os.Exit(1)
	}
}
<|endoftext|>