<commit_before>package version

import (
	"bytes"
	"fmt"
)

var (
	// The git commit that was compiled. This will be filled in by the compiler.
	GitCommit   string
	GitDescribe string

	// The main version number that is being run at the moment.
	Version = "0.10.3"

	// A pre-release marker for the version. If this is "" (empty string)
	// then it means that it is a final release. Otherwise, this is a pre-release
	// such as "dev" (in development), "beta", "rc1", etc.
	VersionPrerelease = "dev"

	// VersionMetadata is metadata further describing the build type.
	VersionMetadata = ""
)

// VersionInfo
type VersionInfo struct {
	Revision          string
	Version           string
	VersionPrerelease string
	VersionMetadata   string
}

func GetVersion() *VersionInfo {
	ver := Version
	rel := VersionPrerelease
	md := VersionMetadata
	if GitDescribe != "" {
		ver = GitDescribe
	}
	if GitDescribe == "" && rel == "" && VersionPrerelease != "" {
		rel = "dev"
	}

	return &VersionInfo{
		Revision:          GitCommit,
		Version:           ver,
		VersionPrerelease: rel,
		VersionMetadata:   md,
	}
}

func (c *VersionInfo) VersionNumber() string {
	version := fmt.Sprintf("%s", c.Version)

	if c.VersionPrerelease != "" {
		version = fmt.Sprintf("%s-%s", version, c.VersionPrerelease)
	}

	if c.VersionMetadata != "" {
		version = fmt.Sprintf("%s+%s", version, c.VersionMetadata)
	}

	return version
}

func (c *VersionInfo) FullVersionNumber(rev bool) string {
	var versionString bytes.Buffer

	fmt.Fprintf(&versionString, "Nomad v%s", c.Version)
	if c.VersionPrerelease != "" {
		fmt.Fprintf(&versionString, "-%s", c.VersionPrerelease)
	}

	if c.VersionMetadata != "" {
		fmt.Fprintf(&versionString, "+%s", c.VersionMetadata)
	}

	if rev && c.Revision != "" {
		fmt.Fprintf(&versionString, " (%s)", c.Revision)
	}

	return versionString.String()
}
<commit_msg>nomad/docs: increment version number to 0.10.4<commit_after>package version

import (
	"bytes"
	"fmt"
)

var (
	// The git commit that was compiled. This will be filled in by the compiler.
	GitCommit   string
	GitDescribe string

	// The main version number that is being run at the moment.
	Version = "0.10.4"

	// A pre-release marker for the version. If this is "" (empty string)
	// then it means that it is a final release. Otherwise, this is a pre-release
	// such as "dev" (in development), "beta", "rc1", etc.
	VersionPrerelease = "dev"

	// VersionMetadata is metadata further describing the build type.
	VersionMetadata = ""
)

// VersionInfo
type VersionInfo struct {
	Revision          string
	Version           string
	VersionPrerelease string
	VersionMetadata   string
}

func GetVersion() *VersionInfo {
	ver := Version
	rel := VersionPrerelease
	md := VersionMetadata
	if GitDescribe != "" {
		ver = GitDescribe
	}
	if GitDescribe == "" && rel == "" && VersionPrerelease != "" {
		rel = "dev"
	}

	return &VersionInfo{
		Revision:          GitCommit,
		Version:           ver,
		VersionPrerelease: rel,
		VersionMetadata:   md,
	}
}

func (c *VersionInfo) VersionNumber() string {
	version := fmt.Sprintf("%s", c.Version)

	if c.VersionPrerelease != "" {
		version = fmt.Sprintf("%s-%s", version, c.VersionPrerelease)
	}

	if c.VersionMetadata != "" {
		version = fmt.Sprintf("%s+%s", version, c.VersionMetadata)
	}

	return version
}

func (c *VersionInfo) FullVersionNumber(rev bool) string {
	var versionString bytes.Buffer

	fmt.Fprintf(&versionString, "Nomad v%s", c.Version)
	if c.VersionPrerelease != "" {
		fmt.Fprintf(&versionString, "-%s", c.VersionPrerelease)
	}

	if c.VersionMetadata != "" {
		fmt.Fprintf(&versionString, "+%s", c.VersionMetadata)
	}

	if rev && c.Revision != "" {
		fmt.Fprintf(&versionString, " (%s)", c.Revision)
	}

	return versionString.String()
}
<|endoftext|>


<commit_before>package version

// Version is the version of the build.
const Version = "1.9.3-dev"
<commit_msg>Release v1.10.0<commit_after>package version

// Version is the version of the build.
const Version = "1.10.0"
<|endoftext|>


<commit_before>package version

import "fmt"

var (
	// Version should be updated by hand at each release
	Version = "0.5.5"

	// GitCommit will be overwritten automatically by the build system
	GitCommit = "HEAD"
)

// FullVersion formats the version to be printed
func FullVersion() string {
	return fmt.Sprintf("%s, build %s", Version, GitCommit)
}
<commit_msg>Bump dev version to 0.6.0<commit_after>package version

import "fmt"

var (
	// Version should be updated by hand at each release
	Version = "0.6.0-dev"

	// GitCommit will be overwritten automatically by the build system
	GitCommit = "HEAD"
)

// FullVersion formats the version to be printed
func FullVersion() string {
	return fmt.Sprintf("%s, build %s", Version, GitCommit)
}
<|endoftext|>


<commit_before>// generate generates ps struct based on the schema.
package main

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"reflect"
	"time"

	"github.com/gyuho/psn/process"
)

func main() {
	buf := new(bytes.Buffer)
	buf.WriteString(`package process

	` + "// updated at " + nowPST().String() + `

// Process represents '/proc' in linux.
type Process struct {
	Stat   Stat
	Status Status
}

`)

	buf.WriteString(`// Stat is 'proc/$PID/stat' in linux.
type Stat struct {
`)

	for i := range process.StatList {
		fieldName := process.ToField(process.StatList[i].Col)
		var typeStr string
		switch process.StatList[i].Kind {
		case reflect.Uint64:
			typeStr = "uint64"
		case reflect.Int64:
			typeStr = "int64"
		case reflect.String:
			typeStr = "string"
		}
		buf.WriteString(fmt.Sprintf("\t%s\t%s\t`column:\"%s\"`\n", fieldName, typeStr, process.StatList[i].Col))
		if process.StatList[i].Humanize {
			buf.WriteString(fmt.Sprintf("\t%sHumanize\tstring\t`column:\"%s_humanized\"`\n", fieldName, process.StatList[i].Col))
		}
	}
	for _, line := range additionalFields {
		buf.WriteString(fmt.Sprintf("\t%s\n", line))
	}
	buf.WriteString("}\n\n")

	buf.WriteString(`// Status is 'proc/$PID/status' in linux.
type Status struct {
`)
	for i := range process.StatusListYAML {
		fieldName := process.ToField(process.StatusListYAML[i].Col)
		var typeStr string
		switch process.StatusListYAML[i].Kind {
		case reflect.Uint64:
			typeStr = "uint64"
		case reflect.Int64:
			typeStr = "int64"
		case reflect.String:
			typeStr = "string"
		}
		buf.WriteString(fmt.Sprintf("\t%s\t%s\t`yaml:\"%s\"`\n", fieldName, typeStr, process.StatusListYAML[i].Col))
		if process.StatusListYAML[i].Bytes {
			buf.WriteString(fmt.Sprintf("\t%sBytes\tuint64\t`yaml:\"%s_bytes\"`\n", fieldName, process.StatusListYAML[i].Col))
		}
	}
	buf.WriteString("}\n\n")

	txt := buf.String()
	if err := toFile(txt, filepath.Join(os.Getenv("GOPATH"), "src/github.com/gyuho/psn/ps/process_generated_linux.go")); err != nil {
		log.Fatal(err)
	}
	if err := os.Chdir(filepath.Join(os.Getenv("GOPATH"), "src/github.com/gyuho/psn/ps")); err != nil {
		log.Fatal(err)
	}
	if err := exec.Command("go", "fmt", "./...").Run(); err != nil {
		log.Fatal(err)
	}
}

func nowPST() time.Time {
	tzone, err := time.LoadLocation("America/Los_Angeles")
	if err != nil {
		return time.Now()
	}
	return time.Now().In(tzone)
}

func openToRead(fpath string) (*os.File, error) {
	f, err := os.OpenFile(fpath, os.O_RDONLY, 0444)
	if err != nil {
		return f, err
	}
	return f, nil
}

func toFile(txt, fpath string) error {
	f, err := os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0777)
	if err != nil {
		f, err = os.Create(fpath)
		if err != nil {
			return err
		}
	}
	defer f.Close()
	if _, err := f.WriteString(txt); err != nil {
		return err
	}
	return nil
}

var additionalFields = [...]string{
	"CpuUsage float64 `column:\"cpu_usage\"`",
}
<commit_msg>generate: fix import path<commit_after>// generate generates ps struct based on the schema.
package main

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"reflect"
	"time"

	"github.com/gyuho/psn/process"
)

func main() {
	buf := new(bytes.Buffer)
	buf.WriteString(`package process

	` + "// updated at " + nowPST().String() + `

// Process represents '/proc' in linux.
type Process struct {
	Stat   Stat
	Status Status
}

`)

	buf.WriteString(`// Stat is 'proc/$PID/stat' in linux.
type Stat struct {
`)

	for i := range process.StatList {
		fieldName := process.ToField(process.StatList[i].Col)
		var typeStr string
		switch process.StatList[i].Kind {
		case reflect.Uint64:
			typeStr = "uint64"
		case reflect.Int64:
			typeStr = "int64"
		case reflect.String:
			typeStr = "string"
		}
		buf.WriteString(fmt.Sprintf("\t%s\t%s\t`column:\"%s\"`\n", fieldName, typeStr, process.StatList[i].Col))
		if process.StatList[i].Humanize {
			buf.WriteString(fmt.Sprintf("\t%sHumanize\tstring\t`column:\"%s_humanized\"`\n", fieldName, process.StatList[i].Col))
		}
	}
	for _, line := range additionalFields {
		buf.WriteString(fmt.Sprintf("\t%s\n", line))
	}
	buf.WriteString("}\n\n")

	buf.WriteString(`// Status is 'proc/$PID/status' in linux.
type Status struct {
`)
	for i := range process.StatusListYAML {
		fieldName := process.ToField(process.StatusListYAML[i].Col)
		var typeStr string
		switch process.StatusListYAML[i].Kind {
		case reflect.Uint64:
			typeStr = "uint64"
		case reflect.Int64:
			typeStr = "int64"
		case reflect.String:
			typeStr = "string"
		}
		buf.WriteString(fmt.Sprintf("\t%s\t%s\t`yaml:\"%s\"`\n", fieldName, typeStr, process.StatusListYAML[i].Col))
		if process.StatusListYAML[i].Bytes {
			buf.WriteString(fmt.Sprintf("\t%sBytes\tuint64\t`yaml:\"%s_bytes\"`\n", fieldName, process.StatusListYAML[i].Col))
		}
	}
	buf.WriteString("}\n\n")

	txt := buf.String()
	if err := toFile(txt, filepath.Join(os.Getenv("GOPATH"), "src/github.com/gyuho/psn/process/process_generated_linux.go")); err != nil {
		log.Fatal(err)
	}
	if err := os.Chdir(filepath.Join(os.Getenv("GOPATH"), "src/github.com/gyuho/psn/process")); err != nil {
		log.Fatal(err)
	}
	if err := exec.Command("go", "fmt", "./...").Run(); err != nil {
		log.Fatal(err)
	}
}

func nowPST() time.Time {
	tzone, err := time.LoadLocation("America/Los_Angeles")
	if err != nil {
		return time.Now()
	}
	return time.Now().In(tzone)
}

func openToRead(fpath string) (*os.File, error) {
	f, err := os.OpenFile(fpath, os.O_RDONLY, 0444)
	if err != nil {
		return f, err
	}
	return f, nil
}

func toFile(txt, fpath string) error {
	f, err := os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0777)
	if err != nil {
		f, err = os.Create(fpath)
		if err != nil {
			return err
		}
	}
	defer f.Close()
	if _, err := f.WriteString(txt); err != nil {
		return err
	}
	return nil
}

var additionalFields = [...]string{
	"CpuUsage float64 `column:\"cpu_usage\"`",
}
<|endoftext|>


<commit_before>package pathutil

import (
	"os"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestParent(t *testing.T) {
	temp, err := NewTempDir(TempOpt{})
	assert.NoError(t, err)

	assert.Equal(t, os.TempDir(), temp.Parent().String())

	root, err := New("/")
	assert.NoError(t, err)
	assert.Equal(t, "/", root.Parent().String())
}
<commit_msg>fix windows test<commit_after>package pathutil

import (
	"os"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestParent(t *testing.T) {
	temp, err := NewTempDir(TempOpt{})
	assert.NoError(t, err)

	tempDir, err := New(os.TempDir())
	assert.NoError(t, err)

	assert.Equal(t, tempDir.String(), temp.Parent().String())

	root, err := New("/")
	assert.NoError(t, err)
	assert.Equal(t, "/", root.Parent().String())
}
<|endoftext|>


<commit_before>package parse

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

type GameInfo map[string]string

const BlackPlayerName = "PB"
const BlackPlayerRank = "BR"
const BlackPlayerTeam = "BT"
const WhitePlayerName = "PW"
const WhitePlayerRank = "WR"
const WhitePlayerTeam = "WT"
const Annotator = "AN"
const Copyright = "CP"
const Date = "DT"
const Event = "EV"
const GameComment = "GC"
const Comment = "C"
const GameName = "GN"
const Handicap = "HA"
const Opening = "ON"
const Overtime = "OT"
const Place = "PC"
const Result = "RE"
const Round = "RO"
const Rules = "RU"
const Source = "SO"
const TimeLimits = "TM"
const User = "US"
const Charset = "CA"
const Boardsize = "SZ"
const Komi = "KM"

type Property struct {
	name  string
	value string
}

func (p Property) String() string {
	return fmt.Sprintf("%s[%s]", p.name, p.value)
}

type Point struct {
	x rune
	y rune
}

type Node struct {
	point      Property
	properties []Property
	variations []*Node
	next       *Node
}

func (point *Point) String() string {
	return fmt.Sprintf("[%c%c]", point.x, point.y)
}

func (node Node) String() string {
	attrs := []string{}
	attrs = append(attrs, node.point.String())
	for ndx := 0; ndx < len(node.properties); ndx += 1 {
		attrs = append(attrs, node.properties[ndx].String())
	}
	return strings.Join(attrs, "")
}

func (node *Node) AddProperty(prop Property) {
	switch prop.name {
	case "B", "W":
		node.point = prop
	default:
		node.properties = append(node.properties, prop)
	}
}

func (node *Node) NewNode() *Node {
	node.next = new(Node)
	return node.next
}

func (n *Node) NewVariation() *Node {
	node := new(Node)
	n.variations = append(n.variations, node)
	return node
}

type SGFGame struct {
	gameInfo GameInfo
	gameTree *Node
	errors   []error
}

func (sgf *SGFGame) AddProperty(prop Property) {
	sgf.gameInfo[strings.ToUpper(prop.name)] = prop.value
}

func (sgf *SGFGame) GetProperty(name string) (value string, ok bool) {
	value, ok = sgf.gameInfo[strings.ToUpper(name)]
	return value, ok
}

func (gi GameInfo) SortedKeys() []string {
	var keys sort.StringSlice
	for k, _ := range gi {
		keys = append(keys, k)
	}
	sort.Sort(keys)
	return keys
}

func (gi GameInfo) String() string {
	str := ""
	for _, k := range gi.SortedKeys() {
		str = str + k + "[" + gi[k] + "]"
	}
	return ";" + str
}

func (sgf *SGFGame) GameTreeString() string {
	treeString := ""
	for node := sgf.gameTree; node != nil; node = node.next {
		treeString = treeString + ";" + node.String()
	}
	return treeString
}

func (sgf *SGFGame) String() string {
	return "(" + sgf.gameInfo.String() + sgf.GameTreeString() + ")"
}

func (sgf *SGFGame) NodeCount() int {
	count := 0
	for node := sgf.gameTree; node != nil; node = node.next {
		count += 1
	}
	return count
}

func (sgf *SGFGame) NthNode(n int) (node *Node, err error) {
	if n < 1 {
		return nil, errors.New("n less than 1")
	}
	nodeCount := sgf.NodeCount()

	if n > nodeCount {
		return nil, errors.New(fmt.Sprintf("n greater than node count (%d)", nodeCount))
	}
	for node = sgf.gameTree; n > 1; n -= 1 {
		node = node.next
	}
	return node, nil
}

func (sgf *SGFGame) AddError(msg string) {
	sgf.errors = append(sgf.errors, errors.New(msg))
}

func (sgf *SGFGame) Parse(input string) *SGFGame {
	var currentNode *Node
	l := lex(input)
	prop := Property{}
	parsingSetup := false
	parsingGame := false
	nodeStack := new(Stack)

Loop:
	for {
		i := l.nextItem()
		switch i.typ {
		case itemLeftParen:
			if parsingGame {
				nodeStack.Push(currentNode)
				currentNode = currentNode.NewVariation()
			}
		case itemRightParen:
			if parsingGame {
				node := nodeStack.Pop()
				if node != nil {
					currentNode = node.(*Node)
				}
			}
		case itemSemiColon:
			if !parsingSetup && !parsingGame {
				parsingSetup = true
			} else {
				if !parsingGame {
					parsingSetup = false
					parsingGame = true
					sgf.gameTree = new(Node)
					currentNode = sgf.gameTree
				} else {
					currentNode = currentNode.NewNode()
				}
			}
		case itemPropertyName:
			prop = Property{i.val, ""}
		case itemPropertyValue:
			prop.value = i.val
			if parsingSetup {
				sgf.AddProperty(prop)
			} else {
				currentNode.AddProperty(prop)
			}
		case itemError:
			sgf.AddError(i.val)
			break Loop
		case itemEOF:
			break Loop
		}
	}
	return sgf
}
<commit_msg>SGFGame.ShowAnyErrors()<commit_after>package parse

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

type GameInfo map[string]string

const BlackPlayerName = "PB"
const BlackPlayerRank = "BR"
const BlackPlayerTeam = "BT"
const WhitePlayerName = "PW"
const WhitePlayerRank = "WR"
const WhitePlayerTeam = "WT"
const Annotator = "AN"
const Copyright = "CP"
const Date = "DT"
const Event = "EV"
const GameComment = "GC"
const Comment = "C"
const GameName = "GN"
const Handicap = "HA"
const Opening = "ON"
const Overtime = "OT"
const Place = "PC"
const Result = "RE"
const Round = "RO"
const Rules = "RU"
const Source = "SO"
const TimeLimits = "TM"
const User = "US"
const Charset = "CA"
const Boardsize = "SZ"
const Komi = "KM"

type Property struct {
	name  string
	value string
}

func (p Property) String() string {
	return fmt.Sprintf("%s[%s]", p.name, p.value)
}

type Point struct {
	x rune
	y rune
}

type Node struct {
	point      Property
	properties []Property
	variations []*Node
	next       *Node
}

func (point *Point) String() string {
	return fmt.Sprintf("[%c%c]", point.x, point.y)
}

func (node Node) String() string {
	attrs := []string{}
	attrs = append(attrs, node.point.String())
	for ndx := 0; ndx < len(node.properties); ndx += 1 {
		attrs = append(attrs, node.properties[ndx].String())
	}
	return strings.Join(attrs, "")
}

func (node *Node) AddProperty(prop Property) {
	switch prop.name {
	case "B", "W":
		node.point = prop
	default:
		node.properties = append(node.properties, prop)
	}
}

func (node *Node) NewNode() *Node {
	node.next = new(Node)
	return node.next
}

func (n *Node) NewVariation() *Node {
	node := new(Node)
	n.variations = append(n.variations, node)
	return node
}

type SGFGame struct {
	gameInfo GameInfo
	gameTree *Node
	errors   []error
}

func (sgf *SGFGame) AddProperty(prop Property) {
	sgf.gameInfo[strings.ToUpper(prop.name)] = prop.value
}

func (sgf *SGFGame) GetProperty(name string) (value string, ok bool) {
	value, ok = sgf.gameInfo[strings.ToUpper(name)]
	return value, ok
}

func (gi GameInfo) SortedKeys() []string {
	var keys sort.StringSlice
	for k, _ := range gi {
		keys = append(keys, k)
	}
	sort.Sort(keys)
	return keys
}

func (gi GameInfo) String() string {
	str := ""
	for _, k := range gi.SortedKeys() {
		str = str + k + "[" + gi[k] + "]"
	}
	return ";" + str
}

func (sgf *SGFGame) GameTreeString() string {
	treeString := ""
	for node := sgf.gameTree; node != nil; node = node.next {
		treeString = treeString + ";" + node.String()
	}
	return treeString
}

func (sgf *SGFGame) String() string {
	return "(" + sgf.gameInfo.String() + sgf.GameTreeString() + ")"
}

func (sgf *SGFGame) NodeCount() int {
	count := 0
	for node := sgf.gameTree; node != nil; node = node.next {
		count += 1
	}
	return count
}

func (sgf *SGFGame) NthNode(n int) (node *Node, err error) {
	if n < 1 {
		return nil, errors.New("n less than 1")
	}
	nodeCount := sgf.NodeCount()

	if n > nodeCount {
		return nil, errors.New(fmt.Sprintf("n greater than node count (%d)", nodeCount))
	}
	for node = sgf.gameTree; n > 1; n -= 1 {
		node = node.next
	}
	return node, nil
}

func (sgf *SGFGame) AddError(msg string) {
	sgf.errors = append(sgf.errors, errors.New(msg))
}

func (sgf SGFGame) showAnyErrors() {
	if len(sgf.errors) == 0 {
		return
	}

	fmt.Println("Parsing errors:\n")
	for _, err := range sgf.errors {
		fmt.Println(err)
	}
}

func (sgf *SGFGame) Parse(input string) *SGFGame {
	var currentNode *Node
	l := lex(input)
	prop := Property{}
	parsingSetup := false
	parsingGame := false
	nodeStack := new(Stack)

Loop:
	for {
		i := l.nextItem()
		switch i.typ {
		case itemLeftParen:
			if parsingGame {
				nodeStack.Push(currentNode)
				currentNode = currentNode.NewVariation()
			}
		case itemRightParen:
			if parsingGame {
				node := nodeStack.Pop()
				if node != nil {
					currentNode = node.(*Node)
				}
			}
		case itemSemiColon:
			if !parsingSetup && !parsingGame {
				parsingSetup = true
			} else {
				if !parsingGame {
					parsingSetup = false
					parsingGame = true
					sgf.gameTree = new(Node)
					currentNode = sgf.gameTree
				} else {
					currentNode = currentNode.NewNode()
				}
			}
		case itemPropertyName:
			prop = Property{i.val, ""}
		case itemPropertyValue:
			prop.value = i.val
			if parsingSetup {
				sgf.AddProperty(prop)
			} else {
				currentNode.AddProperty(prop)
			}
		case itemError:
			sgf.AddError(i.val)
			break Loop
		case itemEOF:
			break Loop
		}
	}
	sgf.showAnyErrors()
	return sgf
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/base64"
	"fmt"
	"strconv"

	// "golang.org/x/net/context"

	pubsub "google.golang.org/api/pubsub/v1"

	log "github.com/Sirupsen/logrus"
)

type ProgressNotificationConfig struct {
	Topic    string `json:"topic"`
	LogLevel string `json:"log_level"`
}

func (c *ProgressNotificationConfig) setup() {
	if c.LogLevel == "" {
		c.LogLevel = log.InfoLevel.String()
	}
}

type ProgressNotification struct {
	config    *ProgressNotificationConfig
	publisher Publisher
	logLevel  log.Level
}

func (pn *ProgressNotification) wrap(msg_id string, step JobStep, f func() error) func() error {
	return func() error {
		pn.notify(msg_id, step, STARTING)
		err := f()
		if err != nil {
			pn.notifyWithMessage(msg_id, step, FAILURE, err.Error())
			return err
		}
		pn.notify(msg_id, step, SUCCESS)
		return nil
	}
}

func (pn *ProgressNotification) notify(job_msg_id string, step JobStep, st JobStepStatus) error {
	msg := fmt.Sprintf("%v %v", step, st)
	return pn.notifyWithMessage(job_msg_id, step, st, msg)
}

func (pn *ProgressNotification) notifyWithMessage(job_msg_id string, step JobStep, st JobStepStatus, msg string) error {
	return pn.notifyProgress(job_msg_id, step.progressFor(st), step.completed(st), step.logLevelFor(st), msg)
}

func (pn *ProgressNotification) notifyProgress(job_msg_id string, progress Progress, completed bool, level log.Level, data string) error {
	// https://godoc.org/github.com/sirupsen/logrus#Level
	// log.InfoLevel < log.DebugLevel => true
	if pn.logLevel < level {
		return nil
	}
	opts := map[string]string{
		"progress":       strconv.Itoa(int(progress)),
		"completed":      strconv.FormatBool(completed),
		"job_message_id": job_msg_id,
		"level":          level.String(),
	}
	logAttrs := log.Fields{}
	for k, v := range opts {
		logAttrs[k] = v
	}
	log.WithFields(logAttrs).Debugln("Publishing notification")
	m := &pubsub.PubsubMessage{Data: base64.StdEncoding.EncodeToString([]byte(data)), Attributes: opts}
	_, err := pn.publisher.Publish(pn.config.Topic, m)
	if err != nil {
		logAttrs["error"] = err
		log.WithFields(logAttrs).Debugln("Failed to publish notification")
		return err
	}
	return nil
}
<commit_msg>:recycle: Rename local variable name<commit_after>package main

import (
	"encoding/base64"
	"fmt"
	"strconv"

	// "golang.org/x/net/context"

	pubsub "google.golang.org/api/pubsub/v1"

	log "github.com/Sirupsen/logrus"
)

type ProgressNotificationConfig struct {
	Topic    string `json:"topic"`
	LogLevel string `json:"log_level"`
}

func (c *ProgressNotificationConfig) setup() {
	if c.LogLevel == "" {
		c.LogLevel = log.InfoLevel.String()
	}
}

type ProgressNotification struct {
	config    *ProgressNotificationConfig
	publisher Publisher
	logLevel  log.Level
}

func (pn *ProgressNotification) wrap(msg_id string, step JobStep, f func() error) func() error {
	return func() error {
		pn.notify(msg_id, step, STARTING)
		err := f()
		if err != nil {
			pn.notifyWithMessage(msg_id, step, FAILURE, err.Error())
			return err
		}
		pn.notify(msg_id, step, SUCCESS)
		return nil
	}
}

func (pn *ProgressNotification) notify(job_msg_id string, step JobStep, st JobStepStatus) error {
	msg := fmt.Sprintf("%v %v", step, st)
	return pn.notifyWithMessage(job_msg_id, step, st, msg)
}

func (pn *ProgressNotification) notifyWithMessage(job_msg_id string, step JobStep, st JobStepStatus, msg string) error {
	return pn.notifyProgress(job_msg_id, step.progressFor(st), step.completed(st), step.logLevelFor(st), msg)
}

func (pn *ProgressNotification) notifyProgress(job_msg_id string, progress Progress, completed bool, level log.Level, data string) error {
	// https://godoc.org/github.com/sirupsen/logrus#Level
	// log.InfoLevel < log.DebugLevel => true
	if pn.logLevel < level {
		return nil
	}
	attrs := map[string]string{
		"progress":       strconv.Itoa(int(progress)),
		"completed":      strconv.FormatBool(completed),
		"job_message_id": job_msg_id,
		"level":          level.String(),
	}
	logAttrs := log.Fields{}
	for k, v := range attrs {
		logAttrs[k] = v
	}
	log.WithFields(logAttrs).Debugln("Publishing notification")
	m := &pubsub.PubsubMessage{Data: base64.StdEncoding.EncodeToString([]byte(data)), Attributes: attrs}
	_, err := pn.publisher.Publish(pn.config.Topic, m)
	if err != nil {
		logAttrs["error"] = err
		log.WithFields(logAttrs).Debugln("Failed to publish notification")
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package parser

type Expr interface {
}

type BinaryExpr struct {
	Op    Token // Add, Sub, Mul, Div, Rem, Pow, And, Or, Equal, NotEqual, Less, Greater
	Left  Expr
	Right Expr
}

type BasicLiteral struct {
	Value interface{} // string, *big.Int, *big.Float
}

type Ident struct {
	Name string
}
<commit_msg>add UnaryExpr, BadExpr<commit_after>package parser

type Expr interface {
}

type BinaryExpr struct {
	Op    Token // Add, Sub, Mul, Div, Rem, Pow, And, Or, Equal, NotEqual, Less, Greater
	Left  Expr
	Right Expr
}

type UnaryExpr struct {
	Op   Token // Not, Mul (deref), Ref, LeftParen
	Expr Expr
}

type BadExpr struct {
	Error error
}

type BasicLiteral struct {
	Value interface{} // string, *big.Int, *big.Float
}

type Ident struct {
	Name string
}
<|endoftext|>


<commit_before>package wellington

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"

	"regexp"
	"testing"
)

var rerandom *regexp.Regexp

var spritePreamble string

func init() {
	rerandom = regexp.MustCompile(`-\w{6}(?:\.(png|jpg))`)
}

func TestParser_importer(t *testing.T) {
	p := Parser{
		BuildDir:   "test/build",
		Includes:   []string{"test/sass"},
		MainFile:   "import.css",
		PartialMap: NewPartialMap(),
		SassDir:    os.Getenv("PWD"),
	}

	bs, err := p.Start(fileReader("test/sass/import.scss"), "test/")
	if err != nil {
		log.Fatal(err)
	}
	output := string(bs)

	file, _ := ioutil.ReadFile("test/expected/import.parser")
	e := string(file)
	if e != output {
		t.Skipf("File output did not match, exp:\n%s\nwas:\n~%s~",
			e, output)
	}

	lines := map[int]string{
		0:  "../../sass/sprite",
		60: "var",
		71: "string",
	}
	errors := false
	for i, v := range lines {
		if v != p.Line[i] {
			t.Errorf("Invalid expected: %s, was: %s", lines[i], p.Line[i])
			errors = true
		}
	}
	if errors {
		fmt.Printf("% #v\n", p.Line)
	}
}

func TestParseSpriteArgs(t *testing.T) {
	p := Parser{PartialMap: NewPartialMap()}
	in := bytes.NewBufferString(`$view_sprite: sprite-map("test/*.png",
  $normal-spacing: 2px,
  $normal-hover-spacing: 2px,
  $selected-spacing: 2px,
  $selected-hover-spacing: 2px);
  @include sprite-dimensions($view_sprite,140);
`)
	e := `$rel: ".";
$view_sprite: (); $view_sprite: map_merge($view_sprite,(139: (width: 96, height: 139, x: 0, y: 0, url: 'test-d01d06.png'))); $view_sprite: map_merge($view_sprite,(140: (width: 96, height: 140, x: 0, y: 139, url: 'test-d01d06.png'))); $view_sprite: map_merge($view_sprite,(pixel: (width: 1, height: 1, x: 0, y: 279, url: 'test-d01d06.png')));
  @include sprite-dimensions($view_sprite,140);
`
	bs, _ := p.Start(in, "")
	out := string(bs)

	if out != e {
		t.Skipf("Mismatch expected:\n%s\nwas:\n%s", e, out)
	}
}

func TestParseInt(t *testing.T) {
	p := Parser{PartialMap: NewPartialMap()}
	var (
		e, res string
	)
	r := bytes.NewBufferString(`p {
  $font-size: 12px;
  $line-height: 30px;
  font: #{$font-size}/#{$line-height};
}`)
	bs, _ := p.Start(r, "")
	res = string(bs)

	e = `$rel: ".";
p {
  $font-size: 12px;
  $line-height: 30px;
  font: #{$font-size}/#{$line-height};
}`
	if e != res {
		t.Skipf("Mismatch expected:\n%s\nwas:\n%s", e, res)
	}
	p = Parser{PartialMap: NewPartialMap()}
	r = bytes.NewBufferString(`$name: foo;
$attr: border;
p.#{$name} {
  #{$attr}-color: blue;
}`)
	bs, _ = p.Start(r, "")
	res = string(bs)

	e = `$rel: ".";
$name: foo;
$attr: border;
p.#{$name} {
  #{$attr}-color: blue;
}`
	if e != res {
		t.Errorf("Mismatch expected:\n%s\nwas:\n%s", e, res)
	}
}

func TestParseImage(t *testing.T) {
	p := Parser{
		BuildDir:   "test/build",
		MainFile:   "test",
		PartialMap: NewPartialMap(),
	}
	in := bytes.NewBufferString(`$sprites: sprite-map("img/*.png");
$sfile: sprite-file($sprites, 139);
div {
    height: image-height(sprite-file($sprites, 139));
    width: image-width(test/139.png);
    url: sprite-file($sprites, 139);
}`)
	bs, _ := p.Start(in, "")
	out := string(bs)

	if e := `$rel: "..";
$sprites: (); $sprites: map_merge($sprites,(139: (width: 96, height: 139, x: 0, y: 0, url: 'img/img-554064.png'))); $sprites: map_merge($sprites,(140: (width: 96, height: 140, x: 0, y: 139, url: 'img/img-554064.png')));
$sfile: sprite-file($sprites, 139);
div {
    height: image-height(sprite-file($sprites, 139));
    width: image-width(test/139.png);
    url: sprite-file($sprites, 139);
}`; e != out {
		t.Skipf("Mismatch expected:\n%s\nwas:\n%s\n", e, out)
	}
}

func TestParseImageUrl(t *testing.T) {

	p := Parser{
		BuildDir:   "test/build",
		MainFile:   "test",
		PartialMap: NewPartialMap(),
	}
	in := bytes.NewBufferString(`background: image-url('test/140.png');`)
	bs, _ := p.Start(in, "")
	out := string(bs)

	if e := `$rel: "..";
background: image-url('test/140.png');`; e != out {
		t.Skipf("mismatch expected:\n%s\nwas:\n%s\n", e, out)
	}
	log.SetOutput(os.Stdout)
}

func TestParseLookupFile(t *testing.T) {

	p := Parser{
		BuildDir: "test/build",
		Includes: []string{"test/sass"},
	}
	in := bytes.NewBufferString(`div {
  background: image-url('test/140.png');
}
p {
  line-height: 2em;
  height: 1px;
}`)
	bs, err := p.Start(in, "")
	if err != nil {
		t.Error(err)
	}
	tmap := [...]string{
		3:  "mixin", // Injected mixin, perhaps we need a better name than top level file
		4:  "mixin",
		5:  "mixin",
		6:  "string:1",
		7:  "string:2",
		8:  "string:3",
		9:  "string:4",
		10: "string:5",
		11: "string:6",
	}

	for i := range tmap {
		if tmap[i] == "" {
			continue
		}
		if s := p.LookupFile(i); s != tmap[i] {
			t.Errorf("%2d got: %s wanted: %s", i, s, tmap[i])
		}
	}
	if t.Failed() {
		fmt.Printf("% #v\n", p.Line)
		lineArr := bytes.Split(bs, []byte("\n"))
		for i := range lineArr {
			fmt.Printf("%2d: %2d: %s\n", i+1-5, i+1, string(lineArr[i]))
		}
	}

}

func TestParser_lookupimport(t *testing.T) {
	p := NewParser()
	p.BuildDir = "test/build"
	p.Includes = []string{"test/sass"}
	p.SassDir = os.Getenv("PWD")

	in := bytes.NewBufferString(`@import "file";
p {
  line-height: 2em;
  height: 1px;
}`)
	bs, err := p.Start(in, "")
	if err != nil {
		t.Error(err)
	}
	tmap := [...]string{
		3: "mixin", // Injected mixin, perhaps we need a better name than top level file
		4: "mixin",
		5: "mixin",
		6: "file:1",
		7: "file:2",
		8: "file:3",
	}

	for i := range tmap {
		if tmap[i] == "" {
			continue
		}
		if s := p.LookupFile(i); s != tmap[i] {
			t.Errorf("%2d got: %s wanted: %s", i, s, tmap[i])
		}
	}

	smap := [...]string{
		9:  "string:2",
		10: "string:3",
		11: "string:4",
		12: "string:5",
	}

	for i := range smap {
		if smap[i] == "" {
			continue
		}
		if s := p.LookupFile(i); s != smap[i] {
			t.Skipf("%2d got: %s wanted: %s", i, s, smap[i])
		}
	}
	if t.Failed() {
		fmt.Printf("% #v\n", p.Line)
		lineArr := bytes.Split(bs, []byte("\n"))
		for i := range lineArr {
			fmt.Printf("%2d: %2d: %s\n", i+1-5, i+1, string(lineArr[i]))
		}
	}
}
<commit_msg>update test<commit_after>package wellington

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"

	"regexp"
	"testing"
)

var rerandom *regexp.Regexp

var spritePreamble string

func init() {
	rerandom = regexp.MustCompile(`-\w{6}(?:\.(png|jpg))`)
}

func TestParser_importer(t *testing.T) {
	p := Parser{
		BuildDir:   "test/build",
		Includes:   []string{"test/sass"},
		MainFile:   "import.css",
		PartialMap: NewPartialMap(),
		SassDir:    os.Getenv("PWD"),
	}

	bs, err := p.Start(fileReader("test/sass/import.scss"), "test/")
	if err != nil {
		log.Fatal(err)
	}
	output := string(bs)

	file, _ := ioutil.ReadFile("test/expected/import.parser")
	e := string(file)
	if e != output {
		t.Skipf("File output did not match, exp:\n%s\nwas:\n~%s~",
			e, output)
	}

	lines := map[int]string{
		0:  "../../sass/sprite",
		60: "var",
		71: "string",
	}
	errors := false
	for i, v := range lines {
		if v != p.Line[i] {
			t.Errorf("Invalid expected: %s, was: %s", lines[i], p.Line[i])
			errors = true
		}
	}
	if errors {
		fmt.Printf("% #v\n", p.Line)
	}
}

func TestParseSpriteArgs(t *testing.T) {
	p := Parser{PartialMap: NewPartialMap()}
	in := bytes.NewBufferString(`$view_sprite: sprite-map("test/*.png",
  $normal-spacing: 2px,
  $normal-hover-spacing: 2px,
  $selected-spacing: 2px,
  $selected-hover-spacing: 2px);
  @include sprite-dimensions($view_sprite,140);
`)
	e := `$rel: ".";
$view_sprite: (); $view_sprite: map_merge($view_sprite,(139: (width: 96, height: 139, x: 0, y: 0, url: 'test-d01d06.png'))); $view_sprite: map_merge($view_sprite,(140: (width: 96, height: 140, x: 0, y: 139, url: 'test-d01d06.png'))); $view_sprite: map_merge($view_sprite,(pixel: (width: 1, height: 1, x: 0, y: 279, url: 'test-d01d06.png')));
  @include sprite-dimensions($view_sprite,140);
`
	bs, _ := p.Start(in, "")
	out := string(bs)

	if out != e {
		t.Skipf("Mismatch expected:\n%s\nwas:\n%s", e, out)
	}
}

func TestParseInt(t *testing.T) {
	p := Parser{PartialMap: NewPartialMap()}
	var (
		e, res string
	)
	r := bytes.NewBufferString(`p {
  $font-size: 12px;
  $line-height: 30px;
  font: #{$font-size}/#{$line-height};
}`)
	bs, _ := p.Start(r, "")
	res = string(bs)

	e = `$rel: ".";
p {
  $font-size: 12px;
  $line-height: 30px;
  font: #{$font-size}/#{$line-height};
}`
	if e != res {
		t.Skipf("Mismatch expected:\n%s\nwas:\n%s", e, res)
	}
	p = Parser{PartialMap: NewPartialMap()}
	r = bytes.NewBufferString(`$name: foo;
$attr: border;
p.#{$name} {
  #{$attr}-color: blue;
}`)
	bs, _ = p.Start(r, "")
	res = string(bs)

	e = `$rel: ".";
$name: foo;
$attr: border;
p.#{$name} {
  #{$attr}-color: blue;
}`
	if e != res {
		t.Errorf("Mismatch expected:\n%s\nwas:\n%s", e, res)
	}
}

func TestParseImage(t *testing.T) {
	p := Parser{
		BuildDir:   "test/build",
		MainFile:   "test",
		PartialMap: NewPartialMap(),
	}
	in := bytes.NewBufferString(`$sprites: sprite-map("img/*.png");
$sfile: sprite-file($sprites, 139);
div {
    height: image-height(sprite-file($sprites, 139));
    width: image-width(test/139.png);
    url: sprite-file($sprites, 139);
}`)
	bs, _ := p.Start(in, "")
	out := string(bs)

	if e := `$rel: "..";
$sprites: (); $sprites: map_merge($sprites,(139: (width: 96, height: 139, x: 0, y: 0, url: 'img/img-554064.png'))); $sprites: map_merge($sprites,(140: (width: 96, height: 140, x: 0, y: 139, url: 'img/img-554064.png')));
$sfile: sprite-file($sprites, 139);
div {
    height: image-height(sprite-file($sprites, 139));
    width: image-width(test/139.png);
    url: sprite-file($sprites, 139);
}`; e != out {
		t.Skipf("Mismatch expected:\n%s\nwas:\n%s\n", e, out)
	}
}

func TestParseImageUrl(t *testing.T) {

	p := Parser{
		BuildDir:   "test/build",
		MainFile:   "test",
		PartialMap: NewPartialMap(),
	}
	in := bytes.NewBufferString(`background: image-url('test/140.png');`)
	bs, _ := p.Start(in, "")
	out := string(bs)

	if e := `$rel: "..";
background: image-url('test/140.png');`; e != out {
		t.Skipf("mismatch expected:\n%s\nwas:\n%s\n", e, out)
	}
	log.SetOutput(os.Stdout)
}

func TestParseLookupFile(t *testing.T) {

	p := Parser{
		BuildDir: "test/build",
		Includes: []string{"test/sass"},
	}
	in := bytes.NewBufferString(`div {
  background: image-url('test/140.png');
}
p {
  line-height: 2em;
  height: 1px;
}`)
	bs, err := p.Start(in, "")
	if err != nil {
		t.Error(err)
	}
	tmap := [...]string{
		3:  "mixin", // Injected mixin, perhaps we need a better name than top level file
		4:  "mixin",
		5:  "mixin",
		6:  "stdin:1",
		7:  "stdin:2",
		8:  "stdin:3",
		9:  "stdin:4",
		10: "stdin:5",
		11: "stdin:6",
	}

	for i := range tmap {
		if tmap[i] == "" {
			continue
		}
		if s := p.LookupFile(i); s != tmap[i] {
			t.Errorf("%2d got: %s wanted: %s", i, s, tmap[i])
		}
	}
	if t.Failed() {
		fmt.Printf("% #v\n", p.Line)
		lineArr := bytes.Split(bs, []byte("\n"))
		for i := range lineArr {
			fmt.Printf("%2d: %2d: %s\n", i+1-5, i+1, string(lineArr[i]))
		}
	}

}

func TestParser_lookupimport(t *testing.T) {
	p := NewParser()
	p.BuildDir = "test/build"
	p.Includes = []string{"test/sass"}
	p.SassDir = os.Getenv("PWD")

	in := bytes.NewBufferString(`@import "file";
p {
  line-height: 2em;
  height: 1px;
}`)
	bs, err := p.Start(in, "")
	if err != nil {
		t.Error(err)
	}
	tmap := [...]string{
		3: "mixin", // Injected mixin, perhaps we need a better name than top level file
		4: "mixin",
		5: "mixin",
		6: "file:1",
		7: "file:2",
		8: "file:3",
	}

	for i := range tmap {
		if tmap[i] == "" {
			continue
		}
		if s := p.LookupFile(i); s != tmap[i] {
			t.Errorf("%2d got: %s wanted: %s", i, s, tmap[i])
		}
	}

	smap := [...]string{
		9:  "string:2",
		10: "string:3",
		11: "string:4",
		12: "string:5",
	}

	for i := range smap {
		if smap[i] == "" {
			continue
		}
		if s := p.LookupFile(i); s != smap[i] {
			t.Skipf("%2d got: %s wanted: %s", i, s, smap[i])
		}
	}
	if t.Failed() {
		fmt.Printf("% #v\n", p.Line)
		lineArr := bytes.Split(bs, []byte("\n"))
		for i := range lineArr {
			fmt.Printf("%2d: %2d: %s\n", i+1-5, i+1, string(lineArr[i]))
		}
	}
}
<|endoftext|>


<commit_before>package pbkdf2

import (
	"bytes"
	"crypto/sha1"
	"crypto/sha256"
	"hash"
	"testing"
)

type testVector struct {
	password string
	salt     string
	iter     int
	output   []byte
}

// Test vectors from RFC 6070, http://tools.ietf.org/html/rfc6070
var sha1TestVectors = []testVector{
	{
		"password",
		"salt",
		1,
		[]byte{0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71, 0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06, 0x2f, 0xe0, 0x37, 0xa6},
	},
	{
		"password",
		"salt",
		2,
		[]byte{0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c, 0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0, 0xd8, 0xde, 0x89, 0x57},
	},
	{
		"password",
		"salt",
		4096,
		[]byte{0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a, 0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0, 0x65, 0xa4, 0x29, 0xc1},
	},
	//// Takes too long:
	//	{
	//		"password",
	//		"salt",
	//		16777216,
	//		[]byte{0xee,0xfe,0x3d,0x61,0xcd,0x4d,0xa4,0xe4,0xe9,0x94,0x5b,0x3d,0x6b,0xa2,0x15,0x8c,0x26,0x34,0xe9,0x84},
	//	},
	{
		"passwordPASSWORDpassword",
		"saltSALTsaltSALTsaltSALTsaltSALTsalt",
		4096,
		[]byte{0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b, 0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a, 0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70, 0x38},
	},
	{
		"pass\000word",
		"sa\000lt",
		4096,
		[]byte{0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d, 0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3},
	},
}

// Test vectors from http://stackoverflow.com/questions/5130513/pbkdf2-hmac-sha2-test-vectors
var sha256TestVectors = []testVector{
	{
		"password",
		"salt",
		1,
		[]byte{0x12,0x0f,0xb6,0xcf,0xfc,0xf8,0xb3,0x2c,0x43,0xe7,0x22,0x52,0x56,0xc4,0xf8,0x37,0xa8,0x65,0x48,0xc9},
	},
	{
		"password",
		"salt",
		2,
		[]byte{0xae,0x4d,0x0c,0x95,0xaf,0x6b,0x46,0xd3,0x2d,0x0a,0xdf,0xf9,0x28,0xf0,0x6d,0xd0,0x2a,0x30,0x3f,0x8e},
	},
	{
		"password",
		"salt",
		4096,
		[]byte{0xc5,0xe4,0x78,0xd5,0x92,0x88,0xc8,0x41,0xaa,0x53,0x0d,0xb6,0x84,0x5c,0x4c,0x8d,0x96,0x28,0x93,0xa0},
	},
	{
		"passwordPASSWORDpassword",
		"saltSALTsaltSALTsaltSALTsaltSALTsalt",
		4096,
		[]byte{0x34,0x8c,0x89,0xdb,0xcb,0xd3,0x2b,0x2f,0x32,0xd8,0x14,0xb8,0x11,0x6e,0x84,0xcf,0x2b,0x17,0x34,0x7e,0xbc,0x18,0x00,0x18,0x1c},
	},
	{
		"pass\000word",
		"sa\000lt",
		4096,
		[]byte{0x89,0xb6,0x9d,0x05,0x16,0xf8,0x29,0x89,0x3c,0x69,0x62,0x26,0x65,0x0a,0x86,0x87},
	},
}

func testWithHash(t *testing.T, hash func() hash.Hash, vectors []testVector) {
	for i, v := range vectors {
		o := WithHMAC(hash, []byte(v.password), []byte(v.salt), v.iter, len(v.output))
		if !bytes.Equal(o, v.output) {
			t.Errorf("%d: expected %x, got %x", i, v.output, o)
		}
	}
}

func TestWithHMAC(t *testing.T) {
	testWithHash(t, sha1.New, sha1TestVectors)
	testWithHash(t, sha256.New, sha256TestVectors)
}
<commit_msg>test: reformat, refactor.<commit_after>package pbkdf2

import (
	"bytes"
	"crypto/sha1"
	"crypto/sha256"
	"hash"
	"testing"
)

type testVector struct {
	password string
	salt     string
	iter     int
	output   []byte
}

// Test vectors from RFC 6070, http://tools.ietf.org/html/rfc6070
var sha1TestVectors = []testVector{
	{
		"password",
		"salt",
		1,
		[]byte{0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71, 0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06, 0x2f, 0xe0, 0x37, 0xa6},
	},
	{
		"password",
		"salt",
		2,
		[]byte{0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c, 0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0, 0xd8, 0xde, 0x89, 0x57},
	},
	{
		"password",
		"salt",
		4096,
		[]byte{0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a, 0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0, 0x65, 0xa4, 0x29, 0xc1},
	},
	//// Takes too long:
	//	{
	//		"password",
	//		"salt",
	//		16777216,
	//		[]byte{0xee,0xfe,0x3d,0x61,0xcd,0x4d,0xa4,0xe4,0xe9,0x94,0x5b,0x3d,0x6b,0xa2,0x15,0x8c,0x26,0x34,0xe9,0x84},
	//	},
	{
		"passwordPASSWORDpassword",
		"saltSALTsaltSALTsaltSALTsaltSALTsalt",
		4096,
		[]byte{0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b, 0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a, 0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70, 0x38},
	},
	{
		"pass\000word",
		"sa\000lt",
		4096,
		[]byte{0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d, 0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3},
	},
}

// Test vectors from http://stackoverflow.com/questions/5130513/pbkdf2-hmac-sha2-test-vectors
var sha256TestVectors = []testVector{
	{
		"password",
		"salt",
		1,
		[]byte{0x12, 0x0f, 0xb6, 0xcf, 0xfc, 0xf8, 0xb3, 0x2c, 0x43, 0xe7, 0x22, 0x52, 0x56, 0xc4, 0xf8, 0x37, 0xa8, 0x65, 0x48, 0xc9},
	},
	{
		"password",
		"salt",
		2,
		[]byte{0xae, 0x4d, 0x0c, 0x95, 0xaf, 0x6b, 0x46, 0xd3, 0x2d, 0x0a, 0xdf, 0xf9, 0x28, 0xf0, 0x6d, 0xd0, 0x2a, 0x30, 0x3f, 0x8e},
	},
	{
		"password",
		"salt",
		4096,
		[]byte{0xc5, 0xe4, 0x78, 0xd5, 0x92, 0x88, 0xc8, 0x41, 0xaa, 0x53, 0x0d, 0xb6, 0x84, 0x5c, 0x4c, 0x8d, 0x96, 0x28, 0x93, 0xa0},
	},
	{
		"passwordPASSWORDpassword",
		"saltSALTsaltSALTsaltSALTsaltSALTsalt",
		4096,
		[]byte{0x34, 0x8c, 0x89, 0xdb, 0xcb, 0xd3, 0x2b, 0x2f, 0x32, 0xd8, 0x14, 0xb8, 0x11, 0x6e, 0x84, 0xcf, 0x2b, 0x17, 0x34, 0x7e, 0xbc, 0x18, 0x00, 0x18, 0x1c},
	},
	{
		"pass\000word",
		"sa\000lt",
		4096,
		[]byte{0x89, 0xb6, 0x9d, 0x05, 0x16, 0xf8, 0x29, 0x89, 0x3c, 0x69, 0x62, 0x26, 0x65, 0x0a, 0x86, 0x87},
	},
}

func testHash(t *testing.T, hash func() hash.Hash, vectors []testVector) {
	for i, v := range vectors {
		o := WithHMAC(hash, []byte(v.password), []byte(v.salt), v.iter, len(v.output))
		if !bytes.Equal(o, v.output) {
			t.Errorf("%d: expected %x, got %x", i, v.output, o)
		}
	}
}

func TestWithHMAC(t *testing.T) {
	testHash(t, sha1.New, sha1TestVectors)
	testHash(t, sha256.New, sha256TestVectors)
}
<|endoftext|>


<commit_before>package pconn

import (
	"log"
	"time"

	"github.com/gorilla/websocket"
	"github.com/msbu-tech/go-pconn/msg"
	"github.com/satori/go.uuid"
)

//连接定义
type Pconn struct {
	rid             string          //请求id
	cuid            string          //uid
	timestamp       int64           //建连时间戳
	closed          bool            //连接是否关闭
	connected       bool            //是否已经建立连接（客户端是否已经发送connect命令）
	hub             *MyHub          //连接所在的HUB
	c               *websocket.Conn //链接的ws指针
	connectedTimer  *time.Timer     //连接计时器，用于关闭超时未发送connect的连接
	connTimeoutChan chan bool
	pushChan chan msg.Message
}

//新建连接，一般由Hub接收到连接请求时发起
func New(h *MyHub, conn *websocket.Conn) *Pconn {
	c := Pconn{
		rid:             uuid.NewV4().String(),
		hub:             h,
		c:               conn,
		timestamp:       time.Now().Unix(),
		closed:          false,
		connected:       false,
		connTimeoutChan: make(chan bool),
		pushChan:        make(chan msg.Message),
	}

	go c.run()

	//设置客户端未连接超时，用于清理建连接后未发请求的连接
	if true {
		c.connectedTimer = time.AfterFunc(10*time.Second, c.connectTimeout)
	}

	return &c
}

//请求主循环，监听ws的消息，和关闭链接的channel
func (c *Pconn) run() {
	var message = msg.Message{}
	for {
		select {
		case <-c.connTimeoutChan:
			if !c.connected && !c.closed {
				c.disconnect()
				log.Printf("connenction timeout, goroutine exit, rid: %s", c.rid)
				return
			}
		case message = <- c.pushChan:
			err := c.push(message.Body)
			if err != nil {
				//todo 失败处理
				log.Println("push error: ", err)
			}
		default:
			_, message, err := c.c.ReadMessage()
			if err != nil {
				log.Println("read:", err)
				c.disconnect()
				return
			}
			//TODO 解包，处理msg
			log.Printf("recv: %s", message)
		}
	}
}

func (c *Pconn) Push(message msg.Message) {
	c.pushChan <- message
}

func (c *Pconn) push(message string) error {
	err := c.c.WriteMessage(websocket.TextMessage, []byte(message))
	if err != nil {
		log.Println("write error:", err)
		return err
	}
	return nil
}

func (c *Pconn) connect() error {
	err := c.hub.AddPconn(c.cuid, c)
	if err != nil {
		log.Println("connect error:", err)
		return err
	}
	c.connected = true
	return nil
}

func (c *Pconn) disconnect() error {
	err := c.c.Close()
	log.Println("close ws connnection")
	if err != nil {
		log.Println("disconnect error[ws close]:", err)
		return err
	}
	err = c.hub.DelPconn(c.cuid)
	if err != nil {
		log.Println("disconnect error[RemoveConn]:", err)
		return err
	}
	c.closed = true

	log.Printf("disconnect link, rid: %s", c.rid)
	return nil
}

func (c *Pconn) connectTimeout() {
	c.connTimeoutChan <- true
	log.Printf("close unconnected link, rid: %s", c.rid)
}
<commit_msg>Push param msg -> string<commit_after>package pconn

import (
	"log"
	"time"

	"github.com/gorilla/websocket"
	"github.com/msbu-tech/go-pconn/msg"
	"github.com/satori/go.uuid"
)

//连接定义
type Pconn struct {
	rid             string          //请求id
	cuid            string          //uid
	timestamp       int64           //建连时间戳
	closed          bool            //连接是否关闭
	connected       bool            //是否已经建立连接（客户端是否已经发送connect命令）
	hub             *MyHub          //连接所在的HUB
	c               *websocket.Conn //链接的ws指针
	connectedTimer  *time.Timer     //连接计时器，用于关闭超时未发送connect的连接
	connTimeoutChan chan bool
	pushChan chan msg.Message
}

//新建连接，一般由Hub接收到连接请求时发起
func New(h *MyHub, conn *websocket.Conn) *Pconn {
	c := Pconn{
		rid:             uuid.NewV4().String(),
		hub:             h,
		c:               conn,
		timestamp:       time.Now().Unix(),
		closed:          false,
		connected:       false,
		connTimeoutChan: make(chan bool),
		pushChan:        make(chan msg.Message),
	}

	go c.run()

	//设置客户端未连接超时，用于清理建连接后未发请求的连接
	if true {
		c.connectedTimer = time.AfterFunc(10*time.Second, c.connectTimeout)
	}

	return &c
}

//请求主循环，监听ws的消息，和关闭链接的channel
func (c *Pconn) run() {
	var message = msg.Message{}
	for {
		select {
		case <-c.connTimeoutChan:
			if !c.connected && !c.closed {
				c.disconnect()
				log.Printf("connenction timeout, goroutine exit, rid: %s", c.rid)
				return
			}
		case message = <- c.pushChan:
			err := c.push(&message)
			if err != nil {
				//todo 失败处理
				log.Println("push error: ", err)
			}
		default:
			_, message, err := c.c.ReadMessage()
			if err != nil {
				log.Println("read:", err)
				c.disconnect()
				return
			}
			//TODO 解包，处理msg
			log.Printf("recv: %s", message)
		}
	}
}

func (c *Pconn) Push(messageStr string) {
	message := msg.Message{Body:messageStr}
	c.pushChan <- message
}

func (c *Pconn) push(message *msg.Message) error {
	messageStr := message.Body
	err := c.c.WriteMessage(websocket.TextMessage, []byte(messageStr))
	if err != nil {
		log.Println("write error:", err)
		return err
	}
	return nil
}

func (c *Pconn) connect() error {
	err := c.hub.AddPconn(c.cuid, c)
	if err != nil {
		log.Println("connect error:", err)
		return err
	}
	c.connected = true
	return nil
}

func (c *Pconn) disconnect() error {
	err := c.c.Close()
	log.Println("close ws connnection")
	if err != nil {
		log.Println("disconnect error[ws close]:", err)
		return err
	}
	err = c.hub.DelPconn(c.cuid)
	if err != nil {
		log.Println("disconnect error[RemoveConn]:", err)
		return err
	}
	c.closed = true

	log.Printf("disconnect link, rid: %s", c.rid)
	return nil
}

func (c *Pconn) connectTimeout() {
	c.connTimeoutChan <- true
	log.Printf("close unconnected link, rid: %s", c.rid)
}
<|endoftext|>


<commit_before>// go-rst - A reStructuredText parser for Go
// 2014 (c) The go-rst Authors
// MIT Licensed. See LICENSE for details.
package parse

import (
	"bufio"
	"bytes"
	"fmt"
	"github.com/demizer/go-elog"
	"github.com/demizer/go-spew/spew"
	"os"
	"strings"
	"testing"
)

var lexTests []lexTest

type lexTest struct {
	name           string
	description    string
	data           string
	items          string
	expect         string
	collectedItems []item
}

var (
	tEOF = item{ElementType: itemEOF, Position: 0, Value: ""}
)

var spd = spew.ConfigState{Indent: "\t"}

func init() {
	log.SetLevel(log.LEVEL_DEBUG)
	log.SetTemplate("{{if .Date}}{{.Date}} {{end}}" +
		"{{if .Prefix}}{{.Prefix}} {{end}}" +
		"{{if .LogLabel}}{{.LogLabel}} {{end}}" +
		"{{if .FileName}}{{.FileName}}: {{end}}" +
		"{{if .FunctionName}}{{.FunctionName}}{{end}}" +
		"{{if .LineNumber}}#{{.LineNumber}}: {{end}}" +
		"{{if .Text}}{{.Text}}{{end}}")
	log.SetFlags(log.Lansi | log.LnoPrefix | log.LfunctionName |
		log.LlineNumber)
}

func parseTestData(t *testing.T, filepath string) ([]lexTest, error) {
	testData, err := os.Open(filepath)
	defer testData.Close()
	if err != nil {
		return nil, err
	}

	var lexTests []lexTest
	var curTest = new(lexTest)
	var buffer bytes.Buffer

	scanner := bufio.NewScanner(testData)

	for scanner.Scan() {
		switch scanner.Text() {
		case "#name":
			// buffer = bytes.NewBuffer(buffer.Bytes())
			// name starts a new section
			if buffer.Len() > 0 {
				// Apend the last section to the array and
				// reset
				curTest.expect = buffer.String()
				lexTests = append(lexTests, *curTest)
			}
			curTest = new(lexTest)
			buffer.Reset()
		case "#description":
			curTest.name = strings.TrimRight(buffer.String(), "\n")
			buffer.Reset()
		case "#data":
			curTest.description = strings.TrimRight(buffer.String(), "\n")
			buffer.Reset()
		case "#items":
			curTest.data = strings.TrimRight(buffer.String(), "\n")
			buffer.Reset()
		case "#expect":
			curTest.items = buffer.String()
			buffer.Reset()
		default:
			// Collect the text in between sections
			buffer.WriteString(fmt.Sprintln(scanner.Text()))
		}
	}

	if err := scanner.Err(); err != nil {
		t.Error(err)
	}

	if buffer.Len() > 0 {
		// Apend the last section to the array and
		curTest.expect = buffer.String()
		lexTests = append(lexTests, *curTest)
	}

	return lexTests, nil
}

// collect gathers the emitted items into a slice.
func collect(t *lexTest) (items []item) {
	l := lex(t.name, t.data)
	for {
		item := l.nextItem()
		items = append(items, item)
		if item.ElementType == itemEOF || item.ElementType == itemError {
			break
		}
	}
	return
}

func runTest(t *testing.T, testName string) []item {
	var err error
	if lexTests == nil {
		lexTests, err = parseTestData(t, "../testdata/test_lex_sections.dat")
		if err != nil {
			t.FailNow()
		}
	}
	for _, test := range lexTests {
		if test.name == testName {
			log.Printf("Test Name: \t%s\n", test.name)
			log.Printf("Description: \t%s\n", test.description)
			log.Printf("Test Input:\n-----------\n%s\n----------\n", test.data)
			items := collect(&test)
			return items
		}
	}
	return nil
}

func TestSectionTitlePara(t *testing.T) {
	items := runTest(t, "SectionTitlePara")
	log.Println("Collected items:\n\n", spd.Sdump(items))
}

func TestSectionTitleParaNoBlankline(t *testing.T) {
	items := runTest(t, "SectionTitleParaNoBlankline")
	log.Println("Collected items:\n\n", spd.Sdump(items))
}

func TestSectionParaHeadPara(t *testing.T) {
	items := runTest(t, "SectionParaHeadPara")
	log.Println("Collected items:\n\n", spd.Sdump(items))
}

func TestSectionUnexpectedTitles(t *testing.T) {
	items := runTest(t, "SectionUnexpectedTitles")
	log.Println("Collected items:\n\n", spd.Sdump(items))
}
<commit_msg>lex_test.go: Change Println to Debugln<commit_after>// go-rst - A reStructuredText parser for Go
// 2014 (c) The go-rst Authors
// MIT Licensed. See LICENSE for details.
package parse

import (
	"bufio"
	"bytes"
	"fmt"
	"github.com/demizer/go-elog"
	"github.com/demizer/go-spew/spew"
	"os"
	"strings"
	"testing"
)

var lexTests []lexTest

type lexTest struct {
	name           string
	description    string
	data           string
	items          string
	expect         string
	collectedItems []item
}

var (
	tEOF = item{ElementType: itemEOF, Position: 0, Value: ""}
)

var spd = spew.ConfigState{Indent: "\t"}

func init() {
	log.SetLevel(log.LEVEL_DEBUG)
	log.SetTemplate("{{if .Date}}{{.Date}} {{end}}" +
		"{{if .Prefix}}{{.Prefix}} {{end}}" +
		"{{if .LogLabel}}{{.LogLabel}} {{end}}" +
		"{{if .FileName}}{{.FileName}}: {{end}}" +
		"{{if .FunctionName}}{{.FunctionName}}{{end}}" +
		"{{if .LineNumber}}#{{.LineNumber}}: {{end}}" +
		"{{if .Text}}{{.Text}}{{end}}")
	log.SetFlags(log.Lansi | log.LnoPrefix | log.LfunctionName |
		log.LlineNumber)
}

func parseTestData(t *testing.T, filepath string) ([]lexTest, error) {
	testData, err := os.Open(filepath)
	defer testData.Close()
	if err != nil {
		return nil, err
	}

	var lexTests []lexTest
	var curTest = new(lexTest)
	var buffer bytes.Buffer

	scanner := bufio.NewScanner(testData)

	for scanner.Scan() {
		switch scanner.Text() {
		case "#name":
			// buffer = bytes.NewBuffer(buffer.Bytes())
			// name starts a new section
			if buffer.Len() > 0 {
				// Apend the last section to the array and
				// reset
				curTest.expect = buffer.String()
				lexTests = append(lexTests, *curTest)
			}
			curTest = new(lexTest)
			buffer.Reset()
		case "#description":
			curTest.name = strings.TrimRight(buffer.String(), "\n")
			buffer.Reset()
		case "#data":
			curTest.description = strings.TrimRight(buffer.String(), "\n")
			buffer.Reset()
		case "#items":
			curTest.data = strings.TrimRight(buffer.String(), "\n")
			buffer.Reset()
		case "#expect":
			curTest.items = buffer.String()
			buffer.Reset()
		default:
			// Collect the text in between sections
			buffer.WriteString(fmt.Sprintln(scanner.Text()))
		}
	}

	if err := scanner.Err(); err != nil {
		t.Error(err)
	}

	if buffer.Len() > 0 {
		// Apend the last section to the array and
		curTest.expect = buffer.String()
		lexTests = append(lexTests, *curTest)
	}

	return lexTests, nil
}

// collect gathers the emitted items into a slice.
func collect(t *lexTest) (items []item) {
	l := lex(t.name, t.data)
	for {
		item := l.nextItem()
		items = append(items, item)
		if item.ElementType == itemEOF || item.ElementType == itemError {
			break
		}
	}
	return
}

func runTest(t *testing.T, testName string) []item {
	var err error
	if lexTests == nil {
		lexTests, err = parseTestData(t, "../testdata/test_lex_sections.dat")
		if err != nil {
			t.FailNow()
		}
	}
	for _, test := range lexTests {
		if test.name == testName {
			log.Debugf("Test Name: \t%s\n", test.name)
			log.Debugf("Description: \t%s\n", test.description)
			log.Debugf("Test Input:\n-----------\n%s\n----------\n", test.data)
			items := collect(&test)
			return items
		}
	}
	return nil
}

func TestSectionTitlePara(t *testing.T) {
	items := runTest(t, "SectionTitlePara")
	log.Debugln("Collected items:\n\n", spd.Sdump(items))
}

func TestSectionTitleParaNoBlankline(t *testing.T) {
	items := runTest(t, "SectionTitleParaNoBlankline")
	log.Debugln("Collected items:\n\n", spd.Sdump(items))
}

func TestSectionParaHeadPara(t *testing.T) {
	items := runTest(t, "SectionParaHeadPara")
	log.Debugln("Collected items:\n\n", spd.Sdump(items))
}

func TestSectionUnexpectedTitles(t *testing.T) {
	items := runTest(t, "SectionUnexpectedTitles")
	log.Debugln("Collected items:\n\n", spd.Sdump(items))
}
<|endoftext|>


<commit_before>/**
 * Copyright 2015 @ z3q.net.
 * name : editor_c.go
 * author : jarryliu
 * date : 2015-08-18 17:09
 * description :
 * history :
 */
package partner

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/jrsix/gof/web"
	"github.com/jrsix/gof/web/mvc"
	"gobx/share/variable"
	"io/ioutil"
	"net/http"
	"os"
	"sort"
	"strconv"
	"strings"
    "time"
    "bufio"
    "io"
	"math/rand"
	"regexp"
)

var _ sort.Interface = new(SorterFiles)

type SorterFiles struct {
	files  []os.FileInfo
	sortBy string
}

func (this *SorterFiles) Len() int {
	return len(this.files)
}

// Less reports whether the element with
// index i should sort before the element with index j.
func (this *SorterFiles) Less(i, j int) bool {
	switch strings.ToLower(this.sortBy) {
	case "size":
		return this.files[i].Size() < this.files[j].Size()
	case "name":
		return this.files[i].Name() < this.files[j].Name()
	case "type":
		iN, jN := this.files[i].Name(), this.files[j].Name()
		return iN[strings.Index(iN, ".")+1:] < jN[strings.Index(jN, ".")+1:]
	}
	return true
}

// Swap swaps the elements with indexes i and j.
func (this *SorterFiles) Swap(i, j int) {
	tmp := this.files[i]
	this.files[i] = this.files[j]
	this.files[j] = tmp
}

//图片扩展名
var imgFileTypes string = "gif,jpg,jpeg,png,bmp"
var (
	moveUpRegexp *regexp.Regexp = regexp.MustCompile("(.*?)[^\\/]+\\/$")
)

// 文件管理
// @rootDir : 根目录路径，相对路径
// @rootUrl : 根目录URL，可以指定绝对路径，比如 http://www.yoursite.com/attached/
func fileManager(r *http.Request, rootDir, rootUrl string) ([]byte, error) {
	var currentPath = ""
	var currentUrl = ""
	var currentDirPath = ""
	var moveUpDirPath = ""
	var dirPath string = rootDir

	urlQuery := r.URL.Query()
	var dirName string = urlQuery.Get("dir")

	if len(dirName) != 0 {
		if dirName == "image" || dirName == "flash" ||
			dirName == "media" || dirName == "file" {
			dirPath += dirName + "/"
			rootUrl += dirName + "/"
			if _, err := os.Stat(dirPath); os.IsNotExist(err) {
				os.MkdirAll(dirPath, os.ModePerm)
			}
		} else {
			return nil, errors.New("Invalid Directory name")
		}
	}

	//根据path参数，设置各路径和URL
	var path string = urlQuery.Get("path")
	if len(path) == 0 {
		currentPath = dirPath
		currentUrl = rootUrl
		currentDirPath = ""
		moveUpDirPath = ""
	} else {
		currentPath = dirPath + path
		currentUrl = rootUrl + path
		currentDirPath = path
		moveUpDirPath = moveUpRegexp.ReplaceAllString(currentDirPath,"$1")
	}

	//不允许使用..移动到上一级目录
	if strings.Index(path, "\\.\\.") != -1 {
		return nil, errors.New("Access is not allowed.")
	}

	//最后一个字符不是/
	if path != "" && !strings.HasSuffix(path, "/") {
		return nil, errors.New("Parameter is not valid.")
	}
	//目录不存在或不是目录
	dir, err := os.Stat(currentPath)
	if os.IsNotExist(err) || !dir.IsDir() {
		return nil, errors.New("no such directory or file not directory,path:" + currentPath)
	}

	//排序形式，name or size or type
	var order string = strings.ToLower(urlQuery.Get("order"))

	//遍历目录取得文件信息
	var dirList *SorterFiles = &SorterFiles{
		files:  []os.FileInfo{},
		sortBy: order,
	}
	var fileList *SorterFiles = &SorterFiles{
		files:  []os.FileInfo{},
		sortBy: order,
	}

	// 遍历目录获取子目录和文件
	files, err := ioutil.ReadDir(currentPath)
	if err != nil {
		return nil, err
	}
	for _, v := range files {
		if v.IsDir() {
			dirList.files = append(dirList.files, v)
		} else {
			fileList.files = append(fileList.files, v)
		}
	}

	// 排序
	sort.Sort(dirList)
	sort.Sort(fileList)

	var result = make(map[string]interface{})
	result["moveup_dir_path"] = moveUpDirPath
	result["current_dir_path"] = currentDirPath
	result["current_url"] = currentUrl
	result["total_count"] = dirList.Len() + fileList.Len()
	var dirFileList = []map[string]interface{}{}
	for i := 0; i < dirList.Len(); i++ {
		hash := make(map[string]interface{})
		fs, _ := ioutil.ReadDir(currentPath + "/" + dirList.files[i].Name())
		fmt.Println("----",currentPath + "/" + dirList.files[i].Name())
		hash["is_dir"] = true
		hash["has_file"] = len(fs) > 0
		hash["is_photo"] = false
		hash["filetype"] = ""
		hash["filename"] = dirList.files[i].Name()
		hash["datetime"] = dirList.files[i].ModTime().Format("2006-01-02 15:04:05")
		dirFileList = append(dirFileList, hash)
	}

	var fN, ext string
	for i := 0; i < fileList.Len(); i++ {
		hash := make(map[string]interface{})
		fN = fileList.files[i].Name()
		ext = fN[strings.Index(fN, ".")+1:]
		hash["is_dir"] = false
		hash["has_file"] = false
		hash["filesize"] = fileList.files[i].Size()
		hash["is_photo"] = strings.Index(imgFileTypes, ext)
		hash["filetype"] = ext
		hash["filename"] = fN
		hash["datetime"] = fileList.files[i].ModTime().Format("2006-01-02 15:04:05")
		dirFileList = append(dirFileList, hash)
	}

	result["file_list"] = dirFileList
	return json.Marshal(result)
}

// 文件上传
func fileUpload(r *http.Request, savePath, rootPath string) (fileUrl string,err error) {

    //定义允许上传的文件扩展名
    var extTable map[string]string = map[string]string{
        "image": "gif,jpg,jpeg,png,bmp",
        "flash": "swf,flv",
        "media": "swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb",
        "file":  "doc,docx,xls,xlsx,ppt,htm,html,txt,zip,rar,gz,bz2,7z,pdf",
    }

    //最大文件大小
    const maxSize int64 = 1000000

    // 取得上传文件
    r.ParseMultipartForm(maxSize)
    f, header, err := r.FormFile("imgFile")
    if f == nil {
        return "", errors.New("no such upload file")
    }
    if err != nil {
        return "", err
    }

    var fileName string = header.Filename
    var fileExt string = strings.ToLower(fileName[strings.Index(fileName, ".")+1:])

    // 检查上传目录
    var dirPath string = rootPath
    var dirName string = r.URL.Query().Get("dir")
    if len(dirName) == 0 {
        dirName = "image"
    }
    if _, ok := extTable[dirName]; !ok {
        return "", errors.New("incorrent file type")
    }

    // 检查扩展名
    if strings.Index(extTable[dirName], fileExt) == -1 &&
    !strings.HasSuffix(extTable[dirName], fileExt) {
        return "", errors.New("上传文件扩展名是不允许的扩展名。\n只允许" + extTable[dirName] + "格式。")
    }

    // 检查上传超出文件大小
    if i, _ := strconv.Atoi(header.Header.Get("Content-Length")); int64(i) > maxSize {
        return "", errors.New("上传文件大小超过限制。")
    }

    //创建文件夹
    dirPath += dirName + "/";
    savePath += dirName + "/";

    var now = time.Now()
    var ymd string = now.Format("200601")
    dirPath += ymd + "/";
    savePath += ymd + "/";

    if _,err := os.Stat(savePath);os.IsNotExist(err){
        os.MkdirAll(savePath,os.ModePerm)
    }

    var newFileName string = fmt.Sprintf("%d_%d.%s", now.Unix(),
		100+rand.Intn(899), fileExt)
    var filePath string = savePath + newFileName;

    fi, err := os.OpenFile(filePath,
        os.O_CREATE|os.O_TRUNC|os.O_WRONLY,
        os.ModePerm)

    if err == nil {
        buf := bufio.NewWriter(fi)
        bufSize := 100
        buffer := make([]byte, bufSize)
        var n int
        var leng int
        for {
            if n, err = f.Read(buffer); err == io.EOF {
                break
            }

            if n != bufSize {
                buf.Write(buffer[:n])
            } else {
                buf.Write(buffer)
            }

            leng += n
        }
    }

    return dirPath + newFileName, nil
}

var _ mvc.Filter = new(editorC)

type editorC struct {
	*baseC
}

func (this *editorC) File_manager(ctx *web.Context) {
	partnerId := this.GetPartnerId(ctx)
	d, err := fileManager(ctx.Request,
		fmt.Sprintf("./static/uploads/%d/upload/", partnerId),
		fmt.Sprintf("%s/%d/upload/", ctx.App.Config().GetString(variable.ImageServer), partnerId),
	)
	ctx.Response.Header().Add("Content-Type", "application/json")
	if err != nil {
		ctx.Response.Write([]byte("{error:'" + strings.Replace(err.Error(), "'", "\\'", -1) + "'}"))
	} else {
		ctx.Response.Write(d)
	}
}

func (this *editorC) File_upload_post(ctx *web.Context) {
    partnerId := this.GetPartnerId(ctx)
    fileUrl, err := fileUpload(ctx.Request,
        fmt.Sprintf("./static/uploads/%d/upload/", partnerId),
        fmt.Sprintf("%s/%d/upload/", ctx.App.Config().GetString(variable.ImageServer), partnerId),
    )
    var hash map[string]interface{} = make(map[string]interface{})
    if err == nil {
        hash["error"] = 0;
        hash["url"] = fileUrl;
    }else {
        hash["error"] = 1
        hash["message"] = err.Error()
    }
    ctx.Response.Header().Add("Content-Type", "application/json")
    d, _ := json.Marshal(hash)
    ctx.Response.Write(d)
}
<commit_msg>commit<commit_after>/**
 * Copyright 2015 @ z3q.net.
 * name : editor_c.go
 * author : jarryliu
 * date : 2015-08-18 17:09
 * description :
 * history :
 */
package partner

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/jrsix/gof/web"
	"github.com/jrsix/gof/web/mvc"
	"gobx/share/variable"
	"io/ioutil"
	"net/http"
	"os"
	"sort"
	"strconv"
	"strings"
    "time"
    "bufio"
    "io"
	"math/rand"
	"regexp"
)

var _ sort.Interface = new(SorterFiles)

type SorterFiles struct {
	files  []os.FileInfo
	sortBy string
}

func (this *SorterFiles) Len() int {
	return len(this.files)
}

// Less reports whether the element with
// index i should sort before the element with index j.
func (this *SorterFiles) Less(i, j int) bool {
	switch strings.ToLower(this.sortBy) {
	case "size":
		return this.files[i].Size() < this.files[j].Size()
	case "name":
		return this.files[i].Name() < this.files[j].Name()
	case "type":
		iN, jN := this.files[i].Name(), this.files[j].Name()
		return iN[strings.Index(iN, ".")+1:] < jN[strings.Index(jN, ".")+1:]
	}
	return true
}

// Swap swaps the elements with indexes i and j.
func (this *SorterFiles) Swap(i, j int) {
	tmp := this.files[i]
	this.files[i] = this.files[j]
	this.files[j] = tmp
}

//图片扩展名
var imgFileTypes string = "gif,jpg,jpeg,png,bmp"
var (
	moveUpRegexp *regexp.Regexp = regexp.MustCompile("(.*?)[^\\/]+\\/$")
)

// 文件管理
// @rootDir : 根目录路径，相对路径
// @rootUrl : 根目录URL，可以指定绝对路径，比如 http://www.yoursite.com/attached/
func fileManager(r *http.Request, rootDir, rootUrl string) ([]byte, error) {
	var currentPath = ""
	var currentUrl = ""
	var currentDirPath = ""
	var moveUpDirPath = ""
	var dirPath string = rootDir

	urlQuery := r.URL.Query()
	var dirName string = urlQuery.Get("dir")

	if len(dirName) != 0 {
		if dirName == "image" || dirName == "flash" ||
			dirName == "media" || dirName == "file" {
			dirPath += dirName + "/"
			rootUrl += dirName + "/"
			if _, err := os.Stat(dirPath); os.IsNotExist(err) {
				os.MkdirAll(dirPath, os.ModePerm)
			}
		} else {
			return nil, errors.New("Invalid Directory name")
		}
	}

	//根据path参数，设置各路径和URL
	var path string = urlQuery.Get("path")
	if len(path) == 0 {
		currentPath = dirPath
		currentUrl = rootUrl
		currentDirPath = ""
		moveUpDirPath = ""
	} else {
		currentPath = dirPath + path
		currentUrl = rootUrl + path
		currentDirPath = path
		moveUpDirPath = moveUpRegexp.ReplaceAllString(currentDirPath,"$1")
	}

	//不允许使用..移动到上一级目录
	if strings.Index(path, "\\.\\.") != -1 {
		return nil, errors.New("Access is not allowed.")
	}

	//最后一个字符不是/
	if path != "" && !strings.HasSuffix(path, "/") {
		return nil, errors.New("Parameter is not valid.")
	}
	//目录不存在或不是目录
	dir, err := os.Stat(currentPath)
	if os.IsNotExist(err) || !dir.IsDir() {
		return nil, errors.New("no such directory or file not directory,path:" + currentPath)
	}

	//排序形式，name or size or type
	var order string = strings.ToLower(urlQuery.Get("order"))

	//遍历目录取得文件信息
	var dirList *SorterFiles = &SorterFiles{
		files:  []os.FileInfo{},
		sortBy: order,
	}
	var fileList *SorterFiles = &SorterFiles{
		files:  []os.FileInfo{},
		sortBy: order,
	}

	// 遍历目录获取子目录和文件
	files, err := ioutil.ReadDir(currentPath)
	if err != nil {
		return nil, err
	}
	for _, v := range files {
		if v.IsDir() {
			dirList.files = append(dirList.files, v)
		} else {
			fileList.files = append(fileList.files, v)
		}
	}

	// 排序
	sort.Sort(dirList)
	sort.Sort(fileList)

	var result = make(map[string]interface{})
	result["moveup_dir_path"] = moveUpDirPath
	result["current_dir_path"] = currentDirPath
	result["current_url"] = currentUrl
	result["total_count"] = dirList.Len() + fileList.Len()
	var dirFileList = []map[string]interface{}{}
	for i := 0; i < dirList.Len(); i++ {
		hash := make(map[string]interface{})
		fs, _ := ioutil.ReadDir(currentPath + "/" + dirList.files[i].Name())
		fmt.Println("----",currentPath + "/" + dirList.files[i].Name())
		hash["is_dir"] = true
		hash["has_file"] = len(fs) > 0
		hash["is_photo"] = false
		hash["filetype"] = ""
		hash["filename"] = dirList.files[i].Name()
		hash["datetime"] = dirList.files[i].ModTime().Format("2006-01-02 15:04:05")
		dirFileList = append(dirFileList, hash)
	}

	var fN, ext string
	for i := 0; i < fileList.Len(); i++ {
		hash := make(map[string]interface{})
		fN = fileList.files[i].Name()
		ext = fN[strings.Index(fN, ".")+1:]
		hash["is_dir"] = false
		hash["has_file"] = false
		hash["filesize"] = fileList.files[i].Size()
		hash["is_photo"] = strings.Index(imgFileTypes, ext)
		hash["filetype"] = ext
		hash["filename"] = fN
		hash["datetime"] = fileList.files[i].ModTime().Format("2006-01-02 15:04:05")
		dirFileList = append(dirFileList, hash)
	}

	result["file_list"] = dirFileList
	return json.Marshal(result)
}

// 文件上传
func fileUpload(r *http.Request, savePath, rootPath string) (fileUrl string,err error) {

    //定义允许上传的文件扩展名
    var extTable map[string]string = map[string]string{
        "image": "gif,jpg,jpeg,png,bmp",
        "flash": "swf,flv",
        "media": "swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb",
        "file":  "doc,docx,xls,xlsx,ppt,htm,html,txt,zip,rar,gz,bz2,7z,pdf",
    }

    //最大文件大小
    const maxSize int64 = 1000000

    // 取得上传文件
    r.ParseMultipartForm(maxSize)
    f, header, err := r.FormFile("imgFile")
    if f == nil {
        return "", errors.New("no such upload file")
    }
    if err != nil {
        return "", err
    }

    var fileName string = header.Filename
    var fileExt string = strings.ToLower(fileName[strings.Index(fileName, ".")+1:])

    // 检查上传目录
    var dirPath string = rootPath
    var dirName string = r.URL.Query().Get("dir")
    if len(dirName) == 0 {
        dirName = "image"
    }
    if _, ok := extTable[dirName]; !ok {
        return "", errors.New("incorrent file type")
    }

    // 检查扩展名
    if strings.Index(extTable[dirName], fileExt) == -1 &&
    !strings.HasSuffix(extTable[dirName], fileExt) {
        return "", errors.New("上传文件扩展名是不允许的扩展名。\n只允许" + extTable[dirName] + "格式。")
    }

    // 检查上传超出文件大小
    if i, _ := strconv.Atoi(header.Header.Get("Content-Length")); int64(i) > maxSize {
        return "", errors.New("上传文件大小超过限制。")
    }

    //创建文件夹
    dirPath += dirName + "/";
    savePath += dirName + "/";

    var now = time.Now()
    var ymd string = now.Format("200601")
    dirPath += ymd + "/";
    savePath += ymd + "/";

    if _,err := os.Stat(savePath);os.IsNotExist(err){
        os.MkdirAll(savePath,os.ModePerm)
    }

    var newFileName string = fmt.Sprintf("%d_%d.%s", now.Unix(),
		100+rand.Intn(899), fileExt)
    var filePath string = savePath + newFileName;

    fi, err := os.OpenFile(filePath,
        os.O_CREATE|os.O_TRUNC|os.O_WRONLY,
        os.ModePerm)

    if err == nil {
        buf := bufio.NewWriter(fi)
        bufSize := 100
        buffer := make([]byte, bufSize)
        var n int
        var leng int
        for {
            if n, err = f.Read(buffer); err == io.EOF {
                break
            }

            if n != bufSize {
                buf.Write(buffer[:n])
            } else {
                buf.Write(buffer)
            }

            leng += n
        }
    }

    return dirPath + newFileName, nil
}

var _ mvc.Filter = new(editorC)

type editorC struct {
	*baseC
}

func (this *editorC) File_manager(ctx *web.Context) {
	partnerId := this.GetPartnerId(ctx)
	d, err := fileManager(ctx.Request,
		fmt.Sprintf("./static/uploads/%d/upload/", partnerId),
		fmt.Sprintf("%s/%d/upload/", ctx.App.Config().GetString(variable.ImageServer), partnerId),
	)
	ctx.Response.Header().Add("Content-Type", "application/json")
	if err != nil {
		ctx.Response.Write([]byte("{error:'" + strings.Replace(err.Error(), "'", "\\'", -1) + "'}"))
	} else {
		ctx.Response.Write(d)
	}
}

func (this *editorC) File_upload_post(ctx *web.Context) {
    partnerId := this.GetPartnerId(ctx)
    fileUrl, err := fileUpload(ctx.Request,
        fmt.Sprintf("./static/uploads/%d/upload/", partnerId),
        fmt.Sprintf("%s/%d/upload/", ctx.App.Config().GetString(variable.ImageServer), partnerId),
    )
    var hash map[string]interface{} = make(map[string]interface{})
    if err == nil {
        hash["error"] = 0;
        hash["url"] = fileUrl;
    }else {
        hash["error"] = 1
        hash["message"] = err.Error()
    }
    ctx.Response.Header().Add("Content-Type", "application/json")
    d, _ := json.Marshal(hash)
    ctx.Response.Write(d)
}
<|endoftext|>


<commit_before>// Copyright 2013 tsuru 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 juju

import (
	"bufio"
	"fmt"
	"github.com/globocom/tsuru/heal"
	"github.com/globocom/tsuru/log"
	"net"
	"os/exec"
	"strings"
)

func init() {
	heal.Register("bootstrap", &BootstrapMachineHealer{})
	heal.Register("bootstrap-provision", &BootstrapProvisionHealer{})
	heal.Register("instance-machine", &InstanceMachineHealer{})
	heal.Register("instance-unit", &InstanceUnitHealer{})
	heal.Register("zookeeper", &ZookeeperHealer{})
}

// InstanceUnitHealer is an implementation for the Healer interface. For more
// detail on how a healer work, check the documentation of the heal package.
type InstanceUnitHealer struct{}

func (h *InstanceUnitHealer) Heal() error {
	p := JujuProvisioner{}
	output, _ := p.getOutput()
	for _, service := range output.Services {
		for unitName, unit := range service.Units {
			agent := fmt.Sprintf("juju-%s", strings.Join(strings.Split(unitName, "/"), "-"))
			if unit.AgentState == "down" {
				log.Printf("Healing %s", agent)
				upStartCmd("stop", agent, unit.PublicAddress)
				upStartCmd("start", agent, unit.PublicAddress)
			} else {
				log.Printf("%s needs no cure, skipping...", agent)
			}
		}
	}
	return nil
}

// InstanceMachineHealer is an implementation for the Healer interface. For more
// detail on how a healer work, check the documentation of the heal package.
type InstanceMachineHealer struct{}

// Heal iterates through all juju machines verifying if
// a juju-machine-agent is down and heal these machines.
func (h *InstanceMachineHealer) Heal() error {
	p := JujuProvisioner{}
	output, _ := p.getOutput()
	for _, machine := range output.Machines {
		if machine.AgentState == "down" {
			log.Printf("Healing juju-machine-agent in machine %s", machine.InstanceId)
			upStartCmd("stop", "juju-machine-agent", machine.IpAddress)
			upStartCmd("start", "juju-machine-agent", machine.IpAddress)
		} else {
			log.Printf("juju-machine-agent for machine %s needs no cure, skipping...", machine.InstanceId)
		}
	}
	return nil
}

// ZookeeperHealer is an implementation for the Healer interface. For more
// detail on how a healer work, check the documentation of the heal package.
type ZookeeperHealer struct{}

// needsHeal verifies if zookeeper is ok using 'ruok' command.
func (h *ZookeeperHealer) needsHeal() bool {
	bootstrapMachine := getBootstrapMachine()
	conn, err := net.Dial("tcp", fmt.Sprintf("%s:2181", bootstrapMachine.IpAddress))
	if err != nil {
		return true
	}
	defer conn.Close()
	fmt.Fprintf(conn, "ruok\r\n\r\n")
	status, _ := bufio.NewReader(conn).ReadString('\n')
	return !strings.Contains(status, "imok")
}

// Heal restarts the zookeeper using upstart.
func (h *ZookeeperHealer) Heal() error {
	if h.needsHeal() {
		bootstrapMachine := getBootstrapMachine()
		log.Printf("Healing zookeeper")
		upStartCmd("stop", "zookeeper", bootstrapMachine.IpAddress)
		return upStartCmd("start", "zookeeper", bootstrapMachine.IpAddress)
	}
	log.Printf("Zookeeper needs no cure, skipping...")
	return nil
}

// BootstrapProvisionHealer is an import for the Healer interface. For more
// details on how a healer work, check the documentation of the heal package.
type BootstrapProvisionHealer struct{}

// Heal starts the juju-provision-agent using upstart.
func (h *BootstrapProvisionHealer) Heal() error {
	bootstrapMachine := getBootstrapMachine()
	log.Printf("Healing bootstrap juju-provision-agent")
	return upStartCmd("start", "juju-provision-agent", bootstrapMachine.IpAddress)
}

// BootstrapMachineHealer is an implementation for the Healer interface. For more
// details on how a healer work, check the documentation of the heal package.
type BootstrapMachineHealer struct{}

// getBootstrapMachine returns the bootstrap machine.
func getBootstrapMachine() machine {
	p := JujuProvisioner{}
	output, _ := p.getOutput()
	// for juju bootstrap machine always is the machine 0.
	return output.Machines[0]
}

// needsHeal returns true if the AgentState of bootstrap machine is "not-started".
func (h *BootstrapMachineHealer) needsHeal() bool {
	bootstrapMachine := getBootstrapMachine()
	return bootstrapMachine.AgentState == "not-started"
}

func upStartCmd(cmd, daemon, machine string) error {
	args := []string{
		"-o",
		"StrictHostKeyChecking no",
		"-q",
		"-l",
		"ubuntu",
		machine,
		"sudo",
		cmd,
		daemon,
	}
	log.Printf(strings.Join(args, " "))
	c := exec.Command("ssh", args...)
	return c.Run()
}

// Heal executes the action for heal the bootstrap machine agent.
func (h *BootstrapMachineHealer) Heal() error {
	if h.needsHeal() {
		bootstrapMachine := getBootstrapMachine()
		log.Printf("Healing bootstrap juju-machine-agent")
		upStartCmd("stop", "juju-machine-agent", bootstrapMachine.IpAddress)
		return upStartCmd("start", "juju-machine-agent", bootstrapMachine.IpAddress)
	}
	log.Printf("Bootstrap juju-machine-agent needs no cure, skipping...")
	return nil
}
<commit_msg>Added a comment for instance unit heal.<commit_after>// Copyright 2013 tsuru 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 juju

import (
	"bufio"
	"fmt"
	"github.com/globocom/tsuru/heal"
	"github.com/globocom/tsuru/log"
	"net"
	"os/exec"
	"strings"
)

func init() {
	heal.Register("bootstrap", &BootstrapMachineHealer{})
	heal.Register("bootstrap-provision", &BootstrapProvisionHealer{})
	heal.Register("instance-machine", &InstanceMachineHealer{})
	heal.Register("instance-unit", &InstanceUnitHealer{})
	heal.Register("zookeeper", &ZookeeperHealer{})
}

// InstanceUnitHealer is an implementation for the Healer interface. For more
// detail on how a healer work, check the documentation of the heal package.
type InstanceUnitHealer struct{}

// Heal iterates through all juju units verifying if
// a juju-unit-agent is down and heal these machines.
func (h *InstanceUnitHealer) Heal() error {
	p := JujuProvisioner{}
	output, _ := p.getOutput()
	for _, service := range output.Services {
		for unitName, unit := range service.Units {
			agent := fmt.Sprintf("juju-%s", strings.Join(strings.Split(unitName, "/"), "-"))
			if unit.AgentState == "down" {
				log.Printf("Healing %s", agent)
				upStartCmd("stop", agent, unit.PublicAddress)
				upStartCmd("start", agent, unit.PublicAddress)
			} else {
				log.Printf("%s needs no cure, skipping...", agent)
			}
		}
	}
	return nil
}

// InstanceMachineHealer is an implementation for the Healer interface. For more
// detail on how a healer work, check the documentation of the heal package.
type InstanceMachineHealer struct{}

// Heal iterates through all juju machines verifying if
// a juju-machine-agent is down and heal these machines.
func (h *InstanceMachineHealer) Heal() error {
	p := JujuProvisioner{}
	output, _ := p.getOutput()
	for _, machine := range output.Machines {
		if machine.AgentState == "down" {
			log.Printf("Healing juju-machine-agent in machine %s", machine.InstanceId)
			upStartCmd("stop", "juju-machine-agent", machine.IpAddress)
			upStartCmd("start", "juju-machine-agent", machine.IpAddress)
		} else {
			log.Printf("juju-machine-agent for machine %s needs no cure, skipping...", machine.InstanceId)
		}
	}
	return nil
}

// ZookeeperHealer is an implementation for the Healer interface. For more
// detail on how a healer work, check the documentation of the heal package.
type ZookeeperHealer struct{}

// needsHeal verifies if zookeeper is ok using 'ruok' command.
func (h *ZookeeperHealer) needsHeal() bool {
	bootstrapMachine := getBootstrapMachine()
	conn, err := net.Dial("tcp", fmt.Sprintf("%s:2181", bootstrapMachine.IpAddress))
	if err != nil {
		return true
	}
	defer conn.Close()
	fmt.Fprintf(conn, "ruok\r\n\r\n")
	status, _ := bufio.NewReader(conn).ReadString('\n')
	return !strings.Contains(status, "imok")
}

// Heal restarts the zookeeper using upstart.
func (h *ZookeeperHealer) Heal() error {
	if h.needsHeal() {
		bootstrapMachine := getBootstrapMachine()
		log.Printf("Healing zookeeper")
		upStartCmd("stop", "zookeeper", bootstrapMachine.IpAddress)
		return upStartCmd("start", "zookeeper", bootstrapMachine.IpAddress)
	}
	log.Printf("Zookeeper needs no cure, skipping...")
	return nil
}

// BootstrapProvisionHealer is an import for the Healer interface. For more
// details on how a healer work, check the documentation of the heal package.
type BootstrapProvisionHealer struct{}

// Heal starts the juju-provision-agent using upstart.
func (h *BootstrapProvisionHealer) Heal() error {
	bootstrapMachine := getBootstrapMachine()
	log.Printf("Healing bootstrap juju-provision-agent")
	return upStartCmd("start", "juju-provision-agent", bootstrapMachine.IpAddress)
}

// BootstrapMachineHealer is an implementation for the Healer interface. For more
// details on how a healer work, check the documentation of the heal package.
type BootstrapMachineHealer struct{}

// getBootstrapMachine returns the bootstrap machine.
func getBootstrapMachine() machine {
	p := JujuProvisioner{}
	output, _ := p.getOutput()
	// for juju bootstrap machine always is the machine 0.
	return output.Machines[0]
}

// needsHeal returns true if the AgentState of bootstrap machine is "not-started".
func (h *BootstrapMachineHealer) needsHeal() bool {
	bootstrapMachine := getBootstrapMachine()
	return bootstrapMachine.AgentState == "not-started"
}

func upStartCmd(cmd, daemon, machine string) error {
	args := []string{
		"-o",
		"StrictHostKeyChecking no",
		"-q",
		"-l",
		"ubuntu",
		machine,
		"sudo",
		cmd,
		daemon,
	}
	log.Printf(strings.Join(args, " "))
	c := exec.Command("ssh", args...)
	return c.Run()
}

// Heal executes the action for heal the bootstrap machine agent.
func (h *BootstrapMachineHealer) Heal() error {
	if h.needsHeal() {
		bootstrapMachine := getBootstrapMachine()
		log.Printf("Healing bootstrap juju-machine-agent")
		upStartCmd("stop", "juju-machine-agent", bootstrapMachine.IpAddress)
		return upStartCmd("start", "juju-machine-agent", bootstrapMachine.IpAddress)
	}
	log.Printf("Bootstrap juju-machine-agent needs no cure, skipping...")
	return nil
}
<|endoftext|>