<commit_before>package thuder

import (
	"errors"
	"fmt"
	"os"
	"strings"
)

var _ = fmt.Println

var (
	//ErrBadPath is returned when path is not of required formate, such as a absolute
	//path when required. This signals a misconfiguration for the current operating system.
	ErrBadPath = errors.New("the file path is not of required formate")
	//ErrNeedDir is returned when an expected directory does not exist or is not a directory.
	//There for, the operation can not be applied.
	ErrNeedDir = errors.New("a directory is required for this operation")
)

//Collection is a document tree that collects meta data of changes in a directory
//to be made.
type Collection struct {
	nodes  map[string][]Node
	accept func(*Node) bool
}

//NewCollection initializes a new empty Collection, with accept function
func NewCollection(accept func(*Node) bool) *Collection {
	return &Collection{
		nodes:  make(map[string][]Node),
		accept: accept,
	}
}

//PrintTo prints all nodes in a collection, useful for debuging.
func (c *Collection) PrintTo(f func(format string, args ...interface{})) {
	for k, v := range c.nodes {
		f("%s: %s\n", k, &v)
	}
}

//Get returns all nodes seen with this name ignoring case
func (c *Collection) Get(name string) []Node {
	return c.nodes[strings.ToUpper(name)]
}

//Add adds all nodes (direct child of given parent) by filename to the collection.
//Existing files with the same name are overwitten.
//Existing folders are added.
func (c *Collection) Add(parent *Node) error {
	if !parent.info.IsDir() {
		return ErrNeedDir
	}
	f, err := parent.Open()
	if err != nil {
		return err
	}
	defer f.Close()
	list, err := f.Readdir(-1)
	if err != nil {
		return err
	}
	fc := NewFileContext(parent)
	c.AddList(fc, list)
	return nil
}

//AddList is same as Add, but with given FileContext and FileInfo slice
func (c *Collection) AddList(fc *FileContext, list []os.FileInfo) {
	for _, fi := range list {
		node := Node{
			fc:   fc,
			info: fi,
		}
		if !c.accept(&node) {
			break
		}
		name := strings.ToUpper(fi.Name())

		old := c.nodes[name]

		/*
			conflict resolution matrix
			old only checks last element in nodes list

			old: | dif folder| same folder      | empty
							 | file | del | dir |
			new:
			file | R | A | R | A | R
			del  | R | X | A | A | R
			dir  | A | A | A | A | R

			R : replace with new list
			A : use addNode function
			X : no-op
		*/

		if len(old) == 0 { //empty case
			c.nodes[name] = []Node{node}
			continue
		}
		index := len(old) - 1
		last := old[index]

		if !node.IsDir() && !node.SameDir(last) {
			c.nodes[name] = []Node{node}
			continue
		}
		if !node.IsDir() && !last.IsDir() && node.SameDir(last) {
			if node.IsDelete() && !last.IsDelete() {
				continue //no-op
			}
			if !node.IsDelete() && last.IsDelete() {
				c.nodes[name] = []Node{node}
				continue
			}
		}

		c.nodes[name] = addNode(c.nodes[name], node)
	}
}

//GetAppliedTo returns list of nodes as actions to be taken on the target
//path such that the operation is consistent.
//Such as: case-sensitive act as case-preserving.
//
//Returnes are separated for ordering. ie: deletes happen before copies
//
//The target dir must have been created
func (c *Collection) GetAppliedTo(target string) (deletes []Node, changedfiles []Node, dirs [][]Node, err error) {
	exist := NewCollection(c.accept) //Collect nodes from target
	t, err := NewRootNode(target, true)
	if err == nil { //only add if target can be opend
		err = exist.Add(t)
		if err != nil {
			return
		}
	} else if os.IsNotExist(err) {
		err = nil // target is not created yet, so just treat it as empty
	} else {
		return // returns other unexpected errors
	}

	for name, nodes := range c.nodes {
		en := exist.nodes[name]
		/*
			en :| file | dir | none
			c. (last)
			file| U | R | U
			del | D | D | X
			dir | R | A | A

			* del only means delete a file,
			  delete a dir means files inside dir should be deleted

			U : update -> changedfiles (and deletes other capitalizations)
			D : delete -> deletes
			R : replace -> D + U (case 2) or D + A (case 7)
			A : add -> dirs + changedfiles (for new dirs only)
			X : no-op
		*/
		last := nodes[len(nodes)-1]
		updated := false
		for _, e := range en {
			if last.IsDir() && e.IsDir() {
				if !last.IsDelete() && last.info.Name() == e.info.Name() {
					updated = true //avoid creating existing dir
				}
				continue //case 8
			}

			if !last.IsDir() && !e.IsDir() && !last.IsDelete() &&
				last.info.Name() == e.info.Name() {
				//case 1 with same capitalization
				if last.SameData(e) {
					updated = true //avoid updating an updated file
				}
				continue
			}
			deletes = append(deletes, e) // all others delete exisiting
		}

		if last.IsDir() {
			i := len(nodes) - 1
			for ; i >= 0; i-- {
				n := nodes[i]
				if !n.IsDir() {
					break
				}
			}
			dirs = append(dirs, nodes[i+1:]) //cases 7, 8, and 9
			if !last.IsDelete() && !updated {
				changedfiles = append(changedfiles, last) //is new dir
			}
		} else if !last.IsDelete() && !updated {
			changedfiles = append(changedfiles, last) //finish cases 1, 2, and 3
		}
	}
	return
}
<commit_msg>bug fix<commit_after>package thuder

import (
	"errors"
	"fmt"
	"os"
	"strings"
)

var _ = fmt.Println

var (
	//ErrBadPath is returned when path is not of required formate, such as a absolute
	//path when required. This signals a misconfiguration for the current operating system.
	ErrBadPath = errors.New("the file path is not of required formate")
	//ErrNeedDir is returned when an expected directory does not exist or is not a directory.
	//There for, the operation can not be applied.
	ErrNeedDir = errors.New("a directory is required for this operation")
)

//Collection is a document tree that collects meta data of changes in a directory
//to be made.
type Collection struct {
	nodes  map[string][]Node
	accept func(*Node) bool
}

//NewCollection initializes a new empty Collection, with accept function
func NewCollection(accept func(*Node) bool) *Collection {
	return &Collection{
		nodes:  make(map[string][]Node),
		accept: accept,
	}
}

//PrintTo prints all nodes in a collection, useful for debuging.
func (c *Collection) PrintTo(f func(format string, args ...interface{})) {
	for k, v := range c.nodes {
		f("%s: %s\n", k, &v)
	}
}

//Get returns all nodes seen with this name ignoring case
func (c *Collection) Get(name string) []Node {
	return c.nodes[strings.ToUpper(name)]
}

//Add adds all nodes (direct child of given parent) by filename to the collection.
//Existing files with the same name are overwitten.
//Existing folders are added.
func (c *Collection) Add(parent *Node) error {
	if !parent.info.IsDir() {
		return ErrNeedDir
	}
	f, err := parent.Open()
	if err != nil {
		return err
	}
	defer f.Close()
	list, err := f.Readdir(-1)
	if err != nil {
		return err
	}
	fc := NewFileContext(parent)
	c.AddList(fc, list)
	return nil
}

//AddList is same as Add, but with given FileContext and FileInfo slice
func (c *Collection) AddList(fc *FileContext, list []os.FileInfo) {
	for _, fi := range list {
		node := Node{
			fc:   fc,
			info: fi,
		}
		if !c.accept(&node) {
			continue
		}
		name := strings.ToUpper(fi.Name())

		old := c.nodes[name]

		/*
			conflict resolution matrix
			old only checks last element in nodes list

			old: | dif folder| same folder      | empty
							 | file | del | dir |
			new:
			file | R | A | R | A | R
			del  | R | X | A | A | R
			dir  | A | A | A | A | R

			R : replace with new list
			A : use addNode function
			X : no-op
		*/

		if len(old) == 0 { //empty case
			c.nodes[name] = []Node{node}
			continue
		}
		index := len(old) - 1
		last := old[index]

		if !node.IsDir() && !node.SameDir(last) {
			c.nodes[name] = []Node{node}
			continue
		}
		if !node.IsDir() && !last.IsDir() && node.SameDir(last) {
			if node.IsDelete() && !last.IsDelete() {
				continue //no-op
			}
			if !node.IsDelete() && last.IsDelete() {
				c.nodes[name] = []Node{node}
				continue
			}
		}

		c.nodes[name] = addNode(c.nodes[name], node)
	}
}

//GetAppliedTo returns list of nodes as actions to be taken on the target
//path such that the operation is consistent.
//Such as: case-sensitive act as case-preserving.
//
//Returnes are separated for ordering. ie: deletes happen before copies
//
//The target dir must have been created
func (c *Collection) GetAppliedTo(target string) (deletes []Node, changedfiles []Node, dirs [][]Node, err error) {
	exist := NewCollection(c.accept) //Collect nodes from target
	t, err := NewRootNode(target, true)
	if err == nil { //only add if target can be opend
		err = exist.Add(t)
		if err != nil {
			return
		}
	} else if os.IsNotExist(err) {
		err = nil // target is not created yet, so just treat it as empty
	} else {
		return // returns other unexpected errors
	}

	for name, nodes := range c.nodes {
		en := exist.nodes[name]
		/*
			en :| file | dir | none
			c. (last)
			file| U | R | U
			del | D | D | X
			dir | R | A | A

			* del only means delete a file,
			  delete a dir means files inside dir should be deleted

			U : update -> changedfiles (and deletes other capitalizations)
			D : delete -> deletes
			R : replace -> D + U (case 2) or D + A (case 7)
			A : add -> dirs + changedfiles (for new dirs only)
			X : no-op
		*/
		last := nodes[len(nodes)-1]
		updated := false
		for _, e := range en {
			if last.IsDir() && e.IsDir() {
				if !last.IsDelete() && last.info.Name() == e.info.Name() {
					updated = true //avoid creating existing dir
				}
				continue //case 8
			}

			if !last.IsDir() && !e.IsDir() && !last.IsDelete() &&
				last.info.Name() == e.info.Name() {
				//case 1 with same capitalization
				if last.SameData(e) {
					updated = true //avoid updating an updated file
				}
				continue
			}
			deletes = append(deletes, e) // all others delete exisiting
		}

		if last.IsDir() {
			i := len(nodes) - 1
			for ; i >= 0; i-- {
				n := nodes[i]
				if !n.IsDir() {
					break
				}
			}
			dirs = append(dirs, nodes[i+1:]) //cases 7, 8, and 9
			if !last.IsDelete() && !updated {
				changedfiles = append(changedfiles, last) //is new dir
			}
		} else if !last.IsDelete() && !updated {
			changedfiles = append(changedfiles, last) //finish cases 1, 2, and 3
		}
	}
	return
}
<|endoftext|>


<commit_before>package project

import (
	"archive/tar"
	"bytes"
	"compress/gzip"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"gnd.la/util/yaml"
)

const (
	metaFile = "_template.yaml"
)

type Template struct {
	Name        string `json:"name"`
	Description string `json:"desc"`
	URL         string `json:"url"`
	Version     int    `json:"v"`
	dir         string
}

func (t *Template) addFiles(tw *tar.Writer, dir string) error {
	return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		name := strings.TrimPrefix(path, dir)
		if name != "" {
			if name[0] == filepath.Separator {
				name = name[1:]
			}
			if name == "_template.yaml" {
				return nil
			}
			hdr, err := tar.FileInfoHeader(info, "")
			if err != nil {
				return err
			}
			if dir, _ := filepath.Split(name); dir != "" {
				hdr.Name = filepath.ToSlash(filepath.Join(dir, hdr.Name))
			}
			if err := tw.WriteHeader(hdr); err != nil {
				return err
			}
			if !info.IsDir() {
				f, err := os.Open(path)
				if err != nil {
					return err
				}
				defer f.Close()
				if _, err := io.Copy(tw, f); err != nil {
					return err
				}
			}
		}
		return nil
	})
}

func (t *Template) addFilesFromSibling(tw *tar.Writer, name string) error {
	return t.addFiles(tw, filepath.Join(filepath.Dir(t.dir), name))
}

func (t *Template) Data(gae bool) ([]byte, error) {
	var buf bytes.Buffer
	zw, _ := gzip.NewWriterLevel(&buf, gzip.BestCompression)
	tw := tar.NewWriter(zw)
	if err := t.addFiles(tw, t.dir); err != nil {
		return nil, err
	}
	if gae {
		if err := t.addFilesFromSibling(tw, "_appengine"); err != nil {
			return nil, err
		}
	}
	if filepath.Base(t.dir) != "blank" {
		if err := t.addFilesFromSibling(tw, "_common"); err != nil {
			return nil, err
		}
	}
	if err := tw.Close(); err != nil {
		return nil, err
	}
	if err := zw.Close(); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

func LoadTemplates(dir string) ([]*Template, error) {
	dir, err := filepath.Abs(dir)
	if err != nil {
		return nil, err
	}
	files, err := ioutil.ReadDir(dir)
	if err != nil {
		return nil, err
	}
	var templates []*Template
	for _, v := range files {
		if s := v.Name()[0]; s == '.' || s == '_' {
			continue
		}
		tmplDir := filepath.Join(dir, v.Name())
		var tmpl Template
		meta := filepath.Join(tmplDir, metaFile)
		if err := yaml.UnmarshalFile(meta, &tmpl); err != nil {
			return nil, err
		}
		tmpl.dir = tmplDir
		tmpl.Name = v.Name()
		templates = append(templates, &tmpl)
	}
	return templates, nil
}
<commit_msg>Fix order when building project templates from multiple dirs<commit_after>package project

import (
	"archive/tar"
	"bytes"
	"compress/gzip"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"gnd.la/util/yaml"
)

const (
	metaFile = "_template.yaml"
)

type Template struct {
	Name        string `json:"name"`
	Description string `json:"desc"`
	URL         string `json:"url"`
	Version     int    `json:"v"`
	dir         string
}

func (t *Template) addFiles(tw *tar.Writer, dir string) error {
	return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		name := strings.TrimPrefix(path, dir)
		if name != "" {
			if name[0] == filepath.Separator {
				name = name[1:]
			}
			if name == "_template.yaml" {
				return nil
			}
			hdr, err := tar.FileInfoHeader(info, "")
			if err != nil {
				return err
			}
			if dir, _ := filepath.Split(name); dir != "" {
				hdr.Name = filepath.ToSlash(filepath.Join(dir, hdr.Name))
			}
			if err := tw.WriteHeader(hdr); err != nil {
				return err
			}
			if !info.IsDir() {
				f, err := os.Open(path)
				if err != nil {
					return err
				}
				defer f.Close()
				if _, err := io.Copy(tw, f); err != nil {
					return err
				}
			}
		}
		return nil
	})
}

func (t *Template) addFilesFromSibling(tw *tar.Writer, name string) error {
	return t.addFiles(tw, filepath.Join(filepath.Dir(t.dir), name))
}

func (t *Template) Data(gae bool) ([]byte, error) {
	var buf bytes.Buffer
	zw, _ := gzip.NewWriterLevel(&buf, gzip.BestCompression)
	tw := tar.NewWriter(zw)
	// Add common files first
	if filepath.Base(t.dir) != "blank" {
		if err := t.addFilesFromSibling(tw, "_common"); err != nil {
			return nil, err
		}
	}
	// Then add gae-specific files, so they may overwrite the _common ones
	if gae {
		if err := t.addFilesFromSibling(tw, "_appengine"); err != nil {
			return nil, err
		}
	}
	// Finally, add project specific files, so they overwrite anything else
	if err := t.addFiles(tw, t.dir); err != nil {
		return nil, err
	}
	if err := tw.Close(); err != nil {
		return nil, err
	}
	if err := zw.Close(); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

func LoadTemplates(dir string) ([]*Template, error) {
	dir, err := filepath.Abs(dir)
	if err != nil {
		return nil, err
	}
	files, err := ioutil.ReadDir(dir)
	if err != nil {
		return nil, err
	}
	var templates []*Template
	for _, v := range files {
		if s := v.Name()[0]; s == '.' || s == '_' {
			continue
		}
		tmplDir := filepath.Join(dir, v.Name())
		var tmpl Template
		meta := filepath.Join(tmplDir, metaFile)
		if err := yaml.UnmarshalFile(meta, &tmpl); err != nil {
			return nil, err
		}
		tmpl.dir = tmplDir
		tmpl.Name = v.Name()
		templates = append(templates, &tmpl)
	}
	return templates, nil
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	"crypto/sha512"
	"encoding/base64"
	"fmt"
	"log"
	"net/http"
	"strings"
	"text/template"
	"time"

	"github.com/codegangsta/martini"

	"google.golang.org/appengine"
	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/user"
)

func PublishPost(rw http.ResponseWriter, req *http.Request, params martini.Params) {
	c := appengine.NewContext(req)
	u := user.Current(c)
	if u == nil {
		http.Error(rw, fmt.Sprintf("wat %s", u), http.StatusForbidden)
		return
	}

	if !isAuthedToMakeChanges(u) {
		http.Error(rw, fmt.Sprintf("wat? %s", u), http.StatusForbidden)
		return
	}

	req.ParseForm()
	postslug := req.PostFormValue("slug")
	if postslug == "" {
		postslug = fmt.Sprintf("DRAFT-%s", RandString(10))
	}

	k := datastore.NewKey(c, "Post", postslug, 0, nil)

	postdate, err := time.Parse("2006-01-02 15:04:05", req.PostFormValue("date"))

	if err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
	}

	NP := Post{
		Author:       "Benjojo",
		Content:      base64.StdEncoding.EncodeToString([]byte(req.PostFormValue("post"))),
		Date:         postdate,
		Slug:         postslug,
		Title:        strings.Split(req.PostFormValue("post"), "\n")[0],
		Type:         req.PostFormValue("cata"),
		R1:           req.PostFormValue("R1"),
		R2:           req.PostFormValue("R2"),
		FeatureImage: req.PostFormValue("featureimage"),
	}
	_, err = datastore.Put(c, k, &NP)
	if err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
	} else {
		http.Error(rw, fmt.Sprintf("/post/%s", postslug), http.StatusCreated)
	}
	forceUpdatePostTitleCache(rw, req)
	return
}

func isAuthedToMakeChanges(u *user.User) bool {
	emailHash := sha512.New()
	emailHashString := fmt.Sprintf("%x", emailHash.Sum([]byte(fmt.Sprintf("%s", u))))
	log.Printf("Email Hash Attempt %s / %s", u, emailHashString)
	if emailHashString == "8270bbd8cfc0ff367556e4ee1ec05d7f5873b65d71001c154efbb03dca232307c2616fa81ca7bacbe7e1739b8f49cf9cb4a3c3905df9faebf75992233ff4d170" {
		return true
	}
	if emailHashString == "4d98aa710d2be9770a0d173718a85dfb7b527d6c1aa7952fa3011cc2fcefa5cc22745c563faa95c5dd4a8b616f42b815f00527d4bdd033959dcd443fd3dfd8b2" {
		return true
	}
	if emailHashString == "cffd49359ad9dcadd350f9cbb913f210303d0c20c1a57eaf59c81a3301abee39377095e8ae5b827633ca7624d473361d5c37ff848418185892b7b58cca1b677a" {
		return true
	}
	return false
}

func RemovePost(rw http.ResponseWriter, req *http.Request, params martini.Params) {
	c := appengine.NewContext(req)

	u := user.Current(c)
	if u == nil {
		http.Error(rw, fmt.Sprintf("wat %s", u), http.StatusForbidden)
		return
	}

	if !isAuthedToMakeChanges(u) {
		http.Error(rw, fmt.Sprintf("wat? %s", u), http.StatusForbidden)
		return
	}

	k := datastore.NewKey(c, "Post", params["name"], 0, nil)
	err := datastore.Delete(c, k)
	if err == nil {
		rw.Write([]byte("the deed has been done\r\n"))
	}
}

func Run_GC(rw http.ResponseWriter, req *http.Request) {
	c := appengine.NewContext(req)
	u := user.Current(c)
	if u == nil {
		http.Error(rw, fmt.Sprintf("wat %s", u), http.StatusForbidden)
		return
	}

	if !isAuthedToMakeChanges(u) {
		http.Error(rw, fmt.Sprintf("wat? %s", u), http.StatusForbidden)
		return
	}

	q := datastore.NewQuery("Post").Order("-Date").Limit(100)

	for t := q.Run(c); ; {
		var e Post
		key, err := t.Next(&e)
		if err == datastore.Done {
			break
		}
		if err != nil {
			// return nil, err
			break
		}
		if strings.HasPrefix(e.Slug, "DRAFT-") || e.Title == "" {
			// DESTROY
			err := datastore.Delete(c, key)
			if err == nil {
				rw.Write([]byte("Killed Draft\r\n"))
			}
		}
	}

}

func Admin(rw http.ResponseWriter, req *http.Request, params martini.Params) {

	layoutData := struct {
		Date string
	}{
		Date: time.Now().Format("2006-01-02 15:04:05"),
	}
	var AdminPage = template.Must(template.ParseFiles("public2/admin.html"))

	err := AdminPage.Execute(rw, layoutData)
	if err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
	}
}

func RandString(n int) string {
	const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
	var bytes = make([]byte, n)
	rand.Read(bytes)
	for i, b := range bytes {
		bytes[i] = alphanum[b%byte(len(alphanum))]
	}
	return string(bytes)
}
<commit_msg>Fix auth, it turns out I can't read!!<commit_after>package main

import (
	"crypto/rand"
	"crypto/sha512"
	"encoding/base64"
	"fmt"
	"log"
	"net/http"
	"strings"
	"text/template"
	"time"

	"github.com/codegangsta/martini"

	"google.golang.org/appengine"
	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/user"
)

func PublishPost(rw http.ResponseWriter, req *http.Request, params martini.Params) {
	c := appengine.NewContext(req)
	u := user.Current(c)
	if u == nil {
		http.Error(rw, fmt.Sprintf("wat %s", u), http.StatusForbidden)
		return
	}

	if !isAuthedToMakeChanges(u) {
		http.Error(rw, fmt.Sprintf("wat? %s", u), http.StatusForbidden)
		return
	}

	req.ParseForm()
	postslug := req.PostFormValue("slug")
	if postslug == "" {
		postslug = fmt.Sprintf("DRAFT-%s", RandString(10))
	}

	k := datastore.NewKey(c, "Post", postslug, 0, nil)

	postdate, err := time.Parse("2006-01-02 15:04:05", req.PostFormValue("date"))

	if err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
	}

	NP := Post{
		Author:       "Benjojo",
		Content:      base64.StdEncoding.EncodeToString([]byte(req.PostFormValue("post"))),
		Date:         postdate,
		Slug:         postslug,
		Title:        strings.Split(req.PostFormValue("post"), "\n")[0],
		Type:         req.PostFormValue("cata"),
		R1:           req.PostFormValue("R1"),
		R2:           req.PostFormValue("R2"),
		FeatureImage: req.PostFormValue("featureimage"),
	}
	_, err = datastore.Put(c, k, &NP)
	if err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
	} else {
		http.Error(rw, fmt.Sprintf("/post/%s", postslug), http.StatusCreated)
	}
	forceUpdatePostTitleCache(rw, req)
	return
}

func isAuthedToMakeChanges(u *user.User) bool {
	emailHash := sha512.New()
	emailHash.Write([]byte(fmt.Sprintf("%s", u)))
	emailHashString := fmt.Sprintf("%x", emailHash.Sum(nil))
	log.Printf("Email Hash Attempt %s / %s", u, emailHashString)
	if emailHashString == "8270bbd8cfc0ff367556e4ee1ec05d7f5873b65d71001c154efbb03dca232307c2616fa81ca7bacbe7e1739b8f49cf9cb4a3c3905df9faebf75992233ff4d170" {
		return true
	}
	if emailHashString == "4d98aa710d2be9770a0d173718a85dfb7b527d6c1aa7952fa3011cc2fcefa5cc22745c563faa95c5dd4a8b616f42b815f00527d4bdd033959dcd443fd3dfd8b2" {
		return true
	}
	if emailHashString == "cffd49359ad9dcadd350f9cbb913f210303d0c20c1a57eaf59c81a3301abee39377095e8ae5b827633ca7624d473361d5c37ff848418185892b7b58cca1b677a" {
		return true
	}
	return false
}

func RemovePost(rw http.ResponseWriter, req *http.Request, params martini.Params) {
	c := appengine.NewContext(req)

	u := user.Current(c)
	if u == nil {
		http.Error(rw, fmt.Sprintf("wat %s", u), http.StatusForbidden)
		return
	}

	if !isAuthedToMakeChanges(u) {
		http.Error(rw, fmt.Sprintf("wat? %s", u), http.StatusForbidden)
		return
	}

	k := datastore.NewKey(c, "Post", params["name"], 0, nil)
	err := datastore.Delete(c, k)
	if err == nil {
		rw.Write([]byte("the deed has been done\r\n"))
	}
}

func Run_GC(rw http.ResponseWriter, req *http.Request) {
	c := appengine.NewContext(req)
	u := user.Current(c)
	if u == nil {
		http.Error(rw, fmt.Sprintf("wat %s", u), http.StatusForbidden)
		return
	}

	if !isAuthedToMakeChanges(u) {
		http.Error(rw, fmt.Sprintf("wat? %s", u), http.StatusForbidden)
		return
	}

	q := datastore.NewQuery("Post").Order("-Date").Limit(100)

	for t := q.Run(c); ; {
		var e Post
		key, err := t.Next(&e)
		if err == datastore.Done {
			break
		}
		if err != nil {
			// return nil, err
			break
		}
		if strings.HasPrefix(e.Slug, "DRAFT-") || e.Title == "" {
			// DESTROY
			err := datastore.Delete(c, key)
			if err == nil {
				rw.Write([]byte("Killed Draft\r\n"))
			}
		}
	}

}

func Admin(rw http.ResponseWriter, req *http.Request, params martini.Params) {

	layoutData := struct {
		Date string
	}{
		Date: time.Now().Format("2006-01-02 15:04:05"),
	}
	var AdminPage = template.Must(template.ParseFiles("public2/admin.html"))

	err := AdminPage.Execute(rw, layoutData)
	if err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
	}
}

func RandString(n int) string {
	const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
	var bytes = make([]byte, n)
	rand.Read(bytes)
	for i, b := range bytes {
		bytes[i] = alphanum[b%byte(len(alphanum))]
	}
	return string(bytes)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/binary"
	"time"

	"github.com/jurgen-kluft/go-home/metrics"
)

type movingAverage struct {
	history []float64
	index   int
}

func newFilter(sizeOfHistory int) *movingAverage {
	filter := &movingAverage{history: make([]float64, sizeOfHistory), index: -1}
	return filter
}

func (m *movingAverage) sample(sample float64) float64 {
	if m.index == -1 {
		for i := range m.history {
			m.history[i] = sample
		}
		m.index = 0
	}

	m.history[m.index] = sample
	m.index = (m.index + 1) % len(m.history)

	sum := 0.0
	for _, s := range m.history {
		sum += s
	}
	return sum / float64(len(m.history))
}

type context struct {
	name           string
	metrics        *metrics.Metrics
	mavTemperature *movingAverage
	mavHumidity    *movingAverage
	mavPressure    *movingAverage
	index          int64
	timestamp      time.Time
}

type sensordata struct {
	stride      int
	temperature int
	humidity    int
	pressure    int

	magnetic     int
	acceleration int
	gyroscope    int

	data []byte
}

func (s *sensordata) init() {
	s.stride = 16

	s.temperature = 0
	s.humidity = 4
	s.pressure = 8

	s.magnetic = 12
	s.acceleration = 24
	s.gyroscope = 36
}

func (s *sensordata) readTemperature() float64 {
	t := int64(0)
	o := s.temperature
	for i := 0; i <= 16; i++ {
		t += int64(binary.LittleEndian.Uint32(s.data[o : o+4]))
		o += s.stride
	}
	return float64(t)
}
func (s *sensordata) readHumidity() float64 {
	t := int64(0)
	o := s.humidity
	for i := 0; i <= 16; i++ {
		t += int64(binary.LittleEndian.Uint32(s.data[o : o+4]))
		o += s.stride
	}
	return float64(t)
}
func (s *sensordata) readPressure() float64 {
	t := int64(0)
	o := s.pressure
	for i := 0; i <= 16; i++ {
		t += int64(binary.LittleEndian.Uint32(s.data[o : o+4]))
		o += s.stride
	}
	return float64(t)
}

func (s *sensordata) readMagnetic(i int) (X float64, Y float64, Z float64) {
	o := s.magnetic + i*s.stride
	X = float64(binary.LittleEndian.Uint32(s.data[o : o+4]))
	o += 4
	Y = float64(binary.LittleEndian.Uint32(s.data[o : o+4]))
	o += 4
	Z = float64(binary.LittleEndian.Uint32(s.data[o : o+4]))
	return X, Y, Z
}

func (s *sensordata) readAcceleration(i int) (X float64, Y float64, Z float64) {
	o := s.acceleration + i*s.stride
	X = float64(binary.LittleEndian.Uint32(s.data[o : o+4]))
	o += 4
	Y = float64(binary.LittleEndian.Uint32(s.data[o : o+4]))
	o += 4
	Z = float64(binary.LittleEndian.Uint32(s.data[o : o+4]))
	return X, Y, Z
}

func (s *sensordata) readGyroscope(i int) (X float64, Y float64, Z float64) {
	o := s.gyroscope + i*s.stride
	X = float64(binary.LittleEndian.Uint32(s.data[o : o+4]))
	o += 4
	Y = float64(binary.LittleEndian.Uint32(s.data[o : o+4]))
	o += 4
	Z = float64(binary.LittleEndian.Uint32(s.data[o : o+4]))
	return X, Y, Z
}

func new() *context {
	c := &context{}
	c.name = "az3166"
	c.metrics, _ = metrics.New()
	c.metrics.Register("Environment Sensors", map[string]string{"T": "Temperature", "H": "Humidity", "P": "Pressure"}, map[string]interface{}{"T": 20, "H": 20, "P": 1000})
	c.metrics.Register("Movement Sensors", map[string]string{"MX": "Magnetic-X", "MY": "Magnetic-Y", "MZ": "Magnetic-Z", "AX": "Acceleration-X", "AY": "Acceleration-Y", "AZ": "Acceleration-Z", "GX": "Gyroscope-X", "GY": "Gyroscope-Y", "GZ": "Gyroscope-Z"}, map[string]interface{}{"MX": 0, "MY": 0, "MZ": 0, "AX": 0, "AY": 0, "AZ": 0, "GX": 0, "GY": 0, "GZ": 0})
	c.mavTemperature = newFilter(30)
	c.mavHumidity = newFilter(30)
	c.mavPressure = newFilter(30)
	c.index = 0
	return c
}

func main() {

	inbound, inpktpool, err := Listen(":7331", nil)
	if err != nil {
		// handle err
	}

	c := new()
	p := &sensordata{}
	p.init()

	connected := true
	for connected {

		select {
		case inpkt := <-inbound:
			// Do something with UDP packet
			p.data = inpkt
			t := time.Now()

			em, _ := c.metrics.Begin("Environment Sensors")
			temp := p.readTemperature()
			temp = c.mavTemperature.sample(temp)
			hum := p.readHumidity()
			hum = c.mavHumidity.sample(hum)
			press := p.readPressure()
			press = c.mavPressure.sample(press)

			if c.index > 0 {
				em.Set("T", temp)
				em.Set("H", hum)
				em.Set("P", press)
				c.metrics.SendMetric(em, c.timestamp)

				deltatime := t.Sub(c.timestamp) / 16
				di := deltatime
				for i := 0; i <= 16; i++ {
					m, e := c.metrics.Begin("Movement Sensors")
					if e == nil {
						x, y, z := p.readMagnetic(i)
						m.Set("MX", x)
						m.Set("MY", y)
						m.Set("MZ", z)
						x, y, z = p.readAcceleration(i)
						m.Set("AX", x)
						m.Set("AY", y)
						m.Set("AZ", z)
						x, y, z = p.readGyroscope(i)
						m.Set("GX", x)
						m.Set("GY", y)
						m.Set("GZ", z)
						ti := c.timestamp.Add(di)
						c.metrics.SendMetric(m, ti)
					}
					di += deltatime
				}
			}

			c.index++
			c.timestamp = t

			// Release UDP packet back to pool
			inpktpool.Release(inpkt)

		case <-time.After(time.Second * 1):

		}
	}

	return
}
<commit_msg>* udp-to-metrics; print Acc and Gyro<commit_after>package main

import (
	"encoding/binary"
	"fmt"
	"time"

	"github.com/jurgen-kluft/go-home/metrics"
)

type movingAverage struct {
	history []float64
	index   int
}

func newFilter(sizeOfHistory int) *movingAverage {
	filter := &movingAverage{history: make([]float64, sizeOfHistory), index: -1}
	return filter
}

func (m *movingAverage) sample(sample float64) float64 {
	if m.index == -1 {
		for i := range m.history {
			m.history[i] = sample
		}
		m.index = 0
	}

	m.history[m.index] = sample
	m.index = (m.index + 1) % len(m.history)

	sum := 0.0
	for _, s := range m.history {
		sum += s
	}
	return sum / float64(len(m.history))
}

type context struct {
	name           string
	metrics        *metrics.Metrics
	mavTemperature *movingAverage
	mavHumidity    *movingAverage
	mavPressure    *movingAverage
	index          int64
	timestamp      time.Time
}

type sensordata struct {
	stride      int
	temperature int
	humidity    int
	pressure    int

	magnetic     int
	acceleration int
	gyroscope    int

	data []byte
}

func (s *sensordata) init() {
	s.stride = 16

	s.temperature = 0
	s.humidity = 4
	s.pressure = 8

	s.magnetic = 12
	s.acceleration = 24
	s.gyroscope = 36
}

func (s *sensordata) readTemperature() float64 {
	t := int64(0)
	o := s.temperature
	for i := 0; i <= 16; i++ {
		t += int64(binary.LittleEndian.Uint32(s.data[o : o+4]))
		o += s.stride
	}
	return float64(t / 16)
}
func (s *sensordata) readHumidity() float64 {
	t := int64(0)
	o := s.humidity
	for i := 0; i <= 16; i++ {
		t += int64(binary.LittleEndian.Uint32(s.data[o : o+4]))
		o += s.stride
	}
	return float64(t / 16)
}
func (s *sensordata) readPressure() float64 {
	t := int64(0)
	o := s.pressure
	for i := 0; i <= 16; i++ {
		t += int64(binary.LittleEndian.Uint32(s.data[o : o+4]))
		o += s.stride
	}
	return float64(t / 16)
}

func (s *sensordata) readMagnetic(i int) (X float64, Y float64, Z float64) {
	o := s.magnetic + i*s.stride
	X = float64(binary.LittleEndian.Uint32(s.data[o : o+4]))
	o += 4
	Y = float64(binary.LittleEndian.Uint32(s.data[o : o+4]))
	o += 4
	Z = float64(binary.LittleEndian.Uint32(s.data[o : o+4]))
	return X, Y, Z
}

func (s *sensordata) readAcceleration(i int) (X float64, Y float64, Z float64) {
	o := s.acceleration + i*s.stride
	X = float64(binary.LittleEndian.Uint32(s.data[o : o+4]))
	o += 4
	Y = float64(binary.LittleEndian.Uint32(s.data[o : o+4]))
	o += 4
	Z = float64(binary.LittleEndian.Uint32(s.data[o : o+4]))
	return X, Y, Z
}

func (s *sensordata) readGyroscope(i int) (X float64, Y float64, Z float64) {
	o := s.gyroscope + i*s.stride
	X = float64(binary.LittleEndian.Uint32(s.data[o : o+4]))
	o += 4
	Y = float64(binary.LittleEndian.Uint32(s.data[o : o+4]))
	o += 4
	Z = float64(binary.LittleEndian.Uint32(s.data[o : o+4]))
	return X, Y, Z
}

func new() *context {
	c := &context{}
	c.name = "az3166"
	c.metrics, _ = metrics.New()
	c.metrics.Register("Environment Sensors", map[string]string{"T": "Temperature", "H": "Humidity", "P": "Pressure"}, map[string]interface{}{"T": 20, "H": 20, "P": 1000})
	c.metrics.Register("Movement Sensors", map[string]string{"MX": "Magnetic-X", "MY": "Magnetic-Y", "MZ": "Magnetic-Z", "AX": "Acceleration-X", "AY": "Acceleration-Y", "AZ": "Acceleration-Z", "GX": "Gyroscope-X", "GY": "Gyroscope-Y", "GZ": "Gyroscope-Z"}, map[string]interface{}{"MX": 0, "MY": 0, "MZ": 0, "AX": 0, "AY": 0, "AZ": 0, "GX": 0, "GY": 0, "GZ": 0})
	c.mavTemperature = newFilter(30)
	c.mavHumidity = newFilter(30)
	c.mavPressure = newFilter(30)
	c.index = 0
	return c
}

func main() {

	inbound, inpktpool, err := Listen(":7331", nil)
	if err != nil {
		// handle err
	}

	c := new()
	p := &sensordata{}
	p.init()

	connected := true
	for connected {

		select {
		case inpkt := <-inbound:
			// Do something with UDP packet
			p.data = inpkt
			t := time.Now()

			em, _ := c.metrics.Begin("Environment Sensors")
			temp := p.readTemperature()
			temp = c.mavTemperature.sample(temp)
			hum := p.readHumidity()
			hum = c.mavHumidity.sample(hum)
			press := p.readPressure()
			press = c.mavPressure.sample(press)

			if c.index > 0 {
				em.Set("T", temp)
				em.Set("H", hum)
				em.Set("P", press)
				c.metrics.SendMetric(em, c.timestamp)

				deltatime := t.Sub(c.timestamp) / 16
				di := deltatime
				for i := 0; i <= 16; i++ {
					m, e := c.metrics.Begin("Movement Sensors")
					if e == nil {
						x, y, z := p.readMagnetic(i)
						m.Set("MX", x)
						m.Set("MY", y)
						m.Set("MZ", z)

						x, y, z = p.readAcceleration(i)
						m.Set("AX", x)
						m.Set("AY", y)
						m.Set("AZ", z)

						if i == 0 {
							fmt.Printf("Movement Acc: %v:%v:%v\n", x, y, z)
						}

						x, y, z = p.readGyroscope(i)
						m.Set("GX", x)
						m.Set("GY", y)
						m.Set("GZ", z)

						if i == 0 {
							fmt.Printf("Movement Gyro: %v:%v:%v\n", x, y, z)
						}

						ti := c.timestamp.Add(di)
						c.metrics.SendMetric(m, ti)
					}
					di += deltatime
				}
			}

			c.index++
			c.timestamp = t

			// Release UDP packet back to pool
			inpktpool.Release(inpkt)

		case <-time.After(time.Second * 1):

		}
	}

	return
}
<|endoftext|>


<commit_before>package middleware

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"time"

	"github.com/remind101/pkg/httpx"
	"github.com/remind101/pkg/logger"
	"golang.org/x/net/context"
)

type loggerGenerator func(context.Context, *http.Request) logger.Logger

//
func StdoutLoggerWithLevel(lvl string) loggerGenerator {
	l := logger.ParseLevel(lvl)
	return stdLogger(l, os.Stdout)
}

// StdoutLogger is a logger.Logger generator that generates a logger that writes
// to stdout with level debug
var StdoutLogger = stdLogger(logger.DEBUG, os.Stdout)

// LogTo is an httpx middleware that wraps the handler to insert a logger and
// log the request to it.
func LogTo(h httpx.Handler, g loggerGenerator) httpx.Handler {
	return InsertLogger(Log(h), g)
}

// InsertLogger returns an httpx.Handler middleware that will call f to generate
// a logger, then insert it into the context.
func InsertLogger(h httpx.Handler, g loggerGenerator) httpx.Handler {
	return httpx.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
		l := g(ctx, r)
		ctx = logger.WithLogger(ctx, l)
		return h.ServeHTTPContext(ctx, w, r)
	})
}

func stdLogger(level logger.Level, out io.Writer) loggerGenerator {
	return func(ctx context.Context, r *http.Request) logger.Logger {
		return logger.New(
			log.New(out, fmt.Sprintf("request_id=%s ", httpx.RequestID(ctx)), 0),
			level,
		)
	}
}

// Logger is middleware that logs the request details to the logger.Logger
// embedded within the context.
type Logger struct {
	// handler is the wrapped httpx.Handler
	handler httpx.Handler
}

func Log(h httpx.Handler) *Logger {
	return &Logger{
		handler: h,
	}
}

func (h *Logger) ServeHTTPContext(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	rw := NewResponseWriter(w)

	t := time.Now()

	err := h.handler.ServeHTTPContext(ctx, rw, r)

	ms := fmt.Sprintf("%d", (int(time.Now().Sub(t).Seconds() * 1000)))

	logger.Info(ctx, "request",
		"method", r.Method,
		"path", r.URL.Path,
		"status", rw.Status(),
		"ms", ms,
	)

	return err
}
<commit_msg>comments<commit_after>package middleware

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"time"

	"github.com/remind101/pkg/httpx"
	"github.com/remind101/pkg/logger"
	"golang.org/x/net/context"
)

type loggerGenerator func(context.Context, *http.Request) logger.Logger

// returns a loggerGenerator that generates a loggers that write to STDOUT
// with the level parsed from the string (eg "info")
// If the string isnt parsable, it defaults to "debug"
func StdoutLoggerWithLevel(lvl string) loggerGenerator {
	l := logger.ParseLevel(lvl)
	return stdLogger(l, os.Stdout)
}

// Legacy interface, returns a loggerGenerator that logs at DEBUG to stdout.
// Use StdoutLoggerWithLevel() instead.
var StdoutLogger = stdLogger(logger.DEBUG, os.Stdout)

// LogTo is an httpx middleware that wraps the handler to insert a logger and
// log the request to it.
func LogTo(h httpx.Handler, g loggerGenerator) httpx.Handler {
	return InsertLogger(Log(h), g)
}

// InsertLogger returns an httpx.Handler middleware that will call f to generate
// a logger, then insert it into the context.
func InsertLogger(h httpx.Handler, g loggerGenerator) httpx.Handler {
	return httpx.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
		l := g(ctx, r)
		ctx = logger.WithLogger(ctx, l)
		return h.ServeHTTPContext(ctx, w, r)
	})
}

func stdLogger(level logger.Level, out io.Writer) loggerGenerator {
	return func(ctx context.Context, r *http.Request) logger.Logger {
		return logger.New(
			log.New(out, fmt.Sprintf("request_id=%s ", httpx.RequestID(ctx)), 0),
			level,
		)
	}
}

// Logger is middleware that logs the request details to the logger.Logger
// embedded within the context.
type Logger struct {
	// handler is the wrapped httpx.Handler
	handler httpx.Handler
}

func Log(h httpx.Handler) *Logger {
	return &Logger{
		handler: h,
	}
}

func (h *Logger) ServeHTTPContext(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	rw := NewResponseWriter(w)

	t := time.Now()

	err := h.handler.ServeHTTPContext(ctx, rw, r)

	ms := fmt.Sprintf("%d", (int(time.Now().Sub(t).Seconds() * 1000)))

	logger.Info(ctx, "request",
		"method", r.Method,
		"path", r.URL.Path,
		"status", rw.Status(),
		"ms", ms,
	)

	return err
}
<|endoftext|>


<commit_before>//
// command/run.go
//
// Copyright (c) 2016-2017 Junpei Kawamoto
//
// This software is released under the MIT License.
//
// http://opensource.org/licenses/mit-license.php
//

package command

import (
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/signal"
	"path"
	"path/filepath"
	"strings"
	"syscall"

	"golang.org/x/sync/errgroup"

	gitconfig "github.com/tcnksm/go-gitconfig"
	"github.com/urfave/cli"
)

// SourceArchive defines a name of source archive file.
const SourceArchive = "source.tar.gz"

// RunOpt defines a option parameter for run function.
type RunOpt struct {
	// Same options as DockerfileOpt.
	*DockerfileOpt
	// Travis configuration file.
	Filename string
	// Container name.
	Name string
	// Image tag.
	Tag string
	// Max processors to be used.
	Processors int
	// If true, print Dockerfile and entrypoint.sh.
	Verbose bool
	// If true, not using cache during buidling a docker image.
	NoCache bool
	// If true, omit printing color codes.
	NoColor bool
}

// Run implements the action of this command.
func Run(c *cli.Context) error {

	opt := RunOpt{
		DockerfileOpt: &DockerfileOpt{
			BaseImage:  c.String("base"),
			AptProxy:   c.String("apt-proxy"),
			PypiProxy:  c.String("pypi-proxy"),
			HTTPProxy:  c.String("http-proxy"),
			HTTPSProxy: c.String("https-proxy"),
			NoProxy:    c.String("no-proxy"),
		},
		Filename:   c.Args().First(),
		Name:       c.String("name"),
		Tag:        c.String("tag"),
		Processors: c.Int("max-processors"),
		Verbose:    c.Bool("verbose"),
		NoCache:    c.Bool("no-cache"),
		NoColor:    c.Bool("no-color"),
	}
	if err := run(&opt); err != nil {
		return cli.NewExitError(err.Error(), 1)
	}
	return nil
}

func run(opt *RunOpt) (err error) {

	var decorator *TextDecorator
	if opt.NoColor {
		decorator = NewNoopDecorator()
	} else {
		decorator = NewDecorator()
	}

	// Prepare to be canceled.
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, os.Interrupt, os.Kill, syscall.SIGQUIT)
	go func() {
		<-sig
		cancel()
	}()

	// Load a Travis's script file.
	if opt.Filename == "" {
		opt.Filename = ".travis.yml"
	}
	travis, err := NewTravisFromFile(opt.Filename)
	if err != nil {
		return
	}

	// Get repository information.
	origin, err := gitconfig.OriginURL()
	if err != nil {
		return
	}
	opt.Repository = getRepository(origin)

	// Set up the tag name of the container image.
	if opt.Tag == "" {
		opt.Tag = fmt.Sprintf("loci/%s", strings.ToLower(path.Base(opt.Repository)))
	}
	tempDir := filepath.Join(os.TempDir(), opt.Tag)
	if err = os.MkdirAll(tempDir, 0777); err != nil {
		return
	}
	defer os.RemoveAll(tempDir)

	// Archive source files.
	pwd, err := os.Getwd()
	if err != nil {
		return
	}
	fmt.Println(decorator.Bold("Creating archive of source codes."))
	var dstout io.Writer
	if opt.Verbose {
		dstout = os.Stdout
	} else {
		dstout = ioutil.Discard
	}
	if err = Archive(ctx, pwd, filepath.Join(tempDir, SourceArchive), dstout, os.Stderr); err != nil {
		return
	}

	// Create Dockerfile.
	fmt.Println(decorator.Bold("Creating Dockerfile"))
	docker, err := Dockerfile(travis, opt.DockerfileOpt, SourceArchive)
	if err != nil {
		return
	}
	if err = ioutil.WriteFile(filepath.Join(tempDir, "Dockerfile"), docker, 0644); err != nil {
		return
	}
	if opt.Verbose {
		fmt.Println(string(docker))
	}

	// Create entrypoint.sh.
	fmt.Println(decorator.Bold("Creating entrypoint."))
	entry, err := Entrypoint(travis)
	if err != nil {
		return
	}
	if err = ioutil.WriteFile(filepath.Join(tempDir, "entrypoint.sh"), entry, 0644); err != nil {
		return
	}
	if opt.Verbose {
		fmt.Println(string(entry))
	}

	argset, err := travis.ArgumentSet()
	if err != nil {
		return
	}

	// Start testing with goroutines.
	fmt.Println(decorator.Bold("Start testing."))
	wg, ctx := errgroup.WithContext(ctx)
	semaphore := make(chan struct{}, opt.Processors)
	display, err := NewDisplay()
	if err != nil {
		return
	}
	defer display.Close()

	var i int
	for version, set := range argset {

		func(version string, set [][]string) {
			wg.Go(func() (err error) {
				semaphore <- struct{}{}
				defer func() {
					<-semaphore
				}()

				// Build the container image.
				sec := display.AddSection(fmt.Sprintf("Building a image for v%v", version))
				output := sec.Writer()

				tag := fmt.Sprintf("%v/%v", opt.Tag, version)
				err = Build(ctx, tempDir, tag, version, opt.NoCache, output)
				output.Close()
				if err != nil {
					return
				}
				display.DeleteSection(sec)

				for _, envs := range set {

					func(envs []string) {
						wg.Go(func() (err error) {
							semaphore <- struct{}{}
							defer func() {
								<-semaphore
							}()

							// Run tests in sandboxes.
							sec := display.AddSection(fmt.Sprintf("Running tests (v%v: %v)", version, envs))
							output := sec.Writer()
							defer output.Close()

							name := opt.Name
							if name != "" {
								i++
								name = fmt.Sprintf("%s-%d", name, i)
							}
							return Start(ctx, tag, name, envs, output)
						})
					}(envs)

				}

				return

			})
		}(version, set)

	}

	return wg.Wait()
}

// getRepository returns the repository path from a given remote URL of
// origin repository. The repository path consists of a URL without
// sheme, user name, password, and .git suffix.
func getRepository(origin string) (res string) {

	switch {
	case strings.Contains(origin, "@"):
		res = strings.Replace(strings.Split(origin, "@")[1], ":", "/", 1)
	case strings.HasPrefix(origin, "http://"):
		res = origin[len("http://"):]
	case strings.HasPrefix(origin, "https://"):
		res = origin[len("https://"):]
	default:
		res = strings.Replace(origin, ":", "/", 1)
	}
	if strings.HasSuffix(res, ".git") {
		res = res[:len(res)-len(".git")]
	}

	return

}
<commit_msg>Store logging information to files.<commit_after>//
// command/run.go
//
// Copyright (c) 2016-2017 Junpei Kawamoto
//
// This software is released under the MIT License.
//
// http://opensource.org/licenses/mit-license.php
//

package command

import (
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/signal"
	"path"
	"path/filepath"
	"strings"
	"syscall"

	"golang.org/x/sync/errgroup"

	gitconfig "github.com/tcnksm/go-gitconfig"
	"github.com/urfave/cli"
)

// SourceArchive defines a name of source archive file.
const SourceArchive = "source.tar.gz"

// RunOpt defines a option parameter for run function.
type RunOpt struct {
	// Same options as DockerfileOpt.
	*DockerfileOpt
	// Travis configuration file.
	Filename string
	// Container name.
	Name string
	// Image tag.
	Tag string
	// Max processors to be used.
	Processors int
	// If true, print Dockerfile and entrypoint.sh.
	Verbose bool
	// If true, not using cache during buidling a docker image.
	NoCache bool
	// If true, omit printing color codes.
	NoColor bool
}

// Run implements the action of this command.
func Run(c *cli.Context) error {

	opt := RunOpt{
		DockerfileOpt: &DockerfileOpt{
			BaseImage:  c.String("base"),
			AptProxy:   c.String("apt-proxy"),
			PypiProxy:  c.String("pypi-proxy"),
			HTTPProxy:  c.String("http-proxy"),
			HTTPSProxy: c.String("https-proxy"),
			NoProxy:    c.String("no-proxy"),
		},
		Filename:   c.Args().First(),
		Name:       c.String("name"),
		Tag:        c.String("tag"),
		Processors: c.Int("max-processors"),
		Verbose:    c.Bool("verbose"),
		NoCache:    c.Bool("no-cache"),
		NoColor:    c.Bool("no-color"),
	}
	if err := run(&opt); err != nil {
		return cli.NewExitError(err.Error(), 1)
	}
	return nil
}

func run(opt *RunOpt) (err error) {

	var decorator *TextDecorator
	if opt.NoColor {
		decorator = NewNoopDecorator()
	} else {
		decorator = NewDecorator()
	}

	// Prepare to be canceled.
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, os.Interrupt, os.Kill, syscall.SIGQUIT)
	go func() {
		<-sig
		cancel()
	}()

	// Load a Travis's script file.
	if opt.Filename == "" {
		opt.Filename = ".travis.yml"
	}
	travis, err := NewTravisFromFile(opt.Filename)
	if err != nil {
		return
	}

	// Get repository information.
	origin, err := gitconfig.OriginURL()
	if err != nil {
		return
	}
	opt.Repository = getRepository(origin)

	// Set up the tag name of the container image.
	if opt.Tag == "" {
		opt.Tag = fmt.Sprintf("loci/%s", strings.ToLower(path.Base(opt.Repository)))
	}
	tempDir := filepath.Join(os.TempDir(), opt.Tag)
	if err = os.MkdirAll(tempDir, 0777); err != nil {
		return
	}
	defer os.RemoveAll(tempDir)

	// Archive source files.
	pwd, err := os.Getwd()
	if err != nil {
		return
	}
	fmt.Println(decorator.Bold("Creating archive of source codes."))
	var dstout io.Writer
	if opt.Verbose {
		dstout = os.Stdout
	} else {
		dstout = ioutil.Discard
	}
	if err = Archive(ctx, pwd, filepath.Join(tempDir, SourceArchive), dstout, os.Stderr); err != nil {
		return
	}

	// Create Dockerfile.
	fmt.Println(decorator.Bold("Creating Dockerfile"))
	docker, err := Dockerfile(travis, opt.DockerfileOpt, SourceArchive)
	if err != nil {
		return
	}
	if err = ioutil.WriteFile(filepath.Join(tempDir, "Dockerfile"), docker, 0644); err != nil {
		return
	}
	if opt.Verbose {
		fmt.Println(string(docker))
	}

	// Create entrypoint.sh.
	fmt.Println(decorator.Bold("Creating entrypoint."))
	entry, err := Entrypoint(travis)
	if err != nil {
		return
	}
	if err = ioutil.WriteFile(filepath.Join(tempDir, "entrypoint.sh"), entry, 0644); err != nil {
		return
	}
	if opt.Verbose {
		fmt.Println(string(entry))
	}

	argset, err := travis.ArgumentSet()
	if err != nil {
		return
	}

	// Start testing with goroutines.
	fmt.Println(decorator.Bold("Start testing."))
	wg, ctx := errgroup.WithContext(ctx)
	semaphore := make(chan struct{}, opt.Processors)
	display, err := NewDisplay()
	if err != nil {
		return
	}
	defer display.Close()

	var i int
	for version, set := range argset {

		func(version string, set [][]string) {
			wg.Go(func() (err error) {
				semaphore <- struct{}{}
				defer func() {
					<-semaphore
				}()

				// Build a container image.
				fp, err := os.OpenFile(fmt.Sprintf("loci-build-v%v.log", version), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
				if err != nil {
					return
				}
				defer fp.Close()

				sec := display.AddSection(fmt.Sprintf("Building a image for v%v", version))
				defer display.DeleteSection(sec)

				output := sec.Writer()
				defer output.Close()

				tag := fmt.Sprintf("%v/%v", opt.Tag, version)
				err = Build(ctx, tempDir, tag, version, opt.NoCache, io.MultiWriter(fp, output))
				if err != nil {
					return
				}

				for _, envs := range set {

					func(envs []string) {
						wg.Go(func() (err error) {
							semaphore <- struct{}{}
							defer func() {
								<-semaphore
							}()

							// Run tests in a sandbox.
							fp, err := os.OpenFile(
								fmt.Sprintf("loci-v%v.log", strings.Join(append([]string{version}, envs...), "-")),
								os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
							if err != nil {
								return
							}
							defer fp.Close()

							sec := display.AddSection(fmt.Sprintf("Running tests (v%v: %v)", version, envs))
							defer display.DeleteSection(sec)

							output := sec.Writer()
							defer output.Close()

							name := opt.Name
							if name != "" {
								i++
								name = fmt.Sprintf("%s-%d", name, i)
							}

							err = Start(ctx, tag, name, envs, io.MultiWriter(fp, output))
							return

						})
					}(envs)

				}

				return

			})
		}(version, set)

	}

	return wg.Wait()
	err = wg.Wait()
}

// getRepository returns the repository path from a given remote URL of
// origin repository. The repository path consists of a URL without
// sheme, user name, password, and .git suffix.
func getRepository(origin string) (res string) {

	switch {
	case strings.Contains(origin, "@"):
		res = strings.Replace(strings.Split(origin, "@")[1], ":", "/", 1)
	case strings.HasPrefix(origin, "http://"):
		res = origin[len("http://"):]
	case strings.HasPrefix(origin, "https://"):
		res = origin[len("https://"):]
	default:
		res = strings.Replace(origin, ":", "/", 1)
	}
	if strings.HasSuffix(res, ".git") {
		res = res[:len(res)-len(".git")]
	}

	return

}
<|endoftext|>


<commit_before>package command

import (
	"fmt"

	consul "github.com/hashicorp/consul/api"
	cli "gopkg.in/urfave/cli.v1"
)

const setArgs = 3

//CmdSet sets a kv
func CmdSet(c *cli.Context) error {
	if len(c.Args()) != setArgs {
		return fmt.Errorf("Incorrect number of arguments. Found %v, expected %v.\nUsage: consul-kv set <consulAddr> <key> <value>", len(c.Args()), setArgs)
	}

	destHost := c.Args().Get(0)
	key := c.Args().Get(1)
	value := c.Args().Get(2)

	//grab dest kv client
	destKV, err := getKVClient(destHost)
	if err != nil {
		return err
	}

	if _, err = destKV.Put(&consul.KVPair{Key: key, Value: []byte(value)}, nil); err != nil {
		fmt.Printf("Error setting key: %v", err)
	}

	return nil
}
<commit_msg>errorf instead of printf<commit_after>package command

import (
	"fmt"

	consul "github.com/hashicorp/consul/api"
	cli "gopkg.in/urfave/cli.v1"
)

const setArgs = 3

//CmdSet sets a kv
func CmdSet(c *cli.Context) error {
	if len(c.Args()) != setArgs {
		return fmt.Errorf("Incorrect number of arguments. Found %v, expected %v.\nUsage: consul-kv set <consulAddr> <key> <value>", len(c.Args()), setArgs)
	}

	destHost := c.Args().Get(0)
	key := c.Args().Get(1)
	value := c.Args().Get(2)

	//grab dest kv client
	destKV, err := getKVClient(destHost)
	if err != nil {
		return err
	}

	if _, err = destKV.Put(&consul.KVPair{Key: key, Value: []byte(value)}, nil); err != nil {
		return fmt.Errorf("Error setting key: %v", err)
	}

	return nil
}
<|endoftext|>


<commit_before>package main;
//package newrelic_platform_go;

import (
    "log"
    "os"
    "encoding/json"
    "net/http"
    "time"
)

var (
    GUID = "com.example.golang_plugin"
    VERSION = "0.0.1"
    PLUGIN_NAME = "Example Go Plugin"
    REPORT_INTERVAL_IN_SECONDS = 60
)

func NewAgent(Version string) * Agent {
    agent := &Agent{
        Version: Version,
    }
    return agent
}

type Agent struct {
    Host string `json:"host"`
    Version string `json:"version"`
    Pid  int `json:"pid"`
}

func (agent *Agent) CollectEnvironmentInfo() {
    var err error
    agent.Pid = os.Getpid();
    if agent.Host, err = os.Hostname(); err != nil {
        log.Fatalf("Can not get hostname: %#v \n", err)
    }
}

type MetricaValue interface{}
type SimpleMetricaValue float64
type AggregatedMetricaValue struct {
    Min float64          `json:"min"`
    Max float64          `json:"max"`
    Total float64        `json:"total"`
    Count int            `json:"count"`
    SumOfSquares float64 `json:"sum_of_squares"`
}
func NewAggregatedMetricaValue(existValue float64, newValue float64) *AggregatedMetricaValue {
    v = &AggregatedMetricaValue{
        Min: math.Min(newValue, existVal),
        Max: math.Max(newValue, existVal),
        Total: newValue + existVal,
        Count: 2,
        SumOfSquares: newValue * newValue + existValue * existValue
    }
    return v
}

func (aggregatedValue *AggregatedMetricaValue) Aggregate(newValue float64) {
    aggregatedValue.Min = math.Min(newValue, aggregatedValue.Min)
    aggregatedValue.Max = math.Max(newValue, aggregatedValue.Max)
    aggregatedValue.Total += newValue
    aggregatedValue.Count++
    aggregatedValue.SumOfSquares += newValue * newValue
}

type Metrica interface{
    GetValue() (float64, error)
    GetName() string
}

type Component struct {
    Name string `json:"name"`
    GUID string `json:"guid"`
    Duration int `json:"duration"`
    Metrics map[string]MetricaValue `json:"metrics"`
}

type NewrelicPlugin struct {
    Agent *Agent `json:"agent"`
    Components []Component `json:"components"`
    MetricaModels []Metrica `json:"-"`
    LastPollTime time.Time `json:"-"`
}

func NewNewrelicPlugin() *NewrelicPlugin {
    plugin := &NewrelicPlugin{}

    plugin.Agent = NewAgent(plugin.GetVersion())
    plugin.Agent.CollectEnvironmentInfo()

    component := Component{
        GUID: plugin.GetGuid(),
        Name: plugin.GetPluginName(),
        Duration: plugin.GetReportIntervalInSeconds(),
    }
    plugin.Components = []Component{component}

    return plugin
}

func (plugin *NewrelicPlugin) GetGuid() string {
    return GUID
}

func (plugin *NewrelicPlugin) GetReportIntervalInSeconds() int {
    return REPORT_INTERVAL_IN_SECONDS
}

func (plugin *NewrelicPlugin) GetVersion() string {
    return VERSION
}

func (plugin *NewrelicPlugin) GetPluginName() string {
    return PLUGIN_NAME
}

func (plugin *NewrelicPlugin) Harvest() error {
    startTime := time.Now()

    if plugin.LastPollTime == 0 {
        plugin.Components[0].Duration = plugin.GetReportIntervalInSeconds()
    } else {
        plugin.Components[0].Duration = startTime.Sub(plugin.LastPollTime)
    }

    plugin.Components[0].Metrics = make(map[string]MetricaValue, len(plugin.MetricaModels))
    for i := 0; i < len(plugin.MetricaModels); i++ {
        model := plugin.MetricaModels[i]
        if newValue, err := model.GetValue(); err == nil {
            if existMetric, ok := plugin.Components[0].Metrics[model.GetName()], ok {
                if floatExistVal, ok := existMetric.(float64); ok {
                    plugin.Components[0].Metrics[model.GetName()] = NewAggregatedMetricaValue(floatExistVal, newValue)
                }
            } else {
                plugin.Components[0].Metrics[model.GetName()].Aggregate(newValue)
            }
        } else {
            log.Printf("Can not get metrica: %v, got error:%#v", model.GetName(), err)
        }
    }

    if httpCode, err := plugin.SendMetricas(); err != nil {
        log.Printf("Can not send metricas to newrelic: %#v\n", err)
    } else {
        if err, isFatal := plugin.CheckResponse(httpCode); isFatal {
            log.Fatalf("Got fatal error:%v\n")
        } else {
            log.Printf("WARNING: %v", err)
        }
    }
    return err
}

func (plugin *NewrelicPlugin) SendMetricas() int, error {
    res, _ := json.MarshalIndent(plugin, "", "    ");
    log.Printf(string(res));
    return 200, nil
}

func (plugin *NewrelicPlugin) CheckResponse(httpResponseCode int) error, bool {
    isFatal := false
    var err error
    switch httpResponseCode {
        http.StatusOK:{
            plugin.Components[0].Metrics = nil
            plugin.LastPollTime = time.Now()
        }
        http.StatusForbidden:{
            err = fmt.Errorf("Authentication error (no license key header, or invalid license key).\n")
            isFatal = true
        }
        http.StatusBadRequest:{
            err = fmt.Errorf("The request or headers are in the wrong format or the URL is incorrect.\n")
            isFatal = true
        }
        http.StatusNotFound:{
            err = fmt.Errorf("Invalid URL\n")
            isFatal = true
        }
        http.StatusRequestEntityTooLarge:{
            err = fmt.Errorf("Too many metrics were sent in one request, or too many components (instances) were specified in one request, or other single-request limits were reached.\n")
            //discard metrics
            plugin.Components[0].Metrics = nil
            plugin.LastPollTime = time.Now()
        }
        http.StatusInternalServerError, http.StatusBadGateway, http.StatusServiceUnavailable, http.StatusGatewayTimeout: {
            err = fmt.Errorf("Got %v response code.Metricas will be aggregated")
        }
    }
    return err, isFatal
}

func (plugin *NewrelicPlugin) AddMetrica(model Metrica) {
    plugin.MetricaModels = append(plugin.MetricaModels, model)
}

type WaveMetrica struct {
    sawtoothMax int
    sawtoothCounter int
    squarewaveMax int
    squarewaveCounter int
}
func (metrica WaveMetrica) GetName() string {
    return "Wave Metrica"
}
func (metrica WaveMetrica) GetValue() (float64, error) {
    return 5,  nil
}

func main() {
    plugin := NewNewrelicPlugin()
    m := WaveMetrica{}
    plugin.AddMetrica(m);
    plugin.Harvest()
}
<commit_msg>Finish sending but not tested yet<commit_after>package main;
//package newrelic_platform_go;

import (
    "log"
    "os"
    "encoding/json"
    "net/http"
    "time"
    "math"
)

const (
    NEWRELIC_API_URL = "https://platform-api.newrelic.com/platform/v1/metrics"
)

var (
    GUID = "com.example.golang_plugin"
    VERSION = "0.0.1"
    PLUGIN_NAME = "Example Go Plugin"
    REPORT_INTERVAL_IN_SECONDS = 60
    NEWRELIC_LICENSE_KEY = ""
)

func NewAgent(Version string) * Agent {
    agent := &Agent{
        Version: Version,
    }
    return agent
}

type Agent struct {
    Host string `json:"host"`
    Version string `json:"version"`
    Pid  int `json:"pid"`
}

func (agent *Agent) CollectEnvironmentInfo() {
    var err error
    agent.Pid = os.Getpid();
    if agent.Host, err = os.Hostname(); err != nil {
        log.Fatalf("Can not get hostname: %#v \n", err)
    }
}

type MetricaValue interface{}
type SimpleMetricaValue float64
type AggregatedMetricaValue struct {
    Min float64          `json:"min"`
    Max float64          `json:"max"`
    Total float64        `json:"total"`
    Count int            `json:"count"`
    SumOfSquares float64 `json:"sum_of_squares"`
}
func NewAggregatedMetricaValue(existValue float64, newValue float64) *AggregatedMetricaValue {
    v = &AggregatedMetricaValue{
        Min: math.Min(newValue, existVal),
        Max: math.Max(newValue, existVal),
        Total: newValue + existVal,
        Count: 2,
        SumOfSquares: newValue * newValue + existValue * existValue
    }
    return v
}

func (aggregatedValue *AggregatedMetricaValue) Aggregate(newValue float64) {
    aggregatedValue.Min = math.Min(newValue, aggregatedValue.Min)
    aggregatedValue.Max = math.Max(newValue, aggregatedValue.Max)
    aggregatedValue.Total += newValue
    aggregatedValue.Count++
    aggregatedValue.SumOfSquares += newValue * newValue
}

type Metrica interface{
    GetValue() (float64, error)
    GetName() string
}

type Component struct {
    Name string `json:"name"`
    GUID string `json:"guid"`
    Duration int `json:"duration"`
    Metrics map[string]MetricaValue `json:"metrics"`
}

type NewrelicPlugin struct {
    Agent *Agent `json:"agent"`
    Components []Component `json:"components"`
    MetricaModels []Metrica `json:"-"`
    LastPollTime time.Time `json:"-"`
    Verbose bool `json:"-"`
}

func NewNewrelicPlugin() *NewrelicPlugin {
    plugin := &NewrelicPlugin{}

    plugin.Agent = NewAgent(plugin.GetVersion())
    plugin.Agent.CollectEnvironmentInfo()

    component := Component{
        GUID: plugin.GetGuid(),
        Name: plugin.GetPluginName(),
        Duration: plugin.GetReportIntervalInSeconds(),
    }
    plugin.Components = []Component{component}

    return plugin
}

func (plugin *NewrelicPlugin) GetGuid() string {
    return GUID
}

func (plugin *NewrelicPlugin) GetReportIntervalInSeconds() int {
    return REPORT_INTERVAL_IN_SECONDS
}

func (plugin *NewrelicPlugin) GetLicenseKey() string {
    return NEWRELIC_LICENSE_KEY
}

func (plugin *NewrelicPlugin) GetVersion() string {
    return VERSION
}

func (plugin *NewrelicPlugin) GetPluginName() string {
    return PLUGIN_NAME
}

func (plugin *NewrelicPlugin) Harvest() error {
    startTime := time.Now()

    if plugin.LastPollTime == 0 {
        plugin.Components[0].Duration = plugin.GetReportIntervalInSeconds()
    } else {
        plugin.Components[0].Duration = startTime.Sub(plugin.LastPollTime)
    }

    plugin.Components[0].Metrics = make(map[string]MetricaValue, len(plugin.MetricaModels))
    for i := 0; i < len(plugin.MetricaModels); i++ {
        model := plugin.MetricaModels[i]
        if newValue, err := model.GetValue(); err == nil {
            if existMetric, ok := plugin.Components[0].Metrics[model.GetName()], ok {
                if floatExistVal, ok := existMetric.(float64); ok {
                    plugin.Components[0].Metrics[model.GetName()] = NewAggregatedMetricaValue(floatExistVal, newValue)
                }
            } else {
                plugin.Components[0].Metrics[model.GetName()].Aggregate(newValue)
            }
        } else {
            log.Printf("Can not get metrica: %v, got error:%#v", model.GetName(), err)
        }
    }

    if httpCode, err := plugin.SendMetricas(); err != nil {
        log.Printf("Can not send metricas to newrelic: %#v\n", err)
    } else {

        if plugin.Verbose {
            log.Printf("Got HTTP response code:%d", httpCode)
        }

        if err, isFatal := plugin.CheckResponse(httpCode); isFatal {
            log.Fatalf("Got fatal error:%v\n")
        } else {
            log.Printf("WARNING: %v", err)
        }
    }
    return err
}

func (plugin *NewrelicPlugin) SendMetricas() int, error {
    if metricasJson, err := json.MarshalIndent(plugin, "", "    "); err != nil {
        return 0, err
    } else if httpRequest, err := NewRequest("POST", NEWRELIC_API_URL, bytes.NewReader(metricasJson)); err != nil {
        return 0, err
    } else {
        httpRequest.Header.Set("Content-Type", "application/json")
        httpRequest.Header.Set("X-License-Key", plugin.GetLicenseKey())

        //TODO: implement compression
        //httpRequest.Header.Set("Content-Encoding", "gzip")

        if plugin.Verbose {
            log.Printf("Send data:%s", string(metricasJson))
        }

        if httpResponse, err := http.DefaultClient.Do(httpRequest); err != nil {
            return err
        } else {
            defer httpResponse.Body.Close()
            return httpResponse.StatusCode
        }
    }
}

func (plugin *NewrelicPlugin) CheckResponse(httpResponseCode int) error, bool {
    isFatal := false
    var err error
    switch httpResponseCode {
        http.StatusOK:{
            plugin.Components[0].Metrics = nil
            plugin.LastPollTime = time.Now()
        }
        http.StatusForbidden:{
            err = fmt.Errorf("Authentication error (no license key header, or invalid license key).\n")
            isFatal = true
        }
        http.StatusBadRequest:{
            err = fmt.Errorf("The request or headers are in the wrong format or the URL is incorrect.\n")
            isFatal = true
        }
        http.StatusNotFound:{
            err = fmt.Errorf("Invalid URL\n")
            isFatal = true
        }
        http.StatusRequestEntityTooLarge:{
            err = fmt.Errorf("Too many metrics were sent in one request, or too many components (instances) were specified in one request, or other single-request limits were reached.\n")
            //discard metrics
            plugin.Components[0].Metrics = nil
            plugin.LastPollTime = time.Now()
        }
        http.StatusInternalServerError, http.StatusBadGateway, http.StatusServiceUnavailable, http.StatusGatewayTimeout: {
            err = fmt.Errorf("Got %v response code.Metricas will be aggregated")
        }
    }
    return err, isFatal
}

func (plugin *NewrelicPlugin) AddMetrica(model Metrica) {
    plugin.MetricaModels = append(plugin.MetricaModels, model)
}

type WaveMetrica struct {
    sawtoothMax int
    sawtoothCounter int
    squarewaveMax int
    squarewaveCounter int
}
func (metrica WaveMetrica) GetName() string {
    return "Wave Metrica"
}
func (metrica WaveMetrica) GetValue() (float64, error) {
    return 5,  nil
}

func main() {
    plugin := NewNewrelicPlugin()
    m := WaveMetrica{}
    plugin.AddMetrica(m);
    plugin.Harvest()
}
<|endoftext|>


<commit_before>// Copyright 2015 The monmq 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 monmq

import (
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"

	"github.com/jroimartin/rpcmq"
)

type Agent struct {
	s      *rpcmq.Server
	status Status

	TLSConfig *tls.Config

	SoftShutdown func() error
	HardShutdown func() error
	Kill         func(id string) error
}

func NewAgent(uri, exchange, name string) *Agent {
	a := &Agent{}
	a.s = rpcmq.NewServer(uri, "", exchange, "fanout")
	a.status.Name = name
	return a
}

func (a *Agent) Init() error {
	a.s.TLSConfig = a.TLSConfig
	if err := a.s.Register("getStatus", a.getStatus); err != nil {
		return err
	}
	if err := a.s.Register("softShutdown", a.softShutdown); err != nil {
		return err
	}
	if err := a.s.Register("hardShutdown", a.hardShutdown); err != nil {
		return err
	}
	if err := a.s.Register("kill", a.kill); err != nil {
		return err
	}
	if err := a.s.Init(); err != nil {
		return err
	}
	return nil
}

func (a *Agent) Shutdown() error {
	return a.s.Shutdown()
}

func (a *Agent) RegisterTask(id string) {
	a.status.Tasks = append(a.status.Tasks, id)
}

func (a *Agent) RemoveTask(id string) error {
	idx := -1
	for i, t := range a.status.Tasks {
		if t == id {
			idx = i
			break
		}
	}
	if idx == -1 {
		return errors.New("task not found")
	}
	a.status.Tasks = append(a.status.Tasks[:idx], a.status.Tasks[idx+1:]...)
	return nil
}

func (a *Agent) getStatus(id string, data []byte) ([]byte, error) {
	b, err := json.Marshal(a.status)
	if err != nil {
		return nil, err
	}
	return []byte(fmt.Sprintf("getStatus%c%s", sep, b)), nil
}

func (a *Agent) softShutdown(id string, data []byte) ([]byte, error) {
	name := string(data)
	if name != a.status.Name {
		return nil, nil
	}
	if a.SoftShutdown == nil {
		return nil, errors.New("SoftShutdown not implemented")
	}
	b := []byte(fmt.Sprintf("softShutdown%c%s", sep, a.status.Name))
	err := a.SoftShutdown()
	return b, err
}

func (a *Agent) hardShutdown(id string, data []byte) ([]byte, error) {
	name := string(data)
	if name != a.status.Name {
		return nil, nil
	}
	if a.HardShutdown == nil {
		return nil, errors.New("HardShutdown not implemented")
	}
	b := []byte(fmt.Sprintf("hardShutdown%c%s", sep, a.status.Name))
	err := a.HardShutdown()
	return b, err
}

func (a *Agent) kill(id string, data []byte) ([]byte, error) {
	taskID := string(data)
	if !a.ownsTask(taskID) {
		return nil, nil
	}
	if a.Kill == nil {
		return nil, errors.New("Kill not implemented")
	}
	b := []byte(fmt.Sprintf("kill%c%s", sep, taskID))
	err := a.Kill(taskID)
	return b, err
}

func (a *Agent) ownsTask(id string) bool {
	for _, t := range a.status.Tasks {
		if id == t {
			return true
		}
	}
	return false
}
<commit_msg>Minor changes<commit_after>// Copyright 2015 The monmq 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 monmq

import (
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"

	"github.com/jroimartin/rpcmq"
)

type Agent struct {
	s      *rpcmq.Server
	status Status

	TLSConfig *tls.Config

	SoftShutdown func() error
	HardShutdown func() error
	Kill         func(id string) error
}

func NewAgent(uri, exchange, name string) *Agent {
	a := &Agent{}
	a.s = rpcmq.NewServer(uri, "", exchange, "fanout")
	a.status.Name = name
	return a
}

func (a *Agent) Init() error {
	a.s.TLSConfig = a.TLSConfig
	if err := a.s.Register("getStatus", a.getStatus); err != nil {
		return err
	}
	if err := a.s.Register("softShutdown", a.softShutdown); err != nil {
		return err
	}
	if err := a.s.Register("hardShutdown", a.hardShutdown); err != nil {
		return err
	}
	if err := a.s.Register("kill", a.kill); err != nil {
		return err
	}
	if err := a.s.Init(); err != nil {
		return err
	}
	return nil
}

func (a *Agent) Shutdown() error {
	return a.s.Shutdown()
}

func (a *Agent) RegisterTask(id string) {
	a.status.Tasks = append(a.status.Tasks, id)
}

func (a *Agent) RemoveTask(id string) error {
	idx := -1
	for i, t := range a.status.Tasks {
		if t == id {
			idx = i
			break
		}
	}
	if idx == -1 {
		return errors.New("task not found")
	}
	a.status.Tasks = append(a.status.Tasks[:idx], a.status.Tasks[idx+1:]...)
	return nil
}

func (a *Agent) getStatus(id string, data []byte) ([]byte, error) {
	b, err := json.Marshal(a.status)
	if err != nil {
		return nil, err
	}
	return []byte(fmt.Sprintf("getStatus%c%s", sep, b)), nil
}

func (a *Agent) softShutdown(id string, data []byte) ([]byte, error) {
	name := string(data)
	if name != a.status.Name {
		return nil, nil
	}
	if a.SoftShutdown == nil {
		return nil, errors.New("SoftShutdown not implemented")
	}
	b := []byte(fmt.Sprintf("softShutdown%c%s", sep, name))
	err := a.SoftShutdown()
	return b, err
}

func (a *Agent) hardShutdown(id string, data []byte) ([]byte, error) {
	name := string(data)
	if name != a.status.Name {
		return nil, nil
	}
	if a.HardShutdown == nil {
		return nil, errors.New("HardShutdown not implemented")
	}
	b := []byte(fmt.Sprintf("hardShutdown%c%s", sep, name))
	err := a.HardShutdown()
	return b, err
}

func (a *Agent) kill(id string, data []byte) ([]byte, error) {
	taskID := string(data)
	if !a.ownsTask(taskID) {
		return nil, nil
	}
	if a.Kill == nil {
		return nil, errors.New("Kill not implemented")
	}
	b := []byte(fmt.Sprintf("kill%c%s", sep, taskID))
	err := a.Kill(taskID)
	return b, err
}

func (a *Agent) ownsTask(id string) bool {
	for _, t := range a.status.Tasks {
		if id == t {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package al

import (
	"fmt"
	"log"
	"math"
	"time"

	"dasa.cc/snd"

	"golang.org/x/mobile/exp/audio/al"
)

// TODO much of this functionality needs to be generalized
// but that can wait to be hashed out until other backends
// are supported, e.g. jack

const maxbufs = 80 // arbitrary soft limit

var hwa *openal

// Buffer provides adaptive buffering for real-time responses that outpace
// openal's ability to report a buffer as processed.
// Constant-time synchronization is left up to the caller.
// TODO consider naming SourceBuffers and embedding al.Source
type Buffer struct {
	src  al.Source
	bufs []al.Buffer // intrinsic to src
	size int         // size of buffers returned by Get
	idx  int         // last known index still processing or ready for reuse
}

// Get returns a slice of buffers of length b.size ready to receive data and be queued.
// If b.src reports processing at-least as many buffers as b.size, buffers up to b.size
// will be unqueued for reuse. Otherwise, new buffers will be generated.
//
// If the length of b.bufs has grown to be greater than maxbufs, a nil slice is returned.
func (b *Buffer) Get() (bufs []al.Buffer) {
	if proc := int(b.src.BuffersProcessed()); proc >= b.size {
		// advance by size, BuffersProcessed will report that many less next time.
		bufs = b.bufs[b.idx : b.idx+b.size]
		b.src.UnqueueBuffers(bufs...)
		if code := al.Error(); code != 0 {
			log.Printf("snd/al: unqueue buffers failed [err=%v]\n", code)
		}
		b.idx = (b.idx + b.size) % len(b.bufs)
	} else if len(b.bufs) >= maxbufs {
		// likely programmer error, something has gone horribly wrong.
		log.Printf("snd/al: get buffers failed, maxbufs reached [len=%v]\n", len(b.bufs))
		return nil
	} else {
		// make more buffers to fill data regardless of what openal says about processed.
		bufs = al.GenBuffers(b.size)
		if code := al.Error(); code != 0 {
			log.Printf("snd/al: generate buffers failed [err=%v]\n", code)
		}
		b.bufs = append(b.bufs, bufs...)
	}
	return bufs
}

type openal struct {
	source al.Source
	buf    *Buffer

	format uint32
	in     snd.Sound
	out    []byte

	quit chan struct{}

	underruns uint64

	tdur time.Duration
	tc   uint64

	start time.Time

	inputs []*snd.Input
}

func OpenDevice(buflen int) error {
	if err := al.OpenDevice(); err != nil {
		return fmt.Errorf("snd/al: open device failed: %s", err)
	}
	if buflen == 0 || buflen&(buflen-1) != 0 {
		return fmt.Errorf("snd/al: buflen(%v) not a power of 2", buflen)
	}
	hwa = &openal{buf: &Buffer{size: buflen}}
	return nil
}

func CloseDevice() error {
	al.DeleteBuffers(hwa.buf.bufs...)
	al.DeleteSources(hwa.source)
	al.CloseDevice()
	hwa = nil
	return nil
}

func AddSource(in snd.Sound) error {
	switch in.Channels() {
	case 1:
		hwa.format = al.FormatMono16
	case 2:
		hwa.format = al.FormatStereo16
	default:
		return fmt.Errorf("snd/al: can't handle input with channels(%v)", in.Channels())
	}
	hwa.in = in
	hwa.out = make([]byte, in.BufferLen()*2)

	s := al.GenSources(1)
	if code := al.Error(); code != 0 {
		return fmt.Errorf("snd/al: generate source failed [err=%v]", code)
	}
	hwa.source = s[0]
	hwa.buf.src = s[0]

	log.Println("snd/al: software latency", SoftLatency())

	hwa.inputs = snd.GetInputs(in)

	return nil
}

func Notify() {
	if hwa.in != nil {
		hwa.inputs = snd.GetInputs(hwa.in)
	}
}

func SoftLatency() time.Duration {
	nframes := float64(hwa.in.BufferLen() / hwa.in.Channels())
	return time.Duration(nframes * float64(hwa.buf.size) / hwa.in.SampleRate() * float64(time.Second))
}

func Start() {
	if hwa.quit != nil {
		panic("snd/al: hwa.quit not nil")
	}
	hwa.quit = make(chan struct{})
	go func() {
		hwa.start = time.Now()
		Tick()
		refill := time.Tick(SoftLatency())
		for {
			select {
			case <-hwa.quit:
				return
			case <-refill:
				Tick()
			}
		}
	}()
}

func Stop() { close(hwa.quit) }

var dp = new(snd.Dispatcher)

func Tick() {
	start := time.Now()

	if code := al.DeviceError(); code != 0 {
		log.Printf("snd/al: unknown device error [err=%v]\n", code)
	}
	if code := al.Error(); code != 0 {
		log.Printf("snd/al: unknown error [err=%v]\n", code)
	}

	bufs := hwa.buf.Get()

	for _, buf := range bufs {
		hwa.tc++

		// TODO the general idea here is that GetInputs is rather cheap to call, even with the
		// current first-draft implementation, so it could only return inputs that are actually
		// turned on. This would introduce software latency determined by snd.DefaultBufferLen
		// as turning an input back on would not get picked up until the next iteration.
		// if !realtime {
		// hwa.inputs = snd.GetInputs(hwa.in)
		// }

		dp.Dispatch(hwa.tc, hwa.inputs...)

		for i, x := range hwa.in.Samples() {
			// clip
			if x > 1 {
				x = 1
			} else if x < -1 {
				x = -1
			}
			n := int16(math.MaxInt16 * x)
			hwa.out[2*i] = byte(n)
			hwa.out[2*i+1] = byte(n >> 8)
		}

		buf.BufferData(hwa.format, hwa.out, int32(hwa.in.SampleRate()))
		if code := al.Error(); code != 0 {
			log.Printf("snd/al: buffer data failed [err=%v]\n", code)
		}
	}

	if len(bufs) != 0 {
		hwa.source.QueueBuffers(bufs...)
	}
	if code := al.Error(); code != 0 {
		log.Printf("snd/al: queue buffer failed [err=%v]\n", code)
	}

	switch hwa.source.State() {
	case al.Initial:
		al.PlaySources(hwa.source)
	case al.Playing:
	case al.Paused:
	case al.Stopped:
		hwa.underruns++
		al.PlaySources(hwa.source)
	}

	hwa.tdur += time.Now().Sub(start)
}

func BufLen() int {
	return len(hwa.buf.bufs)
}

func Underruns() uint64 {
	return hwa.underruns
}

func TickAverge() time.Duration {
	if hwa.tc == 0 || hwa.buf.size == 0 {
		return 0
	}
	return hwa.tdur / time.Duration(int(hwa.tc)/hwa.buf.size)
}

func DriftApprox() time.Duration {
	if hwa.tc == 0 || hwa.buf.size == 0 {
		return 0
	}
	dt := int64(time.Now().Sub(hwa.start) / time.Duration(int(hwa.tc)/hwa.buf.size))
	lt := int64(SoftLatency())
	return time.Duration(lt - dt)
}
<commit_msg>al: return tick if no inputs<commit_after>package al

import (
	"fmt"
	"log"
	"math"
	"time"

	"dasa.cc/snd"

	"golang.org/x/mobile/exp/audio/al"
)

// TODO much of this functionality needs to be generalized
// but that can wait to be hashed out until other backends
// are supported, e.g. jack

const maxbufs = 80 // arbitrary soft limit

var hwa *openal

// Buffer provides adaptive buffering for real-time responses that outpace
// openal's ability to report a buffer as processed.
// Constant-time synchronization is left up to the caller.
// TODO consider naming SourceBuffers and embedding al.Source
type Buffer struct {
	src  al.Source
	bufs []al.Buffer // intrinsic to src
	size int         // size of buffers returned by Get
	idx  int         // last known index still processing or ready for reuse
}

// Get returns a slice of buffers of length b.size ready to receive data and be queued.
// If b.src reports processing at-least as many buffers as b.size, buffers up to b.size
// will be unqueued for reuse. Otherwise, new buffers will be generated.
//
// If the length of b.bufs has grown to be greater than maxbufs, a nil slice is returned.
func (b *Buffer) Get() (bufs []al.Buffer) {
	if proc := int(b.src.BuffersProcessed()); proc >= b.size {
		// advance by size, BuffersProcessed will report that many less next time.
		bufs = b.bufs[b.idx : b.idx+b.size]
		b.src.UnqueueBuffers(bufs...)
		if code := al.Error(); code != 0 {
			log.Printf("snd/al: unqueue buffers failed [err=%v]\n", code)
		}
		b.idx = (b.idx + b.size) % len(b.bufs)
	} else if len(b.bufs) >= maxbufs {
		// likely programmer error, something has gone horribly wrong.
		log.Printf("snd/al: get buffers failed, maxbufs reached [len=%v]\n", len(b.bufs))
		return nil
	} else {
		// make more buffers to fill data regardless of what openal says about processed.
		bufs = al.GenBuffers(b.size)
		if code := al.Error(); code != 0 {
			log.Printf("snd/al: generate buffers failed [err=%v]\n", code)
		}
		b.bufs = append(b.bufs, bufs...)
	}
	return bufs
}

type openal struct {
	source al.Source
	buf    *Buffer

	format uint32
	in     snd.Sound
	out    []byte

	quit chan struct{}

	underruns uint64

	tdur time.Duration
	tc   uint64

	start time.Time

	inputs []*snd.Input
}

func OpenDevice(buflen int) error {
	if err := al.OpenDevice(); err != nil {
		return fmt.Errorf("snd/al: open device failed: %s", err)
	}
	if buflen == 0 || buflen&(buflen-1) != 0 {
		return fmt.Errorf("snd/al: buflen(%v) not a power of 2", buflen)
	}
	hwa = &openal{buf: &Buffer{size: buflen}}
	return nil
}

func CloseDevice() error {
	al.DeleteBuffers(hwa.buf.bufs...)
	al.DeleteSources(hwa.source)
	al.CloseDevice()
	hwa = nil
	return nil
}

func AddSource(in snd.Sound) error {
	switch in.Channels() {
	case 1:
		hwa.format = al.FormatMono16
	case 2:
		hwa.format = al.FormatStereo16
	default:
		return fmt.Errorf("snd/al: can't handle input with channels(%v)", in.Channels())
	}
	hwa.in = in
	hwa.out = make([]byte, in.BufferLen()*2)

	s := al.GenSources(1)
	if code := al.Error(); code != 0 {
		return fmt.Errorf("snd/al: generate source failed [err=%v]", code)
	}
	hwa.source = s[0]
	hwa.buf.src = s[0]

	log.Println("snd/al: software latency", SoftLatency())

	hwa.inputs = snd.GetInputs(in)

	return nil
}

func Notify() {
	if hwa.in != nil {
		hwa.inputs = snd.GetInputs(hwa.in)
	}
}

func SoftLatency() time.Duration {
	nframes := float64(hwa.in.BufferLen() / hwa.in.Channels())
	return time.Duration(nframes * float64(hwa.buf.size) / hwa.in.SampleRate() * float64(time.Second))
}

func Start() {
	if hwa.quit != nil {
		panic("snd/al: hwa.quit not nil")
	}
	hwa.quit = make(chan struct{})
	go func() {
		hwa.start = time.Now()
		Tick()
		refill := time.Tick(SoftLatency())
		for {
			select {
			case <-hwa.quit:
				return
			case <-refill:
				Tick()
			}
		}
	}()
}

func Stop() { close(hwa.quit) }

var dp = new(snd.Dispatcher)

func Tick() {
	start := time.Now()

	if code := al.DeviceError(); code != 0 {
		log.Printf("snd/al: unknown device error [err=%v]\n", code)
	}
	if code := al.Error(); code != 0 {
		log.Printf("snd/al: unknown error [err=%v]\n", code)
	}
	if len(hwa.inputs) == 0 {
		log.Println("snd/al: inputs not ready")
		return
	}

	bufs := hwa.buf.Get()

	for _, buf := range bufs {
		hwa.tc++

		// TODO the general idea here is that GetInputs is rather cheap to call, even with the
		// current first-draft implementation, so it could only return inputs that are actually
		// turned on. This would introduce software latency determined by snd.DefaultBufferLen
		// as turning an input back on would not get picked up until the next iteration.
		// if !realtime {
		// hwa.inputs = snd.GetInputs(hwa.in)
		// }

		dp.Dispatch(hwa.tc, hwa.inputs...)

		for i, x := range hwa.in.Samples() {
			// clip
			if x > 1 {
				x = 1
			} else if x < -1 {
				x = -1
			}
			n := int16(math.MaxInt16 * x)
			hwa.out[2*i] = byte(n)
			hwa.out[2*i+1] = byte(n >> 8)
		}

		buf.BufferData(hwa.format, hwa.out, int32(hwa.in.SampleRate()))
		if code := al.Error(); code != 0 {
			log.Printf("snd/al: buffer data failed [err=%v]\n", code)
		}
	}

	if len(bufs) != 0 {
		hwa.source.QueueBuffers(bufs...)
	}
	if code := al.Error(); code != 0 {
		log.Printf("snd/al: queue buffer failed [err=%v]\n", code)
	}

	switch hwa.source.State() {
	case al.Initial:
		al.PlaySources(hwa.source)
	case al.Playing:
	case al.Paused:
	case al.Stopped:
		hwa.underruns++
		al.PlaySources(hwa.source)
	}

	hwa.tdur += time.Now().Sub(start)
}

func BufLen() int {
	return len(hwa.buf.bufs)
}

func Underruns() uint64 {
	return hwa.underruns
}

func TickAverge() time.Duration {
	if hwa.tc == 0 || hwa.buf.size == 0 {
		return 0
	}
	return hwa.tdur / time.Duration(int(hwa.tc)/hwa.buf.size)
}

func DriftApprox() time.Duration {
	if hwa.tc == 0 || hwa.buf.size == 0 {
		return 0
	}
	dt := int64(time.Now().Sub(hwa.start) / time.Duration(int(hwa.tc)/hwa.buf.size))
	lt := int64(SoftLatency())
	return time.Duration(lt - dt)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"log"
	"os/exec"
	"strings"
	"sync"
	"syscall"

	pp "github.com/paulstuart/ping"
)

/*
http://www.supermicro.com/support/faqs/faq.cfm?faq=12600

To get UID status, please issue: ipmitool raw 0x30 0xC
Returned value: 0 = OFF; 1 = ON

To enable UID, please issue: ipmitool raw 0x30 0xD
To disable UID, please issue: ipmitool raw 0x30 0xE

If successful, the completion Code is 0x00.
*/

var (
	pingTimeout       = 3
	ErrNoPing         = fmt.Errorf("cannot ping address")
	ErrBadIPMI        = fmt.Errorf("IPMI command failed")
	ErrLoginIPMI      = fmt.Errorf("unable to log into IPMI")
	ErrIncompleteIPMI = fmt.Errorf("incomplete IPMI response")
	ErrExecFailed     = fmt.Errorf("command execution failed")
	ErrNoAddress      = fmt.Errorf("no address specified")
	ErrNoUsername     = fmt.Errorf("no username specified")
	ErrNoPassword     = fmt.Errorf("no password specified")
)

func ping(ip string, timeout int) bool {
	return pp.Ping(ip, timeout)
}

type pingable struct {
	IP string
	OK bool
}

func bulkPing(timeout int, ips ...string) map[string]bool {
	hits := make(map[string]bool)
	c := make(chan pingable)

	for _, ip := range ips {
		go func(addr string) {
			ok := ping(addr, timeout)
			c <- pingable{addr, ok}
		}(ip)
	}
	for range ips {
		r := <-c
		hits[r.IP] = r.OK
	}
	return hits
}

func Blink(ip string, on bool) error {
	cmd := "0xE"
	if on {
		cmd = "0xD"
	}
	u, p, _ := GetCredentials(ip)
	rc, _, _, err := ipmicmd(ip, u, p, fmt.Sprintf("raw 0x30 %s", cmd))
	if err != nil {
		return err
	}
	if rc > 0 {
		return fmt.Errorf("ipmitool returned: %d", rc)
	}
	return nil
}

func BlinkStatus(ip string) (bool, error) {
	u, p, _ := GetCredentials(ip)
	rc, _, _, err := ipmicmd(ip, u, p, "raw 0x30 0xC")
	on := false
	if rc == 1 {
		on = true
	}
	return on, err
}

func ipmiexec(ip, username, password, input string) (int, string, string, error) {
	if len(ip) == 0 {
		return -1, "", "", ErrNoAddress
	}
	if len(username) == 0 {
		return -1, "", "", ErrNoUsername
	}
	if len(password) == 0 {
		return -1, "", "", ErrNoPassword
	}
	args := []string{"-Ilanplus", "-H", ip, "-U", username, "-P", password}
	args = append(args, strings.Fields(input)...)
	cmd := exec.Command("ipmitool", args...)
	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	err := cmd.Run()
	status := cmd.ProcessState.Sys().(syscall.WaitStatus)
	rc := status.ExitStatus()

	return rc, stdout.String(), stderr.String(), err
}

func ipmicmd(ip, username, password, input string) (int, string, string, error) {
	if len(ip) == 0 {
		return -1, "", "", ErrNoAddress
	}
	if !ping(ip, pingTimeout) {
		return -1, "", "", ErrNoPing
	}
	return ipmiexec(ip, username, password, input)
}

func ipmigo(ip, username, password, input string) error {
	rc, stdout, stderr, err := ipmiexec(ip, username, password, input)
	if err != nil {
		return err
	}
	if rc > 0 {
		log.Printf("RC:%d OUT:%s ERR:%s\n", rc, stdout, stderr)
		return ErrExecFailed
	}
	return nil
}

func ipmichk(ip, username, password string) error {
	const chkcmd = "session info active"
	rc, stdout, stderr, err := ipmiexec(ip, username, password, chkcmd)
	if err != nil {
		return err
	}
	if rc > 0 {
		return ErrExecFailed
	}
	if strings.Contains(stdout, "active session") {
		return nil
	}
	if len(stdout) > 0 {
		log.Println("unexpected stdout:", stdout)
	}
	if len(stderr) > 0 {
		log.Println("unexpected stderr:", stderr)
	}
	return ErrBadIPMI
}

// verify credentials
func fixCredentials(ip string) error {
	if !ping(ip, pingTimeout) {
		return ErrNoPing
	}
	versions := []string{"ADMIN", "Admin", "admin"}
	for _, u := range versions {
		for _, p := range versions {
			if err := ipmichk(ip, u, p); err == nil {
				SetCredentials(ip, u, p)
				return nil
			}
		}
	}
	return ErrLoginIPMI
}

func repairCredentials() (int, int) {
	unknown := noCredentials()
	fixed := 0
	var mu sync.Mutex
	var wg sync.WaitGroup
	for _, ip := range unknown {
		wg.Add(1)
		ipv4 := ip // avoid capturing range variable ip
		go func() {
			if err := fixCredentials(ipv4); err == nil {
				mu.Lock()
				fixed++
				mu.Unlock()
				wg.Done()
			}
		}()
	}
	wg.Wait()
	return fixed, len(unknown)
}

func FindMAC(ipmi string) (string, error) {
	const cmd = "raw 0x30 0x21"
	u, p, err := GetCredentials(ipmi)
	if err != nil {
		if err = fixCredentials(ipmi); err != nil {
			return "", err
		}
		u, p, err = GetCredentials(ipmi)
		if err != nil {
			return "", err
		}
	}
	rc, stdout, _, err := ipmicmd(ipmi, u, p, cmd)
	if err != nil {
		return "", err
	}
	if rc != 0 {
		return "", err
	}
	if len(stdout) < 13 {
		return "", ErrIncompleteIPMI
	}
	return strings.Replace(stdout[13:], " ", ":", -1), nil
}

func noCredentials() []string {
	// TODO: make this a view
	query := "select ip_ipmi from servers where ip_ipmi > '' and ip_ipmi not in (select ip from credentials)"
	rows, err := dbRows(query)
	if err != nil {
		log.Println("blank credentials error:", err)
	}
	return rows
}

func ipmiCredentials(ipmi string) (string, string, error) {
	query := "select username, password from credentials where ip=?"
	results, err := dbRow(query, ipmi)
	if err != nil {
		return "", "", err
	}
	if len(results) < 2 {
		return "", "", fmt.Errorf("incomplete results")
	}
	log.Println("RESULTS:", results)
	return results[0], results[1], nil
}

func GetCredentials(ipmi string) (string, string, error) {
	if u, p, err := ipmiCredentials(ipmi); err == nil {
		return u, p, nil
	}
	if err := fixCredentials(ipmi); err != nil {
		return "", "", err
	}
	return ipmiCredentials(ipmi)
}

func SetCredentials(ipmi, username, password string) error {
	query := "replace into credentials (ip,username,password) values(?,?,?)"
	return dbExec(query, ipmi, username, password)
}
<commit_msg>trim debug output<commit_after>package main

import (
	"bytes"
	"fmt"
	"log"
	"os/exec"
	"strings"
	"sync"
	"syscall"

	pp "github.com/paulstuart/ping"
)

/*
http://www.supermicro.com/support/faqs/faq.cfm?faq=12600

To get UID status, please issue: ipmitool raw 0x30 0xC
Returned value: 0 = OFF; 1 = ON

To enable UID, please issue: ipmitool raw 0x30 0xD
To disable UID, please issue: ipmitool raw 0x30 0xE

If successful, the completion Code is 0x00.
*/

var (
	pingTimeout       = 3
	ErrNoPing         = fmt.Errorf("cannot ping address")
	ErrBadIPMI        = fmt.Errorf("IPMI command failed")
	ErrLoginIPMI      = fmt.Errorf("unable to log into IPMI")
	ErrIncompleteIPMI = fmt.Errorf("incomplete IPMI response")
	ErrExecFailed     = fmt.Errorf("command execution failed")
	ErrNoAddress      = fmt.Errorf("no address specified")
	ErrNoUsername     = fmt.Errorf("no username specified")
	ErrNoPassword     = fmt.Errorf("no password specified")
)

func ping(ip string, timeout int) bool {
	return pp.Ping(ip, timeout)
}

type pingable struct {
	IP string
	OK bool
}

func bulkPing(timeout int, ips ...string) map[string]bool {
	hits := make(map[string]bool)
	c := make(chan pingable)

	for _, ip := range ips {
		go func(addr string) {
			ok := ping(addr, timeout)
			c <- pingable{addr, ok}
		}(ip)
	}
	for range ips {
		r := <-c
		hits[r.IP] = r.OK
	}
	return hits
}

func Blink(ip string, on bool) error {
	cmd := "0xE"
	if on {
		cmd = "0xD"
	}
	u, p, _ := GetCredentials(ip)
	rc, _, _, err := ipmicmd(ip, u, p, fmt.Sprintf("raw 0x30 %s", cmd))
	if err != nil {
		return err
	}
	if rc > 0 {
		return fmt.Errorf("ipmitool returned: %d", rc)
	}
	return nil
}

func BlinkStatus(ip string) (bool, error) {
	u, p, _ := GetCredentials(ip)
	rc, _, _, err := ipmicmd(ip, u, p, "raw 0x30 0xC")
	on := false
	if rc == 1 {
		on = true
	}
	return on, err
}

func ipmiexec(ip, username, password, input string) (int, string, string, error) {
	if len(ip) == 0 {
		return -1, "", "", ErrNoAddress
	}
	if len(username) == 0 {
		return -1, "", "", ErrNoUsername
	}
	if len(password) == 0 {
		return -1, "", "", ErrNoPassword
	}
	args := []string{"-Ilanplus", "-H", ip, "-U", username, "-P", password}
	args = append(args, strings.Fields(input)...)
	cmd := exec.Command("ipmitool", args...)
	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	err := cmd.Run()
	status := cmd.ProcessState.Sys().(syscall.WaitStatus)
	rc := status.ExitStatus()

	return rc, stdout.String(), stderr.String(), err
}

func ipmicmd(ip, username, password, input string) (int, string, string, error) {
	if len(ip) == 0 {
		return -1, "", "", ErrNoAddress
	}
	if !ping(ip, pingTimeout) {
		return -1, "", "", ErrNoPing
	}
	return ipmiexec(ip, username, password, input)
}

func ipmigo(ip, username, password, input string) error {
	rc, stdout, stderr, err := ipmiexec(ip, username, password, input)
	if err != nil {
		return err
	}
	if rc > 0 {
		log.Printf("RC:%d OUT:%s ERR:%s\n", rc, stdout, stderr)
		return ErrExecFailed
	}
	return nil
}

func ipmichk(ip, username, password string) error {
	const chkcmd = "session info active"
	rc, stdout, stderr, err := ipmiexec(ip, username, password, chkcmd)
	if err != nil {
		return err
	}
	if rc > 0 {
		return ErrExecFailed
	}
	if strings.Contains(stdout, "active session") {
		return nil
	}
	if len(stdout) > 0 {
		log.Println("unexpected stdout:", stdout)
	}
	if len(stderr) > 0 {
		log.Println("unexpected stderr:", stderr)
	}
	return ErrBadIPMI
}

// verify credentials
func fixCredentials(ip string) error {
	if !ping(ip, pingTimeout) {
		return ErrNoPing
	}
	versions := []string{"ADMIN", "Admin", "admin"}
	for _, u := range versions {
		for _, p := range versions {
			if err := ipmichk(ip, u, p); err == nil {
				SetCredentials(ip, u, p)
				return nil
			}
		}
	}
	return ErrLoginIPMI
}

func repairCredentials() (int, int) {
	unknown := noCredentials()
	fixed := 0
	var mu sync.Mutex
	var wg sync.WaitGroup
	for _, ip := range unknown {
		wg.Add(1)
		ipv4 := ip // avoid capturing range variable ip
		go func() {
			if err := fixCredentials(ipv4); err == nil {
				mu.Lock()
				fixed++
				mu.Unlock()
				wg.Done()
			}
		}()
	}
	wg.Wait()
	return fixed, len(unknown)
}

func FindMAC(ipmi string) (string, error) {
	const cmd = "raw 0x30 0x21"
	u, p, err := GetCredentials(ipmi)
	if err != nil {
		if err = fixCredentials(ipmi); err != nil {
			return "", err
		}
		u, p, err = GetCredentials(ipmi)
		if err != nil {
			return "", err
		}
	}
	rc, stdout, _, err := ipmicmd(ipmi, u, p, cmd)
	if err != nil {
		return "", err
	}
	if rc != 0 {
		return "", err
	}
	if len(stdout) < 13 {
		return "", ErrIncompleteIPMI
	}
	return strings.Replace(stdout[13:], " ", ":", -1), nil
}

func noCredentials() []string {
	// TODO: make this a view
	query := "select ip_ipmi from servers where ip_ipmi > '' and ip_ipmi not in (select ip from credentials)"
	rows, err := dbRows(query)
	if err != nil {
		log.Println("blank credentials error:", err)
	}
	return rows
}

func ipmiCredentials(ipmi string) (string, string, error) {
	query := "select username, password from credentials where ip=?"
	results, err := dbRow(query, ipmi)
	if err != nil {
		return "", "", err
	}
	if len(results) < 2 {
		return "", "", fmt.Errorf("incomplete results")
	}
	return results[0], results[1], nil
}

func GetCredentials(ipmi string) (string, string, error) {
	if u, p, err := ipmiCredentials(ipmi); err == nil {
		return u, p, nil
	}
	if err := fixCredentials(ipmi); err != nil {
		return "", "", err
	}
	return ipmiCredentials(ipmi)
}

func SetCredentials(ipmi, username, password string) error {
	query := "replace into credentials (ip,username,password) values(?,?,?)"
	return dbExec(query, ipmi, username, password)
}
<|endoftext|>