<commit_before>// Package plate provides a Recorder for testing Go's HTML templates.
package plate

import (
	"bytes"
	"io"
	"sync"
)

// Execution represents one occurence of template being executed.
// It provides access to the output produced,
// the context that was passed to the template
// and the error returned from the Execute*() function, if any.
type Execution struct {
	Output  []byte
	Context interface{}

	Error error
}

// Recorder wraps an Executor and
// records results of executions for later checks.
type Recorder struct {
	// The original template to wrap.
	Template Executor

	// Go's templates are already safe to be used in parallel,
	// this mutex only protects our own fields, like `execs`.
	mu sync.RWMutex
	// Stores exucution info
	execs []Execution
}

func New(tmpl Executor) {
	return Recorder{Template: tmpl}
}

func (r *Recorder) save(exec Execution) {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.execs = append(r.execs, exec)
}

// Execute executes the wrapped template,
// saving information into the Recorder.
func (r *Recorder) Execute(wr io.Writer, data interface{}) error {
	exec := Execution{Context: data}

	// Substitute the reader
	buf := &bytes.Buffer{}
	writer := io.MultiWriter(buf, wr)

	// Execute and fill out the results
	err := r.Template.Execute(writer, data)
	exec.Output = buf.Bytes()
	exec.Error = err

	r.save(exec)
	return err
}

// ExecuteTemplate is like Execute, but for named teplates.
func (r *Recorder) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
	exec := Execution{Context: data}

	// Substitute the reader
	buf := &bytes.Buffer{}
	writer := io.MultiWriter(buf, wr)

	// Execute and fill out the results
	err := r.Template.ExecuteTemplate(writer, name, data)
	exec.Output = buf.Bytes()
	exec.Error = err

	r.save(exec)
	return err
}

// Executions returns all executions that have occured
// since the construction of a Recorder (or since Reset()).
func (r *Recorder) Executions() []Execution {
	tmpExecs := make([]Execution, len(r.execs))
	// We do a copy, because callee may mess around with internal []Execution
	// and we do not want this.
	r.mu.RLock()
	defer r.mu.RUnlock()
	copy(tmpExecs, r.execs)
	return tmpExecs
}

// LastExecution returns the information of the latest execution.
// It panics if no executions have occured yet.
func (r *Recorder) LastExecution() Execution {
	if len(r.execs) < 1 {
		panic("No executions are available yet.")
	}
	r.mu.RLock()
	defer r.mu.RUnlock()
	return r.execs[len(r.execs)-1]
}

// TimesExecuted returns the count of times
// template has been executed
// since construction or calling Reset().
func (r *Recorder) TimesExecuted() int {
	return len(r.execs)
}

// FailedExecutions returns all executions that have Error != nil
func (r *Recorder) FailedExecutions() []Execution {
	failedExecs := make([]Execution, 0)
	r.mu.RLock()
	defer r.mu.RUnlock()
	for _, exec := range r.execs {
		if exec.Error != nil {
			failedExecs = append(failedExecs, exec)
		}
	}

	return failedExecs
}

// Reset clears all executions. Recorder is thus restored to its initial state.
func (r *Recorder) Reset() {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.execs = make([]Execution, 0)
}

// Ensure interface compliance
var _ Executor = &Recorder{}
<commit_msg>Oops.<commit_after>// Package plate provides a Recorder for testing Go's HTML templates.
package plate

import (
	"bytes"
	"io"
	"sync"
)

// Execution represents one occurence of template being executed.
// It provides access to the output produced,
// the context that was passed to the template
// and the error returned from the Execute*() function, if any.
type Execution struct {
	Output  []byte
	Context interface{}

	Error error
}

// Recorder wraps an Executor and
// records results of executions for later checks.
type Recorder struct {
	// The original template to wrap.
	Template Executor

	// Go's templates are already safe to be used in parallel,
	// this mutex only protects our own fields, like `execs`.
	mu sync.RWMutex
	// Stores exucution info
	execs []Execution
}

func New(tmpl Executor) *Recorder {
	return &Recorder{Template: tmpl}
}

func (r *Recorder) save(exec Execution) {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.execs = append(r.execs, exec)
}

// Execute executes the wrapped template,
// saving information into the Recorder.
func (r *Recorder) Execute(wr io.Writer, data interface{}) error {
	exec := Execution{Context: data}

	// Substitute the reader
	buf := &bytes.Buffer{}
	writer := io.MultiWriter(buf, wr)

	// Execute and fill out the results
	err := r.Template.Execute(writer, data)
	exec.Output = buf.Bytes()
	exec.Error = err

	r.save(exec)
	return err
}

// ExecuteTemplate is like Execute, but for named teplates.
func (r *Recorder) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
	exec := Execution{Context: data}

	// Substitute the reader
	buf := &bytes.Buffer{}
	writer := io.MultiWriter(buf, wr)

	// Execute and fill out the results
	err := r.Template.ExecuteTemplate(writer, name, data)
	exec.Output = buf.Bytes()
	exec.Error = err

	r.save(exec)
	return err
}

// Executions returns all executions that have occured
// since the construction of a Recorder (or since Reset()).
func (r *Recorder) Executions() []Execution {
	tmpExecs := make([]Execution, len(r.execs))
	// We do a copy, because callee may mess around with internal []Execution
	// and we do not want this.
	r.mu.RLock()
	defer r.mu.RUnlock()
	copy(tmpExecs, r.execs)
	return tmpExecs
}

// LastExecution returns the information of the latest execution.
// It panics if no executions have occured yet.
func (r *Recorder) LastExecution() Execution {
	if len(r.execs) < 1 {
		panic("No executions are available yet.")
	}
	r.mu.RLock()
	defer r.mu.RUnlock()
	return r.execs[len(r.execs)-1]
}

// TimesExecuted returns the count of times
// template has been executed
// since construction or calling Reset().
func (r *Recorder) TimesExecuted() int {
	return len(r.execs)
}

// FailedExecutions returns all executions that have Error != nil
func (r *Recorder) FailedExecutions() []Execution {
	failedExecs := make([]Execution, 0)
	r.mu.RLock()
	defer r.mu.RUnlock()
	for _, exec := range r.execs {
		if exec.Error != nil {
			failedExecs = append(failedExecs, exec)
		}
	}

	return failedExecs
}

// Reset clears all executions. Recorder is thus restored to its initial state.
func (r *Recorder) Reset() {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.execs = make([]Execution, 0)
}

// Ensure interface compliance
var _ Executor = &Recorder{}
<|endoftext|>


<commit_before>// Package recovery implements couple of middleware interfaces
//
// package main
//
// import (
//     "github.com/vanng822/r2router"
//     "github.com/vanng822/recovery"
//     "net/http"
// )
//
// func main() {
//     seefor := r2router.NewSeeforRouter()
//     rec := recovery.NewRecovery()
//     rec.PrintStack = true
//     seefor.Before(rec.Handler)
// 	   seefor.Get("/user/keys/:id", func(w http.ResponseWriter, r *http.Request, _ r2router.Params) {
// 	   		panic("This shouldn't crash Seefor")
// 	   })
//
//     http.ListenAndServe(":8080", seefor)
// }
package recovery

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"runtime"
)

type Logger interface {
	Printf(format string, v ...interface{})
}

type Recovery struct {
	Logger     Logger
	StackAll   bool
	StackSize  int
	PrintStack bool
}

func (rec *Recovery) recovery(w http.ResponseWriter) {
	if err := recover(); err != nil {
		w.WriteHeader(http.StatusInternalServerError)

		stack := make([]byte, rec.StackSize)
		stack = stack[:runtime.Stack(stack, rec.StackAll)]
		format := "PANIC: %s\n%s"
		rec.Logger.Printf(format, err, stack)

		if rec.PrintStack {
			fmt.Fprintf(w, format, err, stack)
		} else {
			w.Write([]byte(http.StatusText(http.StatusInternalServerError)))
		}
	}
}

func NewRecovery() *Recovery {
	return &Recovery{
		Logger:     log.New(os.Stdout, "[error] ", 0),
		StackAll:   false,
		StackSize:  1024 * 8,
		PrintStack: false,
	}
}

func (rec *Recovery) Handler(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		defer rec.recovery(w)
		next.ServeHTTP(w, req)
	})
}

func (rec *Recovery) HandlerFuncWithNext(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	defer rec.recovery(w)
	next(w, r)
}
<commit_msg>Autoformatting<commit_after>// Package recovery implements couple of middleware interfaces
//
// package main
//
// import (
//     "github.com/vanng822/r2router"
//     "github.com/vanng822/recovery"
//     "net/http"
// )
//
// func main() {
//     seefor := r2router.NewSeeforRouter()
//     rec := recovery.NewRecovery()
//     rec.PrintStack = true
//     seefor.Before(rec.Handler)
// seefor.Get("/user/keys/:id", func(w http.ResponseWriter, r *http.Request, _ r2router.Params) {
// 	   		panic("This shouldn't crash Seefor")
// 	   })
//
//     http.ListenAndServe(":8080", seefor)
// }
package recovery

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"runtime"
)

type Logger interface {
	Printf(format string, v ...interface{})
}

type Recovery struct {
	Logger     Logger
	StackAll   bool
	StackSize  int
	PrintStack bool
}

func (rec *Recovery) recovery(w http.ResponseWriter) {
	if err := recover(); err != nil {
		w.WriteHeader(http.StatusInternalServerError)

		stack := make([]byte, rec.StackSize)
		stack = stack[:runtime.Stack(stack, rec.StackAll)]
		format := "PANIC: %s\n%s"
		rec.Logger.Printf(format, err, stack)

		if rec.PrintStack {
			fmt.Fprintf(w, format, err, stack)
		} else {
			w.Write([]byte(http.StatusText(http.StatusInternalServerError)))
		}
	}
}

func NewRecovery() *Recovery {
	return &Recovery{
		Logger:     log.New(os.Stdout, "[error] ", 0),
		StackAll:   false,
		StackSize:  1024 * 8,
		PrintStack: false,
	}
}

func (rec *Recovery) Handler(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		defer rec.recovery(w)
		next.ServeHTTP(w, req)
	})
}

func (rec *Recovery) HandlerFuncWithNext(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	defer rec.recovery(w)
	next(w, r)
}
<|endoftext|>


<commit_before>package eliteConfiguration_test

import (
	"github.com/EliteSystems/eliteConfiguration"
	"testing"
)

var (
	jsonContent = []byte("{\"Name\": \"ConfigurationName\", \"Properties\": {\"Property1\": {\"Key\":\"Key1\", \"Value\":\"Value1\"}, \"Property2\": {\"Key\":\"Key2\", \"Value\":\"Value2\"}}}")
)

/*
Print the tested Library's version
*/
func TestVersion(t *testing.T) {
	eliteConfiguration.PrintVersion()
}

/*
Try to create New Configuration from valid JSON content
*/
func TestNew(t *testing.T) {
	switch configuration, err := eliteConfiguration.New(jsonContent); true {
	case err != nil:
		t.Errorf(err.Error())
	case configuration.Name != "ConfigurationName":
		t.Errorf("Configuration.Name should be \"ConfigurationName\"")
	case len(configuration.Properties) != 2:
		t.Errorf("Configuration should have 2 Properties")
	case configuration.Properties["Property1"].Key != "Key1":
		t.Errorf("Configuration.Properties[\"Property1\"].Key should be \"Key1\"")
	case configuration.Properties["Property1"].Value != "Value1":
		t.Errorf("Configuration.Properties[\"Property1\"].Value should be \"Value1\"")
	}
}

/*
Try to create New Configuration from invalid JSON content
*/
func TestNewWithInvalidJSON(t *testing.T) {
	incompleteJSONContent := jsonContent[1:]
	switch _, err := eliteConfiguration.New(incompleteJSONContent); true {
	case err == nil:
		t.Errorf("New() method should be throw an error")
	}
}

/*
Try to Add a Property to the Test Configuration
*/
func TestConfigurationAddProperty(t *testing.T) {
	if configuration, err := eliteConfiguration.New(jsonContent); err == nil {
		if _, ok := configuration.AddProperty(eliteConfiguration.Property{Key: "KeyAdded", Value: "ValueAdded"}).Properties["KeyAdded"]; !ok {
			t.Errorf("Property [\"KeyAdded\"] should exist")
		}
	}
}
<commit_msg>eliteConfiguration - AddProperty<commit_after>package eliteConfiguration_test

import (
	"github.com/EliteSystems/eliteConfiguration"
	"testing"
)

var (
	jsonContent = []byte("{\"Name\": \"ConfigurationName\", \"Properties\": {\"Property1\": {\"Key\":\"Key1\", \"Value\":\"Value1\"}, \"Property2\": {\"Key\":\"Key2\", \"Value\":\"Value2\"}}}")
)

/*
Print the tested Library's version
*/
func TestVersion(t *testing.T) {
	eliteConfiguration.PrintVersion()
}

/*
Try to create New Configuration from valid JSON content
*/
func TestNew(t *testing.T) {
	switch configuration, err := eliteConfiguration.New(jsonContent); true {
	case err != nil:
		t.Errorf(err.Error())
	case configuration.Name != "ConfigurationName":
		t.Errorf("Configuration.Name should be \"ConfigurationName\"")
	case len(configuration.Properties) != 2:
		t.Errorf("Configuration should have 2 Properties")
	case configuration.Properties["Property1"].Key != "Key1":
		t.Errorf("Configuration.Properties[\"Property1\"].Key should be \"Key1\"")
	case configuration.Properties["Property1"].Value != "Value1":
		t.Errorf("Configuration.Properties[\"Property1\"].Value should be \"Value1\"")
	}
}

/*
Try to create New Configuration from invalid JSON content
*/
func TestNewWithInvalidJSON(t *testing.T) {
	incompleteJSONContent := jsonContent[1:]
	switch _, err := eliteConfiguration.New(incompleteJSONContent); true {
	case err == nil:
		t.Errorf("New() method should be throw an error")
	}
}

/*
Try to Add a Property to the Test Configuration
*/
func TestConfigurationAddProperty(t *testing.T) {
	if configuration, err := eliteConfiguration.New(jsonContent); err == nil {
		configuration = configuration.AddProperty(eliteConfiguration.Property{Key: "KeyAdded", Value: "ValueAdded"})
		if _, ok := configuration.Properties["KeyAdded"]; !ok {
			t.Errorf("Property [\"KeyAdded\"] should exist")
		}
		if _, ok := configuration.Properties["Property1"]; !ok {
			t.Errorf("Property [\"Property1\"] should exist")
		}
	}
}
<|endoftext|>


<commit_before>package exec

import (
	"context"
	"errors"
	"fmt"
	"github.com/concourse/concourse/atc/metric"
	"io"

	"code.cloudfoundry.org/lager"
	"code.cloudfoundry.org/lager/lagerctx"
	"github.com/concourse/concourse/atc"
	"github.com/concourse/concourse/atc/creds"
	"github.com/concourse/concourse/atc/db"
	"github.com/concourse/concourse/atc/exec/build"
	"github.com/concourse/concourse/atc/resource"
	"github.com/concourse/concourse/atc/runtime"
	"github.com/concourse/concourse/atc/worker"
	"github.com/concourse/concourse/tracing"
	"go.opentelemetry.io/otel/api/trace"
)

type ErrPipelineNotFound struct {
	PipelineName string
}

func (e ErrPipelineNotFound) Error() string {
	return fmt.Sprintf("pipeline '%s' not found", e.PipelineName)
}

type ErrResourceNotFound struct {
	ResourceName string
}

func (e ErrResourceNotFound) Error() string {
	return fmt.Sprintf("resource '%s' not found", e.ResourceName)
}

//go:generate counterfeiter . GetDelegateFactory

type GetDelegateFactory interface {
	GetDelegate(state RunState) GetDelegate
}

//go:generate counterfeiter . GetDelegate

type GetDelegate interface {
	StartSpan(context.Context, string, tracing.Attrs) (context.Context, trace.Span)

	FetchImage(context.Context, atc.ImageResource, atc.VersionedResourceTypes, bool) (worker.ImageSpec, error)

	Stdout() io.Writer
	Stderr() io.Writer

	Initializing(lager.Logger)
	Starting(lager.Logger)
	Finished(lager.Logger, ExitStatus, runtime.VersionResult)
	SelectedWorker(lager.Logger, string)
	Errored(lager.Logger, string)

	UpdateVersion(lager.Logger, atc.GetPlan, runtime.VersionResult)
}

// GetStep will fetch a version of a resource on a worker that supports the
// resource type.
type GetStep struct {
	planID               atc.PlanID
	plan                 atc.GetPlan
	metadata             StepMetadata
	containerMetadata    db.ContainerMetadata
	resourceFactory      resource.ResourceFactory
	resourceCacheFactory db.ResourceCacheFactory
	strategy             worker.ContainerPlacementStrategy
	workerPool           worker.Pool
	delegateFactory      GetDelegateFactory
}

func NewGetStep(
	planID atc.PlanID,
	plan atc.GetPlan,
	metadata StepMetadata,
	containerMetadata db.ContainerMetadata,
	resourceFactory resource.ResourceFactory,
	resourceCacheFactory db.ResourceCacheFactory,
	strategy worker.ContainerPlacementStrategy,
	delegateFactory GetDelegateFactory,
	pool worker.Pool,
) Step {
	return &GetStep{
		planID:               planID,
		plan:                 plan,
		metadata:             metadata,
		containerMetadata:    containerMetadata,
		resourceFactory:      resourceFactory,
		resourceCacheFactory: resourceCacheFactory,
		strategy:             strategy,
		delegateFactory:      delegateFactory,
		workerPool:           pool,
	}
}

func (step *GetStep) Run(ctx context.Context, state RunState) (bool, error) {
	delegate := step.delegateFactory.GetDelegate(state)
	ctx, span := delegate.StartSpan(ctx, "get", tracing.Attrs{
		"name":     step.plan.Name,
		"resource": step.plan.Resource,
	})

	ok, err := step.run(ctx, state, delegate)
	tracing.End(span, err)

	return ok, err
}

func (step *GetStep) run(ctx context.Context, state RunState, delegate GetDelegate) (bool, error) {
	logger := lagerctx.FromContext(ctx)
	logger = logger.Session("get-step", lager.Data{
		"step-name": step.plan.Name,
	})

	delegate.Initializing(logger)

	source, err := creds.NewSource(state, step.plan.Source).Evaluate()
	if err != nil {
		return false, err
	}

	params, err := creds.NewParams(state, step.plan.Params).Evaluate()
	if err != nil {
		return false, err
	}

	workerSpec := worker.WorkerSpec{
		Tags:         step.plan.Tags,
		TeamID:       step.metadata.TeamID,
		ResourceType: step.plan.VersionedResourceTypes.Base(step.plan.Type),
	}

	var imageSpec worker.ImageSpec
	resourceType, found := step.plan.VersionedResourceTypes.Lookup(step.plan.Type)
	if found {
		image := atc.ImageResource{
			Name:    resourceType.Name,
			Type:    resourceType.Type,
			Source:  resourceType.Source,
			Params:  resourceType.Params,
			Version: resourceType.Version,
			Tags:    resourceType.Tags,
		}
		if len(image.Tags) == 0 {
			image.Tags = step.plan.Tags
		}

		types := step.plan.VersionedResourceTypes.Without(step.plan.Type)

		var err error
		imageSpec, err = delegate.FetchImage(ctx, image, types, resourceType.Privileged)
		if err != nil {
			return false, err
		}
	} else {
		imageSpec.ResourceType = step.plan.Type
	}

	resourceTypes, err := creds.NewVersionedResourceTypes(state, step.plan.VersionedResourceTypes).Evaluate()
	if err != nil {
		return false, err
	}

	version, err := NewVersionSourceFromPlan(&step.plan).Version(state)
	if err != nil {
		return false, err
	}

	containerSpec := worker.ContainerSpec{
		ImageSpec: imageSpec,
		TeamID:    step.metadata.TeamID,
		Env:       step.metadata.Env(),
	}
	tracing.Inject(ctx, &containerSpec)

	resourceCache, err := step.resourceCacheFactory.FindOrCreateResourceCache(
		db.ForBuild(step.metadata.BuildID),
		step.plan.Type,
		version,
		source,
		params,
		resourceTypes,
	)
	if err != nil {
		logger.Error("failed-to-create-resource-cache", err)
		return false, err
	}

	getResult, found, err := step.getFromLocalCache(logger, step.metadata.TeamID, resourceCache, workerSpec)
	if err != nil {
		return false, err
	}
	if found {
		fmt.Fprintln(delegate.Stderr(), "\x1b[1;36mINFO: found resouce cache from local cache\x1b[0m")
		fmt.Fprintln(delegate.Stderr(), "")

		state.StoreResult(step.planID, resourceCache)

		state.ArtifactRepository().RegisterArtifact(
			build.ArtifactName(step.plan.Name),
			getResult.GetArtifact,
		)

		delegate.Finished(
			logger,
			ExitStatus(getResult.ExitStatus),
			getResult.VersionResult,
		)

		metric.Metrics.GetStepCacheHits.Inc()

		return true, nil
	}

	processSpec := runtime.ProcessSpec{
		Path:         "/opt/resource/in",
		Args:         []string{resource.ResourcesDir("get")},
		StdoutWriter: delegate.Stdout(),
		StderrWriter: delegate.Stderr(),
	}

	resourceToGet := step.resourceFactory.NewResource(
		source,
		params,
		version,
	)

	containerOwner := db.NewBuildStepContainerOwner(step.metadata.BuildID, step.planID, step.metadata.TeamID)

	processCtx, cancel, err := MaybeTimeout(ctx, step.plan.Timeout)
	if err != nil {
		return false, err
	}

	defer cancel()

	worker, err := step.workerPool.SelectWorker(
		lagerctx.NewContext(processCtx, logger),
		containerOwner,
		containerSpec,
		workerSpec,
		step.strategy,
	)
	if err != nil {
		return false, err
	}
	delegate.SelectedWorker(logger, worker.Name())

	getResult, err = worker.RunGetStep(
		lagerctx.NewContext(processCtx, logger),
		containerOwner,
		containerSpec,
		step.containerMetadata,
		processSpec,
		delegate,
		resourceCache,
		resourceToGet,
	)
	if err != nil {
		if errors.Is(err, context.DeadlineExceeded) {
			delegate.Errored(logger, TimeoutLogMessage)
			return false, nil
		}

		return false, err
	}

	var succeeded bool
	if getResult.ExitStatus == 0 {
		state.StoreResult(step.planID, resourceCache)

		state.ArtifactRepository().RegisterArtifact(
			build.ArtifactName(step.plan.Name),
			getResult.GetArtifact,
		)

		if step.plan.Resource != "" {
			delegate.UpdateVersion(logger, step.plan, getResult.VersionResult)
		}

		succeeded = true
	}

	delegate.Finished(
		logger,
		ExitStatus(getResult.ExitStatus),
		getResult.VersionResult,
	)

	return succeeded, nil
}

func (step *GetStep) getFromLocalCache(
	logger lager.Logger,
	teamId int,
	resourceCache db.UsedResourceCache,
	workerSpec worker.WorkerSpec) (worker.GetResult, bool, error) {
	volume, found := step.findResourceCache(logger, teamId, resourceCache, workerSpec)
	if !found {
		return worker.GetResult{}, false, nil
	}
	metadata, err := resourceCache.LoadVersionMetadata()
	if err != nil {
		return worker.GetResult{}, false, err
	}
	return worker.GetResult{
		ExitStatus: 0,
		VersionResult: runtime.VersionResult{
			Version:  resourceCache.Version(),
			Metadata: metadata,
		},
		GetArtifact: runtime.GetArtifact{volume.Handle()},
	}, true, nil
}

func (step *GetStep) findResourceCache(
	logger lager.Logger,
	teamId int,
	resourceCache db.UsedResourceCache,
	workerSpec worker.WorkerSpec) (worker.Volume, bool) {
	workers, err := step.workerPool.FindWorkersForResourceCache(logger, teamId, resourceCache.ID(), workerSpec)
	if err != nil {
		return nil, false
	}

	for _, sourceWorker := range workers {
		volume, found, err := sourceWorker.FindVolumeForResourceCache(logger, resourceCache)
		if err != nil {
			logger.Debug("ignore-error", lager.Data{"error": err})
			continue
		}
		if !found {
			continue
		}
		return volume, true
	}

	return nil, false
}
<commit_msg>address review comment.<commit_after>package exec

import (
	"context"
	"errors"
	"fmt"
	"github.com/concourse/concourse/atc/metric"
	"io"

	"code.cloudfoundry.org/lager"
	"code.cloudfoundry.org/lager/lagerctx"
	"github.com/concourse/concourse/atc"
	"github.com/concourse/concourse/atc/creds"
	"github.com/concourse/concourse/atc/db"
	"github.com/concourse/concourse/atc/exec/build"
	"github.com/concourse/concourse/atc/resource"
	"github.com/concourse/concourse/atc/runtime"
	"github.com/concourse/concourse/atc/worker"
	"github.com/concourse/concourse/tracing"
	"go.opentelemetry.io/otel/api/trace"
)

type ErrPipelineNotFound struct {
	PipelineName string
}

func (e ErrPipelineNotFound) Error() string {
	return fmt.Sprintf("pipeline '%s' not found", e.PipelineName)
}

type ErrResourceNotFound struct {
	ResourceName string
}

func (e ErrResourceNotFound) Error() string {
	return fmt.Sprintf("resource '%s' not found", e.ResourceName)
}

//go:generate counterfeiter . GetDelegateFactory

type GetDelegateFactory interface {
	GetDelegate(state RunState) GetDelegate
}

//go:generate counterfeiter . GetDelegate

type GetDelegate interface {
	StartSpan(context.Context, string, tracing.Attrs) (context.Context, trace.Span)

	FetchImage(context.Context, atc.ImageResource, atc.VersionedResourceTypes, bool) (worker.ImageSpec, error)

	Stdout() io.Writer
	Stderr() io.Writer

	Initializing(lager.Logger)
	Starting(lager.Logger)
	Finished(lager.Logger, ExitStatus, runtime.VersionResult)
	SelectedWorker(lager.Logger, string)
	Errored(lager.Logger, string)

	UpdateVersion(lager.Logger, atc.GetPlan, runtime.VersionResult)
}

// GetStep will fetch a version of a resource on a worker that supports the
// resource type.
type GetStep struct {
	planID               atc.PlanID
	plan                 atc.GetPlan
	metadata             StepMetadata
	containerMetadata    db.ContainerMetadata
	resourceFactory      resource.ResourceFactory
	resourceCacheFactory db.ResourceCacheFactory
	strategy             worker.ContainerPlacementStrategy
	workerPool           worker.Pool
	delegateFactory      GetDelegateFactory
}

func NewGetStep(
	planID atc.PlanID,
	plan atc.GetPlan,
	metadata StepMetadata,
	containerMetadata db.ContainerMetadata,
	resourceFactory resource.ResourceFactory,
	resourceCacheFactory db.ResourceCacheFactory,
	strategy worker.ContainerPlacementStrategy,
	delegateFactory GetDelegateFactory,
	pool worker.Pool,
) Step {
	return &GetStep{
		planID:               planID,
		plan:                 plan,
		metadata:             metadata,
		containerMetadata:    containerMetadata,
		resourceFactory:      resourceFactory,
		resourceCacheFactory: resourceCacheFactory,
		strategy:             strategy,
		delegateFactory:      delegateFactory,
		workerPool:           pool,
	}
}

func (step *GetStep) Run(ctx context.Context, state RunState) (bool, error) {
	delegate := step.delegateFactory.GetDelegate(state)
	ctx, span := delegate.StartSpan(ctx, "get", tracing.Attrs{
		"name":     step.plan.Name,
		"resource": step.plan.Resource,
	})

	ok, err := step.run(ctx, state, delegate)
	tracing.End(span, err)

	return ok, err
}

func (step *GetStep) run(ctx context.Context, state RunState, delegate GetDelegate) (bool, error) {
	logger := lagerctx.FromContext(ctx)
	logger = logger.Session("get-step", lager.Data{
		"step-name": step.plan.Name,
	})

	delegate.Initializing(logger)

	source, err := creds.NewSource(state, step.plan.Source).Evaluate()
	if err != nil {
		return false, err
	}

	params, err := creds.NewParams(state, step.plan.Params).Evaluate()
	if err != nil {
		return false, err
	}

	workerSpec := worker.WorkerSpec{
		Tags:         step.plan.Tags,
		TeamID:       step.metadata.TeamID,
		ResourceType: step.plan.VersionedResourceTypes.Base(step.plan.Type),
	}

	var imageSpec worker.ImageSpec
	resourceType, found := step.plan.VersionedResourceTypes.Lookup(step.plan.Type)
	if found {
		image := atc.ImageResource{
			Name:    resourceType.Name,
			Type:    resourceType.Type,
			Source:  resourceType.Source,
			Params:  resourceType.Params,
			Version: resourceType.Version,
			Tags:    resourceType.Tags,
		}
		if len(image.Tags) == 0 {
			image.Tags = step.plan.Tags
		}

		types := step.plan.VersionedResourceTypes.Without(step.plan.Type)

		var err error
		imageSpec, err = delegate.FetchImage(ctx, image, types, resourceType.Privileged)
		if err != nil {
			return false, err
		}
	} else {
		imageSpec.ResourceType = step.plan.Type
	}

	resourceTypes, err := creds.NewVersionedResourceTypes(state, step.plan.VersionedResourceTypes).Evaluate()
	if err != nil {
		return false, err
	}

	version, err := NewVersionSourceFromPlan(&step.plan).Version(state)
	if err != nil {
		return false, err
	}

	containerSpec := worker.ContainerSpec{
		ImageSpec: imageSpec,
		TeamID:    step.metadata.TeamID,
		Env:       step.metadata.Env(),
	}
	tracing.Inject(ctx, &containerSpec)

	resourceCache, err := step.resourceCacheFactory.FindOrCreateResourceCache(
		db.ForBuild(step.metadata.BuildID),
		step.plan.Type,
		version,
		source,
		params,
		resourceTypes,
	)
	if err != nil {
		logger.Error("failed-to-create-resource-cache", err)
		return false, err
	}

	getResult, found, err := step.getFromLocalCache(logger, step.metadata.TeamID, resourceCache, workerSpec)
	if err != nil {
		return false, err
	}
	if found {
		fmt.Fprintln(delegate.Stderr(), "\x1b[1;36mINFO: found resouce cache from local cache\x1b[0m")
		fmt.Fprintln(delegate.Stderr(), "")

		state.StoreResult(step.planID, resourceCache)

		state.ArtifactRepository().RegisterArtifact(
			build.ArtifactName(step.plan.Name),
			getResult.GetArtifact,
		)

		if step.plan.Resource != "" {
			delegate.UpdateVersion(logger, step.plan, getResult.VersionResult)
		}

		delegate.Finished(
			logger,
			ExitStatus(getResult.ExitStatus),
			getResult.VersionResult,
		)

		metric.Metrics.GetStepCacheHits.Inc()

		return true, nil
	}

	processSpec := runtime.ProcessSpec{
		Path:         "/opt/resource/in",
		Args:         []string{resource.ResourcesDir("get")},
		StdoutWriter: delegate.Stdout(),
		StderrWriter: delegate.Stderr(),
	}

	resourceToGet := step.resourceFactory.NewResource(
		source,
		params,
		version,
	)

	containerOwner := db.NewBuildStepContainerOwner(step.metadata.BuildID, step.planID, step.metadata.TeamID)

	processCtx, cancel, err := MaybeTimeout(ctx, step.plan.Timeout)
	if err != nil {
		return false, err
	}

	defer cancel()

	worker, err := step.workerPool.SelectWorker(
		lagerctx.NewContext(processCtx, logger),
		containerOwner,
		containerSpec,
		workerSpec,
		step.strategy,
	)
	if err != nil {
		return false, err
	}
	delegate.SelectedWorker(logger, worker.Name())

	getResult, err = worker.RunGetStep(
		lagerctx.NewContext(processCtx, logger),
		containerOwner,
		containerSpec,
		step.containerMetadata,
		processSpec,
		delegate,
		resourceCache,
		resourceToGet,
	)
	if err != nil {
		if errors.Is(err, context.DeadlineExceeded) {
			delegate.Errored(logger, TimeoutLogMessage)
			return false, nil
		}

		return false, err
	}

	var succeeded bool
	if getResult.ExitStatus == 0 {
		state.StoreResult(step.planID, resourceCache)

		state.ArtifactRepository().RegisterArtifact(
			build.ArtifactName(step.plan.Name),
			getResult.GetArtifact,
		)

		if step.plan.Resource != "" {
			delegate.UpdateVersion(logger, step.plan, getResult.VersionResult)
		}

		succeeded = true
	}

	delegate.Finished(
		logger,
		ExitStatus(getResult.ExitStatus),
		getResult.VersionResult,
	)

	return succeeded, nil
}

func (step *GetStep) getFromLocalCache(
	logger lager.Logger,
	teamId int,
	resourceCache db.UsedResourceCache,
	workerSpec worker.WorkerSpec) (worker.GetResult, bool, error) {
	volume, found := step.findResourceCache(logger, teamId, resourceCache, workerSpec)
	if !found {
		return worker.GetResult{}, false, nil
	}
	metadata, err := resourceCache.LoadVersionMetadata()
	if err != nil {
		return worker.GetResult{}, false, err
	}
	return worker.GetResult{
		ExitStatus: 0,
		VersionResult: runtime.VersionResult{
			Version:  resourceCache.Version(),
			Metadata: metadata,
		},
		GetArtifact: runtime.GetArtifact{volume.Handle()},
	}, true, nil
}

func (step *GetStep) findResourceCache(
	logger lager.Logger,
	teamId int,
	resourceCache db.UsedResourceCache,
	workerSpec worker.WorkerSpec) (worker.Volume, bool) {
	workers, err := step.workerPool.FindWorkersForResourceCache(logger, teamId, resourceCache.ID(), workerSpec)
	if err != nil {
		return nil, false
	}

	for _, sourceWorker := range workers {
		volume, found, err := sourceWorker.FindVolumeForResourceCache(logger, resourceCache)
		if err != nil {
			logger.Debug("ignore-error", lager.Data{"error": err})
			continue
		}
		if !found {
			continue
		}
		return volume, true
	}

	return nil, false
}
<|endoftext|>


<commit_before>// +build js

package time

import (
	"runtime"

	"github.com/gopherjs/gopherjs/js"
)

// Make sure time.Unix func and time.Time struct it returns are always included with this package (despite DCE),
// because they're needed for internalization/externalization of time.Time/Date. See issue https://github.com/gopherjs/gopherjs/issues/279.
func init() {
	// avoid dead code elimination
	var _ Time = Unix(0, 0)
}

type runtimeTimer struct {
	i       int32
	when    int64
	period  int64
	f       func(interface{}, uintptr)
	arg     interface{}
	timeout *js.Object
	active  bool
}

func initLocal() {
	d := js.Global.Get("Date").New()
	s := d.String()
	i := indexByte(s, '(')
	j := indexByte(s, ')')
	if i == -1 || j == -1 {
		localLoc.name = "UTC"
		return
	}
	localLoc.name = s[i+1 : j]
	localLoc.zone = []zone{{localLoc.name, d.Call("getTimezoneOffset").Int() * -60, false}}
}

func runtimeNano() int64 {
	return js.Global.Get("Date").New().Call("getTime").Int64() * int64(Millisecond)
}

func now() (sec int64, nsec int32, mono int64) {
	// TODO: Use mono if needed/possible.
	n := runtimeNano()
	return n / int64(Second), int32(n % int64(Second)), 0
}

func Sleep(d Duration) {
	c := make(chan struct{})
	js.Global.Call("$setTimeout", js.InternalObject(func() { close(c) }), int(d/Millisecond))
	<-c
}

func startTimer(t *runtimeTimer) {
	t.active = true
	diff := (t.when - runtimeNano()) / int64(Millisecond)
	if diff > 1<<31-1 { // math.MaxInt32
		return
	}
	if diff < 0 {
		diff = 0
	}
	t.timeout = js.Global.Call("$setTimeout", js.InternalObject(func() {
		t.active = false
		if t.period != 0 {
			t.when += t.period
			startTimer(t)
		}
		go t.f(t.arg, 0)
	}), diff+1)
}

func stopTimer(t *runtimeTimer) bool {
	js.Global.Call("clearTimeout", t.timeout)
	wasActive := t.active
	t.active = false
	return wasActive
}

func loadLocation(name string) (*Location, error) {
	return loadZoneFile(runtime.GOROOT()+"/lib/time/zoneinfo.zip", name)
}

func forceZipFileForTesting(zipOnly bool) {
}

func initTestingZone() {
	z, err := loadLocation("America/Los_Angeles")
	if err != nil {
		panic("cannot load America/Los_Angeles for testing: " + err.Error())
	}
	z.name = "Local"
	localLoc = *z
}

// indexByte is copied from strings package to avoid importing it (since the real time package doesn't).
func indexByte(s string, c byte) int {
	return js.InternalObject(s).Call("indexOf", js.Global.Get("String").Call("fromCharCode", c)).Int()
}
<commit_msg>compiler/natives/src/time: Add initial support for monotonic clock.<commit_after>// +build js

package time

import (
	"runtime"

	"github.com/gopherjs/gopherjs/js"
)

// Make sure time.Unix func and time.Time struct it returns are always included with this package (despite DCE),
// because they're needed for internalization/externalization of time.Time/Date. See issue https://github.com/gopherjs/gopherjs/issues/279.
func init() {
	// avoid dead code elimination
	var _ Time = Unix(0, 0)
}

type runtimeTimer struct {
	i       int32
	when    int64
	period  int64
	f       func(interface{}, uintptr)
	arg     interface{}
	timeout *js.Object
	active  bool
}

func initLocal() {
	d := js.Global.Get("Date").New()
	s := d.String()
	i := indexByte(s, '(')
	j := indexByte(s, ')')
	if i == -1 || j == -1 {
		localLoc.name = "UTC"
		return
	}
	localLoc.name = s[i+1 : j]
	localLoc.zone = []zone{{localLoc.name, d.Call("getTimezoneOffset").Int() * -60, false}}
}

func runtimeNano() int64 {
	return js.Global.Get("Date").New().Call("getTime").Int64() * int64(Millisecond)
}

func now() (sec int64, nsec int32, mono int64) {
	n := runtimeNano()
	return n / int64(Second), int32(n % int64(Second)), n
}

func Sleep(d Duration) {
	c := make(chan struct{})
	js.Global.Call("$setTimeout", js.InternalObject(func() { close(c) }), int(d/Millisecond))
	<-c
}

func startTimer(t *runtimeTimer) {
	t.active = true
	diff := (t.when - runtimeNano()) / int64(Millisecond)
	if diff > 1<<31-1 { // math.MaxInt32
		return
	}
	if diff < 0 {
		diff = 0
	}
	t.timeout = js.Global.Call("$setTimeout", js.InternalObject(func() {
		t.active = false
		if t.period != 0 {
			t.when += t.period
			startTimer(t)
		}
		go t.f(t.arg, 0)
	}), diff+1)
}

func stopTimer(t *runtimeTimer) bool {
	js.Global.Call("clearTimeout", t.timeout)
	wasActive := t.active
	t.active = false
	return wasActive
}

func loadLocation(name string) (*Location, error) {
	return loadZoneFile(runtime.GOROOT()+"/lib/time/zoneinfo.zip", name)
}

func forceZipFileForTesting(zipOnly bool) {
}

func initTestingZone() {
	z, err := loadLocation("America/Los_Angeles")
	if err != nil {
		panic("cannot load America/Los_Angeles for testing: " + err.Error())
	}
	z.name = "Local"
	localLoc = *z
}

// indexByte is copied from strings package to avoid importing it (since the real time package doesn't).
func indexByte(s string, c byte) int {
	return js.InternalObject(s).Call("indexOf", js.Global.Get("String").Call("fromCharCode", c)).Int()
}
<|endoftext|>


<commit_before>// Copyright 2012 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.

// This file contains the code snippets included in "The Go image/draw package."

package main

import (
	"image"
	"image/color"
	"image/draw"
)

func main() {
	Color()
	Rect()
	RectAndScroll()
	ConvAndCircle()
	Glyph()
}

func Color() {
	c := color.RGBA{255, 0, 255, 255}
	r := image.Rect(0, 0, 640, 480)
	dst := image.NewRGBA(r)

	// ZERO OMIT
	// image.ZP is the zero point -- the origin.
	draw.Draw(dst, r, &image.Uniform{c}, image.ZP, draw.Src)
	// STOP OMIT

	// BLUE OMIT
	m := image.NewRGBA(image.Rect(0, 0, 640, 480))
	blue := color.RGBA{0, 0, 255, 255}
	draw.Draw(m, m.Bounds(), &image.Uniform{blue}, image.ZP, draw.Src)
	// STOP OMIT

	// RESET OMIT
	draw.Draw(m, m.Bounds(), image.Transparent, image.ZP, draw.Src)
	// STOP OMIT
}

func Rect() {
	dst := image.NewRGBA(image.Rect(0, 0, 640, 480))
	sr := image.Rect(0, 0, 200, 200)
	src := image.Black
	dp := image.Point{100, 100}

	// RECT OMIT
	r := image.Rectangle{dp, dp.Add(sr.Size())}
	draw.Draw(dst, r, src, sr.Min, draw.Src)
	// STOP OMIT
}

func RectAndScroll() {
	dst := image.NewRGBA(image.Rect(0, 0, 640, 480))
	sr := image.Rect(0, 0, 200, 200)
	src := image.Black
	dp := image.Point{100, 100}

	// RECT2 OMIT
	r := sr.Sub(sr.Min).Add(dp)
	draw.Draw(dst, r, src, sr.Min, draw.Src)
	// STOP OMIT

	m := dst

	// SCROLL OMIT
	b := m.Bounds()
	p := image.Pt(0, 20)
	// Note that even though the second argument is b,
	// the effective rectangle is smaller due to clipping.
	draw.Draw(m, b, m, b.Min.Add(p), draw.Src)
	dirtyRect := b.Intersect(image.Rect(b.Min.X, b.Max.Y-20, b.Max.X, b.Max.Y))
	// STOP OMIT

	_ = dirtyRect // noop
}

func ConvAndCircle() {
	src := image.NewRGBA(image.Rect(0, 0, 640, 480))
	dst := image.NewRGBA(image.Rect(0, 0, 640, 480))

	// CONV OMIT
	b := src.Bounds()
	m := image.NewRGBA(image.Rect(0, 0, b.Dx(), b.Dy()))
	draw.Draw(m, m.Bounds(), src, b.Min, draw.Src)
	// STOP OMIT

	p := image.Point{100, 100}
	r := 50

	// CIRCLE2 OMIT
	draw.DrawMask(dst, dst.Bounds(), src, image.ZP, &circle{p, r}, image.ZP, draw.Over)
	// STOP OMIT
}

func theGlyphImageForAFont() image.Image {
	return image.NewRGBA(image.Rect(0, 0, 640, 480))
}

func theBoundsFor(index int) image.Rectangle {
	return image.Rect(0, 0, 32, 32)
}

func Glyph() {
	p := image.Point{100, 100}
	dst := image.NewRGBA(image.Rect(0, 0, 640, 480))
	glyphIndex := 42

	// GLYPH OMIT
	src := &image.Uniform{color.RGBA{0, 0, 255, 255}}
	mask := theGlyphImageForAFont()
	mr := theBoundsFor(glyphIndex)
	draw.DrawMask(dst, mr.Sub(mr.Min).Add(p), src, image.ZP, mask, mr.Min, draw.Over)
	// STOP OMIT
}

//CIRCLESTRUCT OMIT
type circle struct {
	p image.Point
	r int
}

func (c *circle) ColorModel() color.Model {
	return color.AlphaModel
}

func (c *circle) Bounds() image.Rectangle {
	return image.Rect(c.p.X-c.r, c.p.Y-c.r, c.p.X+c.r, c.p.Y+c.r)
}

func (c *circle) At(x, y int) color.Color {
	xx, yy, rr := float64(x-c.p.X)+0.5, float64(y-c.p.Y)+0.5, float64(c.r)
	if xx*xx+yy*yy < rr*rr {
		return color.Alpha{255}
	}
	return color.Alpha{0}
}

//STOP OMIT
<commit_msg>doc: simplify the image_draw article example for converting an image to RGBA.<commit_after>// Copyright 2012 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.

// This file contains the code snippets included in "The Go image/draw package."

package main

import (
	"image"
	"image/color"
	"image/draw"
)

func main() {
	Color()
	Rect()
	RectAndScroll()
	ConvAndCircle()
	Glyph()
}

func Color() {
	c := color.RGBA{255, 0, 255, 255}
	r := image.Rect(0, 0, 640, 480)
	dst := image.NewRGBA(r)

	// ZERO OMIT
	// image.ZP is the zero point -- the origin.
	draw.Draw(dst, r, &image.Uniform{c}, image.ZP, draw.Src)
	// STOP OMIT

	// BLUE OMIT
	m := image.NewRGBA(image.Rect(0, 0, 640, 480))
	blue := color.RGBA{0, 0, 255, 255}
	draw.Draw(m, m.Bounds(), &image.Uniform{blue}, image.ZP, draw.Src)
	// STOP OMIT

	// RESET OMIT
	draw.Draw(m, m.Bounds(), image.Transparent, image.ZP, draw.Src)
	// STOP OMIT
}

func Rect() {
	dst := image.NewRGBA(image.Rect(0, 0, 640, 480))
	sr := image.Rect(0, 0, 200, 200)
	src := image.Black
	dp := image.Point{100, 100}

	// RECT OMIT
	r := image.Rectangle{dp, dp.Add(sr.Size())}
	draw.Draw(dst, r, src, sr.Min, draw.Src)
	// STOP OMIT
}

func RectAndScroll() {
	dst := image.NewRGBA(image.Rect(0, 0, 640, 480))
	sr := image.Rect(0, 0, 200, 200)
	src := image.Black
	dp := image.Point{100, 100}

	// RECT2 OMIT
	r := sr.Sub(sr.Min).Add(dp)
	draw.Draw(dst, r, src, sr.Min, draw.Src)
	// STOP OMIT

	m := dst

	// SCROLL OMIT
	b := m.Bounds()
	p := image.Pt(0, 20)
	// Note that even though the second argument is b,
	// the effective rectangle is smaller due to clipping.
	draw.Draw(m, b, m, b.Min.Add(p), draw.Src)
	dirtyRect := b.Intersect(image.Rect(b.Min.X, b.Max.Y-20, b.Max.X, b.Max.Y))
	// STOP OMIT

	_ = dirtyRect // noop
}

func ConvAndCircle() {
	src := image.NewRGBA(image.Rect(0, 0, 640, 480))
	dst := image.NewRGBA(image.Rect(0, 0, 640, 480))

	// CONV OMIT
	b := src.Bounds()
	m := image.NewRGBA(b)
	draw.Draw(m, b, src, b.Min, draw.Src)
	// STOP OMIT

	p := image.Point{100, 100}
	r := 50

	// CIRCLE2 OMIT
	draw.DrawMask(dst, dst.Bounds(), src, image.ZP, &circle{p, r}, image.ZP, draw.Over)
	// STOP OMIT
}

func theGlyphImageForAFont() image.Image {
	return image.NewRGBA(image.Rect(0, 0, 640, 480))
}

func theBoundsFor(index int) image.Rectangle {
	return image.Rect(0, 0, 32, 32)
}

func Glyph() {
	p := image.Point{100, 100}
	dst := image.NewRGBA(image.Rect(0, 0, 640, 480))
	glyphIndex := 42

	// GLYPH OMIT
	src := &image.Uniform{color.RGBA{0, 0, 255, 255}}
	mask := theGlyphImageForAFont()
	mr := theBoundsFor(glyphIndex)
	draw.DrawMask(dst, mr.Sub(mr.Min).Add(p), src, image.ZP, mask, mr.Min, draw.Over)
	// STOP OMIT
}

//CIRCLESTRUCT OMIT
type circle struct {
	p image.Point
	r int
}

func (c *circle) ColorModel() color.Model {
	return color.AlphaModel
}

func (c *circle) Bounds() image.Rectangle {
	return image.Rect(c.p.X-c.r, c.p.Y-c.r, c.p.X+c.r, c.p.Y+c.r)
}

func (c *circle) At(x, y int) color.Color {
	xx, yy, rr := float64(x-c.p.X)+0.5, float64(y-c.p.Y)+0.5, float64(c.r)
	if xx*xx+yy*yy < rr*rr {
		return color.Alpha{255}
	}
	return color.Alpha{0}
}

//STOP OMIT
<|endoftext|>


<commit_before>// Copyright 2014 Simon Zimmermann. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

// Package swift registers the "swift" blobserver storage type, storing
// blobs in an OpenStack Swift storage.

package swift

import (
	"fmt"
	"strings"

	"github.com/ncw/swift"
	"github.com/simonz05/blobserver"
	"github.com/simonz05/blobserver/blob"
	"github.com/simonz05/blobserver/config"
)

type swiftStorage struct {
	conn             *swift.Connection
	containerName    string
	shard            bool
	containerReadACL string
	cdnUrl           string
}

func (s *swiftStorage) String() string {
	return fmt.Sprintf("\"swift\" blob storage at host %q, container %q", s.conn.AuthUrl, s.container)
}

func (s *swiftStorage) Config() *blobserver.Config {
	return &blobserver.Config{
		CDNUrl: s.cdnUrl,
		Name:   "swift",
	}
}

func (s *swiftStorage) container(b blob.Ref) string {
	if !s.shard {
		return s.containerName
	}

	return fmt.Sprintf("%s-%s", s.containerName, shards[b.Sum32()%uint32(shardCount)])
}

func (s *swiftStorage) createPathRef(b blob.Ref) blob.Ref {
	return blob.Ref{Path: s.container(b) + "/" + b.String()}
}

func (s *swiftStorage) refContainer(b blob.Ref) (string, string) {
	ref := b.String()
	idx := strings.Index(ref, "/")

	if idx > 0 && len(ref) > idx+1 {
		return ref[idx+1:], ref[:idx]
	}

	return b.String(), s.container(b)
}

func newFromConfig(config *config.Config) (blobserver.Storage, error) {
	swiftConf := config.Swift

	conn := &swift.Connection{
		UserName: swiftConf.APIUser,
		ApiKey:   swiftConf.APIKey,
		AuthUrl:  swiftConf.AuthURL,
		Region:   swiftConf.Region,
		Tenant:   swiftConf.Tenant,
		//TenantId: swiftConf.TenantID,
	}

	sto := &swiftStorage{
		conn:             conn,
		shard:            swiftConf.Shard,
		containerName:    swiftConf.Container,
		containerReadACL: ".r:*,.rlistings",
		cdnUrl:           swiftConf.CDNUrl,
	}

	if swiftConf.ContainerReadACL != "" {
		sto.containerReadACL = swiftConf.ContainerReadACL
	}

	err := sto.conn.Authenticate()
	if err != nil {
		return nil, err
	}
	return sto, nil
}

const shardCount = 2 // 8<<5

var shards [shardCount]string

func init() {
	for i := range shards {
		shards[i] = fmt.Sprintf("%0.2X", i)
	}
	blobserver.RegisterStorageConstructor("swift", blobserver.StorageConstructor(newFromConfig))
}
<commit_msg>swift: 1024 containers as default<commit_after>// Copyright 2014 Simon Zimmermann. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

// Package swift registers the "swift" blobserver storage type, storing
// blobs in an OpenStack Swift storage.

package swift

import (
	"fmt"
	"strings"

	"github.com/ncw/swift"
	"github.com/simonz05/blobserver"
	"github.com/simonz05/blobserver/blob"
	"github.com/simonz05/blobserver/config"
)

type swiftStorage struct {
	conn             *swift.Connection
	containerName    string
	shard            bool
	containerReadACL string
	cdnUrl           string
}

func (s *swiftStorage) String() string {
	return fmt.Sprintf("\"swift\" blob storage at host %q, container %q", s.conn.AuthUrl, s.container)
}

func (s *swiftStorage) Config() *blobserver.Config {
	return &blobserver.Config{
		CDNUrl: s.cdnUrl,
		Name:   "swift",
	}
}

func (s *swiftStorage) container(b blob.Ref) string {
	if !s.shard {
		return s.containerName
	}

	return fmt.Sprintf("%s-%s", s.containerName, shards[b.Sum32()%uint32(shardCount)])
}

func (s *swiftStorage) createPathRef(b blob.Ref) blob.Ref {
	return blob.Ref{Path: s.container(b) + "/" + b.String()}
}

func (s *swiftStorage) refContainer(b blob.Ref) (string, string) {
	ref := b.String()
	idx := strings.Index(ref, "/")

	if idx > 0 && len(ref) > idx+1 {
		return ref[idx+1:], ref[:idx]
	}

	return b.String(), s.container(b)
}

func newFromConfig(config *config.Config) (blobserver.Storage, error) {
	swiftConf := config.Swift

	conn := &swift.Connection{
		UserName: swiftConf.APIUser,
		ApiKey:   swiftConf.APIKey,
		AuthUrl:  swiftConf.AuthURL,
		Region:   swiftConf.Region,
		Tenant:   swiftConf.Tenant,
		//TenantId: swiftConf.TenantID,
	}

	sto := &swiftStorage{
		conn:             conn,
		shard:            swiftConf.Shard,
		containerName:    swiftConf.Container,
		containerReadACL: ".r:*,.rlistings",
		cdnUrl:           swiftConf.CDNUrl,
	}

	if swiftConf.ContainerReadACL != "" {
		sto.containerReadACL = swiftConf.ContainerReadACL
	}

	err := sto.conn.Authenticate()
	if err != nil {
		return nil, err
	}
	return sto, nil
}

const shardCount = 8<<7

var shards [shardCount]string

func init() {
	for i := range shards {
		shards[i] = fmt.Sprintf("%0.2X", i)
	}
	blobserver.RegisterStorageConstructor("swift", blobserver.StorageConstructor(newFromConfig))
}
<|endoftext|>


<commit_before>package synq

import (
	"bytes"
	"database/sql/driver"
	"encoding/json"
	"errors"
	"fmt"
	"time"

	"github.com/SYNQfm/SYNQ-Golang/upload"
)

type VideoResp struct {
	Video VideoV2 `json:"data"`
}

type Account struct {
	Id string `json:"account_id"`
}

type VideoV2 struct {
	Id                string          `json:"id"`
	Userdata          json.RawMessage `json:"user_data"`
	Metadata          json.RawMessage `json:"metadata"`
	CreatedAt         time.Time       `json:"created_at"`
	UpdatedAt         time.Time       `json:"updated_at"`
	Api               *ApiV2          `json:"-"`
	Assets            []Asset         `json:"assets"`
	Accounts          []Account       `json:"video_accounts"`
	CompletenessScore float64         `json:"completeness_score"`
}

func (v VideoV2) Value() (driver.Value, error) {
	json, err := json.Marshal(v)
	return json, err
}

func (v *VideoV2) Scan(src interface{}) error {
	source, ok := src.([]byte)
	if !ok {
		return errors.New("Type assertion .([]byte) failed.")
	}

	err := json.Unmarshal(source, &v)
	if err != nil {
		return err
	}
	return nil
}

func (v *VideoV2) GetVideoAssetList() error {
	list := AssetList{}
	url := v.Api.getBaseUrl() + "/videos/" + v.Id + "/assets"
	err := v.Api.handleGet(url, &list)
	if err != nil {
		return err
	}
	v.Assets = list.Assets
	return nil
}

func (v *VideoV2) Update() error {
	url := v.Api.getBaseUrl() + "/videos/" + v.Id
	type Update struct {
		Metadata          json.RawMessage `json:"metadata"`
		Userdata          json.RawMessage `json:"user_data"`
		CompletenessScore float64         `json:"completeness_score"`
	}
	update := Update{Metadata: v.Metadata, Userdata: v.Userdata, CompletenessScore: v.CompletenessScore}
	b, _ := json.Marshal(update)
	body := bytes.NewBuffer(b)
	req, err := v.Api.makeRequest("PUT", url, body)
	if err != nil {
		return err
	}
	resp := VideoResp{}
	err = handleReq(v.Api, req, &resp)
	if err != nil {
		return err
	}
	v.Metadata = resp.Video.Metadata
	v.Userdata = resp.Video.Userdata
	v.CompletenessScore = resp.Video.CompletenessScore
	return nil
}

func (v *VideoV2) AddAccount(accountId string) error {
	url := v.Api.getBaseUrl() + "/videos/" + v.Id
	account := Account{Id: accountId}
	update := struct {
		Accounts []Account `json:"video_accounts"`
	}{}
	update.Accounts = append(v.Accounts, account)
	b, _ := json.Marshal(update)
	body := bytes.NewBuffer(b)
	req, err := v.Api.makeRequest("PUT", url, body)
	if err != nil {
		return err
	}
	resp := VideoResp{}
	err = handleReq(v.Api, req, &resp)
	if err != nil {
		return err
	}
	return nil
}

func (v VideoV2) GetAsset(assetId string) (Asset, error) {
	url := v.Api.getBaseUrl() + "/assets/" + assetId
	var asset Asset
	asset.Api = *v.Api
	err := asset.handleAssetReq("GET", url, nil)
	return asset, err
}

func (v *VideoV2) FindAsset(location string) (Asset, bool) {
	for _, a := range v.Assets {
		if (a.Location == location || a.Id == location) && a.Id != "" {
			return a, true
		}
	}
	return Asset{}, false
}

func (v *VideoV2) CreateOrUpdateAsset(asset *Asset) error {
	// make sure the API is set
	asset.Api = *v.Api
	// check if this asset exists, if it does, just update
	a, found := v.FindAsset(asset.Location)
	if found {
		asset.Id = a.Id
		return asset.Update()
	} else {
		url := v.Api.getBaseUrl() + "/assets"
		data, _ := json.Marshal(asset)
		body := bytes.NewBuffer(data)
		err := asset.handleAssetReq("POST", url, body)
		if err == nil {
			v.Assets = append(v.Assets, *asset)
		}
		return err
	}
}

// This will get the upload params for a sepcific video, if assetId is passed in
// it will be used instead (assuming it exists)
func (v *VideoV2) GetUploadParams(ctype string, assetId ...string) (up upload.UploadParameters, err error) {
	api := v.Api
	if api == nil {
		return up, errors.New("api is blank")
	}
	params := UnicornParam{
		Ctype: ctype,
	}
	if len(assetId) > 0 {
		params.AssetId = assetId[0]
	}
	return api.GetUploadParams(v.Id, params)
}

// This will call Unicorn's /v2/video/<id>/upload API, which will
// create an asset and create a signed S3 location to upload to, including
// the signature url for multipart uploads
func (v *VideoV2) CreateAssetForUpload(ctype string) (asset Asset, err error) {
	up, err := v.GetUploadParams(ctype)
	if err != nil {
		return asset, err
	}
	// now load the asset
	asset, err = v.GetAsset(up.AssetId)
	if err != nil {
		return asset, err
	}
	asset.UploadParameters = up
	v.Assets = append(v.Assets, asset)
	return asset, nil
}

func (v *VideoV2) CreateAsset(state, fileType, location string) (Asset, error) {
	var asset Asset
	asset.VideoId = v.Id
	asset.State = state
	asset.Type = fileType
	asset.Location = location
	err := v.CreateOrUpdateAsset(&asset)
	return asset, err
}

// Helper function to display information about a file
func (v *VideoV2) Display() (str string) {
	if v.Id == "" {
		str = fmt.Sprintf("Empty Video\n")
	} else {
		str = fmt.Sprintf("Video %s\n\tAssets : %d\n", v.Id, len(v.Assets))
	}
	return str
}
<commit_msg>remove accounts from video object (#70)<commit_after>package synq

import (
	"bytes"
	"database/sql/driver"
	"encoding/json"
	"errors"
	"fmt"
	"time"

	"github.com/SYNQfm/SYNQ-Golang/upload"
)

type VideoResp struct {
	Video VideoV2 `json:"data"`
}

type Account struct {
	Id string `json:"account_id"`
}

type VideoV2 struct {
	Id                string          `json:"id"`
	Userdata          json.RawMessage `json:"user_data"`
	Metadata          json.RawMessage `json:"metadata"`
	CreatedAt         time.Time       `json:"created_at"`
	UpdatedAt         time.Time       `json:"updated_at"`
	Api               *ApiV2          `json:"-"`
	Assets            []Asset         `json:"assets"`
	CompletenessScore float64         `json:"completeness_score"`
}

func (v VideoV2) Value() (driver.Value, error) {
	json, err := json.Marshal(v)
	return json, err
}

func (v *VideoV2) Scan(src interface{}) error {
	source, ok := src.([]byte)
	if !ok {
		return errors.New("Type assertion .([]byte) failed.")
	}

	err := json.Unmarshal(source, &v)
	if err != nil {
		return err
	}
	return nil
}

func (v *VideoV2) GetVideoAssetList() error {
	list := AssetList{}
	url := v.Api.getBaseUrl() + "/videos/" + v.Id + "/assets"
	err := v.Api.handleGet(url, &list)
	if err != nil {
		return err
	}
	v.Assets = list.Assets
	return nil
}

func (v *VideoV2) Update() error {
	url := v.Api.getBaseUrl() + "/videos/" + v.Id
	type Update struct {
		Metadata          json.RawMessage `json:"metadata"`
		Userdata          json.RawMessage `json:"user_data"`
		CompletenessScore float64         `json:"completeness_score"`
	}
	update := Update{Metadata: v.Metadata, Userdata: v.Userdata, CompletenessScore: v.CompletenessScore}
	b, _ := json.Marshal(update)
	body := bytes.NewBuffer(b)
	req, err := v.Api.makeRequest("PUT", url, body)
	if err != nil {
		return err
	}
	resp := VideoResp{}
	err = handleReq(v.Api, req, &resp)
	if err != nil {
		return err
	}
	v.Metadata = resp.Video.Metadata
	v.Userdata = resp.Video.Userdata
	v.CompletenessScore = resp.Video.CompletenessScore
	return nil
}

func (v *VideoV2) AddAccount(accountId string) error {
	url := v.Api.getBaseUrl() + "/videos/" + v.Id
	account := Account{Id: accountId}
	update := struct {
		Accounts []Account `json:"video_accounts"`
	}{}
	update.Accounts = append(update.Accounts, account)
	b, _ := json.Marshal(update)
	body := bytes.NewBuffer(b)
	req, err := v.Api.makeRequest("PUT", url, body)
	if err != nil {
		return err
	}
	resp := VideoResp{}
	err = handleReq(v.Api, req, &resp)
	if err != nil {
		return err
	}
	return nil
}

func (v VideoV2) GetAsset(assetId string) (Asset, error) {
	url := v.Api.getBaseUrl() + "/assets/" + assetId
	var asset Asset
	asset.Api = *v.Api
	err := asset.handleAssetReq("GET", url, nil)
	return asset, err
}

func (v *VideoV2) FindAsset(location string) (Asset, bool) {
	for _, a := range v.Assets {
		if (a.Location == location || a.Id == location) && a.Id != "" {
			return a, true
		}
	}
	return Asset{}, false
}

func (v *VideoV2) CreateOrUpdateAsset(asset *Asset) error {
	// make sure the API is set
	asset.Api = *v.Api
	// check if this asset exists, if it does, just update
	a, found := v.FindAsset(asset.Location)
	if found {
		asset.Id = a.Id
		return asset.Update()
	} else {
		url := v.Api.getBaseUrl() + "/assets"
		data, _ := json.Marshal(asset)
		body := bytes.NewBuffer(data)
		err := asset.handleAssetReq("POST", url, body)
		if err == nil {
			v.Assets = append(v.Assets, *asset)
		}
		return err
	}
}

// This will get the upload params for a sepcific video, if assetId is passed in
// it will be used instead (assuming it exists)
func (v *VideoV2) GetUploadParams(ctype string, assetId ...string) (up upload.UploadParameters, err error) {
	api := v.Api
	if api == nil {
		return up, errors.New("api is blank")
	}
	params := UnicornParam{
		Ctype: ctype,
	}
	if len(assetId) > 0 {
		params.AssetId = assetId[0]
	}
	return api.GetUploadParams(v.Id, params)
}

// This will call Unicorn's /v2/video/<id>/upload API, which will
// create an asset and create a signed S3 location to upload to, including
// the signature url for multipart uploads
func (v *VideoV2) CreateAssetForUpload(ctype string) (asset Asset, err error) {
	up, err := v.GetUploadParams(ctype)
	if err != nil {
		return asset, err
	}
	// now load the asset
	asset, err = v.GetAsset(up.AssetId)
	if err != nil {
		return asset, err
	}
	asset.UploadParameters = up
	v.Assets = append(v.Assets, asset)
	return asset, nil
}

func (v *VideoV2) CreateAsset(state, fileType, location string) (Asset, error) {
	var asset Asset
	asset.VideoId = v.Id
	asset.State = state
	asset.Type = fileType
	asset.Location = location
	err := v.CreateOrUpdateAsset(&asset)
	return asset, err
}

// Helper function to display information about a file
func (v *VideoV2) Display() (str string) {
	if v.Id == "" {
		str = fmt.Sprintf("Empty Video\n")
	} else {
		str = fmt.Sprintf("Video %s\n\tAssets : %d\n", v.Id, len(v.Assets))
	}
	return str
}
<|endoftext|>


<commit_before>package connectors

import (
	"github.com/hpcloud/tail"
	"github.com/projectjane/jane/models"
	"github.com/projectjane/jane/parse"
	"log"
)

type Logging struct {
}

func (x Logging) Listen(commandMsgs chan<- models.Message, connector models.Connector) {
	defer Recovery(connector)
	t, err := tail.TailFile(connector.File, tail.Config{Follow: true, Location: SeekInfo{Offset: 0, Whence: 2}})
	if err != nil {
		log.Print(err)
	}
	for line := range t.Lines {
		for _, chk := range connector.Checks {
			if match, _ := parse.Match(chk.Check, line.Text); match {
				var m models.Message
				m.Routes = connector.Routes
				m.In.Process = false
				m.Out.Text = connector.File + ": " + chk.Name
				m.Out.Detail = line.Text
				commandMsgs <- m
			}

		}
	}
}

func (x Logging) Command(message models.Message, publishMsgs chan<- models.Message, connector models.Connector) {
	return
}

func (x Logging) Publish(connector models.Connector, message models.Message, target string) {
	return
}

func (x Logging) Help(connector models.Connector) (help string) {
	return
}
<commit_msg>Fixing seek on the logging connector to start at end of file<commit_after>package connectors

import (
	"github.com/hpcloud/tail"
	"github.com/projectjane/jane/models"
	"github.com/projectjane/jane/parse"
	"log"
)

type Logging struct {
}

func (x Logging) Listen(commandMsgs chan<- models.Message, connector models.Connector) {
	defer Recovery(connector)
	seek := tail.SeekInfo{Offset: 0, Whence: 2}
	t, err := tail.TailFile(connector.File, tail.Config{Follow: true, Location: &seek})
	if err != nil {
		log.Print(err)
	}
	for line := range t.Lines {
		for _, chk := range connector.Checks {
			if match, _ := parse.Match(chk.Check, line.Text); match {
				var m models.Message
				m.Routes = connector.Routes
				m.In.Process = false
				m.Out.Text = connector.File + ": " + chk.Name
				m.Out.Detail = line.Text
				commandMsgs <- m
			}

		}
	}
}

func (x Logging) Command(message models.Message, publishMsgs chan<- models.Message, connector models.Connector) {
	return
}

func (x Logging) Publish(connector models.Connector, message models.Message, target string) {
	return
}

func (x Logging) Help(connector models.Connector) (help string) {
	return
}
<|endoftext|>


<commit_before>package backends

import (
	"fmt"
)

type User struct {
	Uid    int64
	Name   string
	Active bool
}

func (u User) String() string {
	var active rune
	if u.Active {
		active = 'Y'
	} else {
		active = 'N'
	}
	return fmt.Sprintf("%s:%d:%c", u.Name, u.Uid, active)
}

type Group struct {
	Gid  int64
	Name string
}

func (g Group) String() string {
	return fmt.Sprintf("%s:%d", g.Name, g.Gid)
}

type Error struct {
	Code    string
	Message string
}

type Abstract interface {
	CreateUser(name string, password string) (int64, *Error)
	DisableUser(nameuid string) *Error
	EnableUser(nameuid string) *Error
	SetUserData(nameuid string, key string, value string) *Error
	GetUserData(nameuid string, key string) (string, *Error)
	LoginUser(name string, password string) (int64, *Error)
	ChangeUserPassword(nameuid string, password string, newpassword string) *Error
	ChangeUserName(nameuid string, password string, newname string) *Error
	UserGroups(nameuid string) ([]Group, *Error)
	DeleteUser(nameuid string) *Error
	Users() ([]User, *Error)
	CreateGroup(name string) (int64, *Error)
	AddUserToGroup(nameuid string, groupgid string) *Error
	RemoveUserFromGroup(nameuid string, groupgid string) *Error
	DeleteGroup(groupgid string) *Error
	Groups() ([]Group, *Error)
	GroupUsers(groupgid string) ([]User, *Error)
	Stats() (stats map[string]int64, err *Error)
	Close()
}
<commit_msg>[backends] Error implements error interface<commit_after>package backends

import (
	"fmt"
)

type User struct {
	Uid    int64
	Name   string
	Active bool
}

func (u User) String() string {
	var active rune
	if u.Active {
		active = 'Y'
	} else {
		active = 'N'
	}
	return fmt.Sprintf("%s:%d:%c", u.Name, u.Uid, active)
}

type Group struct {
	Gid  int64
	Name string
}

func (g Group) String() string {
	return fmt.Sprintf("%s:%d", g.Name, g.Gid)
}

type Error struct {
	Code    string
	Message string
}

func (e *Error) Error() string {
	return fmt.Sprintf("[%s] %s", e.Code, e.Message)
}

type Abstract interface {
	CreateUser(name string, password string) (int64, *Error)
	DisableUser(nameuid string) *Error
	EnableUser(nameuid string) *Error
	SetUserData(nameuid string, key string, value string) *Error
	GetUserData(nameuid string, key string) (string, *Error)
	LoginUser(name string, password string) (int64, *Error)
	ChangeUserPassword(nameuid string, password string, newpassword string) *Error
	ChangeUserName(nameuid string, password string, newname string) *Error
	UserGroups(nameuid string) ([]Group, *Error)
	DeleteUser(nameuid string) *Error
	Users() ([]User, *Error)
	CreateGroup(name string) (int64, *Error)
	AddUserToGroup(nameuid string, groupgid string) *Error
	RemoveUserFromGroup(nameuid string, groupgid string) *Error
	DeleteGroup(groupgid string) *Error
	Groups() ([]Group, *Error)
	GroupUsers(groupgid string) ([]User, *Error)
	Stats() (stats map[string]int64, err *Error)
	Close()
}
<|endoftext|>


<commit_before>package orm

import (
	"context"
	"database/sql"
	"fmt"

	"github.com/pkg/errors"

	"github.com/rbastic/dyndao/object"
)

// Delete function will DELETE a record ...
func (o *ORM) Delete(ctx context.Context, tx *sql.Tx, obj *object.Object) (int64, error) {
	sg := o.sqlGen
	errorString := "Delete error"

	select {
	case <-ctx.Done():
		return 0, ctx.Err()
	default:
	}

	objTable := o.s.GetTable(obj.Type)
	if objTable == nil {
		return 0, errors.New("Delete: unknown object table " + obj.Type)
	}

	err := o.CallBeforeDeleteHookIfNeeded(obj)
	if err != nil {
		o.Error("%s %s %s", errorString, "BeforeUpdateHookError", err.Error())
		return 0, err
	}

	sqlStr, bindWhere, err := sg.BindingDelete(o.sqlGen, o.s, obj)
	if err != nil {
		return 0, err
	}

	tracingString := fmt.Sprintf("Delete: sqlStr:'%s', bindWhere:[%v]", sqlStr, bindWhere)
	if sg.Tracing {
		o.Debug(tracingString)
	}

	stmt, err := stmtFromDbOrTx(ctx, o, tx, sqlStr)
	if err != nil {
		return 0, err
	}

	defer func() {
		stmtErr := stmt.Close()
		if stmtErr != nil {
			o.Error("%s", stmtErr)
		}
	}()

	res, err := stmt.ExecContext(ctx, bindWhere...)
	if err != nil {
		return 0, errors.Wrap(err, "Delete/ExecContext")
	}

	rowsAff, err := res.RowsAffected()
	if err != nil {
		return 0, err
	}

	if rowsAff == 0 {
		return 0, ErrNoResult
	}

	err = o.CallAfterDeleteHookIfNeeded(obj)
	if err != nil {
		o.Error(errorString, err)
		return 0, err
	}

	obj.MarkDirty(false)      // Flag that the object has been recently saved
	obj.ResetChangedColumns() // Reset the 'changed fields', if any

	return rowsAff, nil

}
<commit_msg>rename Delete to DeleteTx, add Delete methods<commit_after>package orm

import (
	"context"
	"database/sql"
	"fmt"

	"github.com/pkg/errors"

	"github.com/rbastic/dyndao/object"
)

func (o *ORM) Delete(ctx context.Context, obj *object.Object) (int64, error) {
	return o.DeleteTx(ctx, nil, obj)
}

func (o *ORM) DeleteTx(ctx context.Context, tx *sql.Tx, obj *object.Object) (int64, error) {
	sg := o.sqlGen
	errorString := "Delete error"

	select {
	case <-ctx.Done():
		return 0, ctx.Err()
	default:
	}

	objTable := o.s.GetTable(obj.Type)
	if objTable == nil {
		return 0, errors.New("Delete: unknown object table " + obj.Type)
	}

	err := o.CallBeforeDeleteHookIfNeeded(obj)
	if err != nil {
		o.Error("%s %s %s", errorString, "BeforeUpdateHookError", err.Error())
		return 0, err
	}

	sqlStr, bindWhere, err := sg.BindingDelete(o.sqlGen, o.s, obj)
	if err != nil {
		return 0, err
	}

	tracingString := fmt.Sprintf("Delete: sqlStr:'%s', bindWhere:[%v]", sqlStr, bindWhere)
	if sg.Tracing {
		o.Debug(tracingString)
	}

	stmt, err := stmtFromDbOrTx(ctx, o, tx, sqlStr)
	if err != nil {
		return 0, err
	}

	defer func() {
		stmtErr := stmt.Close()
		if stmtErr != nil {
			o.Error("%s", stmtErr)
		}
	}()

	res, err := stmt.ExecContext(ctx, bindWhere...)
	if err != nil {
		return 0, errors.Wrap(err, "Delete/ExecContext")
	}

	rowsAff, err := res.RowsAffected()
	if err != nil {
		return 0, err
	}

	if rowsAff == 0 {
		return 0, ErrNoResult
	}

	err = o.CallAfterDeleteHookIfNeeded(obj)
	if err != nil {
		o.Error(errorString, err)
		return 0, err
	}

	obj.MarkDirty(false)      // Flag that the object has been recently saved
	obj.ResetChangedColumns() // Reset the 'changed fields', if any

	return rowsAff, nil

}
<|endoftext|>


<commit_before>package boxconn

import (
	"net"
)

type (
	Listener struct {
		underlying            net.Listener
		privateKey, publicKey [32]byte
		allowedKeys           [][32]byte
	}
)

// Listen starts a listener and wraps it in a secure connection. (See net.Listener for details on network and laddr).
func Listen(network, laddr string, privateKey, publicKey [32]byte, allowedKeys ...[32]byte) (net.Listener, error) {
	underlying, err := net.Listen(network, laddr)
	if err != nil {
		return nil, err
	}
	return &Listener{
		underlying:  underlying,
		privateKey:  privateKey,
		publicKey:   publicKey,
		allowedKeys: allowedKeys,
	}, nil
}

// Accept waits for and returns the next connection to the listener.
func (l *Listener) Accept() (net.Conn, error) {
	conn, err := l.underlying.Accept()
	if err != nil {
		return nil, err
	}

	boxconn, err := Handshake(conn, l.privateKey, l.publicKey, l.allowedKeys...)
	if err != nil {
		conn.Close()
		return nil, err
	}

	return boxconn, nil
}

// Close closes the listener.
// Any blocked Accept operations will be unblocked and return errors.
func (l *Listener) Close() error {
	return l.underlying.Close()
}

// Addr returns the listener's network address.
func (l *Listener) Addr() net.Addr {
	return l.underlying.Addr()
}
<commit_msg>return a boxconn listener instead of the generic net listener<commit_after>package boxconn

import (
	"net"
)

type (
	Listener struct {
		underlying            net.Listener
		privateKey, publicKey [32]byte
		allowedKeys           [][32]byte
	}
)

// Listen starts a listener and wraps it in a secure connection. (See net.Listener for details on network and laddr).
func Listen(network, laddr string, privateKey, publicKey [32]byte, allowedKeys ...[32]byte) (*Listener, error) {
	underlying, err := net.Listen(network, laddr)
	if err != nil {
		return nil, err
	}
	return &Listener{
		underlying:  underlying,
		privateKey:  privateKey,
		publicKey:   publicKey,
		allowedKeys: allowedKeys,
	}, nil
}

// Accept waits for and returns the next connection to the listener.
func (l *Listener) Accept() (net.Conn, error) {
	conn, err := l.underlying.Accept()
	if err != nil {
		return nil, err
	}

	boxconn, err := Handshake(conn, l.privateKey, l.publicKey, l.allowedKeys...)
	if err != nil {
		conn.Close()
		return nil, err
	}

	return boxconn, nil
}

// Close closes the listener.
// Any blocked Accept operations will be unblocked and return errors.
func (l *Listener) Close() error {
	return l.underlying.Close()
}

// Addr returns the listener's network address.
func (l *Listener) Addr() net.Addr {
	return l.underlying.Addr()
}
<|endoftext|>


<commit_before>package bxmpp

import (
	"crypto/tls"
	"strings"
	"time"

	"github.com/42wim/matterbridge/bridge"
	"github.com/42wim/matterbridge/bridge/config"
	"github.com/42wim/matterbridge/bridge/helper"
	"github.com/jpillora/backoff"
	"github.com/matterbridge/go-xmpp"
	"github.com/rs/xid"
)

type Bxmpp struct {
	*bridge.Config

	startTime time.Time
	xc        *xmpp.Client
	xmppMap   map[string]string
}

func New(cfg *bridge.Config) bridge.Bridger {
	return &Bxmpp{
		Config:  cfg,
		xmppMap: make(map[string]string),
	}
}

func (b *Bxmpp) Connect() error {
	b.Log.Infof("Connecting %s", b.GetString("Server"))
	if err := b.createXMPP(); err != nil {
		b.Log.Debugf("%#v", err)
		return err
	}

	b.Log.Info("Connection succeeded")
	go b.manageConnection()
	return nil
}

func (b *Bxmpp) Disconnect() error {
	return nil
}

func (b *Bxmpp) JoinChannel(channel config.ChannelInfo) error {
	if channel.Options.Key != "" {
		b.Log.Debugf("using key %s for channel %s", channel.Options.Key, channel.Name)
		b.xc.JoinProtectedMUC(channel.Name+"@"+b.GetString("Muc"), b.GetString("Nick"), channel.Options.Key, xmpp.NoHistory, 0, nil)
	} else {
		b.xc.JoinMUCNoHistory(channel.Name+"@"+b.GetString("Muc"), b.GetString("Nick"))
	}
	return nil
}

func (b *Bxmpp) Send(msg config.Message) (string, error) {
	// ignore delete messages
	if msg.Event == config.EventMsgDelete {
		return "", nil
	}
	b.Log.Debugf("=> Receiving %#v", msg)

	// Upload a file (in XMPP case send the upload URL because XMPP has no native upload support).
	if msg.Extra != nil {
		for _, rmsg := range helper.HandleExtra(&msg, b.General) {
			b.Log.Debugf("=> Sending attachement message %#v", rmsg)
			if _, err := b.xc.Send(xmpp.Chat{
				Type:   "groupchat",
				Remote: rmsg.Channel + "@" + b.GetString("Muc"),
				Text:   rmsg.Username + rmsg.Text,
			}); err != nil {
				b.Log.WithError(err).Error("Unable to send message with share URL.")
			}
		}
		if len(msg.Extra["file"]) > 0 {
			return "", b.handleUploadFile(&msg)
		}
	}

	var msgReplaceID string
	msgID := xid.New().String()
	if msg.ID != "" {
		msgID = msg.ID
		msgReplaceID = msg.ID
	}
	// Post normal message.
	b.Log.Debugf("=> Sending message %#v", msg)
	if _, err := b.xc.Send(xmpp.Chat{
		Type:      "groupchat",
		Remote:    msg.Channel + "@" + b.GetString("Muc"),
		Text:      msg.Username + msg.Text,
		ID:        msgID,
		ReplaceID: msgReplaceID,
	}); err != nil {
		return "", err
	}
	return msgID, nil
}

func (b *Bxmpp) createXMPP() error {
	tc := &tls.Config{
		ServerName:         strings.Split(b.GetString("Jid"), "@")[1],
		InsecureSkipVerify: b.GetBool("SkipTLSVerify"), // nolint: gosec
	}
	options := xmpp.Options{
		Host:                         b.GetString("Server"),
		User:                         b.GetString("Jid"),
		Password:                     b.GetString("Password"),
		NoTLS:                        true,
		StartTLS:                     true,
		TLSConfig:                    tc,
		Debug:                        b.GetBool("debug"),
		Logger:                       b.Log.Writer(),
		Session:                      true,
		Status:                       "",
		StatusMessage:                "",
		Resource:                     "",
		InsecureAllowUnencryptedAuth: false,
	}
	var err error
	b.xc, err = options.NewClient()
	return err
}

func (b *Bxmpp) manageConnection() {
	initial := true
	bf := &backoff.Backoff{
		Min:    time.Second,
		Max:    5 * time.Minute,
		Jitter: true,
	}

	// Main connection loop. Each iteration corresponds to a successful
	// connection attempt and the subsequent handling of the connection.
	for {
		if initial {
			initial = false
		} else {
			b.Remote <- config.Message{
				Username: "system",
				Text:     "rejoin",
				Channel:  "",
				Account:  b.Account,
				Event:    config.EventRejoinChannels,
			}
		}

		if err := b.handleXMPP(); err != nil {
			b.Log.WithError(err).Error("Disconnected.")
		}

		// Reconnection loop using an exponential back-off strategy. We
		// only break out of the loop if we have successfully reconnected.
		for {
			d := bf.Duration()
			b.Log.Infof("Reconnecting in %s.", d)
			time.Sleep(d)

			b.Log.Infof("Reconnecting now.")
			if err := b.createXMPP(); err == nil {
				bf.Reset()
				break
			}
			b.Log.Warn("Failed to reconnect.")
		}
	}
}

func (b *Bxmpp) xmppKeepAlive() chan bool {
	done := make(chan bool)
	go func() {
		ticker := time.NewTicker(90 * time.Second)
		defer ticker.Stop()
		for {
			select {
			case <-ticker.C:
				b.Log.Debugf("PING")
				if err := b.xc.PingC2S("", ""); err != nil {
					b.Log.Debugf("PING failed %#v", err)
				}
			case <-done:
				return
			}
		}
	}()
	return done
}

func (b *Bxmpp) handleXMPP() error {
	b.startTime = time.Now()

	done := b.xmppKeepAlive()
	defer close(done)

	for {
		m, err := b.xc.Recv()
		if err != nil {
			return err
		}

		switch v := m.(type) {
		case xmpp.Chat:
			if v.Type == "groupchat" {
				b.Log.Debugf("== Receiving %#v", v)

				// Skip invalid messages.
				if b.skipMessage(v) {
					continue
				}

				var event string
				if strings.Contains(v.Text, "has set the subject to:") {
					event = config.EventTopicChange
				}

				msgID := v.ID
				if v.ReplaceID != "" {
					msgID = v.ReplaceID
				}
				rmsg := config.Message{
					Username: b.parseNick(v.Remote),
					Text:     v.Text,
					Channel:  b.parseChannel(v.Remote),
					Account:  b.Account,
					UserID:   v.Remote,
					ID:       msgID,
					Event:    event,
				}

				// Check if we have an action event.
				var ok bool
				rmsg.Text, ok = b.replaceAction(rmsg.Text)
				if ok {
					rmsg.Event = config.EventUserAction
				}

				b.Log.Debugf("<= Sending message from %s on %s to gateway", rmsg.Username, b.Account)
				b.Log.Debugf("<= Message is %#v", rmsg)
				b.Remote <- rmsg
			}
		case xmpp.Presence:
			// Do nothing.
		}
	}
}

func (b *Bxmpp) replaceAction(text string) (string, bool) {
	if strings.HasPrefix(text, "/me ") {
		return strings.Replace(text, "/me ", "", -1), true
	}
	return text, false
}

// handleUploadFile handles native upload of files
func (b *Bxmpp) handleUploadFile(msg *config.Message) error {
	var urlDesc string

	for _, file := range msg.Extra["file"] {
		fileInfo := file.(config.FileInfo)
		if fileInfo.Comment != "" {
			msg.Text += fileInfo.Comment + ": "
		}
		if fileInfo.URL != "" {
			msg.Text = fileInfo.URL
			if fileInfo.Comment != "" {
				msg.Text = fileInfo.Comment + ": " + fileInfo.URL
				urlDesc = fileInfo.Comment
			}
		}
		if _, err := b.xc.Send(xmpp.Chat{
			Type:   "groupchat",
			Remote: msg.Channel + "@" + b.GetString("Muc"),
			Text:   msg.Username + msg.Text,
		}); err != nil {
			return err
		}

		if fileInfo.URL != "" {
			if _, err := b.xc.SendOOB(xmpp.Chat{
				Type:    "groupchat",
				Remote:  msg.Channel + "@" + b.GetString("Muc"),
				Ooburl:  fileInfo.URL,
				Oobdesc: urlDesc,
			}); err != nil {
				b.Log.WithError(err).Warn("Failed to send share URL.")
			}
		}
	}
	return nil
}

func (b *Bxmpp) parseNick(remote string) string {
	s := strings.Split(remote, "@")
	if len(s) > 0 {
		s = strings.Split(s[1], "/")
		if len(s) == 2 {
			return s[1] // nick
		}
	}
	return ""
}

func (b *Bxmpp) parseChannel(remote string) string {
	s := strings.Split(remote, "@")
	if len(s) >= 2 {
		return s[0] // channel
	}
	return ""
}

// skipMessage skips messages that need to be skipped
func (b *Bxmpp) skipMessage(message xmpp.Chat) bool {
	// skip messages from ourselves
	if b.parseNick(message.Remote) == b.GetString("Nick") {
		return true
	}

	// skip empty messages
	if message.Text == "" {
		return true
	}

	// skip subject messages
	if strings.Contains(message.Text, "</subject>") {
		return true
	}

	// do not show subjects on connect #732
	if strings.Contains(message.Text, "has set the subject to:") && time.Since(b.startTime) < time.Second*5 {
		return true
	}

	// skip delayed messages
	return !message.Stamp.IsZero() && time.Since(message.Stamp).Minutes() > 5
}
<commit_msg>Keep connection state. Fixes #856<commit_after>package bxmpp

import (
	"crypto/tls"
	"fmt"
	"strings"
	"sync"
	"time"

	"github.com/42wim/matterbridge/bridge"
	"github.com/42wim/matterbridge/bridge/config"
	"github.com/42wim/matterbridge/bridge/helper"
	"github.com/jpillora/backoff"
	"github.com/matterbridge/go-xmpp"
	"github.com/rs/xid"
)

type Bxmpp struct {
	*bridge.Config

	startTime time.Time
	xc        *xmpp.Client
	xmppMap   map[string]string
	connected bool
	sync.RWMutex
}

func New(cfg *bridge.Config) bridge.Bridger {
	return &Bxmpp{
		Config:  cfg,
		xmppMap: make(map[string]string),
	}
}

func (b *Bxmpp) Connect() error {
	b.Log.Infof("Connecting %s", b.GetString("Server"))
	if err := b.createXMPP(); err != nil {
		b.Log.Debugf("%#v", err)
		return err
	}

	b.Log.Info("Connection succeeded")
	go b.manageConnection()
	return nil
}

func (b *Bxmpp) Disconnect() error {
	return nil
}

func (b *Bxmpp) JoinChannel(channel config.ChannelInfo) error {
	if channel.Options.Key != "" {
		b.Log.Debugf("using key %s for channel %s", channel.Options.Key, channel.Name)
		b.xc.JoinProtectedMUC(channel.Name+"@"+b.GetString("Muc"), b.GetString("Nick"), channel.Options.Key, xmpp.NoHistory, 0, nil)
	} else {
		b.xc.JoinMUCNoHistory(channel.Name+"@"+b.GetString("Muc"), b.GetString("Nick"))
	}
	return nil
}

func (b *Bxmpp) Send(msg config.Message) (string, error) {
	// should be fixed by using a cache instead of dropping
	if !b.Connected() {
		return "", fmt.Errorf("bridge %s not connected, dropping message %#v to bridge", b.Account, msg)
	}
	// ignore delete messages
	if msg.Event == config.EventMsgDelete {
		return "", nil
	}
	b.Log.Debugf("=> Receiving %#v", msg)

	// Upload a file (in XMPP case send the upload URL because XMPP has no native upload support).
	if msg.Extra != nil {
		for _, rmsg := range helper.HandleExtra(&msg, b.General) {
			b.Log.Debugf("=> Sending attachement message %#v", rmsg)
			if _, err := b.xc.Send(xmpp.Chat{
				Type:   "groupchat",
				Remote: rmsg.Channel + "@" + b.GetString("Muc"),
				Text:   rmsg.Username + rmsg.Text,
			}); err != nil {
				b.Log.WithError(err).Error("Unable to send message with share URL.")
			}
		}
		if len(msg.Extra["file"]) > 0 {
			return "", b.handleUploadFile(&msg)
		}
	}

	var msgReplaceID string
	msgID := xid.New().String()
	if msg.ID != "" {
		msgID = msg.ID
		msgReplaceID = msg.ID
	}
	// Post normal message.
	b.Log.Debugf("=> Sending message %#v", msg)
	if _, err := b.xc.Send(xmpp.Chat{
		Type:      "groupchat",
		Remote:    msg.Channel + "@" + b.GetString("Muc"),
		Text:      msg.Username + msg.Text,
		ID:        msgID,
		ReplaceID: msgReplaceID,
	}); err != nil {
		return "", err
	}
	return msgID, nil
}

func (b *Bxmpp) createXMPP() error {
	tc := &tls.Config{
		ServerName:         strings.Split(b.GetString("Jid"), "@")[1],
		InsecureSkipVerify: b.GetBool("SkipTLSVerify"), // nolint: gosec
	}
	options := xmpp.Options{
		Host:                         b.GetString("Server"),
		User:                         b.GetString("Jid"),
		Password:                     b.GetString("Password"),
		NoTLS:                        true,
		StartTLS:                     true,
		TLSConfig:                    tc,
		Debug:                        b.GetBool("debug"),
		Logger:                       b.Log.Writer(),
		Session:                      true,
		Status:                       "",
		StatusMessage:                "",
		Resource:                     "",
		InsecureAllowUnencryptedAuth: false,
	}
	var err error
	b.xc, err = options.NewClient()
	return err
}

func (b *Bxmpp) manageConnection() {
	b.setConnected(true)
	initial := true
	bf := &backoff.Backoff{
		Min:    time.Second,
		Max:    5 * time.Minute,
		Jitter: true,
	}

	// Main connection loop. Each iteration corresponds to a successful
	// connection attempt and the subsequent handling of the connection.
	for {
		if initial {
			initial = false
		} else {
			b.Remote <- config.Message{
				Username: "system",
				Text:     "rejoin",
				Channel:  "",
				Account:  b.Account,
				Event:    config.EventRejoinChannels,
			}
		}

		if err := b.handleXMPP(); err != nil {
			b.Log.WithError(err).Error("Disconnected.")
			b.setConnected(false)
		}

		// Reconnection loop using an exponential back-off strategy. We
		// only break out of the loop if we have successfully reconnected.
		for {
			d := bf.Duration()
			b.Log.Infof("Reconnecting in %s.", d)
			time.Sleep(d)

			b.Log.Infof("Reconnecting now.")
			if err := b.createXMPP(); err == nil {
				b.setConnected(true)
				bf.Reset()
				break
			}
			b.Log.Warn("Failed to reconnect.")
		}
	}
}

func (b *Bxmpp) xmppKeepAlive() chan bool {
	done := make(chan bool)
	go func() {
		ticker := time.NewTicker(90 * time.Second)
		defer ticker.Stop()
		for {
			select {
			case <-ticker.C:
				b.Log.Debugf("PING")
				if err := b.xc.PingC2S("", ""); err != nil {
					b.Log.Debugf("PING failed %#v", err)
				}
			case <-done:
				return
			}
		}
	}()
	return done
}

func (b *Bxmpp) handleXMPP() error {
	b.startTime = time.Now()

	done := b.xmppKeepAlive()
	defer close(done)

	for {
		m, err := b.xc.Recv()
		if err != nil {
			return err
		}

		switch v := m.(type) {
		case xmpp.Chat:
			if v.Type == "groupchat" {
				b.Log.Debugf("== Receiving %#v", v)

				// Skip invalid messages.
				if b.skipMessage(v) {
					continue
				}

				var event string
				if strings.Contains(v.Text, "has set the subject to:") {
					event = config.EventTopicChange
				}

				msgID := v.ID
				if v.ReplaceID != "" {
					msgID = v.ReplaceID
				}
				rmsg := config.Message{
					Username: b.parseNick(v.Remote),
					Text:     v.Text,
					Channel:  b.parseChannel(v.Remote),
					Account:  b.Account,
					UserID:   v.Remote,
					ID:       msgID,
					Event:    event,
				}

				// Check if we have an action event.
				var ok bool
				rmsg.Text, ok = b.replaceAction(rmsg.Text)
				if ok {
					rmsg.Event = config.EventUserAction
				}

				b.Log.Debugf("<= Sending message from %s on %s to gateway", rmsg.Username, b.Account)
				b.Log.Debugf("<= Message is %#v", rmsg)
				b.Remote <- rmsg
			}
		case xmpp.Presence:
			// Do nothing.
		}
	}
}

func (b *Bxmpp) replaceAction(text string) (string, bool) {
	if strings.HasPrefix(text, "/me ") {
		return strings.Replace(text, "/me ", "", -1), true
	}
	return text, false
}

// handleUploadFile handles native upload of files
func (b *Bxmpp) handleUploadFile(msg *config.Message) error {
	var urlDesc string

	for _, file := range msg.Extra["file"] {
		fileInfo := file.(config.FileInfo)
		if fileInfo.Comment != "" {
			msg.Text += fileInfo.Comment + ": "
		}
		if fileInfo.URL != "" {
			msg.Text = fileInfo.URL
			if fileInfo.Comment != "" {
				msg.Text = fileInfo.Comment + ": " + fileInfo.URL
				urlDesc = fileInfo.Comment
			}
		}
		if _, err := b.xc.Send(xmpp.Chat{
			Type:   "groupchat",
			Remote: msg.Channel + "@" + b.GetString("Muc"),
			Text:   msg.Username + msg.Text,
		}); err != nil {
			return err
		}

		if fileInfo.URL != "" {
			if _, err := b.xc.SendOOB(xmpp.Chat{
				Type:    "groupchat",
				Remote:  msg.Channel + "@" + b.GetString("Muc"),
				Ooburl:  fileInfo.URL,
				Oobdesc: urlDesc,
			}); err != nil {
				b.Log.WithError(err).Warn("Failed to send share URL.")
			}
		}
	}
	return nil
}

func (b *Bxmpp) parseNick(remote string) string {
	s := strings.Split(remote, "@")
	if len(s) > 0 {
		s = strings.Split(s[1], "/")
		if len(s) == 2 {
			return s[1] // nick
		}
	}
	return ""
}

func (b *Bxmpp) parseChannel(remote string) string {
	s := strings.Split(remote, "@")
	if len(s) >= 2 {
		return s[0] // channel
	}
	return ""
}

// skipMessage skips messages that need to be skipped
func (b *Bxmpp) skipMessage(message xmpp.Chat) bool {
	// skip messages from ourselves
	if b.parseNick(message.Remote) == b.GetString("Nick") {
		return true
	}

	// skip empty messages
	if message.Text == "" {
		return true
	}

	// skip subject messages
	if strings.Contains(message.Text, "</subject>") {
		return true
	}

	// do not show subjects on connect #732
	if strings.Contains(message.Text, "has set the subject to:") && time.Since(b.startTime) < time.Second*5 {
		return true
	}

	// skip delayed messages
	return !message.Stamp.IsZero() && time.Since(message.Stamp).Minutes() > 5
}

func (b *Bxmpp) setConnected(state bool) {
	b.Lock()
	b.connected = state
	defer b.Unlock()
}

func (b *Bxmpp) Connected() bool {
	b.RLock()
	defer b.RUnlock()
	return b.connected
}
<|endoftext|>


<commit_before>// +build !windows

package buildkite

// Logic for this file is largely based on:
// https://github.com/jarib/childprocess/blob/783f7a00a1678b5d929062564ef5ae76822dfd62/lib/childprocess/unix/process.rb

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/kr/pty"
	"io"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"sync"
	"syscall"
	"time"
)

type Process struct {
	Output     string
	Pid        int
	Running    bool
	RunInPty   bool
	ExitStatus string
	command    *exec.Cmd
	callback   func(*Process)
}

// Implement the Stringer thingy
func (p Process) String() string {
	return fmt.Sprintf("Process{Pid: %d, Running: %t, ExitStatus: %s}", p.Pid, p.Running, p.ExitStatus)
}

func InitProcess(scriptPath string, env []string, runInPty bool, callback func(*Process)) *Process {
	// Create a new instance of our process struct
	var process Process
	process.RunInPty = runInPty

	process.command = exec.Command(scriptPath)

	// Set the working directory of the process
	pathToScript, _ := filepath.Abs(path.Dir(scriptPath))
	process.command.Dir = pathToScript

	// Children of the forked process will inherit its process group
	// This is to make sure that all grandchildren dies when this Process instance is killed
	process.command.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}

	// Copy the current processes ENV and merge in the new ones. We do this
	// so the sub process gets PATH and stuff.
	currentEnv := os.Environ()
	process.command.Env = append(currentEnv, env...)

	// Set the callback
	process.callback = callback

	return &process
}

func (p *Process) Start() error {
	var buffer bytes.Buffer
	var waitGroup sync.WaitGroup

	Logger.Infof("Starting to run script: %s", p.command.Path)

	// Toggle between running in a pty
	if p.RunInPty {
		pty, err := pty.Start(p.command)
		if err != nil {
			p.ExitStatus = "1"
			return err
		}

		p.Pid = p.command.Process.Pid
		p.Running = true

		waitGroup.Add(2)

		go func() {
			Logger.Debug("Starting to copy PTY to the buffer")

			// Copy the pty to our buffer. This will block until it EOF's
			// or something breaks.
			_, err = io.Copy(&buffer, pty)
			if e, ok := err.(*os.PathError); ok && e.Err == syscall.EIO {
				// We can safely ignore this error, because
				// it's just the PTY telling us that it closed
				// successfully.
				// See: https://github.com/buildkite/agent/pull/34#issuecomment-46080419
			} else if err != nil {
				Logger.Errorf("io.Copy failed with error: %T: %v", err, err)
			} else {
				Logger.Debug("io.Copy finsihed")
			}

			waitGroup.Done()
		}()
	} else {
		p.command.Stdout = &buffer
		p.command.Stderr = &buffer

		err := p.command.Start()
		if err != nil {
			p.ExitStatus = "1"
			return err
		}

		p.Pid = p.command.Process.Pid
		p.Running = true

		// We only have to wait for 1 thing if we're not running in a PTY.
		waitGroup.Add(1)
	}

	Logger.Infof("Process is running with PID: %d", p.Pid)

	go func() {
		for p.Running {
			Logger.Debug("Copying buffer to the process output")

			// Convert the stdout buffer to a string
			p.Output = buffer.String()

			// Call the callback and pass in our process object
			p.callback(p)

			// Sleep for 1 second
			time.Sleep(1000 * time.Millisecond)
		}

		Logger.Debug("Finished routine that copies the buffer to the process output")

		waitGroup.Done()
	}()

	// Wait until the process has finished. The returned error is nil if the command runs,
	// has no problems copying stdin, stdout, and stderr, and exits with a zero exit status.
	waitResult := p.command.Wait()

	// The process is no longer running at this point
	p.Running = false

	// Find the exit status of the script
	p.ExitStatus = getExitStatus(waitResult)

	Logger.Infof("Process with PID: %d finished with Exit Status: %s", p.Pid, p.ExitStatus)

	// Sometimes (in docker containers) io.Copy never seems to finish. This is a mega
	// hack around it. If it doesn't finish after 1 second, just continue.
	Logger.Debug("Waiting for io.Copy and incremental output to finish")
	err := timeoutWait(&waitGroup)
	if err != nil {
		Logger.Errorf("Timed out waiting for wait group: (%T: %v)", err, err)
	}

	// Copy the final output back to the process
	p.Output = buffer.String()

	// No error occured so we can return nil
	return nil
}

func (p *Process) Kill() error {
	// Send a sigterm
	err := p.signal(syscall.SIGTERM)
	if err != nil {
		return err
	}

	// Make a chanel that we'll use as a timeout
	c := make(chan int, 1)
	checking := true

	// Start a routine that checks to see if the process
	// is still alive.
	go func() {
		for checking {
			Logger.Debugf("Checking to see if PID: %d is still alive", p.Pid)

			foundProcess, err := os.FindProcess(p.Pid)

			// Can't find the process at all
			if err != nil {
				Logger.Debugf("Could not find process with PID: %d", p.Pid)

				break
			}

			// We have some information about the procss
			if foundProcess != nil {
				processState, err := foundProcess.Wait()

				if err != nil || processState.Exited() {
					Logger.Debugf("Process with PID: %d has exited.", p.Pid)

					break
				}
			}

			// Retry in a moment
			sleepTime := time.Duration(1 * time.Second)
			time.Sleep(sleepTime)
		}

		c <- 1
	}()

	// Timeout this process after 3 seconds
	select {
	case _ = <-c:
		// Was successfully terminated
	case <-time.After(10 * time.Second):
		// Stop checking in the routine above
		checking = false

		// Forcefully kill the thing
		err = p.signal(syscall.SIGKILL)

		if err != nil {
			return err
		}
	}

	return nil
}

func (p *Process) signal(sig os.Signal) error {
	Logger.Debugf("Sending signal: %s to PID: %d", sig.String(), p.Pid)

	err := p.command.Process.Signal(syscall.SIGTERM)
	if err != nil {
		Logger.Errorf("Failed to send signal: %s to PID: %d (%T: %v)", sig.String(), p.Pid, err, err)
		return err
	}

	return nil
}

// https://github.com/hnakamur/commango/blob/fe42b1cf82bf536ce7e24dceaef6656002e03743/os/executil/executil.go#L29
// TODO: Can this be better?
func getExitStatus(waitResult error) string {
	exitStatus := -1

	if waitResult != nil {
		if err, ok := waitResult.(*exec.ExitError); ok {
			if s, ok := err.Sys().(syscall.WaitStatus); ok {
				exitStatus = s.ExitStatus()
			} else {
				Logger.Error("Unimplemented for system where exec.ExitError.Sys() is not syscall.WaitStatus.")
			}
		}
	} else {
		exitStatus = 0
	}

	return fmt.Sprintf("%d", exitStatus)
}

func timeoutWait(waitGroup *sync.WaitGroup) error {
	// Make a chanel that we'll use as a timeout
	c := make(chan int, 1)

	// Start waiting for the routines to finish
	go func() {
		waitGroup.Wait()
		c <- 1
	}()

	select {
	case _ = <-c:
		return nil
	case <-time.After(5 * time.Second):
		return errors.New("Timeout")
	}

	return nil
}
<commit_msg>Fix for running scripts from a relative directory.<commit_after>// +build !windows

package buildkite

// Logic for this file is largely based on:
// https://github.com/jarib/childprocess/blob/783f7a00a1678b5d929062564ef5ae76822dfd62/lib/childprocess/unix/process.rb

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/kr/pty"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"sync"
	"syscall"
	"time"
)

type Process struct {
	Output     string
	Pid        int
	Running    bool
	RunInPty   bool
	ExitStatus string
	command    *exec.Cmd
	callback   func(*Process)
}

// Implement the Stringer thingy
func (p Process) String() string {
	return fmt.Sprintf("Process{Pid: %d, Running: %t, ExitStatus: %s}", p.Pid, p.Running, p.ExitStatus)
}

func InitProcess(scriptPath string, env []string, runInPty bool, callback func(*Process)) *Process {
	// Create a new instance of our process struct
	var process Process
	process.RunInPty = runInPty

	// Find the script to run
	absolutePath, _ := filepath.Abs(scriptPath)
	scriptDirectory := filepath.Dir(absolutePath)

	process.command = exec.Command(absolutePath)
	process.command.Dir = scriptDirectory

	// Children of the forked process will inherit its process group
	// This is to make sure that all grandchildren dies when this Process instance is killed
	process.command.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}

	// Copy the current processes ENV and merge in the new ones. We do this
	// so the sub process gets PATH and stuff.
	currentEnv := os.Environ()
	process.command.Env = append(currentEnv, env...)

	// Set the callback
	process.callback = callback

	return &process
}

func (p *Process) Start() error {
	var buffer bytes.Buffer
	var waitGroup sync.WaitGroup

	Logger.Infof("Starting to run script: %s", p.command.Path)

	// Toggle between running in a pty
	if p.RunInPty {
		pty, err := pty.Start(p.command)
		if err != nil {
			p.ExitStatus = "1"
			return err
		}

		p.Pid = p.command.Process.Pid
		p.Running = true

		waitGroup.Add(2)

		go func() {
			Logger.Debug("Starting to copy PTY to the buffer")

			// Copy the pty to our buffer. This will block until it EOF's
			// or something breaks.
			_, err = io.Copy(&buffer, pty)
			if e, ok := err.(*os.PathError); ok && e.Err == syscall.EIO {
				// We can safely ignore this error, because
				// it's just the PTY telling us that it closed
				// successfully.
				// See: https://github.com/buildkite/agent/pull/34#issuecomment-46080419
			} else if err != nil {
				Logger.Errorf("io.Copy failed with error: %T: %v", err, err)
			} else {
				Logger.Debug("io.Copy finsihed")
			}

			waitGroup.Done()
		}()
	} else {
		p.command.Stdout = &buffer
		p.command.Stderr = &buffer

		err := p.command.Start()
		if err != nil {
			p.ExitStatus = "1"
			return err
		}

		p.Pid = p.command.Process.Pid
		p.Running = true

		// We only have to wait for 1 thing if we're not running in a PTY.
		waitGroup.Add(1)
	}

	Logger.Infof("Process is running with PID: %d", p.Pid)

	go func() {
		for p.Running {
			Logger.Debug("Copying buffer to the process output")

			// Convert the stdout buffer to a string
			p.Output = buffer.String()

			// Call the callback and pass in our process object
			p.callback(p)

			// Sleep for 1 second
			time.Sleep(1000 * time.Millisecond)
		}

		Logger.Debug("Finished routine that copies the buffer to the process output")

		waitGroup.Done()
	}()

	// Wait until the process has finished. The returned error is nil if the command runs,
	// has no problems copying stdin, stdout, and stderr, and exits with a zero exit status.
	waitResult := p.command.Wait()

	// The process is no longer running at this point
	p.Running = false

	// Find the exit status of the script
	p.ExitStatus = getExitStatus(waitResult)

	Logger.Infof("Process with PID: %d finished with Exit Status: %s", p.Pid, p.ExitStatus)

	// Sometimes (in docker containers) io.Copy never seems to finish. This is a mega
	// hack around it. If it doesn't finish after 1 second, just continue.
	Logger.Debug("Waiting for io.Copy and incremental output to finish")
	err := timeoutWait(&waitGroup)
	if err != nil {
		Logger.Errorf("Timed out waiting for wait group: (%T: %v)", err, err)
	}

	// Copy the final output back to the process
	p.Output = buffer.String()

	// No error occured so we can return nil
	return nil
}

func (p *Process) Kill() error {
	// Send a sigterm
	err := p.signal(syscall.SIGTERM)
	if err != nil {
		return err
	}

	// Make a chanel that we'll use as a timeout
	c := make(chan int, 1)
	checking := true

	// Start a routine that checks to see if the process
	// is still alive.
	go func() {
		for checking {
			Logger.Debugf("Checking to see if PID: %d is still alive", p.Pid)

			foundProcess, err := os.FindProcess(p.Pid)

			// Can't find the process at all
			if err != nil {
				Logger.Debugf("Could not find process with PID: %d", p.Pid)

				break
			}

			// We have some information about the procss
			if foundProcess != nil {
				processState, err := foundProcess.Wait()

				if err != nil || processState.Exited() {
					Logger.Debugf("Process with PID: %d has exited.", p.Pid)

					break
				}
			}

			// Retry in a moment
			sleepTime := time.Duration(1 * time.Second)
			time.Sleep(sleepTime)
		}

		c <- 1
	}()

	// Timeout this process after 3 seconds
	select {
	case _ = <-c:
		// Was successfully terminated
	case <-time.After(10 * time.Second):
		// Stop checking in the routine above
		checking = false

		// Forcefully kill the thing
		err = p.signal(syscall.SIGKILL)

		if err != nil {
			return err
		}
	}

	return nil
}

func (p *Process) signal(sig os.Signal) error {
	Logger.Debugf("Sending signal: %s to PID: %d", sig.String(), p.Pid)

	err := p.command.Process.Signal(syscall.SIGTERM)
	if err != nil {
		Logger.Errorf("Failed to send signal: %s to PID: %d (%T: %v)", sig.String(), p.Pid, err, err)
		return err
	}

	return nil
}

// https://github.com/hnakamur/commango/blob/fe42b1cf82bf536ce7e24dceaef6656002e03743/os/executil/executil.go#L29
// TODO: Can this be better?
func getExitStatus(waitResult error) string {
	exitStatus := -1

	if waitResult != nil {
		if err, ok := waitResult.(*exec.ExitError); ok {
			if s, ok := err.Sys().(syscall.WaitStatus); ok {
				exitStatus = s.ExitStatus()
			} else {
				Logger.Error("Unimplemented for system where exec.ExitError.Sys() is not syscall.WaitStatus.")
			}
		}
	} else {
		exitStatus = 0
	}

	return fmt.Sprintf("%d", exitStatus)
}

func timeoutWait(waitGroup *sync.WaitGroup) error {
	// Make a chanel that we'll use as a timeout
	c := make(chan int, 1)

	// Start waiting for the routines to finish
	go func() {
		waitGroup.Wait()
		c <- 1
	}()

	select {
	case _ = <-c:
		return nil
	case <-time.After(5 * time.Second):
		return errors.New("Timeout")
	}

	return nil
}
<|endoftext|>