<commit_before>package konnectors

import (
	"archive/tar"
	"bufio"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path"
	"runtime"
	"time"

	"github.com/cozy/cozy-stack/pkg/apps"
	"github.com/cozy/cozy-stack/pkg/config"
	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/cozy/cozy-stack/pkg/couchdb"
	"github.com/cozy/cozy-stack/pkg/instance"
	"github.com/cozy/cozy-stack/pkg/jobs"
	"github.com/cozy/cozy-stack/pkg/logger"
	"github.com/cozy/cozy-stack/pkg/realtime"
	"github.com/sirupsen/logrus"

	"github.com/spf13/afero"
)

func init() {
	jobs.AddWorker("konnector", &jobs.WorkerConfig{
		Concurrency:  runtime.NumCPU() * 2,
		MaxExecCount: 2,
		MaxExecTime:  200 * time.Second,
		Timeout:      200 * time.Second,
		WorkerFunc:   Worker,
		WorkerCommit: commit,
	})
}

// Options contains the options to execute a konnector.
type Options struct {
	Konnector    string `json:"konnector"`
	Account      string `json:"account"`
	FolderToSave string `json:"folder_to_save"`
}

// result stores the result of a konnector execution.
type result struct {
	DocID       string         `json:"_id,omitempty"`
	DocRev      string         `json:"_rev,omitempty"`
	CreatedAt   time.Time      `json:"last_execution"`
	LastSuccess time.Time      `json:"last_success"`
	Logs        []konnectorMsg `json:"logs"`
	Account     string         `json:"account"`
	State       string         `json:"state"`
	Error       string         `json:"error"`
}

func (r *result) ID() string         { return r.DocID }
func (r *result) Rev() string        { return r.DocRev }
func (r *result) DocType() string    { return consts.KonnectorResults }
func (r *result) Clone() couchdb.Doc { c := *r; return &c }
func (r *result) SetID(id string)    { r.DocID = id }
func (r *result) SetRev(rev string)  { r.DocRev = rev }

const konnectorMsgTypeError string = "error"

// const konnectorMsgTypeDebug string = "debug"
// const konnectorMsgTypeWarning string = "warning"
// const konnectorMsgTypeProgress string = "progress"

type konnectorMsg struct {
	Type    string `json:"type"`
	Message string `json:"message"`
}

type konnectorLogs struct {
	Slug     string         `json:"_id,omitempty"`
	DocRev   string         `json:"_rev,omitempty"`
	Messages []konnectorMsg `json:"logs"`
}

func (kl *konnectorLogs) ID() string         { return kl.Slug }
func (kl *konnectorLogs) Rev() string        { return kl.DocRev }
func (kl *konnectorLogs) DocType() string    { return consts.KonnectorLogs }
func (kl *konnectorLogs) Clone() couchdb.Doc { c := *kl; return &c }
func (kl *konnectorLogs) SetID(id string)    {}
func (kl *konnectorLogs) SetRev(rev string)  { kl.DocRev = rev }

// Worker is the worker that runs a konnector by executing an external process.
func Worker(ctx context.Context, m *jobs.Message) error {
	opts := &Options{}
	if err := m.Unmarshal(&opts); err != nil {
		return err
	}

	slug := opts.Konnector
	fields := struct {
		Account      string `json:"account"`
		FolderToSave string `json:"folder_to_save"`
	}{
		Account:      opts.Account,
		FolderToSave: opts.FolderToSave,
	}
	domain := ctx.Value(jobs.ContextDomainKey).(string)
	worker := ctx.Value(jobs.ContextWorkerKey).(string)
	jobID := fmt.Sprintf("%s/%s/%s", worker, slug, domain)

	inst, err := instance.Get(domain)
	if err != nil {
		return err
	}

	man, err := apps.GetKonnectorBySlug(inst, slug)
	if err != nil {
		return err
	}
	if man.State() != apps.Ready {
		return errors.New("Konnector is not ready")
	}

	token := inst.BuildKonnectorToken(man)

	osFS := afero.NewOsFs()
	workDir, err := afero.TempDir(osFS, "", "konnector-"+slug)
	if err != nil {
		return err
	}
	defer osFS.RemoveAll(workDir)
	workFS := afero.NewBasePathFs(osFS, workDir)

	fileServer := inst.KonnectorsFileServer()
	tarFile, err := fileServer.Open(slug, man.Version(), apps.KonnectorArchiveName)
	if err != nil {
		return err
	}

	tr := tar.NewReader(tarFile)
	for {
		var hdr *tar.Header
		hdr, err = tr.Next()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}
		dirname := path.Dir(hdr.Name)
		if dirname != "." {
			if err = workFS.MkdirAll(dirname, 0755); err != nil {
				return nil
			}
		}
		var f afero.File
		f, err = workFS.OpenFile(hdr.Name, os.O_CREATE|os.O_WRONLY, 0644)
		if err != nil {
			return err
		}
		_, err = io.Copy(f, tr)
		errc := f.Close()
		if err != nil {
			return err
		}
		if errc != nil {
			return errc
		}
	}

	fieldsJSON, err := json.Marshal(fields)
	if err != nil {
		return err
	}

	konnCmd := config.GetConfig().Konnectors.Cmd
	cmd := exec.CommandContext(ctx, konnCmd, workDir) // #nosec
	cmd.Env = []string{
		"COZY_URL=" + inst.PageURL("/", nil),
		"COZY_CREDENTIALS=" + token,
		"COZY_FIELDS=" + string(fieldsJSON),
		"COZY_TYPE=" + man.Type,
		"COZY_JOB_ID=" + jobID,
	}

	cmdErr, err := cmd.StderrPipe()
	if err != nil {
		return err
	}
	cmdOut, err := cmd.StdoutPipe()
	if err != nil {
		return err
	}

	scanErr := bufio.NewScanner(cmdErr)
	scanOut := bufio.NewScanner(cmdOut)
	scanOut.Buffer(nil, 256*1024)

	var messages []konnectorMsg

	log := logger.WithDomain(domain)

	if err = cmd.Start(); err != nil {
		return wrapErr(ctx, err)
	}

	go doScanErr(jobID, scanErr, log)

	hub := realtime.GetHub()

	for scanOut.Scan() {
		line := scanOut.Bytes()
		var msg konnectorMsg
		if err = json.Unmarshal(line, &msg); err != nil {
			log.Warnf("[konnector] %s: Could not parse stdout as JSON: \"\"", jobID, string(line))
			continue
		}
		// TODO: filter some of the messages
		messages = append(messages, msg)
		hub.Publish(&realtime.Event{
			Verb: realtime.EventCreate,
			Doc: couchdb.JSONDoc{Type: consts.JobEvents, M: map[string]interface{}{
				"type":    msg.Type,
				"message": msg.Message,
			}},
			Domain: domain,
		})
	}

	if err = cmd.Wait(); err != nil {
		err = wrapErr(ctx, err)
		log.Errorf("[konnector] %s: Konnector has failed: %s", jobID, err.Error())
	}

	errLogs := couchdb.Upsert(inst, &konnectorLogs{
		Slug:     slug,
		Messages: messages,
	})
	if errLogs != nil {
		fmt.Println("Failed to save konnector logs", errLogs)
	}

	for _, msg := range messages {
		if msg.Type == konnectorMsgTypeError {
			// konnector err is more explicit
			return errors.New(msg.Message)
		}
	}

	return err
}

func doScanErr(jobID string, scanner *bufio.Scanner, log *logrus.Entry) {
	for scanner.Scan() {
		log.Errorf("[konnector] %s: Stderr: %s", jobID, scanner.Text())
	}
}

func commit(ctx context.Context, m *jobs.Message, errjob error) error {
	opts := &Options{}
	if err := m.Unmarshal(&opts); err != nil {
		return err
	}

	slug := opts.Konnector
	domain := ctx.Value(jobs.ContextDomainKey).(string)

	inst, err := instance.Get(domain)
	if err != nil {
		return err
	}

	lastResult := &result{}
	err = couchdb.GetDoc(inst, consts.KonnectorResults, slug, lastResult)
	if err != nil {
		if !couchdb.IsNotFoundError(err) {
			return err
		}
		lastResult = nil
	}

	var state, errstr string
	var lastSuccess time.Time
	if errjob != nil {
		if lastResult != nil {
			lastSuccess = lastResult.LastSuccess
		}
		errstr = errjob.Error()
		state = jobs.Errored
	} else {
		lastSuccess = time.Now()
		state = jobs.Done
	}
	result := &result{
		DocID:       slug,
		Account:     opts.Account,
		CreatedAt:   time.Now(),
		LastSuccess: lastSuccess,
		State:       state,
		Error:       errstr,
	}
	if lastResult == nil {
		err = couchdb.CreateNamedDocWithDB(inst, result)
	} else {
		result.SetRev(lastResult.Rev())
		err = couchdb.UpdateDoc(inst, result)
	}
	// if err != nil {
	// 	return err
	// }

	return err
	// // if it is the first try we do not take into account an error, we bail.
	// if lastResult == nil {
	// 	return nil
	// }
	// // if the job has not errored, or the last one was already errored, we bail.
	// if state != jobs.Errored || lastResult.State == jobs.Errored {
	// 	return nil
	// }

	// konnectorURL := inst.SubDomain(consts.CollectSlug)
	// konnectorURL.Fragment = "/category/all/" + slug
	// mail := mails.Options{
	// 	Mode:         mails.ModeNoReply,
	// 	Subject:      inst.Translate("Error Konnector execution", domain),
	// 	TemplateName: "konnector_error_" + inst.Locale,
	// 	TemplateValues: map[string]string{
	// 		"KonnectorName": slug,
	// 		"KonnectorPage": konnectorURL.String(),
	// 	},
	// }
	// msg, err := jobs.NewMessage(jobs.JSONEncoding, &mail)
	// if err != nil {
	// 	return err
	// }
	// log := logger.WithDomain(domain)
	// log.Info("Konnector has failed definitively, should send mail.", mail)
	// _, err = stack.GetBroker().PushJob(&jobs.JobRequest{
	// 	Domain:     domain,
	// 	WorkerType: "sendmail",
	// 	Message:    msg,
	// })
	// return err
}

func wrapErr(ctx context.Context, err error) error {
	if ctx.Err() == context.DeadlineExceeded {
		return context.DeadlineExceeded
	}
	return err
}
<commit_msg>Fix bad fmt<commit_after>package konnectors

import (
	"archive/tar"
	"bufio"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path"
	"runtime"
	"time"

	"github.com/cozy/cozy-stack/pkg/apps"
	"github.com/cozy/cozy-stack/pkg/config"
	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/cozy/cozy-stack/pkg/couchdb"
	"github.com/cozy/cozy-stack/pkg/instance"
	"github.com/cozy/cozy-stack/pkg/jobs"
	"github.com/cozy/cozy-stack/pkg/logger"
	"github.com/cozy/cozy-stack/pkg/realtime"
	"github.com/sirupsen/logrus"

	"github.com/spf13/afero"
)

func init() {
	jobs.AddWorker("konnector", &jobs.WorkerConfig{
		Concurrency:  runtime.NumCPU() * 2,
		MaxExecCount: 2,
		MaxExecTime:  200 * time.Second,
		Timeout:      200 * time.Second,
		WorkerFunc:   Worker,
		WorkerCommit: commit,
	})
}

// Options contains the options to execute a konnector.
type Options struct {
	Konnector    string `json:"konnector"`
	Account      string `json:"account"`
	FolderToSave string `json:"folder_to_save"`
}

// result stores the result of a konnector execution.
type result struct {
	DocID       string         `json:"_id,omitempty"`
	DocRev      string         `json:"_rev,omitempty"`
	CreatedAt   time.Time      `json:"last_execution"`
	LastSuccess time.Time      `json:"last_success"`
	Logs        []konnectorMsg `json:"logs"`
	Account     string         `json:"account"`
	State       string         `json:"state"`
	Error       string         `json:"error"`
}

func (r *result) ID() string         { return r.DocID }
func (r *result) Rev() string        { return r.DocRev }
func (r *result) DocType() string    { return consts.KonnectorResults }
func (r *result) Clone() couchdb.Doc { c := *r; return &c }
func (r *result) SetID(id string)    { r.DocID = id }
func (r *result) SetRev(rev string)  { r.DocRev = rev }

const konnectorMsgTypeError string = "error"

// const konnectorMsgTypeDebug string = "debug"
// const konnectorMsgTypeWarning string = "warning"
// const konnectorMsgTypeProgress string = "progress"

type konnectorMsg struct {
	Type    string `json:"type"`
	Message string `json:"message"`
}

type konnectorLogs struct {
	Slug     string         `json:"_id,omitempty"`
	DocRev   string         `json:"_rev,omitempty"`
	Messages []konnectorMsg `json:"logs"`
}

func (kl *konnectorLogs) ID() string         { return kl.Slug }
func (kl *konnectorLogs) Rev() string        { return kl.DocRev }
func (kl *konnectorLogs) DocType() string    { return consts.KonnectorLogs }
func (kl *konnectorLogs) Clone() couchdb.Doc { c := *kl; return &c }
func (kl *konnectorLogs) SetID(id string)    {}
func (kl *konnectorLogs) SetRev(rev string)  { kl.DocRev = rev }

// Worker is the worker that runs a konnector by executing an external process.
func Worker(ctx context.Context, m *jobs.Message) error {
	opts := &Options{}
	if err := m.Unmarshal(&opts); err != nil {
		return err
	}

	slug := opts.Konnector
	fields := struct {
		Account      string `json:"account"`
		FolderToSave string `json:"folder_to_save"`
	}{
		Account:      opts.Account,
		FolderToSave: opts.FolderToSave,
	}
	domain := ctx.Value(jobs.ContextDomainKey).(string)
	worker := ctx.Value(jobs.ContextWorkerKey).(string)
	jobID := fmt.Sprintf("%s/%s/%s", worker, slug, domain)

	inst, err := instance.Get(domain)
	if err != nil {
		return err
	}

	man, err := apps.GetKonnectorBySlug(inst, slug)
	if err != nil {
		return err
	}
	if man.State() != apps.Ready {
		return errors.New("Konnector is not ready")
	}

	token := inst.BuildKonnectorToken(man)

	osFS := afero.NewOsFs()
	workDir, err := afero.TempDir(osFS, "", "konnector-"+slug)
	if err != nil {
		return err
	}
	defer osFS.RemoveAll(workDir)
	workFS := afero.NewBasePathFs(osFS, workDir)

	fileServer := inst.KonnectorsFileServer()
	tarFile, err := fileServer.Open(slug, man.Version(), apps.KonnectorArchiveName)
	if err != nil {
		return err
	}

	tr := tar.NewReader(tarFile)
	for {
		var hdr *tar.Header
		hdr, err = tr.Next()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}
		dirname := path.Dir(hdr.Name)
		if dirname != "." {
			if err = workFS.MkdirAll(dirname, 0755); err != nil {
				return nil
			}
		}
		var f afero.File
		f, err = workFS.OpenFile(hdr.Name, os.O_CREATE|os.O_WRONLY, 0644)
		if err != nil {
			return err
		}
		_, err = io.Copy(f, tr)
		errc := f.Close()
		if err != nil {
			return err
		}
		if errc != nil {
			return errc
		}
	}

	fieldsJSON, err := json.Marshal(fields)
	if err != nil {
		return err
	}

	konnCmd := config.GetConfig().Konnectors.Cmd
	cmd := exec.CommandContext(ctx, konnCmd, workDir) // #nosec
	cmd.Env = []string{
		"COZY_URL=" + inst.PageURL("/", nil),
		"COZY_CREDENTIALS=" + token,
		"COZY_FIELDS=" + string(fieldsJSON),
		"COZY_TYPE=" + man.Type,
		"COZY_JOB_ID=" + jobID,
	}

	cmdErr, err := cmd.StderrPipe()
	if err != nil {
		return err
	}
	cmdOut, err := cmd.StdoutPipe()
	if err != nil {
		return err
	}

	scanErr := bufio.NewScanner(cmdErr)
	scanOut := bufio.NewScanner(cmdOut)
	scanOut.Buffer(nil, 256*1024)

	var messages []konnectorMsg

	log := logger.WithDomain(domain)

	if err = cmd.Start(); err != nil {
		return wrapErr(ctx, err)
	}

	go doScanErr(jobID, scanErr, log)

	hub := realtime.GetHub()

	for scanOut.Scan() {
		line := scanOut.Bytes()
		var msg konnectorMsg
		if err = json.Unmarshal(line, &msg); err != nil {
			log.Warnf("[konnector] %s: Could not parse stdout as JSON: \"%s\"", jobID, string(line))
			continue
		}
		// TODO: filter some of the messages
		messages = append(messages, msg)
		hub.Publish(&realtime.Event{
			Verb: realtime.EventCreate,
			Doc: couchdb.JSONDoc{Type: consts.JobEvents, M: map[string]interface{}{
				"type":    msg.Type,
				"message": msg.Message,
			}},
			Domain: domain,
		})
	}

	if err = cmd.Wait(); err != nil {
		err = wrapErr(ctx, err)
		log.Errorf("[konnector] %s: Konnector has failed: %s", jobID, err.Error())
	}

	errLogs := couchdb.Upsert(inst, &konnectorLogs{
		Slug:     slug,
		Messages: messages,
	})
	if errLogs != nil {
		fmt.Println("Failed to save konnector logs", errLogs)
	}

	for _, msg := range messages {
		if msg.Type == konnectorMsgTypeError {
			// konnector err is more explicit
			return errors.New(msg.Message)
		}
	}

	return err
}

func doScanErr(jobID string, scanner *bufio.Scanner, log *logrus.Entry) {
	for scanner.Scan() {
		log.Errorf("[konnector] %s: Stderr: %s", jobID, scanner.Text())
	}
}

func commit(ctx context.Context, m *jobs.Message, errjob error) error {
	opts := &Options{}
	if err := m.Unmarshal(&opts); err != nil {
		return err
	}

	slug := opts.Konnector
	domain := ctx.Value(jobs.ContextDomainKey).(string)

	inst, err := instance.Get(domain)
	if err != nil {
		return err
	}

	lastResult := &result{}
	err = couchdb.GetDoc(inst, consts.KonnectorResults, slug, lastResult)
	if err != nil {
		if !couchdb.IsNotFoundError(err) {
			return err
		}
		lastResult = nil
	}

	var state, errstr string
	var lastSuccess time.Time
	if errjob != nil {
		if lastResult != nil {
			lastSuccess = lastResult.LastSuccess
		}
		errstr = errjob.Error()
		state = jobs.Errored
	} else {
		lastSuccess = time.Now()
		state = jobs.Done
	}
	result := &result{
		DocID:       slug,
		Account:     opts.Account,
		CreatedAt:   time.Now(),
		LastSuccess: lastSuccess,
		State:       state,
		Error:       errstr,
	}
	if lastResult == nil {
		err = couchdb.CreateNamedDocWithDB(inst, result)
	} else {
		result.SetRev(lastResult.Rev())
		err = couchdb.UpdateDoc(inst, result)
	}
	// if err != nil {
	// 	return err
	// }

	return err
	// // if it is the first try we do not take into account an error, we bail.
	// if lastResult == nil {
	// 	return nil
	// }
	// // if the job has not errored, or the last one was already errored, we bail.
	// if state != jobs.Errored || lastResult.State == jobs.Errored {
	// 	return nil
	// }

	// konnectorURL := inst.SubDomain(consts.CollectSlug)
	// konnectorURL.Fragment = "/category/all/" + slug
	// mail := mails.Options{
	// 	Mode:         mails.ModeNoReply,
	// 	Subject:      inst.Translate("Error Konnector execution", domain),
	// 	TemplateName: "konnector_error_" + inst.Locale,
	// 	TemplateValues: map[string]string{
	// 		"KonnectorName": slug,
	// 		"KonnectorPage": konnectorURL.String(),
	// 	},
	// }
	// msg, err := jobs.NewMessage(jobs.JSONEncoding, &mail)
	// if err != nil {
	// 	return err
	// }
	// log := logger.WithDomain(domain)
	// log.Info("Konnector has failed definitively, should send mail.", mail)
	// _, err = stack.GetBroker().PushJob(&jobs.JobRequest{
	// 	Domain:     domain,
	// 	WorkerType: "sendmail",
	// 	Message:    msg,
	// })
	// return err
}

func wrapErr(ctx context.Context, err error) error {
	if ctx.Err() == context.DeadlineExceeded {
		return context.DeadlineExceeded
	}
	return err
}
<|endoftext|>


<commit_before>package ir

import "github.com/rthornton128/calc/token"

func FoldConstants(o Object) Object {
	if pkg, ok := o.(*Package); ok {
		for k, v := range pkg.scope.m {
			pkg.scope.m[k] = fold(v)
		}
		return pkg
	}
	return fold(o)
}

func fold(o Object) Object {
	switch t := o.(type) {
	case *Assignment:
		t.Rhs = fold(t.Rhs)
	case *Binary:
		t.Lhs = fold(t.Lhs)
		t.Rhs = fold(t.Rhs)
		return foldBinary(t)
	case *Block:
		for i, e := range t.Exprs {
			t.Exprs[i] = fold(e)
		}
	case *Declaration:
		t.Body = fold(t.Body)
	case *If:
		t.Cond = fold(t.Cond)
		t.Then = fold(t.Then)
		if t.Else != nil {
			t.Else = fold(t.Else)
		}
	case *Unary:
		t.Rhs = fold(t.Rhs)
		return foldUnary(t)
	case *Variable:
		t.Assign = fold(t.Assign)
	}
	return o
}

func foldBinary(b *Binary) Object {
	lhs, lhsOk := b.Lhs.(*Constant)
	rhs, rhsOk := b.Rhs.(*Constant)

	if lhsOk && rhsOk {
		switch b.Type() {
		case Int:
			l, r := int64(lhs.value.(intValue)), int64(rhs.value.(intValue))
			switch b.Op {
			case token.ADD:
				lhs.value = intValue(l + r)
			case token.MUL:
				lhs.value = intValue(l * r)
			case token.QUO:
				lhs.value = intValue(l / r)
			case token.REM:
				lhs.value = intValue(l % r)
			case token.SUB:
				lhs.value = intValue(l - r)
			}
			return lhs
		case Bool:
			switch lhs.Type() {
			case Bool:
				l, r := bool(lhs.value.(boolValue)), bool(rhs.value.(boolValue))
				switch b.Op {
				case token.EQL:
					lhs.value = boolValue(l == r)
				case token.NEQ:
					lhs.value = boolValue(l != r)
				}
			case Int:
				l, r := int64(lhs.value.(intValue)), int64(rhs.value.(intValue))
				switch b.Op {
				case token.EQL:
					lhs.value = boolValue(l == r)
				case token.NEQ:
					lhs.value = boolValue(l != r)
				case token.GTT:
					lhs.value = boolValue(l > r)
				case token.GTE:
					lhs.value = boolValue(l >= r)
				case token.LST:
					lhs.value = boolValue(l < r)
				case token.LTE:
					lhs.value = boolValue(l <= r)
				}
			}
			return lhs
		}
	}
	return b
}

func foldUnary(u *Unary) Object {
	if c, ok := u.Rhs.(*Constant); ok {
		switch u.Op {
		case "+":
			c.value = intValue(+int64(c.value.(intValue)))
		case "-":
			c.value = intValue(-int64(c.value.(intValue)))
		}
		return c
	}
	return u
}
<commit_msg>fold call arguments<commit_after>package ir

import "github.com/rthornton128/calc/token"

func FoldConstants(o Object) Object {
	if pkg, ok := o.(*Package); ok {
		for k, v := range pkg.scope.m {
			pkg.scope.m[k] = fold(v)
		}
		return pkg
	}
	return fold(o)
}

func fold(o Object) Object {
	switch t := o.(type) {
	case *Assignment:
		t.Rhs = fold(t.Rhs)
	case *Binary:
		t.Lhs = fold(t.Lhs)
		t.Rhs = fold(t.Rhs)
		return foldBinary(t)
	case *Block:
		for i, e := range t.Exprs {
			t.Exprs[i] = fold(e)
		}
	case *Call:
		for i, e := range t.Args {
			t.Args[i] = fold(e)
		}
	case *Declaration:
		t.Body = fold(t.Body)
	case *If:
		t.Cond = fold(t.Cond)
		t.Then = fold(t.Then)
		if t.Else != nil {
			t.Else = fold(t.Else)
		}
	case *Unary:
		t.Rhs = fold(t.Rhs)
		return foldUnary(t)
	case *Variable:
		t.Assign = fold(t.Assign)
	}
	return o
}

func foldBinary(b *Binary) Object {
	lhs, lhsOk := b.Lhs.(*Constant)
	rhs, rhsOk := b.Rhs.(*Constant)

	if lhsOk && rhsOk {
		switch b.Type() {
		case Int:
			l, r := int64(lhs.value.(intValue)), int64(rhs.value.(intValue))
			switch b.Op {
			case token.ADD:
				lhs.value = intValue(l + r)
			case token.MUL:
				lhs.value = intValue(l * r)
			case token.QUO:
				// TODO div by zero
				lhs.value = intValue(l / r)
			case token.REM:
				lhs.value = intValue(l % r)
			case token.SUB:
				lhs.value = intValue(l - r)
			}
			return lhs
		case Bool:
			switch lhs.Type() {
			case Bool:
				l, r := bool(lhs.value.(boolValue)), bool(rhs.value.(boolValue))
				switch b.Op {
				case token.EQL:
					lhs.value = boolValue(l == r)
				case token.NEQ:
					lhs.value = boolValue(l != r)
				}
			case Int:
				l, r := int64(lhs.value.(intValue)), int64(rhs.value.(intValue))
				switch b.Op {
				case token.EQL:
					lhs.value = boolValue(l == r)
				case token.NEQ:
					lhs.value = boolValue(l != r)
				case token.GTT:
					lhs.value = boolValue(l > r)
				case token.GTE:
					lhs.value = boolValue(l >= r)
				case token.LST:
					lhs.value = boolValue(l < r)
				case token.LTE:
					lhs.value = boolValue(l <= r)
				}
			}
			return lhs
		}
	}
	return b
}

func foldUnary(u *Unary) Object {
	if c, ok := u.Rhs.(*Constant); ok {
		switch u.Op {
		case "+":
			c.value = intValue(+int64(c.value.(intValue)))
		case "-":
			c.value = intValue(-int64(c.value.(intValue)))
		}
		return c
	}
	return u
}
<|endoftext|>


<commit_before>package url

import (
	"math/rand"
	"net/url"
	"time"
)

//region TYPES

type Url struct {
	Id              string
	CreationDate    time.Time
	Destination     string
}

type Repository interface {
	IdExists(id string) bool
	FindById(id string) *Url
	FindByUrl(url string) *Url
	Save(url Url) error
}

//endregion

//region CONST AND VARS

const (
	size    = 5
	symbols = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_-+"
)

var repo Repository

//endregion

//region MAIN FUNCTIONS

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

//endregion

//region PUBLIC FUNCIONS

func ConfigRepository(r Repository) {
	repo = r
}

func Find(id string) *Url {
	return repo.FindById(id)
}

func GetUrl(destiny string) (u *Url, new bool, err error) {
	if u = repo.FindByUrl(destiny); u != nil {
		return u, false, nil
	}

	if _, err = url.ParseRequestURI(destiny); err != nil {
		return nil, false, err
	}

	url := Url{generateId(), time.Now(), destiny}
	repo.Save(url)

	return &url, true, nil
}

//endregion

//region PRIVATE FUNCIONS

func generateId() {
	newId := func() string {
		id := make([]byte, size)

		for i := range id {
			id[i] = symbols[rand.Intn(len(symbols))]
		}

		return string(id)
	}

	for {
		if id := newId(); !repo.IdExists(id) {
			return id
		}
	}
}

//endregion
<commit_msg>Finalization of base code<commit_after>package url

import (
	"math/rand"
	"net/url"
	"time"
)

//region TYPES

type Url struct {
	Id              string
	CreationDate    time.Time
	Destination     string
}

type Repository interface {
	IdExists(id string) bool
	FindById(id string) *Url
	FindByUrl(url string) *Url
	Save(url Url) error
}

//endregion

//region CONST AND VARS

const (
	size    = 5
	symbols = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_-+"
)

var repo Repository

//endregion

//region MAIN FUNCTIONS

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

//endregion

//region PUBLIC FUNCIONS

func ConfigRepository(r Repository) {
	repo = r
}

func Find(id string) *Url {
	return repo.FindById(id)
}

func GetUrl(destiny string) (u *Url, new bool, err error) {
	if u = repo.FindByUrl(destiny); u != nil {
		return u, false, nil
	}

	if _, err = url.ParseRequestURI(destiny); err != nil {
		return nil, false, err
	}

	url := Url{generateId(), time.Now(), destiny}
	repo.Save(url)

	return &url, true, nil
}

//endregion

//region PRIVATE FUNCIONS

func generateId() string {
	newId := func() string {
		id := make([]byte, size)

		for i := range id {
			id[i] = symbols[rand.Intn(len(symbols))]
		}

		return string(id)
	}

	for {
		if id := newId(); !repo.IdExists(id) {
			return id
		}
	}
}

//endregion
<|endoftext|>


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

// Package facts handles processong of the /procs/cpuinfo file as facts.
package facts

import (
	"io"
	"strconv"
	"sync"
	"time"

	"github.com/SermoDigital/helpers"
	joe "github.com/mohae/joefriday"
)

const procFile = "/proc/cpuinfo"

// Facts are a collection of facts, cpuinfo, about the system's cpus.
type Facts struct {
	Timestamp int64
	CPU       []Fact `json:"cpu"`
}

// Fact holds the /proc/cpuinfo for a single processor.
type Fact struct {
	Processor       int16   `json:"processor"`
	VendorID        string  `json:"vendor_id"`
	CPUFamily       string  `json:"cpu_family"`
	Model           string  `json:"model"`
	ModelName       string  `json:"model_name"`
	Stepping        string  `json:"stepping"`
	Microcode       string  `json:"microcode"`
	CPUMHz          float32 `json:"cpu_mhz"`
	CacheSize       string  `json:"cache_size"`
	PhysicalID      int16   `json:"physical_id"`
	Siblings        int16   `json:"siblings"`
	CoreID          int16   `json:"core_id"`
	CPUCores        int16   `json:"cpu_cores"`
	ApicID          int16   `json:"apicid"`
	InitialApicID   int16   `json:"initial_apicid"`
	FPU             string  `json:"fpu"`
	FPUException    string  `json:"fpu_exception"`
	CPUIDLevel      string  `json:"cpuid_level"`
	WP              string  `json:"wp"`
	Flags           string  `json:"flags"` // should this be a []string?
	BogoMIPS        float32 `json:"bogomips"`
	CLFlushSize     string  `json:"clflush_size"`
	CacheAlignment  string  `json:"cache_alignment"`
	AddressSizes    string  `json:"address_sizes"`
	PowerManagement string  `json:"power_management"`
}

// Profiler is used to process the /proc/cpuinfo file as facts.
type Profiler struct {
	*joe.Proc
}

// Returns an initialized Profiler; ready to use.
func NewProfiler() (prof *Profiler, err error) {
	proc, err := joe.New(procFile)
	if err != nil {
		return nil, err
	}
	return &Profiler{Proc: proc}, nil
}

// Get returns the current cpuinfo (Facts).
func (prof *Profiler) Get() (facts *Facts, err error) {
	var (
		cpuCnt, i, pos, nameLen int
		n                       uint64
		v                       byte
		cpu                     Fact
	)
	err = prof.Reset()
	if err != nil {
		return nil, err
	}
	facts = &Facts{Timestamp: time.Now().UTC().UnixNano()}
	for {
		prof.Line, err = prof.Buf.ReadSlice('\n')
		if err != nil {
			if err == io.EOF {
				break
			}
			return nil, &joe.ReadError{Err: err}
		}
		prof.Val = prof.Val[:0]
		// First grab the attribute name; everything up to the ':'.  The key may have
		// spaces and has trailing spaces; that gets trimmed.
		for i, v = range prof.Line {
			if v == 0x3A {
				prof.Val = prof.Line[:i]
				pos = i + 1
				break
			}
			//prof.Val = append(prof.Val, v)
		}
		prof.Val = joe.TrimTrailingSpaces(prof.Val[:])
		nameLen = len(prof.Val)
		// if there's no name; skip.
		if nameLen == 0 {
			continue
		}
		// if there's anything left, the value is everything else; trim spaces
		if pos+1 < len(prof.Line) {
			prof.Val = append(prof.Val, joe.TrimTrailingSpaces(prof.Line[pos+1:])...)
		}
		v = prof.Val[0]
		if v == 'a' {
			v = prof.Val[1]
			if v == 'd' { // address sizes
				cpu.AddressSizes = string(prof.Val[nameLen:])
				continue
			}
			if v == 'p' { // apicid
				n, err = helpers.ParseUint(prof.Val[nameLen:])
				if err != nil {
					return nil, &joe.ParseError{Info: string(prof.Val[:nameLen]), Err: err}
				}
				cpu.ApicID = int16(n)
			}
			continue
		}
		if v == 'c' {
			v = prof.Val[1]
			if v == 'p' {
				v = prof.Val[4]
				if v == 'c' { // cpu cores
					n, err = helpers.ParseUint(prof.Val[nameLen:])
					if err != nil {
						return nil, &joe.ParseError{Info: string(prof.Val[:nameLen]), Err: err}
					}
					cpu.CPUCores = int16(n)
					continue
				}
				if v == 'f' { // cpu family
					cpu.CPUFamily = string(prof.Val[nameLen:])
					continue
				}
				if v == 'M' { // cpu MHz
					f, err := strconv.ParseFloat(string(prof.Val[nameLen:]), 32)
					if err != nil {
						return nil, &joe.ParseError{Info: string(prof.Val[:nameLen]), Err: err}
					}
					cpu.CPUMHz = float32(f)
					continue
				}
				if v == 'd' { // cpuid level
					cpu.CPUIDLevel = string(prof.Val[nameLen:])
				}
				continue
			}
			v = prof.Val[5]
			if v == '_' { // cache_alignment
				cpu.CacheAlignment = string(prof.Val[nameLen:])
				continue
			}
			if v == ' ' { // cache size
				cpu.CacheSize = string(prof.Val[nameLen:])
				continue
			}
			if v == 's' { // clflush size
				cpu.CLFlushSize = string(prof.Val[nameLen:])
				continue
			}
			if v == 'i' { // core id
				n, err = helpers.ParseUint(prof.Val[nameLen:])
				if err != nil {
					return nil, &joe.ParseError{Info: string(prof.Val[:nameLen]), Err: err}
				}
				cpu.CoreID = int16(n)
			}
			continue
		}
		if v == 'f' {
			v = prof.Val[1]
			if v == 'l' { // flags
				cpu.Flags = string(prof.Val[nameLen:])
				continue
			}
			if v == 'p' {
				if nameLen == 3 { // fpu
					cpu.FPU = string(prof.Val[nameLen:])
				} else { // fpu_exception
					cpu.FPUException = string(prof.Val[nameLen:])
				}
			}
			continue
		}
		if v == 'm' {
			v = prof.Val[1]
			if v == 'i' { // microcode
				cpu.Microcode = string(prof.Val[nameLen:])
				continue
			}
			if v == 'o' {
				if nameLen == 5 { // model
					cpu.Model = string(prof.Val[nameLen:])
					continue
				}
				cpu.ModelName = string(prof.Val[nameLen:])
			}
			continue
		}
		if v == 'p' {
			v = prof.Val[1]
			if v == 'h' { // physical id
				n, err = helpers.ParseUint(prof.Val[nameLen:])
				if err != nil {
					return nil, &joe.ParseError{Info: string(prof.Val[:nameLen]), Err: err}
				}
				cpu.PhysicalID = int16(n)
				continue
			}
			if v == 'o' { // power management
				cpu.PowerManagement = string(prof.Val[nameLen:])
				continue
			}
			// processor starts information about a processor.
			if v == 'r' { // processor
				if cpuCnt > 0 {
					facts.CPU = append(facts.CPU, cpu)
				}
				cpuCnt++
				n, err = helpers.ParseUint(prof.Val[nameLen:])
				if err != nil {
					return nil, &joe.ParseError{Info: string(prof.Val[:nameLen]), Err: err}
				}
				cpu = Fact{Processor: int16(n)}
			}
			continue
		}
		if v == 's' {
			v = prof.Val[1]
			if v == 'i' { // siblings
				n, err = helpers.ParseUint(prof.Val[nameLen:])
				if err != nil {
					return nil, &joe.ParseError{Info: string(prof.Val[:nameLen]), Err: err}
				}
				cpu.Siblings = int16(n)
				continue
			}
			if v == 't' { // stepping
				cpu.Stepping = string(prof.Val[nameLen:])
			}
			continue
		}
		if v == 'b' { // bogomips
			f, err := strconv.ParseFloat(string(prof.Val[nameLen:]), 32)
			if err != nil {
				return nil, &joe.ParseError{Info: string(prof.Val[:nameLen]), Err: err}
			}
			cpu.BogoMIPS = float32(f)
			continue
		}
		if v == 'i' { // initial apicid
			n, err = helpers.ParseUint(prof.Val[nameLen:])
			if err != nil {
				return nil, &joe.ParseError{Info: string(prof.Val[:nameLen]), Err: err}
			}
			cpu.InitialApicID = int16(n)
			continue
		}
		if v == 'W' { // WP
			cpu.WP = string(prof.Val[nameLen:])
			continue
		}
		if v == 'v' { // vendor_id
			cpu.VendorID = string(prof.Val[nameLen:])
		}
	}
	// append the current processor informatin
	facts.CPU = append(facts.CPU, cpu)
	return facts, nil
}

var std *Profiler
var stdMu sync.Mutex

// Get returns the current cpuinfo (Facts) using the package's global
// Profiler.
func Get() (facts *Facts, err error) {
	stdMu.Lock()
	defer stdMu.Unlock()
	if std == nil {
		std, err = NewProfiler()
		if err != nil {
			return nil, err
		}
	}
	return std.Get()
}
<commit_msg>add check of 2nd char in name for bogomips as some systems also have a "bugs" line<commit_after>// Copyright 2016 Joel Scoble and The JoeFriday authors.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package facts handles processong of the /procs/cpuinfo file as facts.
package facts

import (
	"io"
	"strconv"
	"sync"
	"time"

	"github.com/SermoDigital/helpers"
	joe "github.com/mohae/joefriday"
)

const procFile = "/proc/cpuinfo"

// Facts are a collection of facts, cpuinfo, about the system's cpus.
type Facts struct {
	Timestamp int64
	CPU       []Fact `json:"cpu"`
}

// Fact holds the /proc/cpuinfo for a single processor.
type Fact struct {
	Processor       int16   `json:"processor"`
	VendorID        string  `json:"vendor_id"`
	CPUFamily       string  `json:"cpu_family"`
	Model           string  `json:"model"`
	ModelName       string  `json:"model_name"`
	Stepping        string  `json:"stepping"`
	Microcode       string  `json:"microcode"`
	CPUMHz          float32 `json:"cpu_mhz"`
	CacheSize       string  `json:"cache_size"`
	PhysicalID      int16   `json:"physical_id"`
	Siblings        int16   `json:"siblings"`
	CoreID          int16   `json:"core_id"`
	CPUCores        int16   `json:"cpu_cores"`
	ApicID          int16   `json:"apicid"`
	InitialApicID   int16   `json:"initial_apicid"`
	FPU             string  `json:"fpu"`
	FPUException    string  `json:"fpu_exception"`
	CPUIDLevel      string  `json:"cpuid_level"`
	WP              string  `json:"wp"`
	Flags           string  `json:"flags"` // should this be a []string?
	BogoMIPS        float32 `json:"bogomips"`
	CLFlushSize     string  `json:"clflush_size"`
	CacheAlignment  string  `json:"cache_alignment"`
	AddressSizes    string  `json:"address_sizes"`
	PowerManagement string  `json:"power_management"`
}

// Profiler is used to process the /proc/cpuinfo file as facts.
type Profiler struct {
	*joe.Proc
}

// Returns an initialized Profiler; ready to use.
func NewProfiler() (prof *Profiler, err error) {
	proc, err := joe.New(procFile)
	if err != nil {
		return nil, err
	}
	return &Profiler{Proc: proc}, nil
}

// Get returns the current cpuinfo (Facts).
func (prof *Profiler) Get() (facts *Facts, err error) {
	var (
		cpuCnt, i, pos, nameLen int
		n                       uint64
		v                       byte
		cpu                     Fact
	)
	err = prof.Reset()
	if err != nil {
		return nil, err
	}
	facts = &Facts{Timestamp: time.Now().UTC().UnixNano()}
	for {
		prof.Line, err = prof.Buf.ReadSlice('\n')
		if err != nil {
			if err == io.EOF {
				break
			}
			return nil, &joe.ReadError{Err: err}
		}
		prof.Val = prof.Val[:0]
		// First grab the attribute name; everything up to the ':'.  The key may have
		// spaces and has trailing spaces; that gets trimmed.
		for i, v = range prof.Line {
			if v == 0x3A {
				prof.Val = prof.Line[:i]
				pos = i + 1
				break
			}
			//prof.Val = append(prof.Val, v)
		}
		prof.Val = joe.TrimTrailingSpaces(prof.Val[:])
		nameLen = len(prof.Val)
		// if there's no name; skip.
		if nameLen == 0 {
			continue
		}
		// if there's anything left, the value is everything else; trim spaces
		if pos+1 < len(prof.Line) {
			prof.Val = append(prof.Val, joe.TrimTrailingSpaces(prof.Line[pos+1:])...)
		}
		v = prof.Val[0]
		if v == 'a' {
			v = prof.Val[1]
			if v == 'd' { // address sizes
				cpu.AddressSizes = string(prof.Val[nameLen:])
				continue
			}
			if v == 'p' { // apicid
				n, err = helpers.ParseUint(prof.Val[nameLen:])
				if err != nil {
					return nil, &joe.ParseError{Info: string(prof.Val[:nameLen]), Err: err}
				}
				cpu.ApicID = int16(n)
			}
			continue
		}
		if v == 'c' {
			v = prof.Val[1]
			if v == 'p' {
				v = prof.Val[4]
				if v == 'c' { // cpu cores
					n, err = helpers.ParseUint(prof.Val[nameLen:])
					if err != nil {
						return nil, &joe.ParseError{Info: string(prof.Val[:nameLen]), Err: err}
					}
					cpu.CPUCores = int16(n)
					continue
				}
				if v == 'f' { // cpu family
					cpu.CPUFamily = string(prof.Val[nameLen:])
					continue
				}
				if v == 'M' { // cpu MHz
					f, err := strconv.ParseFloat(string(prof.Val[nameLen:]), 32)
					if err != nil {
						return nil, &joe.ParseError{Info: string(prof.Val[:nameLen]), Err: err}
					}
					cpu.CPUMHz = float32(f)
					continue
				}
				if v == 'd' { // cpuid level
					cpu.CPUIDLevel = string(prof.Val[nameLen:])
				}
				continue
			}
			v = prof.Val[5]
			if v == '_' { // cache_alignment
				cpu.CacheAlignment = string(prof.Val[nameLen:])
				continue
			}
			if v == ' ' { // cache size
				cpu.CacheSize = string(prof.Val[nameLen:])
				continue
			}
			if v == 's' { // clflush size
				cpu.CLFlushSize = string(prof.Val[nameLen:])
				continue
			}
			if v == 'i' { // core id
				n, err = helpers.ParseUint(prof.Val[nameLen:])
				if err != nil {
					return nil, &joe.ParseError{Info: string(prof.Val[:nameLen]), Err: err}
				}
				cpu.CoreID = int16(n)
			}
			continue
		}
		if v == 'f' {
			v = prof.Val[1]
			if v == 'l' { // flags
				cpu.Flags = string(prof.Val[nameLen:])
				continue
			}
			if v == 'p' {
				if nameLen == 3 { // fpu
					cpu.FPU = string(prof.Val[nameLen:])
				} else { // fpu_exception
					cpu.FPUException = string(prof.Val[nameLen:])
				}
			}
			continue
		}
		if v == 'm' {
			v = prof.Val[1]
			if v == 'i' { // microcode
				cpu.Microcode = string(prof.Val[nameLen:])
				continue
			}
			if v == 'o' {
				if nameLen == 5 { // model
					cpu.Model = string(prof.Val[nameLen:])
					continue
				}
				cpu.ModelName = string(prof.Val[nameLen:])
			}
			continue
		}
		if v == 'p' {
			v = prof.Val[1]
			if v == 'h' { // physical id
				n, err = helpers.ParseUint(prof.Val[nameLen:])
				if err != nil {
					return nil, &joe.ParseError{Info: string(prof.Val[:nameLen]), Err: err}
				}
				cpu.PhysicalID = int16(n)
				continue
			}
			if v == 'o' { // power management
				cpu.PowerManagement = string(prof.Val[nameLen:])
				continue
			}
			// processor starts information about a processor.
			if v == 'r' { // processor
				if cpuCnt > 0 {
					facts.CPU = append(facts.CPU, cpu)
				}
				cpuCnt++
				n, err = helpers.ParseUint(prof.Val[nameLen:])
				if err != nil {
					return nil, &joe.ParseError{Info: string(prof.Val[:nameLen]), Err: err}
				}
				cpu = Fact{Processor: int16(n)}
			}
			continue
		}
		if v == 's' {
			v = prof.Val[1]
			if v == 'i' { // siblings
				n, err = helpers.ParseUint(prof.Val[nameLen:])
				if err != nil {
					return nil, &joe.ParseError{Info: string(prof.Val[:nameLen]), Err: err}
				}
				cpu.Siblings = int16(n)
				continue
			}
			if v == 't' { // stepping
				cpu.Stepping = string(prof.Val[nameLen:])
			}
			continue
		}
		// also check 2nd name pos for o as some output also have a bugs line.
		if v == 'b' && prof.Val[1] == 'o' { // bogomips
			f, err := strconv.ParseFloat(string(prof.Val[nameLen:]), 32)
			if err != nil {
				return nil, &joe.ParseError{Info: string(prof.Val[:nameLen]), Err: err}
			}
			cpu.BogoMIPS = float32(f)
			continue
		}
		if v == 'i' { // initial apicid
			n, err = helpers.ParseUint(prof.Val[nameLen:])
			if err != nil {
				return nil, &joe.ParseError{Info: string(prof.Val[:nameLen]), Err: err}
			}
			cpu.InitialApicID = int16(n)
			continue
		}
		if v == 'W' { // WP
			cpu.WP = string(prof.Val[nameLen:])
			continue
		}
		if v == 'v' { // vendor_id
			cpu.VendorID = string(prof.Val[nameLen:])
		}
	}
	// append the current processor informatin
	facts.CPU = append(facts.CPU, cpu)
	return facts, nil
}

var std *Profiler
var stdMu sync.Mutex

// Get returns the current cpuinfo (Facts) using the package's global
// Profiler.
func Get() (facts *Facts, err error) {
	stdMu.Lock()
	defer stdMu.Unlock()
	if std == nil {
		std, err = NewProfiler()
		if err != nil {
			return nil, err
		}
	}
	return std.Get()
}
<|endoftext|>


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

package appsignals

import (
	"os"
	"os/signal"
	"sync"
	"syscall"

	"istio.io/istio/pkg/log"

	"github.com/howeyc/fsnotify"
)

var handlers struct {
	sync.Mutex
	listeners []chan<- Signal
	signals   chan os.Signal
}

type Signal struct {
	// Source of the event trigger as we simulate signal generation from a variety of triggers
	Source string
	Signal os.Signal
}

// Notify a channel if a an event is triggered. A notification is always triggered for SIGUSR1
func Watch(c chan<- Signal) {
	if c == nil {
		panic("reload: Watch using nil channel")
	}

	handlers.Lock()
	defer handlers.Unlock()

	if handlers.listeners == nil {
		// Watch for SIGUSR1 by default
		handlers.signals = make(chan os.Signal, 1)
		signal.Notify(handlers.signals, syscall.SIGUSR1)
		go func() {
			for range handlers.signals {
				Notify("os", syscall.SIGUSR1)
			}
		}()
		handlers.listeners = make([]chan<- Signal, 0, 10)
	}
	handlers.listeners = append(handlers.listeners, c)
}

// Directly trigger a notification
func Notify(trigger string, signal os.Signal) {
	handlers.Lock()
	defer handlers.Unlock()
	for _, v := range handlers.listeners {
		select {
		case v <- Signal{trigger, signal}:
		default:
		}
	}
}

// Trigger notifications when a file is mutated
func FileTrigger(path string, signal os.Signal, shutdown chan os.Signal) error {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return err
	}
	err = watcher.Watch(path)
	if err != nil {
		return err
	}
	go func() {
		loop := true
		for loop {
			select {
			case _, ok := <-watcher.Event:
				if ok {
					log.Warnf("File watch triggered: %v", path)
					Notify(path, signal)
				} else {
					loop = false
				}
			case err := <-watcher.Error:
				log.Warnf("Error watching file trigger: %v %v", path, err)
				loop = false
			case signal := <-shutdown:
				log.Infof("Shutting down file watcher: %v %v", path, signal)
				loop = false
			}
		}
		err = watcher.Close()
		if err != nil {
			log.Warnf("Error stopping file watcher: %v %v", path, err)
		}
	}()
	return nil
}
<commit_msg>Fix MCP dial-out mode. (#13399)<commit_after>// Copyright 2019 Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package appsignals

import (
	"os"
	"os/signal"
	"sync"
	"syscall"

	"istio.io/istio/pkg/log"

	"github.com/howeyc/fsnotify"
)

var handlers struct {
	sync.Mutex
	listeners []chan<- Signal
	signals   chan os.Signal
}

type Signal struct {
	// Source of the event trigger as we simulate signal generation from a variety of triggers
	Source string
	Signal os.Signal
}

// Notify a channel if a an event is triggered. A notification is always triggered for SIGUSR1
func Watch(c chan<- Signal) {
	if c == nil {
		panic("reload: Watch using nil channel")
	}

	handlers.Lock()
	defer handlers.Unlock()

	if handlers.listeners == nil {
		// Watch for SIGUSR1 by default
		handlers.signals = make(chan os.Signal, 1)
		signal.Notify(handlers.signals, syscall.SIGUSR1)
		go func() {
			for range handlers.signals {
				Notify("os", syscall.SIGUSR1)
			}
		}()
		handlers.listeners = make([]chan<- Signal, 0, 10)
	}
	handlers.listeners = append(handlers.listeners, c)
}

// Directly trigger a notification
func Notify(trigger string, signal os.Signal) {
	handlers.Lock()
	defer handlers.Unlock()
	log.Infof("watcher.Notify: (trigger: %q, signal: %v)", trigger, signal)
	for _, v := range handlers.listeners {
		log.Debugf("watcher.Notify: Dispatching to listener '%v' (trigger: %q, signal: %v)", v, trigger, signal)
		select {
		case v <- Signal{trigger, signal}:
		default:
			log.Warnf("watcher.Notify: Signal channel is full (trigger: %q, signal: %v)", trigger, signal)
		}
	}
}

// Trigger notifications when a file is mutated
func FileTrigger(path string, signal os.Signal, shutdown chan os.Signal) error {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return err
	}
	err = watcher.Watch(path)
	if err != nil {
		return err
	}
	go func() {
		loop := true
		for loop {
			select {
			case _, ok := <-watcher.Event:
				if ok {
					log.Warnf("File watch triggered: %v", path)
					Notify(path, signal)
				} else {
					loop = false
				}
			case err := <-watcher.Error:
				log.Warnf("Error watching file trigger: %v %v", path, err)
				loop = false
			case signal := <-shutdown:
				log.Infof("Shutting down file watcher: %v %v", path, signal)
				loop = false
			}
		}
		err = watcher.Close()
		if err != nil {
			log.Warnf("Error stopping file watcher: %v %v", path, err)
		}
	}()
	return nil
}
<|endoftext|>


<commit_before>package watcher

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"
	"sync"

	"gopkg.in/fsnotify.v1"
)

// Op describes a set of file operations. Wraps fsnotify.
type Op fsnotify.Op

// FileEvent wraps information about the file events
// from fsnotify.
type FileEvent struct {
	// Absolute path of file.
	Path string
	// Name of the file.
	Name string
	// The file extension, ex. html, js
	Ext string
	// The operation that triggered the event
	Op
}

// Watcher watches files for changes
type Watcher struct {
	fsw *fsnotify.Watcher

	files map[string]struct{}

	ignorers []func(string) bool
	done     chan struct{}

	isClosed bool
}

func (w *Watcher) wait() {
	defer func() {
		close(w.done)
	}()
	for {
		select {
		case <-w.done:
			w.fsw.Close()
			return
		default:
		}
	}
}

// Close the watcher.
func (w *Watcher) Close() {
	if w.isClosed {
		return
	}
	log.Println("CLOSING WATCHER")
	w.isClosed = true
	w.done <- struct{}{}
}

// New creates a Watcher.
func New(root string, ignorers ...func(string) bool) (*Watcher, error) {
	w := Watcher{
		done: make(chan struct{}),
	}
	fsw, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, err
	}

	w.fsw = fsw
	w.ignorers = append(w.ignorers, IgnoreDotfiles)

	for _, ign := range ignorers {
		w.ignorers = append(w.ignorers, ign)
	}

	err = w.addFiles(root)
	if err != nil {
		return nil, err
	}

	// Wait for the close signal.
	go w.wait()
	return &w, nil
}

// AddFiles starts to recurse from the root and add files to
// the watch list.
func (w *Watcher) addFiles(root string) error {
	root = os.ExpandEnv(root)
	errc := w.walkFS(root)

	if err := <-errc; err != nil && err != filepath.SkipDir {
		return err
	}
	return nil
}

// Watch watches stuff.
func (w *Watcher) Watch() <-chan *FileEvent {
	fchan := make(chan *FileEvent, 5)
	go func() {
		defer func() {
			close(fchan)
			w.done <- struct{}{}
			log.Println("EXITING GOROUTINE")
		}()

		for {
			select {
			case ev, ok := <-w.fsw.Events:
				// If the fsnotify event chan is closed
				// there's no reason for this goroutine to
				// keep running.
				if !ok {
					break
				}
				fchan <- parseEvent(ev)
			case err, ok := <-w.fsw.Errors:
				// If the channel is closed done has
				// already been shutdown.
				if !ok {
					break
				}

				log.Fatal(err)
			}
		}
	}()

	return fchan
}

// ignore loops through our ignorers to see if we should ignore
// the path.
func (w *Watcher) ignore(path string) bool {
	for _, i := range w.ignorers {
		if i(path) {
			return true
		}
	}
	return false
}

// walkFS walks the filesystem.
func (w *Watcher) walkFS(root string) <-chan error {
	errc := make(chan error, 1)
	go func() {
		var wg sync.WaitGroup
		err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
			if err != nil {
				return err
			}

			// If it's an directory and it matches our ignore
			// clause, then skip looking at the whole directory
			if w.ignore(filepath.Base(info.Name())) && info.IsDir() {
				return filepath.SkipDir
			}

			// If the file isn't regular and not a directory, move on.
			if !info.Mode().IsRegular() && !info.IsDir() {
				return nil
			}

			// If a file matches a ignore clause or is a directory move on.
			if !info.IsDir() {
				return nil
			}

			log.Println(path)
			wg.Add(1)
			go func() {
				defer wg.Done()
				log.Println("ADDING:", info.Name())
				w.fsw.Add(path)
			}()
			return nil
		})

		go func() {
			wg.Wait()
		}()
		errc <- err

	}()
	return errc
}

// parseEvent parses the event wrapping it into a filevent
// making it easier to work with.
func parseEvent(ev fsnotify.Event) *FileEvent {
	spl := strings.Split(ev.String(), ": ")
	// fmt.Println(spl, len(spl))

	fi := &FileEvent{}

	if len(spl) > 0 {
		path := spl[0]
		// op := Op(ev.Op)

		path = strings.Trim(path, "\"")

		fmt.Println(path)
		fi.Ext = filepath.Ext(path)
		fi.Name = filepath.Base(path)
		fi.Path = path
		fi.Op = Op(ev.Op)
	}
	return fi
}
<commit_msg>added Op type<commit_after>package watcher

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"
	"sync"

	"github.com/go-fsnotify/fsnotify"
)

// Op describes a set of file operations. Wraps fsnotify.
type Op uint32

const (
	Create Op = iota
	Write
	Remove
	Rename
	Chmod
)

// FileEvent wraps information about the file events
// from fsnotify.
type FileEvent struct {
	// Absolute path of file.
	Path string
	// Name of the file.
	Name string
	// The file extension, ex. html, js
	Ext string
	// The operation that triggered the event
	Op
}

// Watcher watches files for changes
type Watcher struct {
	fsw *fsnotify.Watcher

	files map[string]struct{}

	ignorers []func(string) bool
	done     chan struct{}

	isClosed bool
}

func (w *Watcher) wait() {
	defer func() {
		close(w.done)
	}()
	for {
		select {
		case <-w.done:
			w.fsw.Close()
			return
		default:
		}
	}
}

// Close the watcher.
func (w *Watcher) Close() {
	if w.isClosed {
		return
	}
	log.Println("CLOSING WATCHER")
	w.isClosed = true
	w.done <- struct{}{}
}

// New creates a Watcher.
func New(root string, ignorers ...func(string) bool) (*Watcher, error) {
	w := Watcher{
		done: make(chan struct{}),
	}
	fsw, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, err
	}

	w.fsw = fsw
	w.ignorers = append(w.ignorers, IgnoreDotfiles)

	for _, ign := range ignorers {
		w.ignorers = append(w.ignorers, ign)
	}

	err = w.addFiles(root)
	if err != nil {
		return nil, err
	}

	// Wait for the close signal.
	go w.wait()
	return &w, nil
}

// AddFiles starts to recurse from the root and add files to
// the watch list.
func (w *Watcher) addFiles(root string) error {
	root = os.ExpandEnv(root)
	errc := w.walkFS(root)

	if err := <-errc; err != nil && err != filepath.SkipDir {
		return err
	}
	return nil
}

// Watch watches stuff.
func (w *Watcher) Watch() <-chan *FileEvent {
	fchan := make(chan *FileEvent, 5)
	go func() {
		defer func() {
			close(fchan)
			w.done <- struct{}{}
			log.Println("EXITING GOROUTINE")
		}()

		for {
			select {
			case ev, ok := <-w.fsw.Events:
				// If the fsnotify event chan is closed
				// there's no reason for this goroutine to
				// keep running.
				if !ok {
					break
				}
				fchan <- parseEvent(ev)
			case err, ok := <-w.fsw.Errors:
				// If the channel is closed done has
				// already been shutdown.
				if !ok {
					break
				}

				log.Fatal(err)
			}
		}
	}()

	return fchan
}

// ignore loops through our ignorers to see if we should ignore
// the path.
func (w *Watcher) ignore(path string) bool {
	for _, i := range w.ignorers {
		if i(path) {
			return true
		}
	}
	return false
}

// walkFS walks the filesystem.
func (w *Watcher) walkFS(root string) <-chan error {
	errc := make(chan error, 1)
	go func() {
		var wg sync.WaitGroup
		err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
			if err != nil {
				return err
			}

			// If it's an directory and it matches our ignore
			// clause, then skip looking at the whole directory
			if w.ignore(filepath.Base(info.Name())) && info.IsDir() {
				return filepath.SkipDir
			}

			// If the file isn't regular and not a directory, move on.
			if !info.Mode().IsRegular() && !info.IsDir() {
				return nil
			}

			// If a file matches a ignore clause or is a directory move on.
			if !info.IsDir() {
				return nil
			}

			log.Println(path)
			wg.Add(1)
			go func() {
				defer wg.Done()
				log.Println("ADDING:", info.Name())
				w.fsw.Add(path)
			}()
			return nil
		})

		go func() {
			wg.Wait()
		}()
		errc <- err

	}()
	return errc
}

// parseEvent parses the event wrapping it into a filevent
// making it easier to work with.
func parseEvent(ev fsnotify.Event) *FileEvent {
	spl := strings.Split(ev.String(), ": ")

	fi := &FileEvent{}

	if len(spl) > 0 {
		path := spl[0]

		path = strings.Trim(path, "\"")

		fmt.Println(path)
		fi.Ext = filepath.Ext(path)
		fi.Name = filepath.Base(path)
		fi.Path = path

		switch ev.Op {
		case fsnotify.Create:
			fi.Op = Create
		case fsnotify.Chmod:
			fi.Op = Chmod
		case fsnotify.Write:
			fi.Op = Write
		case fsnotify.Remove:
			fi.Op = Remove
		case fsnotify.Rename:
			fi.Op = Rename
		}
	}

	fmt.Println(fi)
	return fi
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
)

type Content struct {
	Query struct {
		Results struct {
			Channel struct {
				Item struct {
					Condition struct {
						Temp string `json:"temp"`
					} `json:"condition"`
				} `json:"item"`
			} `json:"channel"`
		} `json:"results"`
	} `json:"query"`
}

func (c Content) Convert() (converted int) {
	str := c.Query.Results.Channel.Item.Condition.Temp
	var err error
	converted, err = strconv.Atoi(str)
	if err != nil {
		log.Println(err)
	}
	return
}

func getWeather() (int, int){
	var fahr Content
	var fahrOy Content
	weatherMoscow := "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(2122265)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys"
	weatherOymyakon := "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22oymyakon%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys"

	res, err := http.Get(weatherMoscow)

	if err != nil {
		log.Println(err)
	}

	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)

	if err != nil {
		log.Println(err)
	}
	err = json.Unmarshal(body, &fahr)
	if err != nil {
		log.Fatal(err)
	}

	res, err = http.Get(weatherOymyakon)

	if err != nil {
		log.Println(err)
	}

	defer res.Body.Close()

	body, err = ioutil.ReadAll(res.Body)

	if err != nil {
		log.Println(err)
	}
	err = json.Unmarshal(body, &fahrOy)
	if err != nil {
		log.Fatal(err)
	}

	return fahr.Convert(), fahrOy.Convert()
}
<commit_msg>Use new fast and simple json lib<commit_after>package main

import (
	"github.com/tidwall/gjson"

	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
)

func main(int, int) {
	weatherMoscow := "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(2122265)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys"
	weatherOymyakon := "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22oymyakon%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys"

	res, err := http.Get(weatherMoscow)

	if err != nil {
		panic(err)
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		log.Println(err)
	}
	fahr := gjson.GetBytes(body, "query.results.channel.item.condition.temp")

	res, err = http.Get(weatherOymyakon)

	if err != nil {
		panic(err)
	}

	body, err = ioutil.ReadAll(res.Body)
	if err != nil {
		log.Println(err)
	}

	defer res.Body.Close()

	fahrOy := gjson.GetBytes(body, "query.results.channel.item.condition.temp")

	return int(fahr.Int()), int(fahrOy.Int())
}
<|endoftext|>


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

package web

import (
	"code.google.com/p/gorest"
	"flag"
	"github.com/prometheus/client_golang"
	"github.com/prometheus/prometheus/storage/metric"
	"github.com/prometheus/prometheus/web/api"
	"net/http"
	_ "net/http/pprof"
)

// Commandline flags.
var (
	listenAddress = flag.String("listenAddress", ":9090", "Address to listen on for web interface.")
)

func StartServing(persistence metric.MetricPersistence) {
	gorest.RegisterService(api.NewMetricsService(persistence))
	exporter := registry.DefaultRegistry.YieldExporter()

	http.Handle("/", gorest.Handle())
	http.Handle("/metrics.json", exporter)
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("web/static"))))

	go http.ListenAndServe(*listenAddress, nil)
}
<commit_msg>The Prometheus Go client has a new handler API.<commit_after>// Copyright 2013 Prometheus Team
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package web

import (
	"code.google.com/p/gorest"
	"flag"
	"github.com/prometheus/client_golang"
	"github.com/prometheus/prometheus/storage/metric"
	"github.com/prometheus/prometheus/web/api"
	"net/http"
	_ "net/http/pprof"
)

// Commandline flags.
var (
	listenAddress = flag.String("listenAddress", ":9090", "Address to listen on for web interface.")
)

func StartServing(persistence metric.MetricPersistence) {
	gorest.RegisterService(api.NewMetricsService(persistence))

	http.Handle("/", gorest.Handle())
	http.Handle("/metrics.json", registry.DefaultHandler)
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("web/static"))))

	go http.ListenAndServe(*listenAddress, nil)
}
<|endoftext|>


<commit_before>package assertions

import (
	"fmt"
	"reflect"
	"strings"
)

// ShouldStartWith receives exactly 2 string parameters and ensures that the first starts with the second.
func ShouldStartWith(actual interface{}, expected ...interface{}) string {
	if fail := need(1, expected); fail != success {
		return fail
	}

	value, valueIsString := actual.(string)
	prefix, prefixIsString := expected[0].(string)

	if !valueIsString || !prefixIsString {
		return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0]))
	}

	return shouldStartWith(value, prefix)
}
func shouldStartWith(value, prefix string) string {
	if !strings.HasPrefix(value, prefix) {
		return fmt.Sprintf(shouldHaveStartedWith, value, prefix)
	}
	return success
}

// ShouldNotStartWith receives exactly 2 string parameters and ensures that the first does not start with the second.
func ShouldNotStartWith(actual interface{}, expected ...interface{}) string {
	if fail := need(1, expected); fail != success {
		return fail
	}

	value, valueIsString := actual.(string)
	prefix, prefixIsString := expected[0].(string)

	if !valueIsString || !prefixIsString {
		return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0]))
	}

	return shouldNotStartWith(value, prefix)
}
func shouldNotStartWith(value, prefix string) string {
	if strings.HasPrefix(value, prefix) {
		if value == "" {
			value = "<empty>"
		}
		if prefix == "" {
			prefix = "<empty>"
		}
		return fmt.Sprintf(shouldNotHaveStartedWith, value, prefix)
	}
	return success
}

// ShouldEndWith receives exactly 2 string parameters and ensures that the first ends with the second.
func ShouldEndWith(actual interface{}, expected ...interface{}) string {
	if fail := need(1, expected); fail != success {
		return fail
	}

	value, valueIsString := actual.(string)
	suffix, suffixIsString := expected[0].(string)

	if !valueIsString || !suffixIsString {
		return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0]))
	}

	return shouldEndWith(value, suffix)
}
func shouldEndWith(value, suffix string) string {
	if !strings.HasSuffix(value, suffix) {
		return fmt.Sprintf(shouldHaveEndedWith, value, suffix)
	}
	return success
}

// ShouldEndWith receives exactly 2 string parameters and ensures that the first does not end with the second.
func ShouldNotEndWith(actual interface{}, expected ...interface{}) string {
	if fail := need(1, expected); fail != success {
		return fail
	}

	value, valueIsString := actual.(string)
	suffix, suffixIsString := expected[0].(string)

	if !valueIsString || !suffixIsString {
		return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0]))
	}

	return shouldNotEndWith(value, suffix)
}
func shouldNotEndWith(value, suffix string) string {
	if strings.HasSuffix(value, suffix) {
		if value == "" {
			value = "<empty>"
		}
		if suffix == "" {
			suffix = "<empty>"
		}
		return fmt.Sprintf(shouldNotHaveEndedWith, value, suffix)
	}
	return success
}

func ShouldContainSubstring(actual interface{}, expected ...interface{}) string {
	if fail := need(1, expected); fail != success {
		return fail
	}

	long, longOk := actual.(string)
	short, shortOk := expected[0].(string)

	if !longOk || !shortOk {
		return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0]))
	}

	if !strings.Contains(long, short) {
		return fmt.Sprintf(shouldHaveContainedSubstring, long, short)
	}
	return success
}

func ShouldNotContainSubstring(actual interface{}, expected ...interface{}) string {
	if fail := need(1, expected); fail != success {
		return fail
	}

	long, longOk := actual.(string)
	short, shortOk := expected[0].(string)

	if !longOk || !shortOk {
		return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0]))
	}

	if strings.Contains(long, short) {
		return fmt.Sprintf(shouldNotHaveContainedSubstring, long, short)
	}
	return success
}
<commit_msg>Documentation<commit_after>package assertions

import (
	"fmt"
	"reflect"
	"strings"
)

// ShouldStartWith receives exactly 2 string parameters and ensures that the first starts with the second.
func ShouldStartWith(actual interface{}, expected ...interface{}) string {
	if fail := need(1, expected); fail != success {
		return fail
	}

	value, valueIsString := actual.(string)
	prefix, prefixIsString := expected[0].(string)

	if !valueIsString || !prefixIsString {
		return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0]))
	}

	return shouldStartWith(value, prefix)
}
func shouldStartWith(value, prefix string) string {
	if !strings.HasPrefix(value, prefix) {
		return fmt.Sprintf(shouldHaveStartedWith, value, prefix)
	}
	return success
}

// ShouldNotStartWith receives exactly 2 string parameters and ensures that the first does not start with the second.
func ShouldNotStartWith(actual interface{}, expected ...interface{}) string {
	if fail := need(1, expected); fail != success {
		return fail
	}

	value, valueIsString := actual.(string)
	prefix, prefixIsString := expected[0].(string)

	if !valueIsString || !prefixIsString {
		return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0]))
	}

	return shouldNotStartWith(value, prefix)
}
func shouldNotStartWith(value, prefix string) string {
	if strings.HasPrefix(value, prefix) {
		if value == "" {
			value = "<empty>"
		}
		if prefix == "" {
			prefix = "<empty>"
		}
		return fmt.Sprintf(shouldNotHaveStartedWith, value, prefix)
	}
	return success
}

// ShouldEndWith receives exactly 2 string parameters and ensures that the first ends with the second.
func ShouldEndWith(actual interface{}, expected ...interface{}) string {
	if fail := need(1, expected); fail != success {
		return fail
	}

	value, valueIsString := actual.(string)
	suffix, suffixIsString := expected[0].(string)

	if !valueIsString || !suffixIsString {
		return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0]))
	}

	return shouldEndWith(value, suffix)
}
func shouldEndWith(value, suffix string) string {
	if !strings.HasSuffix(value, suffix) {
		return fmt.Sprintf(shouldHaveEndedWith, value, suffix)
	}
	return success
}

// ShouldEndWith receives exactly 2 string parameters and ensures that the first does not end with the second.
func ShouldNotEndWith(actual interface{}, expected ...interface{}) string {
	if fail := need(1, expected); fail != success {
		return fail
	}

	value, valueIsString := actual.(string)
	suffix, suffixIsString := expected[0].(string)

	if !valueIsString || !suffixIsString {
		return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0]))
	}

	return shouldNotEndWith(value, suffix)
}
func shouldNotEndWith(value, suffix string) string {
	if strings.HasSuffix(value, suffix) {
		if value == "" {
			value = "<empty>"
		}
		if suffix == "" {
			suffix = "<empty>"
		}
		return fmt.Sprintf(shouldNotHaveEndedWith, value, suffix)
	}
	return success
}

// ShouldContainSubstring receives exactly 2 string parameters and ensures that the first contains the second as a substring.
func ShouldContainSubstring(actual interface{}, expected ...interface{}) string {
	if fail := need(1, expected); fail != success {
		return fail
	}

	long, longOk := actual.(string)
	short, shortOk := expected[0].(string)

	if !longOk || !shortOk {
		return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0]))
	}

	if !strings.Contains(long, short) {
		return fmt.Sprintf(shouldHaveContainedSubstring, long, short)
	}
	return success
}

// ShouldNotContainSubstring receives exactly 2 string parameters and ensures that the first does NOT contain the second as a substring.
func ShouldNotContainSubstring(actual interface{}, expected ...interface{}) string {
	if fail := need(1, expected); fail != success {
		return fail
	}

	long, longOk := actual.(string)
	short, shortOk := expected[0].(string)

	if !longOk || !shortOk {
		return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0]))
	}

	if strings.Contains(long, short) {
		return fmt.Sprintf(shouldNotHaveContainedSubstring, long, short)
	}
	return success
}
<|endoftext|>


<commit_before>package builder

import (
	"fmt"
	"io"
	"os"
	"path"
	"path/filepath"
	"strings"

	"golang.org/x/net/context"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/builder"
	"github.com/docker/docker/builder/dockerignore"
	"github.com/docker/docker/pkg/archive"
	"github.com/docker/docker/pkg/fileutils"
	"github.com/docker/docker/pkg/jsonmessage"
	"github.com/docker/docker/pkg/progress"
	"github.com/docker/docker/pkg/streamformatter"
	"github.com/docker/docker/pkg/term"
	"github.com/docker/engine-api/client"
	"github.com/docker/engine-api/types"
)

// DefaultDockerfileName is the default name of a Dockerfile
const DefaultDockerfileName = "Dockerfile"

// Builder defines methods to provide a docker builder. This makes libcompose
// not tied up to the docker daemon builder.
type Builder interface {
	Build(imageName string) error
}

// DaemonBuilder is the daemon "docker build" Builder implementation.
type DaemonBuilder struct {
	Client           client.ImageAPIClient
	ContextDirectory string
	Dockerfile       string
	AuthConfigs      map[string]types.AuthConfig
	NoCache          bool
	ForceRemove      bool
	Pull             bool
	BuildArgs        map[string]string
}

// Build implements Builder. It consumes the docker build API endpoint and sends
// a tar of the specified service build context.
func (d *DaemonBuilder) Build(ctx context.Context, imageName string) error {
	buildCtx, err := createTar(d.ContextDirectory, d.Dockerfile)
	if err != nil {
		return err
	}
	defer buildCtx.Close()

	var progBuff io.Writer = os.Stdout
	var buildBuff io.Writer = os.Stdout

	// Setup an upload progress bar
	progressOutput := streamformatter.NewStreamFormatter().NewProgressOutput(progBuff, true)

	var body io.Reader = progress.NewProgressReader(buildCtx, progressOutput, 0, "", "Sending build context to Docker daemon")

	logrus.Infof("Building %s...", imageName)

	outFd, isTerminalOut := term.GetFdInfo(os.Stdout)

	response, err := d.Client.ImageBuild(ctx, body, types.ImageBuildOptions{
		Tags:        []string{imageName},
		NoCache:     d.NoCache,
		Remove:      true,
		ForceRemove: d.ForceRemove,
		PullParent:  d.Pull,
		Dockerfile:  d.Dockerfile,
		AuthConfigs: d.AuthConfigs,
		BuildArgs:   d.BuildArgs,
	})
	if err != nil {
		return err
	}

	err = jsonmessage.DisplayJSONMessagesStream(response.Body, buildBuff, outFd, isTerminalOut, nil)
	if err != nil {
		if jerr, ok := err.(*jsonmessage.JSONError); ok {
			// If no error code is set, default to 1
			if jerr.Code == 0 {
				jerr.Code = 1
			}
			return fmt.Errorf("Status: %s, Code: %d", jerr.Message, jerr.Code)
		}
	}
	return err
}

// CreateTar create a build context tar for the specified project and service name.
func createTar(contextDirectory, dockerfile string) (io.ReadCloser, error) {
	// This code was ripped off from docker/api/client/build.go
	dockerfileName := filepath.Join(contextDirectory, dockerfile)

	absContextDirectory, err := filepath.Abs(contextDirectory)
	if err != nil {
		return nil, err
	}

	filename := dockerfileName

	if dockerfile == "" {
		// No -f/--file was specified so use the default
		dockerfileName = DefaultDockerfileName
		filename = filepath.Join(absContextDirectory, dockerfileName)

		// Just to be nice ;-) look for 'dockerfile' too but only
		// use it if we found it, otherwise ignore this check
		if _, err = os.Lstat(filename); os.IsNotExist(err) {
			tmpFN := path.Join(absContextDirectory, strings.ToLower(dockerfileName))
			if _, err = os.Lstat(tmpFN); err == nil {
				dockerfileName = strings.ToLower(dockerfileName)
				filename = tmpFN
			}
		}
	}

	origDockerfile := dockerfileName // used for error msg
	if filename, err = filepath.Abs(filename); err != nil {
		return nil, err
	}

	// Now reset the dockerfileName to be relative to the build context
	dockerfileName, err = filepath.Rel(absContextDirectory, filename)
	if err != nil {
		return nil, err
	}

	// And canonicalize dockerfile name to a platform-independent one
	dockerfileName, err = archive.CanonicalTarNameForPath(dockerfileName)
	if err != nil {
		return nil, fmt.Errorf("Cannot canonicalize dockerfile path %s: %v", dockerfileName, err)
	}

	if _, err = os.Lstat(filename); os.IsNotExist(err) {
		return nil, fmt.Errorf("Cannot locate Dockerfile: %s", origDockerfile)
	}
	var includes = []string{"."}
	var excludes []string

	dockerIgnorePath := path.Join(contextDirectory, ".dockerignore")
	dockerIgnore, err := os.Open(dockerIgnorePath)
	if err != nil {
		if !os.IsNotExist(err) {
			return nil, err
		}
		logrus.Warnf("Error while reading .dockerignore (%s) : %s", dockerIgnorePath, err.Error())
		excludes = make([]string, 0)
	} else {
		excludes, err = dockerignore.ReadAll(dockerIgnore)
		if err != nil {
			return nil, err
		}
	}

	// If .dockerignore mentions .dockerignore or the Dockerfile
	// then make sure we send both files over to the daemon
	// because Dockerfile is, obviously, needed no matter what, and
	// .dockerignore is needed to know if either one needs to be
	// removed.  The deamon will remove them for us, if needed, after it
	// parses the Dockerfile.
	keepThem1, _ := fileutils.Matches(".dockerignore", excludes)
	keepThem2, _ := fileutils.Matches(dockerfileName, excludes)
	if keepThem1 || keepThem2 {
		includes = append(includes, ".dockerignore", dockerfileName)
	}

	if err := builder.ValidateContextDirectory(contextDirectory, excludes); err != nil {
		return nil, fmt.Errorf("Error checking context is accessible: '%s'. Please check permissions and try again.", err)
	}

	options := &archive.TarOptions{
		Compression:     archive.Uncompressed,
		ExcludePatterns: excludes,
		IncludeFiles:    includes,
	}

	return archive.TarWithOptions(contextDirectory, options)
}
<commit_msg>Expose builder.createTar<commit_after>package builder

import (
	"fmt"
	"io"
	"os"
	"path"
	"path/filepath"
	"strings"

	"golang.org/x/net/context"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/builder"
	"github.com/docker/docker/builder/dockerignore"
	"github.com/docker/docker/pkg/archive"
	"github.com/docker/docker/pkg/fileutils"
	"github.com/docker/docker/pkg/jsonmessage"
	"github.com/docker/docker/pkg/progress"
	"github.com/docker/docker/pkg/streamformatter"
	"github.com/docker/docker/pkg/term"
	"github.com/docker/engine-api/client"
	"github.com/docker/engine-api/types"
)

// DefaultDockerfileName is the default name of a Dockerfile
const DefaultDockerfileName = "Dockerfile"

// Builder defines methods to provide a docker builder. This makes libcompose
// not tied up to the docker daemon builder.
type Builder interface {
	Build(imageName string) error
}

// DaemonBuilder is the daemon "docker build" Builder implementation.
type DaemonBuilder struct {
	Client           client.ImageAPIClient
	ContextDirectory string
	Dockerfile       string
	AuthConfigs      map[string]types.AuthConfig
	NoCache          bool
	ForceRemove      bool
	Pull             bool
	BuildArgs        map[string]string
}

// Build implements Builder. It consumes the docker build API endpoint and sends
// a tar of the specified service build context.
func (d *DaemonBuilder) Build(ctx context.Context, imageName string) error {
	buildCtx, err := CreateTar(d.ContextDirectory, d.Dockerfile)
	if err != nil {
		return err
	}
	defer buildCtx.Close()

	var progBuff io.Writer = os.Stdout
	var buildBuff io.Writer = os.Stdout

	// Setup an upload progress bar
	progressOutput := streamformatter.NewStreamFormatter().NewProgressOutput(progBuff, true)

	var body io.Reader = progress.NewProgressReader(buildCtx, progressOutput, 0, "", "Sending build context to Docker daemon")

	logrus.Infof("Building %s...", imageName)

	outFd, isTerminalOut := term.GetFdInfo(os.Stdout)

	response, err := d.Client.ImageBuild(ctx, body, types.ImageBuildOptions{
		Tags:        []string{imageName},
		NoCache:     d.NoCache,
		Remove:      true,
		ForceRemove: d.ForceRemove,
		PullParent:  d.Pull,
		Dockerfile:  d.Dockerfile,
		AuthConfigs: d.AuthConfigs,
		BuildArgs:   d.BuildArgs,
	})
	if err != nil {
		return err
	}

	err = jsonmessage.DisplayJSONMessagesStream(response.Body, buildBuff, outFd, isTerminalOut, nil)
	if err != nil {
		if jerr, ok := err.(*jsonmessage.JSONError); ok {
			// If no error code is set, default to 1
			if jerr.Code == 0 {
				jerr.Code = 1
			}
			return fmt.Errorf("Status: %s, Code: %d", jerr.Message, jerr.Code)
		}
	}
	return err
}

// CreateTar create a build context tar for the specified project and service name.
func CreateTar(contextDirectory, dockerfile string) (io.ReadCloser, error) {
	// This code was ripped off from docker/api/client/build.go
	dockerfileName := filepath.Join(contextDirectory, dockerfile)

	absContextDirectory, err := filepath.Abs(contextDirectory)
	if err != nil {
		return nil, err
	}

	filename := dockerfileName

	if dockerfile == "" {
		// No -f/--file was specified so use the default
		dockerfileName = DefaultDockerfileName
		filename = filepath.Join(absContextDirectory, dockerfileName)

		// Just to be nice ;-) look for 'dockerfile' too but only
		// use it if we found it, otherwise ignore this check
		if _, err = os.Lstat(filename); os.IsNotExist(err) {
			tmpFN := path.Join(absContextDirectory, strings.ToLower(dockerfileName))
			if _, err = os.Lstat(tmpFN); err == nil {
				dockerfileName = strings.ToLower(dockerfileName)
				filename = tmpFN
			}
		}
	}

	origDockerfile := dockerfileName // used for error msg
	if filename, err = filepath.Abs(filename); err != nil {
		return nil, err
	}

	// Now reset the dockerfileName to be relative to the build context
	dockerfileName, err = filepath.Rel(absContextDirectory, filename)
	if err != nil {
		return nil, err
	}

	// And canonicalize dockerfile name to a platform-independent one
	dockerfileName, err = archive.CanonicalTarNameForPath(dockerfileName)
	if err != nil {
		return nil, fmt.Errorf("Cannot canonicalize dockerfile path %s: %v", dockerfileName, err)
	}

	if _, err = os.Lstat(filename); os.IsNotExist(err) {
		return nil, fmt.Errorf("Cannot locate Dockerfile: %s", origDockerfile)
	}
	var includes = []string{"."}
	var excludes []string

	dockerIgnorePath := path.Join(contextDirectory, ".dockerignore")
	dockerIgnore, err := os.Open(dockerIgnorePath)
	if err != nil {
		if !os.IsNotExist(err) {
			return nil, err
		}
		logrus.Warnf("Error while reading .dockerignore (%s) : %s", dockerIgnorePath, err.Error())
		excludes = make([]string, 0)
	} else {
		excludes, err = dockerignore.ReadAll(dockerIgnore)
		if err != nil {
			return nil, err
		}
	}

	// If .dockerignore mentions .dockerignore or the Dockerfile
	// then make sure we send both files over to the daemon
	// because Dockerfile is, obviously, needed no matter what, and
	// .dockerignore is needed to know if either one needs to be
	// removed.  The deamon will remove them for us, if needed, after it
	// parses the Dockerfile.
	keepThem1, _ := fileutils.Matches(".dockerignore", excludes)
	keepThem2, _ := fileutils.Matches(dockerfileName, excludes)
	if keepThem1 || keepThem2 {
		includes = append(includes, ".dockerignore", dockerfileName)
	}

	if err := builder.ValidateContextDirectory(contextDirectory, excludes); err != nil {
		return nil, fmt.Errorf("Error checking context is accessible: '%s'. Please check permissions and try again.", err)
	}

	options := &archive.TarOptions{
		Compression:     archive.Uncompressed,
		ExcludePatterns: excludes,
		IncludeFiles:    includes,
	}

	return archive.TarWithOptions(contextDirectory, options)
}
<|endoftext|>


<commit_before>package blocks

import "testing"

func TestBlocksBasic(t *testing.T) {

	// Test empty data
	empty := []byte{}
	NewBlock(empty)

	// Test nil case
	NewBlock(nil)

	// Test some data
	NewBlock([]byte("Hello world!"))
}
<commit_msg>test: 82% coverage on blocks<commit_after>package blocks

import (
	"bytes"
	"testing"

	mh "gx/ipfs/QmYf7ng2hG5XBtJA3tN34DQ2GUN5HNksEw1rLDkmr6vGku/go-multihash"
	u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
)

func TestBlocksBasic(t *testing.T) {

	// Test empty data
	empty := []byte{}
	NewBlock(empty)

	// Test nil case
	NewBlock(nil)

	// Test some data
	NewBlock([]byte("Hello world!"))
}

func TestData(t *testing.T) {
	data := []byte("some data")
	block := NewBlock(data)

	if !bytes.Equal(block.Data(), data) {
		t.Error("data is wrong")
	}
}

func TestHash(t *testing.T) {
	data := []byte("some other data")
	block := NewBlock(data)

	hash, err := mh.Sum(data, mh.SHA2_256, -1)
	if err != nil {
		t.Fatal(err)
	}

	if !bytes.Equal(block.Multihash(), hash) {
		t.Error("wrong multihash")
	}
}

func TestKey(t *testing.T) {
	data := []byte("yet another data")
	block := NewBlock(data)
	key := block.Key()

	if !bytes.Equal(block.Multihash(), key.ToMultihash()) {
		t.Error("key contains wrong data")
	}
}

func TestManualHash(t *testing.T) {
	oldDebugState := u.Debug
	defer (func() {
		u.Debug = oldDebugState
	})()

	data := []byte("I can't figure out more names .. data")
	hash, err := mh.Sum(data, mh.SHA2_256, -1)
	if err != nil {
		t.Fatal(err)
	}

	u.Debug = false
	block, err := NewBlockWithHash(data, hash)
	if err != nil {
		t.Fatal(err)
	}

	if !bytes.Equal(block.Multihash(), hash) {
		t.Error("wrong multihash")
	}

	data[5] = byte((uint32(data[5]) + 5) % 256) // Transfrom hash to be different
	block, err = NewBlockWithHash(data, hash)
	if err != nil {
		t.Fatal(err)
	}

	if !bytes.Equal(block.Multihash(), hash) {
		t.Error("wrong multihash")
	}

	u.Debug = true

	block, err = NewBlockWithHash(data, hash)
	if err == nil {
		t.Fatal(err)
	}

}
<|endoftext|>


<commit_before>// Package service provides Start, Status and Stop functions
package service

import (
	"errors"
	"os/exec"
)

var (
	srvControl  control
	controlType ControlType
)

type (
	// ControlType represents the service control type
	ControlType int

	// control is a interface that represents services control (launchctl, initctl, systemctl, etc)
	control interface {
		startCmd(sName string) []string
		stopCmd(sName string) []string
		statusCmd(sName string) []string
		parseStatus(sData string, err error) (Status, error)
	}

	// Execution represents a service instance for execution operation
	Handler struct {
		Sudo        bool
		ServiceName string
	}
	// Status represents a service status
	Status struct {
		Running bool
		PID     int
	}
)

const (
	none ControlType = 1 + iota
	// LaunchCtl - Mac OS implementation (https://developer.applh.com/library/mac/documentation/Darwin/Reference/ManPages/man1/launchctl.1.html)
	LaunchCtl
	// Upstart implementation (http://upstart.ubuntu.com/)
	Upstart
	// SystemD is systemd implementation (https://fedoraproject.org/wiki/Systemd, https://github.com/systemd/systemd)
	SystemD
)

func init() {
	controlType, srvControl = getControlType()
}

// NewExecution constructs a execution with a given namh.
// In linux with sudo true and Mac sudo false
func NewHandler(serviceName string) *Handler {
	return &Handler{sudoDefault(), serviceName}
}

// Start starts service
func (h *Handler) Start() (Status, error) {
	return h.execService(srvControl.startCmd(h.ServiceName))
}

// GetStatus show the status for a given service name
func (h *Handler) GetStatus() (Status, error) {
	out, err := h.execServiceCmd(srvControl.statusCmd(h.ServiceName))
	return srvControl.parseStatus(out, err)
}

// Stop stops service
func (h *Handler) Stop() (Status, error) {
	return h.execService(srvControl.stopCmd(h.ServiceName))
}

func (h *Handler) execService(cmdArr []string) (Status, error) {
	out, err := h.execServiceCmd(cmdArr)
	if err != nil {
		return Status{}, errors.New(out)
	}
	return h.GetStatus()
}

func (h *Handler) execServiceCmd(cmdArr []string) (string, error) {
	if h.Sudo {
		return execCmd("sudo", cmdArr...)
	}
	return execCmd(cmdArr[0], cmdArr[1:len(cmdArr)]...)
}

func execCmd(cmd string, arg ...string) (string, error) {
	out, err := exec.Command(cmd, arg...).CombinedOutput()
	return string(out), err
}
<commit_msg>Added wait for start and stop<commit_after>// Package service provides Start, Status and Stop functions
package service

import (
	"errors"
	"os/exec"
	"time"
)

var (
	srvControl  control
	controlType ControlType
)

type (
	// ControlType represents the service control type
	ControlType int

	// control is a interface that represents services control (launchctl, initctl, systemctl, etc)
	control interface {
		startCmd(sName string) []string
		stopCmd(sName string) []string
		statusCmd(sName string) []string
		parseStatus(sData string, err error) (Status, error)
	}

	// Execution represents a service instance for execution operation
	Handler struct {
		Sudo        bool
		ServiceName string
	}
	// Status represents a service status
	Status struct {
		Running bool
		PID     int
	}
)

const (
	none ControlType = 1 + iota
	// LaunchCtl - Mac OS implementation (https://developer.applh.com/library/mac/documentation/Darwin/Reference/ManPages/man1/launchctl.1.html)
	LaunchCtl
	// Upstart implementation (http://upstart.ubuntu.com/)
	Upstart
	// SystemD is systemd implementation (https://fedoraproject.org/wiki/Systemd, https://github.com/systemd/systemd)
	SystemD
)

func init() {
	controlType, srvControl = getControlType()
}

// NewHandler constructs a handler with a given name.
// In linux with sudo true and Mac sudo false
func NewHandler(serviceName string) *Handler {
	return &Handler{sudoDefault(), serviceName}
}

// Start starts a service
func (h *Handler) Start() (Status, error) {
	return h.execService(srvControl.startCmd(h.ServiceName))
}

// Start starts a service and wait it starts
func (h *Handler) StartAndWait(timeout time.Duration) (Status, error) {
	_, err := h.Start()
	if err != nil {
		return Status{}, err
	}
	return h.waitTimeout(false, timeout)
}

// GetStatus show the status for a service
func (h *Handler) GetStatus() (Status, error) {
	out, err := h.execServiceCmd(srvControl.statusCmd(h.ServiceName))
	return srvControl.parseStatus(out, err)
}

// Stop stops a service
func (h *Handler) Stop() (Status, error) {
	return h.execService(srvControl.stopCmd(h.ServiceName))
}

// Stop stops a service and wait it stops
func (h *Handler) StopAndWait(timeout time.Duration) (Status, error) {
	_, err := h.Stop()
	if err != nil {
		return Status{}, err
	}
	return h.waitTimeout(true, timeout)
}

func (h *Handler) execService(cmdArr []string) (Status, error) {
	out, err := h.execServiceCmd(cmdArr)
	if err != nil {
		return Status{}, errors.New(out)
	}
	return h.GetStatus()
}

func (h *Handler) execServiceCmd(cmdArr []string) (string, error) {
	if h.Sudo {
		return execCmd("sudo", cmdArr...)
	}
	return execCmd(cmdArr[0], cmdArr[1:len(cmdArr)]...)
}

func (h *Handler) waitTimeout(running bool, timeout time.Duration) (Status, error) {
	timeoutChannel := make(chan Status, 1)
	go func() {
		st, _ := h.GetStatus()
		for getRunningCondition(running, st) {
			st, _ = h.GetStatus()
			time.Sleep(100 * time.Millisecond)
		}
		timeoutChannel <- st
	}()

	select {
	case res := <-timeoutChannel:
		return res, nil
	case <-time.After(timeout):
		return Status{}, errors.New("timeout after " + timeout.String())
	}
}

func getRunningCondition(running bool, st Status) bool {
	if running {
		return st.Running
	} else {
		return !st.Running
	}
}

func execCmd(cmd string, arg ...string) (string, error) {
	out, err := exec.Command(cmd, arg...).CombinedOutput()
	return string(out), err
}
<|endoftext|>


<commit_before>// +build ignore

package main

import (
	"archive/zip"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"time"
)

var ZIP *zip.Writer

func check(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func build() {
	cmd := exec.Command("go", "build", "-o", filepath.Join(".bin", "run"), ".")
	cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr

	cmd.Env = os.Environ()
	cmd.Env = append(cmd.Env, "GOOS=linux", "GOARCH=amd64")
	check(cmd.Run())

	AddDir(".bin")

	AddGlob("*.json")
	AddGlob("Docker*")
	AddGlob("LICENSE-*")

	AddDir("assets")
	AddDir("client")
	AddDir("templates")

}

func main() {
	os.Mkdir(".bin", 0755)
	os.Mkdir(".deploy", 0755)

	filename := fmt.Sprintf("%s.zip", time.Now().Format("2006-01-02-15-04"))

	file, err := os.Create(filepath.Join(".deploy", filename))
	check(err)
	defer file.Close()

	fmt.Println("Creating:", filename)

	ZIP = zip.NewWriter(file)
	defer ZIP.Close()

	build()
}

// filename with forward slashes
func AddFile(filename string) {
	fmt.Printf("  %-40s", filename)
	defer fmt.Println("+")

	file, err := os.Open(filepath.FromSlash(filename))
	check(err)
	defer file.Close()

	w, err := ZIP.Create(filename)
	check(err)
	_, err = io.Copy(w, file)
	check(err)
}

// glob with forward slashes
func AddGlob(glob string) {
	fmt.Printf("G %v\n", glob)
	matches, err := filepath.Glob(filepath.FromSlash(glob))
	check(err)
	for _, match := range matches {
		AddFile(filepath.ToSlash(match))
	}
}

// dir with forward slashes
func AddDir(dir string) {
	fmt.Printf("D %v\n", dir)
	check(filepath.Walk(filepath.FromSlash(dir),
		func(path string, info os.FileInfo, err error) error {
			if err != nil {
				return err
			}
			if info.IsDir() {
				return nil
			}

			AddFile(filepath.ToSlash(path))
			return nil
		}))
}
<commit_msg>Fix build script for Go 1.5<commit_after>// +build ignore

package main

import (
	"archive/zip"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"
)

var ZIP *zip.Writer

func check(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func run(name string, args ...string) error {
	fmt.Println("> ", name, strings.Join(args, " "))

	cmd := exec.Command(name, args...)
	cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
	cmd.Env = append([]string{
		"GOOS=linux",
		"GOARCH=amd64",
		"CGO_ENABLED=0",
	}, os.Environ()...)

	return cmd.Run()
}

func build() {
	check(run("go", "build", "-v", "-o", filepath.Join(".bin", "run"), "."))
	AddDir(".bin")

	AddGlob("*.json")
	AddGlob("Docker*")
	AddGlob("LICENSE-*")

	AddDir("assets")
	AddDir("client")
	AddDir("templates")

}

func main() {
	os.Mkdir(".bin", 0755)
	os.Mkdir(".deploy", 0755)

	filename := fmt.Sprintf("%s.zip", time.Now().Format("2006-01-02-15-04"))

	file, err := os.Create(filepath.Join(".deploy", filename))
	check(err)
	defer file.Close()

	fmt.Println("Creating:", filename)

	ZIP = zip.NewWriter(file)
	build()
	ZIP.Close()
}

// filename with forward slashes
func AddFile(filename string) {
	fmt.Printf("  %-40s", filename)
	defer fmt.Println("+")

	file, err := os.Open(filepath.FromSlash(filename))
	check(err)
	defer file.Close()

	w, err := ZIP.Create(filename)
	check(err)
	_, err = io.Copy(w, file)
	check(err)
}

// glob with forward slashes
func AddGlob(glob string) {
	fmt.Printf("G %v\n", glob)
	matches, err := filepath.Glob(filepath.FromSlash(glob))
	check(err)
	for _, match := range matches {
		AddFile(filepath.ToSlash(match))
	}
}

// dir with forward slashes
func AddDir(dir string) {
	fmt.Printf("D %v\n", dir)
	check(filepath.Walk(filepath.FromSlash(dir),
		func(path string, info os.FileInfo, err error) error {
			if err != nil {
				return err
			}
			if info.IsDir() {
				return nil
			}

			AddFile(filepath.ToSlash(path))
			return nil
		}))
}
<|endoftext|>


<commit_before>// $G $D/$F.go && $L $F.$A && ./$A.out

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

package main

// test range over channels

func gen(c chan int, lo, hi int) {
	for i := lo; i <= hi; i++ {
		c <- i;
	}
	close(c);
}

func seq(lo, hi int) chan int {
	c := make(chan int);
	go gen(c, lo, hi);
	return c;
}

func testchan() {
	s := "";
	for i := range seq('a', 'z') {
		s += string(i);
	}
	if s != "abcdefghijklmnopqrstuvwxyz" {
		panicln("Wanted lowercase alphabet; got", s);
	}
}

// test that range over array only evaluates
// the expression after "range" once.

var nmake = 0;
func makearray() []int {
	nmake++;
	return []int{1,2,3,4,5};
}

func testarray() {
	s := 0;
	for _, v := range makearray() {
		s += v;
	}
	if nmake != 1 {
		panicln("range called makearray", nmake, "times");
	}
	if s != 15 {
		panicln("wrong sum ranging over makearray");
	}
}

func main() {
	testchan();
	testarray();
}
<commit_msg>Test evaluation of range variables.<commit_after>// $G $D/$F.go && $L $F.$A && ./$A.out

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

package main

// test range over channels

func gen(c chan int, lo, hi int) {
	for i := lo; i <= hi; i++ {
		c <- i;
	}
	close(c);
}

func seq(lo, hi int) chan int {
	c := make(chan int);
	go gen(c, lo, hi);
	return c;
}

func testchan() {
	s := "";
	for i := range seq('a', 'z') {
		s += string(i);
	}
	if s != "abcdefghijklmnopqrstuvwxyz" {
		panicln("Wanted lowercase alphabet; got", s);
	}
}

// test that range over array only evaluates
// the expression after "range" once.

var nmake = 0;
func makearray() []int {
	nmake++;
	return []int{1,2,3,4,5};
}

func testarray() {
	s := 0;
	for _, v := range makearray() {
		s += v;
	}
	if nmake != 1 {
		panicln("range called makearray", nmake, "times");
	}
	if s != 15 {
		panicln("wrong sum ranging over makearray");
	}
}

// test that range evaluates the index and value expressions
// exactly once per iteration.

var ncalls = 0
func getvar(p *int) *int {
	ncalls++
	return p
}

func testcalls() {
	var i, v int
	si := 0
	sv := 0
	for *getvar(&i), *getvar(&v) = range [2]int{1, 2} {
		si += i
		sv += v
	}
	if ncalls != 4 {
		panicln("wrong number of calls:", ncalls, "!= 4")
	}
	if si != 1 || sv != 3 {
		panicln("wrong sum in testcalls", si, sv)
	}

	ncalls = 0
	for *getvar(&i), *getvar(&v) = range [0]int{} {
		panicln("loop ran on empty array")
	}
	if ncalls != 0 {
		panicln("wrong number of calls:", ncalls, "!= 0")
	}
}

func main() {
	testchan();
	testarray();
	testcalls();
}
<|endoftext|>