<commit_before>package collector

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"strings"
	"sync"
	"time"

	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
	"github.com/karimra/gnmic/outputs"
	"github.com/openconfig/gnmi/proto/gnmi"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"google.golang.org/grpc"
)

// Config is the collector config
type Config struct {
	PrometheusAddress string
	Debug             bool
}

// Collector //
type Collector struct {
	Config        *Config
	Subscriptions map[string]*SubscriptionConfig
	Outputs       map[string][]outputs.Output
	DialOpts      []grpc.DialOption
	//
	m          *sync.Mutex
	Targets    map[string]*Target
	Logger     *log.Logger
	httpServer *http.Server

	ctx      context.Context
	cancelFn context.CancelFunc
}

// NewCollector //
func NewCollector(ctx context.Context,
	config *Config,
	targetConfigs map[string]*TargetConfig,
	subscriptions map[string]*SubscriptionConfig,
	outputs map[string][]outputs.Output,
	dialOpts []grpc.DialOption,
	logger *log.Logger,
) *Collector {
	nctx, cancel := context.WithCancel(ctx)
	grpcMetrics := grpc_prometheus.NewClientMetrics()
	reg := prometheus.NewRegistry()
	reg.MustRegister(prometheus.NewGoCollector())
	grpcMetrics.EnableClientHandlingTimeHistogram()
	reg.MustRegister(grpcMetrics)
	handler := http.NewServeMux()
	handler.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{}))
	httpServer := &http.Server{
		Handler: handler,
		Addr:    config.PrometheusAddress,
	}
	dialOpts = append(dialOpts, grpc.WithStreamInterceptor(grpcMetrics.StreamClientInterceptor()))
	c := &Collector{
		Config:        config,
		Subscriptions: subscriptions,
		Outputs:       outputs,
		DialOpts:      dialOpts,
		m:             new(sync.Mutex),
		Targets:       make(map[string]*Target),
		Logger:        logger,
		httpServer:    httpServer,
		ctx:           nctx,
		cancelFn:      cancel,
	}
	wg := new(sync.WaitGroup)
	wg.Add(len(targetConfigs))
	for _, tc := range targetConfigs {
		go func(tc *TargetConfig) {
			defer wg.Done()
			err := c.InitTarget(tc)
			if err == context.DeadlineExceeded {
				c.Logger.Printf("failed to initialize target '%s' timeout (%s) reached: %v", tc.Name, tc.Timeout, err)
				return
			}
			if err != nil {
				c.Logger.Printf("failed to initialize target '%s': %v", tc.Name, err)
				return
			}
			c.Logger.Printf("target '%s' initialized", tc.Name)
		}(tc)
	}
	wg.Wait()
	return c
}

// InitTarget initializes a target based on *TargetConfig
func (c *Collector) InitTarget(tc *TargetConfig) error {
	t := NewTarget(tc)
	//
	t.Subscriptions = make([]*SubscriptionConfig, 0, len(tc.Subscriptions))
	for _, subName := range tc.Subscriptions {
		if sub, ok := c.Subscriptions[subName]; ok {
			t.Subscriptions = append(t.Subscriptions, sub)
		}
	}
	if len(t.Subscriptions) == 0 {
		t.Subscriptions = make([]*SubscriptionConfig, 0, len(c.Subscriptions))
		for _, sub := range c.Subscriptions {
			t.Subscriptions = append(t.Subscriptions, sub)
		}
	}
	//
	t.Outputs = make([]outputs.Output, 0, len(tc.Outputs))
	for _, outName := range tc.Outputs {
		if outs, ok := c.Outputs[outName]; ok {
			t.Outputs = append(t.Outputs, outs...)
		}
	}
	if len(t.Outputs) == 0 {
		t.Outputs = make([]outputs.Output, 0, len(c.Outputs))
		for _, o := range c.Outputs {
			t.Outputs = append(t.Outputs, o...)
		}
	}
	//
	err := t.CreateGNMIClient(c.ctx, c.DialOpts...)
	if err != nil {
		return err
	}
	c.m.Lock()
	defer c.m.Unlock()
	c.Targets[t.Config.Name] = t
	return nil
}

// Subscribe //
func (c *Collector) Subscribe(tName string) error {
	if t, ok := c.Targets[tName]; ok {
		for _, sc := range t.Subscriptions {
			req, err := sc.CreateSubscribeRequest()
			if err != nil {
				return err
			}
			c.Logger.Printf("sending gnmi SubscribeRequest: subscribe='%+v', mode='%+v', encoding='%+v', to %s",
				req, req.GetSubscribe().GetMode(), req.GetSubscribe().GetEncoding(), t.Config.Name)
			go t.Subscribe(c.ctx, req, sc.Name)
		}
		return nil
	}
	return fmt.Errorf("unknown target name: %s", tName)
}

// Start start the prometheus server as well as a goroutine per target selecting on the response chan, the error chan and the ctx.Done() chan
func (c *Collector) Start() {
	go func() {
		if err := c.httpServer.ListenAndServe(); err != nil {
			c.Logger.Printf("Unable to start prometheus http server: %v", err)
			return
		}
	}()
	wg := new(sync.WaitGroup)
	wg.Add(len(c.Targets))
	for _, t := range c.Targets {
		go func(t *Target) {
			defer wg.Done()
			numOnceSubscriptions := t.numberOfOnceSubscriptions()
			remainingOnceSubscriptions := numOnceSubscriptions
			numSubscriptions := len(t.Subscriptions)
			for {
				select {
				case rsp := <-t.SubscribeResponses:
					m := make(map[string]interface{})
					m["subscription-name"] = rsp.SubscriptionName
					m["source"] = t.Config.Name
					b, err := c.FormatMsg(m, rsp.Response)
					if err != nil {
						c.Logger.Printf("failed formatting msg from target '%s': %v", t.Config.Name, err)
						continue
					}
					go t.Export(b, outputs.Meta{"source": t.Config.Name})
					if remainingOnceSubscriptions > 0 {
						if c.subscriptionMode(rsp.SubscriptionName) == "ONCE" {
							switch rsp.Response.Response.(type) {
							case *gnmi.SubscribeResponse_SyncResponse:
								remainingOnceSubscriptions--
							}
						}
					}
					if remainingOnceSubscriptions == 0 && numSubscriptions == numOnceSubscriptions {
						return
					}
				case err := <-t.Errors:
					if err == io.EOF {
						c.Logger.Printf("target '%s' closed stream(EOF)", t.Config.Name)
						return
					}
					c.Logger.Printf("target '%s' error: %v", t.Config.Name, err)
				}
			}
		}(t)
	}
	wg.Wait()
}

// FormatMsg formats the gnmi.SubscribeResponse and returns a []byte and an error
func (c *Collector) FormatMsg(meta map[string]interface{}, rsp *gnmi.SubscribeResponse) ([]byte, error) {
	if rsp == nil {
		return nil, nil
	}
	switch rsp := rsp.Response.(type) {
	case *gnmi.SubscribeResponse_Update:
		msg := new(msg)
		msg.Timestamp = rsp.Update.Timestamp
		t := time.Unix(0, rsp.Update.Timestamp)
		msg.Time = &t
		if meta == nil {
			meta = make(map[string]interface{})
		}
		msg.Prefix = gnmiPathToXPath(rsp.Update.Prefix)
		var ok bool
		if _, ok = meta["source"]; ok {
			msg.Source = fmt.Sprintf("%s", meta["source"])
		}
		if _, ok = meta["system-name"]; ok {
			msg.SystemName = fmt.Sprintf("%s", meta["system-name"])
		}
		if _, ok = meta["subscription-name"]; ok {
			msg.SubscriptionName = fmt.Sprintf("%s", meta["subscription-name"])
		}
		for i, upd := range rsp.Update.Update {
			pathElems := make([]string, 0, len(upd.Path.Elem))
			for _, pElem := range upd.Path.Elem {
				pathElems = append(pathElems, pElem.GetName())
			}
			value, err := getValue(upd.Val)
			if err != nil {
				c.Logger.Println(err)
			}
			msg.Updates = append(msg.Updates,
				&update{
					Path:   gnmiPathToXPath(upd.Path),
					Values: make(map[string]interface{}),
				})
			msg.Updates[i].Values[strings.Join(pathElems, "/")] = value
		}
		for _, del := range rsp.Update.Delete {
			msg.Deletes = append(msg.Deletes, gnmiPathToXPath(del))
		}
		data, err := json.Marshal(msg)
		if err != nil {
			return nil, err
		}
		return data, nil
	}
	return nil, nil
}

// TargetPoll sends a gnmi.SubscribeRequest_Poll to targetName and returns the response and an error,
// it uses the targetName and the subscriptionName strings to find the gnmi.GNMI_SubscribeClient
func (c *Collector) TargetPoll(targetName, subscriptionName string) (*gnmi.SubscribeResponse, error) {
	if sub, ok := c.Subscriptions[subscriptionName]; ok {
		if strings.ToUpper(sub.Mode) != "POLL" {
			return nil, fmt.Errorf("subscription '%s' is not a POLL subscription", subscriptionName)
		}
		if t, ok := c.Targets[targetName]; ok {
			if subClient, ok := t.SubscribeClients[subscriptionName]; ok {
				err := subClient.Send(&gnmi.SubscribeRequest{
					Request: &gnmi.SubscribeRequest_Poll{
						Poll: &gnmi.Poll{},
					},
				})
				if err != nil {
					return nil, err
				}
				return subClient.Recv()
			}
		}
		return nil, fmt.Errorf("unknown target name '%s'", targetName)
	}
	return nil, fmt.Errorf("unknown subscription name '%s'", subscriptionName)
}

// PolledSubscriptionsTargets returns a map of target name to a list of subscription names that have Mode == POLL
func (c *Collector) PolledSubscriptionsTargets() map[string][]string {
	result := make(map[string][]string)
	for tn, target := range c.Targets {
		for _, sub := range target.Subscriptions {
			if strings.ToUpper(sub.Mode) == "POLL" {
				if result[tn] == nil {
					result[tn] = make([]string, 0)
				}
				result[tn] = append(result[tn], sub.Name)
			}
		}
	}
	return result
}

func (c *Collector) subscriptionMode(name string) string {
	if sub, ok := c.Subscriptions[name]; ok {
		return strings.ToUpper(sub.Mode)
	}
	return ""
}
<commit_msg>set gnmi->gNMI to make it consistent with other log msgs<commit_after>package collector

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"strings"
	"sync"
	"time"

	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
	"github.com/karimra/gnmic/outputs"
	"github.com/openconfig/gnmi/proto/gnmi"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"google.golang.org/grpc"
)

// Config is the collector config
type Config struct {
	PrometheusAddress string
	Debug             bool
}

// Collector //
type Collector struct {
	Config        *Config
	Subscriptions map[string]*SubscriptionConfig
	Outputs       map[string][]outputs.Output
	DialOpts      []grpc.DialOption
	//
	m          *sync.Mutex
	Targets    map[string]*Target
	Logger     *log.Logger
	httpServer *http.Server

	ctx      context.Context
	cancelFn context.CancelFunc
}

// NewCollector //
func NewCollector(ctx context.Context,
	config *Config,
	targetConfigs map[string]*TargetConfig,
	subscriptions map[string]*SubscriptionConfig,
	outputs map[string][]outputs.Output,
	dialOpts []grpc.DialOption,
	logger *log.Logger,
) *Collector {
	nctx, cancel := context.WithCancel(ctx)
	grpcMetrics := grpc_prometheus.NewClientMetrics()
	reg := prometheus.NewRegistry()
	reg.MustRegister(prometheus.NewGoCollector())
	grpcMetrics.EnableClientHandlingTimeHistogram()
	reg.MustRegister(grpcMetrics)
	handler := http.NewServeMux()
	handler.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{}))
	httpServer := &http.Server{
		Handler: handler,
		Addr:    config.PrometheusAddress,
	}
	dialOpts = append(dialOpts, grpc.WithStreamInterceptor(grpcMetrics.StreamClientInterceptor()))
	c := &Collector{
		Config:        config,
		Subscriptions: subscriptions,
		Outputs:       outputs,
		DialOpts:      dialOpts,
		m:             new(sync.Mutex),
		Targets:       make(map[string]*Target),
		Logger:        logger,
		httpServer:    httpServer,
		ctx:           nctx,
		cancelFn:      cancel,
	}
	wg := new(sync.WaitGroup)
	wg.Add(len(targetConfigs))
	for _, tc := range targetConfigs {
		go func(tc *TargetConfig) {
			defer wg.Done()
			err := c.InitTarget(tc)
			if err == context.DeadlineExceeded {
				c.Logger.Printf("failed to initialize target '%s' timeout (%s) reached: %v", tc.Name, tc.Timeout, err)
				return
			}
			if err != nil {
				c.Logger.Printf("failed to initialize target '%s': %v", tc.Name, err)
				return
			}
			c.Logger.Printf("target '%s' initialized", tc.Name)
		}(tc)
	}
	wg.Wait()
	return c
}

// InitTarget initializes a target based on *TargetConfig
func (c *Collector) InitTarget(tc *TargetConfig) error {
	t := NewTarget(tc)
	//
	t.Subscriptions = make([]*SubscriptionConfig, 0, len(tc.Subscriptions))
	for _, subName := range tc.Subscriptions {
		if sub, ok := c.Subscriptions[subName]; ok {
			t.Subscriptions = append(t.Subscriptions, sub)
		}
	}
	if len(t.Subscriptions) == 0 {
		t.Subscriptions = make([]*SubscriptionConfig, 0, len(c.Subscriptions))
		for _, sub := range c.Subscriptions {
			t.Subscriptions = append(t.Subscriptions, sub)
		}
	}
	//
	t.Outputs = make([]outputs.Output, 0, len(tc.Outputs))
	for _, outName := range tc.Outputs {
		if outs, ok := c.Outputs[outName]; ok {
			t.Outputs = append(t.Outputs, outs...)
		}
	}
	if len(t.Outputs) == 0 {
		t.Outputs = make([]outputs.Output, 0, len(c.Outputs))
		for _, o := range c.Outputs {
			t.Outputs = append(t.Outputs, o...)
		}
	}
	//
	err := t.CreateGNMIClient(c.ctx, c.DialOpts...)
	if err != nil {
		return err
	}
	c.m.Lock()
	defer c.m.Unlock()
	c.Targets[t.Config.Name] = t
	return nil
}

// Subscribe //
func (c *Collector) Subscribe(tName string) error {
	if t, ok := c.Targets[tName]; ok {
		for _, sc := range t.Subscriptions {
			req, err := sc.CreateSubscribeRequest()
			if err != nil {
				return err
			}
			c.Logger.Printf("sending gNMI SubscribeRequest: subscribe='%+v', mode='%+v', encoding='%+v', to %s",
				req, req.GetSubscribe().GetMode(), req.GetSubscribe().GetEncoding(), t.Config.Name)
			go t.Subscribe(c.ctx, req, sc.Name)
		}
		return nil
	}
	return fmt.Errorf("unknown target name: %s", tName)
}

// Start start the prometheus server as well as a goroutine per target selecting on the response chan, the error chan and the ctx.Done() chan
func (c *Collector) Start() {
	go func() {
		if err := c.httpServer.ListenAndServe(); err != nil {
			c.Logger.Printf("Unable to start prometheus http server: %v", err)
			return
		}
	}()
	wg := new(sync.WaitGroup)
	wg.Add(len(c.Targets))
	for _, t := range c.Targets {
		go func(t *Target) {
			defer wg.Done()
			numOnceSubscriptions := t.numberOfOnceSubscriptions()
			remainingOnceSubscriptions := numOnceSubscriptions
			numSubscriptions := len(t.Subscriptions)
			for {
				select {
				case rsp := <-t.SubscribeResponses:
					m := make(map[string]interface{})
					m["subscription-name"] = rsp.SubscriptionName
					m["source"] = t.Config.Name
					b, err := c.FormatMsg(m, rsp.Response)
					if err != nil {
						c.Logger.Printf("failed formatting msg from target '%s': %v", t.Config.Name, err)
						continue
					}
					go t.Export(b, outputs.Meta{"source": t.Config.Name})
					if remainingOnceSubscriptions > 0 {
						if c.subscriptionMode(rsp.SubscriptionName) == "ONCE" {
							switch rsp.Response.Response.(type) {
							case *gnmi.SubscribeResponse_SyncResponse:
								remainingOnceSubscriptions--
							}
						}
					}
					if remainingOnceSubscriptions == 0 && numSubscriptions == numOnceSubscriptions {
						return
					}
				case err := <-t.Errors:
					if err == io.EOF {
						c.Logger.Printf("target '%s' closed stream(EOF)", t.Config.Name)
						return
					}
					c.Logger.Printf("target '%s' error: %v", t.Config.Name, err)
				}
			}
		}(t)
	}
	wg.Wait()
}

// FormatMsg formats the gnmi.SubscribeResponse and returns a []byte and an error
func (c *Collector) FormatMsg(meta map[string]interface{}, rsp *gnmi.SubscribeResponse) ([]byte, error) {
	if rsp == nil {
		return nil, nil
	}
	switch rsp := rsp.Response.(type) {
	case *gnmi.SubscribeResponse_Update:
		msg := new(msg)
		msg.Timestamp = rsp.Update.Timestamp
		t := time.Unix(0, rsp.Update.Timestamp)
		msg.Time = &t
		if meta == nil {
			meta = make(map[string]interface{})
		}
		msg.Prefix = gnmiPathToXPath(rsp.Update.Prefix)
		var ok bool
		if _, ok = meta["source"]; ok {
			msg.Source = fmt.Sprintf("%s", meta["source"])
		}
		if _, ok = meta["system-name"]; ok {
			msg.SystemName = fmt.Sprintf("%s", meta["system-name"])
		}
		if _, ok = meta["subscription-name"]; ok {
			msg.SubscriptionName = fmt.Sprintf("%s", meta["subscription-name"])
		}
		for i, upd := range rsp.Update.Update {
			pathElems := make([]string, 0, len(upd.Path.Elem))
			for _, pElem := range upd.Path.Elem {
				pathElems = append(pathElems, pElem.GetName())
			}
			value, err := getValue(upd.Val)
			if err != nil {
				c.Logger.Println(err)
			}
			msg.Updates = append(msg.Updates,
				&update{
					Path:   gnmiPathToXPath(upd.Path),
					Values: make(map[string]interface{}),
				})
			msg.Updates[i].Values[strings.Join(pathElems, "/")] = value
		}
		for _, del := range rsp.Update.Delete {
			msg.Deletes = append(msg.Deletes, gnmiPathToXPath(del))
		}
		data, err := json.Marshal(msg)
		if err != nil {
			return nil, err
		}
		return data, nil
	}
	return nil, nil
}

// TargetPoll sends a gnmi.SubscribeRequest_Poll to targetName and returns the response and an error,
// it uses the targetName and the subscriptionName strings to find the gnmi.GNMI_SubscribeClient
func (c *Collector) TargetPoll(targetName, subscriptionName string) (*gnmi.SubscribeResponse, error) {
	if sub, ok := c.Subscriptions[subscriptionName]; ok {
		if strings.ToUpper(sub.Mode) != "POLL" {
			return nil, fmt.Errorf("subscription '%s' is not a POLL subscription", subscriptionName)
		}
		if t, ok := c.Targets[targetName]; ok {
			if subClient, ok := t.SubscribeClients[subscriptionName]; ok {
				err := subClient.Send(&gnmi.SubscribeRequest{
					Request: &gnmi.SubscribeRequest_Poll{
						Poll: &gnmi.Poll{},
					},
				})
				if err != nil {
					return nil, err
				}
				return subClient.Recv()
			}
		}
		return nil, fmt.Errorf("unknown target name '%s'", targetName)
	}
	return nil, fmt.Errorf("unknown subscription name '%s'", subscriptionName)
}

// PolledSubscriptionsTargets returns a map of target name to a list of subscription names that have Mode == POLL
func (c *Collector) PolledSubscriptionsTargets() map[string][]string {
	result := make(map[string][]string)
	for tn, target := range c.Targets {
		for _, sub := range target.Subscriptions {
			if strings.ToUpper(sub.Mode) == "POLL" {
				if result[tn] == nil {
					result[tn] = make([]string, 0)
				}
				result[tn] = append(result[tn], sub.Name)
			}
		}
	}
	return result
}

func (c *Collector) subscriptionMode(name string) string {
	if sub, ok := c.Subscriptions[name]; ok {
		return strings.ToUpper(sub.Mode)
	}
	return ""
}
<|endoftext|>


<commit_before>package build

import (
	"time"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	kapi "k8s.io/kubernetes/pkg/api"

	"github.com/golang/glog"
)

// BuildToPodLogOptions builds a PodLogOptions object out of a BuildLogOptions.
// Currently BuildLogOptions.Container and BuildLogOptions.Previous aren't used
// so they won't be copied to PodLogOptions.
func BuildToPodLogOptions(opts *BuildLogOptions) *kapi.PodLogOptions {
	return &kapi.PodLogOptions{
		Follow:       opts.Follow,
		SinceSeconds: opts.SinceSeconds,
		SinceTime:    opts.SinceTime,
		Timestamps:   opts.Timestamps,
		TailLines:    opts.TailLines,
		LimitBytes:   opts.LimitBytes,
	}
}

// PredicateFunc is testing an argument and decides does it meet some criteria or not.
// It can be used for filtering elements based on some conditions.
type PredicateFunc func(interface{}) bool

// FilterBuilds returns array of builds that satisfies predicate function.
func FilterBuilds(builds []Build, predicate PredicateFunc) []Build {
	if len(builds) == 0 {
		return builds
	}

	result := make([]Build, 0)
	for _, build := range builds {
		if predicate(build) {
			result = append(result, build)
		}
	}

	return result
}

// ByBuildConfigPredicate matches all builds that have build config annotation or label with specified value.
func ByBuildConfigPredicate(labelValue string) PredicateFunc {
	return func(arg interface{}) bool {
		return (hasBuildConfigAnnotation(arg.(Build), BuildConfigAnnotation, labelValue) ||
			hasBuildConfigLabel(arg.(Build), BuildConfigLabel, labelValue) ||
			hasBuildConfigLabel(arg.(Build), BuildConfigLabelDeprecated, labelValue))
	}
}

func hasBuildConfigLabel(build Build, labelName, labelValue string) bool {
	value, ok := build.Labels[labelName]
	return ok && value == labelValue
}

func hasBuildConfigAnnotation(build Build, annotationName, annotationValue string) bool {
	if build.Annotations == nil {
		return false
	}
	value, ok := build.Annotations[annotationName]
	return ok && value == annotationValue
}

// FindTriggerPolicy retrieves the BuildTrigger(s) of a given type from a build configuration.
// Returns nil if no matches are found.
func FindTriggerPolicy(triggerType BuildTriggerType, config *BuildConfig) (buildTriggers []BuildTriggerPolicy) {
	for _, specTrigger := range config.Spec.Triggers {
		if specTrigger.Type == triggerType {
			buildTriggers = append(buildTriggers, specTrigger)
		}
	}
	return buildTriggers
}

func HasTriggerType(triggerType BuildTriggerType, bc *BuildConfig) bool {
	matches := FindTriggerPolicy(triggerType, bc)
	return len(matches) > 0
}

// RecordStageAndStepInfo records details about each build stage and step
func RecordStageAndStepInfo(stages []StageInfo, stageName StageName, stepName StepName, startTime metav1.Time, endTime metav1.Time) []StageInfo {
	// If the stage already exists in the slice, update the DurationMilliseconds, and append the new step.
	for stageKey, stageVal := range stages {
		if stageVal.Name == stageName {
			for _, step := range stages[stageKey].Steps {
				if step.Name == stepName {
					glog.Warningf("error recording build timing information, step %v already exists in stage %v", stepName, stageName)
				}
			}
			stages[stageKey].DurationMilliseconds = endTime.Time.Sub(stages[stageKey].StartTime.Time).Nanoseconds() / int64(time.Millisecond)
			if len(stages[stageKey].Steps) == 0 {
				stages[stageKey].Steps = make([]StepInfo, 0)
			}
			stages[stageKey].Steps = append(stages[stageKey].Steps, StepInfo{
				Name:                 stepName,
				StartTime:            startTime,
				DurationMilliseconds: endTime.Time.Sub(startTime.Time).Nanoseconds() / int64(time.Millisecond),
			})
			return stages
		}
	}

	// If the stageName does not exist, add it to the slice along with the new step.
	var steps []StepInfo
	steps = append(steps, StepInfo{
		Name:                 stepName,
		StartTime:            startTime,
		DurationMilliseconds: endTime.Time.Sub(startTime.Time).Nanoseconds() / int64(time.Millisecond),
	})
	stages = append(stages, StageInfo{
		Name:                 stageName,
		StartTime:            startTime,
		DurationMilliseconds: endTime.Time.Sub(startTime.Time).Nanoseconds() / int64(time.Millisecond),
		Steps:                steps,
	})
	return stages
}

// AppendStageAndStepInfo appends the step info from one stages slice into another.
func AppendStageAndStepInfo(stages []StageInfo, stagesToMerge []StageInfo) []StageInfo {
	for _, stage := range stagesToMerge {
		for _, step := range stage.Steps {
			stages = RecordStageAndStepInfo(stages, stage.Name, step.Name, step.StartTime, metav1.NewTime(step.StartTime.Add(time.Duration(step.DurationMilliseconds)*time.Millisecond)))
		}
	}
	return stages
}
<commit_msg>upping loglevel for warning from stage and step info<commit_after>package build

import (
	"time"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	kapi "k8s.io/kubernetes/pkg/api"

	"github.com/golang/glog"
)

// BuildToPodLogOptions builds a PodLogOptions object out of a BuildLogOptions.
// Currently BuildLogOptions.Container and BuildLogOptions.Previous aren't used
// so they won't be copied to PodLogOptions.
func BuildToPodLogOptions(opts *BuildLogOptions) *kapi.PodLogOptions {
	return &kapi.PodLogOptions{
		Follow:       opts.Follow,
		SinceSeconds: opts.SinceSeconds,
		SinceTime:    opts.SinceTime,
		Timestamps:   opts.Timestamps,
		TailLines:    opts.TailLines,
		LimitBytes:   opts.LimitBytes,
	}
}

// PredicateFunc is testing an argument and decides does it meet some criteria or not.
// It can be used for filtering elements based on some conditions.
type PredicateFunc func(interface{}) bool

// FilterBuilds returns array of builds that satisfies predicate function.
func FilterBuilds(builds []Build, predicate PredicateFunc) []Build {
	if len(builds) == 0 {
		return builds
	}

	result := make([]Build, 0)
	for _, build := range builds {
		if predicate(build) {
			result = append(result, build)
		}
	}

	return result
}

// ByBuildConfigPredicate matches all builds that have build config annotation or label with specified value.
func ByBuildConfigPredicate(labelValue string) PredicateFunc {
	return func(arg interface{}) bool {
		return (hasBuildConfigAnnotation(arg.(Build), BuildConfigAnnotation, labelValue) ||
			hasBuildConfigLabel(arg.(Build), BuildConfigLabel, labelValue) ||
			hasBuildConfigLabel(arg.(Build), BuildConfigLabelDeprecated, labelValue))
	}
}

func hasBuildConfigLabel(build Build, labelName, labelValue string) bool {
	value, ok := build.Labels[labelName]
	return ok && value == labelValue
}

func hasBuildConfigAnnotation(build Build, annotationName, annotationValue string) bool {
	if build.Annotations == nil {
		return false
	}
	value, ok := build.Annotations[annotationName]
	return ok && value == annotationValue
}

// FindTriggerPolicy retrieves the BuildTrigger(s) of a given type from a build configuration.
// Returns nil if no matches are found.
func FindTriggerPolicy(triggerType BuildTriggerType, config *BuildConfig) (buildTriggers []BuildTriggerPolicy) {
	for _, specTrigger := range config.Spec.Triggers {
		if specTrigger.Type == triggerType {
			buildTriggers = append(buildTriggers, specTrigger)
		}
	}
	return buildTriggers
}

func HasTriggerType(triggerType BuildTriggerType, bc *BuildConfig) bool {
	matches := FindTriggerPolicy(triggerType, bc)
	return len(matches) > 0
}

// RecordStageAndStepInfo records details about each build stage and step
func RecordStageAndStepInfo(stages []StageInfo, stageName StageName, stepName StepName, startTime metav1.Time, endTime metav1.Time) []StageInfo {
	// If the stage already exists in the slice, update the DurationMilliseconds, and append the new step.
	for stageKey, stageVal := range stages {
		if stageVal.Name == stageName {
			for _, step := range stages[stageKey].Steps {
				if step.Name == stepName {
					glog.V(4).Infof("error recording build timing information, step %v already exists in stage %v", stepName, stageName)
				}
			}
			stages[stageKey].DurationMilliseconds = endTime.Time.Sub(stages[stageKey].StartTime.Time).Nanoseconds() / int64(time.Millisecond)
			if len(stages[stageKey].Steps) == 0 {
				stages[stageKey].Steps = make([]StepInfo, 0)
			}
			stages[stageKey].Steps = append(stages[stageKey].Steps, StepInfo{
				Name:                 stepName,
				StartTime:            startTime,
				DurationMilliseconds: endTime.Time.Sub(startTime.Time).Nanoseconds() / int64(time.Millisecond),
			})
			return stages
		}
	}

	// If the stageName does not exist, add it to the slice along with the new step.
	var steps []StepInfo
	steps = append(steps, StepInfo{
		Name:                 stepName,
		StartTime:            startTime,
		DurationMilliseconds: endTime.Time.Sub(startTime.Time).Nanoseconds() / int64(time.Millisecond),
	})
	stages = append(stages, StageInfo{
		Name:                 stageName,
		StartTime:            startTime,
		DurationMilliseconds: endTime.Time.Sub(startTime.Time).Nanoseconds() / int64(time.Millisecond),
		Steps:                steps,
	})
	return stages
}

// AppendStageAndStepInfo appends the step info from one stages slice into another.
func AppendStageAndStepInfo(stages []StageInfo, stagesToMerge []StageInfo) []StageInfo {
	for _, stage := range stagesToMerge {
		for _, step := range stage.Steps {
			stages = RecordStageAndStepInfo(stages, stage.Name, step.Name, step.StartTime, metav1.NewTime(step.StartTime.Add(time.Duration(step.DurationMilliseconds)*time.Millisecond)))
		}
	}
	return stages
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package command

import "github.com/urfave/cli"

// MapEnvOptions : maps environment options from cli context
func MapEnvOptions(c *cli.Context, opts map[string]interface{}) map[string]interface{} {
	if opts == nil {
		opts = make(map[string]interface{})
	}

	syncInterval := c.String("sync_interval")

	if syncInterval != "" {
		opts["sync_interval"] = syncInterval
	}

	submissions := c.String("submissions")

	if submissions == "enable" {
		opts["submissions"] = true
	}

	if submissions == "disable" {
		opts["submissions"] = false
	}

	return opts
}
<commit_msg>fixing reset of sync interval value<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package command

import (
	"fmt"

	"github.com/urfave/cli"
)

// MapEnvOptions : maps environment options from cli context
func MapEnvOptions(c *cli.Context, opts map[string]interface{}) map[string]interface{} {
	if opts == nil {
		opts = make(map[string]interface{})
	}

	fmt.Println(c.IsSet("sync_interval"))

	if c.IsSet("sync_interval") {
		opts["sync_interval"] = c.String("sync_interval")

		if c.String("sync_interval") == "" {
			opts["sync_interval"] = nil
		}
	}

	submissions := c.String("submissions")

	if submissions == "enable" {
		opts["submissions"] = true
	}

	if submissions == "disable" {
		opts["submissions"] = false
	}

	return opts
}
<|endoftext|>


<commit_before>package command

import (
	"net/url"
	"path/filepath"

	"github.com/mitchellh/cli"
	homedir "github.com/mitchellh/go-homedir"
	"github.com/nerdalize/nerd/nerd/client/auth/v1"
	"github.com/nerdalize/nerd/nerd/conf"
	"github.com/nerdalize/nerd/nerd/oauth"
	"github.com/nerdalize/nerd/pkg/populator"
	"github.com/pkg/errors"
)

//ProjectSetOpts determine
type ProjectSetOpts struct {
	Config     string `long:"config-src" default:"env" default-mask:"" description:"type of configuration to use (from env, endpoint, or oidc)"`
	KubeConfig string `long:"kube-config" env:"KUBECONFIG" description:"file at which Nerd will look for Kubernetes credentials" default-mask:"~/.kube/conf"`
}

//ProjectSet command
type ProjectSet struct {
	*command
	opts *ProjectSetOpts
}

//ProjectSetFactory returns a factory method for the join command
func ProjectSetFactory() (cli.Command, error) {
	opts := &ProjectSetOpts{}
	comm, err := newCommand("nerd project set", "Set current working project.", "", opts)
	if err != nil {
		return nil, errors.Wrap(err, "failed to create command")
	}
	cmd := &ProjectSet{
		command: comm,
		opts:    opts,
	}
	cmd.runFunc = cmd.DoRun

	return cmd, nil
}

//DoRun is called by run and allows an error to be returned
func (cmd *ProjectSet) DoRun(args []string) (err error) {
	if len(args) < 1 {
		return errShowHelp("Not enough arguments, see below for usage.")
	}
	projectSlug := args[0]

	authbase, err := url.Parse(cmd.config.Auth.APIEndpoint)
	if err != nil {
		return errors.Wrapf(err, "auth endpoint '%v' is not a valid URL", cmd.config.Auth.APIEndpoint)
	}
	authOpsClient := v1auth.NewOpsClient(v1auth.OpsClientConfig{
		Base:   authbase,
		Logger: cmd.outputter.Logger,
	})
	client := v1auth.NewClient(v1auth.ClientConfig{
		Base:               authbase,
		Logger:             cmd.outputter.Logger,
		OAuthTokenProvider: oauth.NewConfigProvider(authOpsClient, cmd.config.Auth.ClientID, cmd.session),
	})

	// This part should be easier to do if we can get a project with its name instead of its id
	projects, err := client.ListProjects()
	if err != nil {
		return HandleError(err)
	}

	ok := false
	for _, project := range projects.Projects {
		if project.Slug == args[0] {
			ok = true
		}
	}

	if !ok {
		return HandleError(errors.New("Project not found, please check the project name. You can get a list of your projects by running `nerd project list`."))
	}

	if cmd.opts.KubeConfig == "" {
		hdir, err := homedir.Dir()
		if err != nil {
			return HandleError(err)
		}
		cmd.opts.KubeConfig = filepath.Join(hdir, ".kube", "config")
	}
	p, err := populator.New(cmd.opts.Config, cmd.opts.KubeConfig)
	if err != nil {
		return HandleError(err)
	}
	err = p.PopulateKubeConfig(args[0])
	if err != nil {
		return HandleError(err)
	}

	err = cmd.session.WriteProject(projectSlug, conf.DefaultAWSRegion)
	if err != nil {
		return HandleError(err)
	}

	return nil
}
<commit_msg>add feedback when project is set<commit_after>package command

import (
	"net/url"
	"path/filepath"

	"github.com/mitchellh/cli"
	homedir "github.com/mitchellh/go-homedir"
	"github.com/nerdalize/nerd/nerd/client/auth/v1"
	"github.com/nerdalize/nerd/nerd/conf"
	"github.com/nerdalize/nerd/nerd/oauth"
	"github.com/nerdalize/nerd/pkg/populator"
	"github.com/pkg/errors"
)

//ProjectSetOpts determine
type ProjectSetOpts struct {
	Config     string `long:"config-src" default:"env" default-mask:"" description:"type of configuration to use (from env, endpoint, or oidc)"`
	KubeConfig string `long:"kube-config" env:"KUBECONFIG" description:"file at which Nerd will look for Kubernetes credentials" default-mask:"~/.kube/conf"`
}

//ProjectSet command
type ProjectSet struct {
	*command
	opts *ProjectSetOpts
}

//ProjectSetFactory returns a factory method for the join command
func ProjectSetFactory() (cli.Command, error) {
	opts := &ProjectSetOpts{}
	comm, err := newCommand("nerd project set", "Set current working project.", "", opts)
	if err != nil {
		return nil, errors.Wrap(err, "failed to create command")
	}
	cmd := &ProjectSet{
		command: comm,
		opts:    opts,
	}
	cmd.runFunc = cmd.DoRun

	return cmd, nil
}

//DoRun is called by run and allows an error to be returned
func (cmd *ProjectSet) DoRun(args []string) (err error) {
	if len(args) < 1 {
		return errShowHelp("Not enough arguments, see below for usage.")
	}
	projectSlug := args[0]

	authbase, err := url.Parse(cmd.config.Auth.APIEndpoint)
	if err != nil {
		return errors.Wrapf(err, "auth endpoint '%v' is not a valid URL", cmd.config.Auth.APIEndpoint)
	}
	authOpsClient := v1auth.NewOpsClient(v1auth.OpsClientConfig{
		Base:   authbase,
		Logger: cmd.outputter.Logger,
	})
	client := v1auth.NewClient(v1auth.ClientConfig{
		Base:               authbase,
		Logger:             cmd.outputter.Logger,
		OAuthTokenProvider: oauth.NewConfigProvider(authOpsClient, cmd.config.Auth.ClientID, cmd.session),
	})

	// This part should be easier to do if we can get a project with its name instead of its id
	projects, err := client.ListProjects()
	if err != nil {
		return HandleError(err)
	}

	ok := false
	for _, project := range projects.Projects {
		if project.Slug == projectSlug {
			ok = true
		}
	}

	if !ok {
		return HandleError(errors.New("Project not found, please check the project name. You can get a list of your projects by running `nerd project list`."))
	}

	if cmd.opts.KubeConfig == "" {
		hdir, err := homedir.Dir()
		if err != nil {
			return HandleError(err)
		}
		cmd.opts.KubeConfig = filepath.Join(hdir, ".kube", "config")
	}
	p, err := populator.New(cmd.opts.Config, cmd.opts.KubeConfig)
	if err != nil {
		return HandleError(err)
	}
	err = p.PopulateKubeConfig(projectSlug)
	if err != nil {
		return HandleError(err)
	}

	err = cmd.session.WriteProject(projectSlug, conf.DefaultAWSRegion)
	if err != nil {
		return HandleError(err)
	}

	cmd.outputter.Logger.Printf("Project %s set successfully", projectSlug)
	return nil
}
<|endoftext|>


<commit_before>// +build linux

package nsinit

import (
	"fmt"
	"os"
	"runtime"
	"syscall"

	"github.com/dotcloud/docker/pkg/label"
	"github.com/dotcloud/docker/pkg/libcontainer"
	"github.com/dotcloud/docker/pkg/libcontainer/apparmor"
	"github.com/dotcloud/docker/pkg/libcontainer/capabilities"
	"github.com/dotcloud/docker/pkg/libcontainer/network"
	"github.com/dotcloud/docker/pkg/libcontainer/utils"
	"github.com/dotcloud/docker/pkg/system"
	"github.com/dotcloud/docker/pkg/user"
)

// Init is the init process that first runs inside a new namespace to setup mounts, users, networking,
// and other options required for the new container.
func (ns *linuxNs) Init(container *libcontainer.Container, uncleanRootfs, console string, syncPipe *SyncPipe, args []string) error {
	rootfs, err := utils.ResolveRootfs(uncleanRootfs)
	if err != nil {
		return err
	}

	// We always read this as it is a way to sync with the parent as well
	ns.logger.Printf("reading from sync pipe fd %d\n", syncPipe.child.Fd())
	context, err := syncPipe.ReadFromParent()
	if err != nil {
		syncPipe.Close()
		return err
	}
	ns.logger.Println("received context from parent")
	syncPipe.Close()

	if console != "" {
		ns.logger.Printf("setting up %s as console\n", console)
		slave, err := system.OpenTerminal(console, syscall.O_RDWR)
		if err != nil {
			return fmt.Errorf("open terminal %s", err)
		}
		if err := dupSlave(slave); err != nil {
			return fmt.Errorf("dup2 slave %s", err)
		}
	}
	if _, err := system.Setsid(); err != nil {
		return fmt.Errorf("setsid %s", err)
	}
	if console != "" {
		if err := system.Setctty(); err != nil {
			return fmt.Errorf("setctty %s", err)
		}
	}
	// this is our best effort to let the process know that the parent has died and that it
	// should it should act on it how it sees fit
	if err := system.ParentDeathSignal(uintptr(syscall.SIGTERM)); err != nil {
		return fmt.Errorf("parent death signal %s", err)
	}
	if err := setupNetwork(container, context); err != nil {
		return fmt.Errorf("setup networking %s", err)
	}
	ns.logger.Println("setup mount namespace")
	if err := setupNewMountNamespace(rootfs, container.Mounts, console, container.ReadonlyFs, container.NoPivotRoot, container.Context["mount_label"]); err != nil {
		return fmt.Errorf("setup mount namespace %s", err)
	}
	if err := system.Sethostname(container.Hostname); err != nil {
		return fmt.Errorf("sethostname %s", err)
	}
	if err := finalizeNamespace(container); err != nil {
		return fmt.Errorf("finalize namespace %s", err)
	}

	if profile := container.Context["apparmor_profile"]; profile != "" {
		ns.logger.Printf("setting apparmor profile %s\n", profile)
		if err := apparmor.ApplyProfile(os.Getpid(), profile); err != nil {
			return err
		}
	}
	runtime.LockOSThread()
	if err := label.SetProcessLabel(container.Context["process_label"]); err != nil {
		return fmt.Errorf("SetProcessLabel label %s", err)
	}
	ns.logger.Printf("execing %s\n", args[0])
	return system.Execv(args[0], args[0:], container.Env)
}

func setupUser(container *libcontainer.Container) error {
	switch container.User {
	case "root", "":
		if err := system.Setgroups(nil); err != nil {
			return err
		}
		if err := system.Setresgid(0, 0, 0); err != nil {
			return err
		}
		if err := system.Setresuid(0, 0, 0); err != nil {
			return err
		}
	default:
		uid, gid, suppGids, err := user.GetUserGroupSupplementary(container.User, syscall.Getuid(), syscall.Getgid())
		if err != nil {
			return err
		}
		if err := system.Setgroups(suppGids); err != nil {
			return err
		}
		if err := system.Setgid(gid); err != nil {
			return err
		}
		if err := system.Setuid(uid); err != nil {
			return err
		}
	}
	return nil
}

// dupSlave dup2 the pty slave's fd into stdout and stdin and ensures that
// the slave's fd is 0, or stdin
func dupSlave(slave *os.File) error {
	if err := system.Dup2(slave.Fd(), 0); err != nil {
		return err
	}
	if err := system.Dup2(slave.Fd(), 1); err != nil {
		return err
	}
	if err := system.Dup2(slave.Fd(), 2); err != nil {
		return err
	}
	return nil
}

// setupVethNetwork uses the Network config if it is not nil to initialize
// the new veth interface inside the container for use by changing the name to eth0
// setting the MTU and IP address along with the default gateway
func setupNetwork(container *libcontainer.Container, context libcontainer.Context) error {
	for _, config := range container.Networks {
		strategy, err := network.GetStrategy(config.Type)
		if err != nil {
			return err
		}

		err1 := strategy.Initialize(config, context)
		if err1 != nil {
			return err1
		}
	}
	return nil
}

// finalizeNamespace drops the caps and sets the correct user
// and working dir before execing the command inside the namespace
func finalizeNamespace(container *libcontainer.Container) error {
	if err := capabilities.DropCapabilities(container); err != nil {
		return fmt.Errorf("drop capabilities %s", err)
	}
	if err := setupUser(container); err != nil {
		return fmt.Errorf("setup user %s", err)
	}
	if container.WorkingDir != "" {
		if err := system.Chdir(container.WorkingDir); err != nil {
			return fmt.Errorf("chdir to %s %s", container.WorkingDir, err)
		}
	}
	return nil
}
<commit_msg>Don't send prctl to be consistent with other drivers Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)<commit_after>// +build linux

package nsinit

import (
	"fmt"
	"os"
	"runtime"
	"syscall"

	"github.com/dotcloud/docker/pkg/label"
	"github.com/dotcloud/docker/pkg/libcontainer"
	"github.com/dotcloud/docker/pkg/libcontainer/apparmor"
	"github.com/dotcloud/docker/pkg/libcontainer/capabilities"
	"github.com/dotcloud/docker/pkg/libcontainer/network"
	"github.com/dotcloud/docker/pkg/libcontainer/utils"
	"github.com/dotcloud/docker/pkg/system"
	"github.com/dotcloud/docker/pkg/user"
)

// Init is the init process that first runs inside a new namespace to setup mounts, users, networking,
// and other options required for the new container.
func (ns *linuxNs) Init(container *libcontainer.Container, uncleanRootfs, console string, syncPipe *SyncPipe, args []string) error {
	rootfs, err := utils.ResolveRootfs(uncleanRootfs)
	if err != nil {
		return err
	}

	// We always read this as it is a way to sync with the parent as well
	ns.logger.Printf("reading from sync pipe fd %d\n", syncPipe.child.Fd())
	context, err := syncPipe.ReadFromParent()
	if err != nil {
		syncPipe.Close()
		return err
	}
	ns.logger.Println("received context from parent")
	syncPipe.Close()

	if console != "" {
		ns.logger.Printf("setting up %s as console\n", console)
		slave, err := system.OpenTerminal(console, syscall.O_RDWR)
		if err != nil {
			return fmt.Errorf("open terminal %s", err)
		}
		if err := dupSlave(slave); err != nil {
			return fmt.Errorf("dup2 slave %s", err)
		}
	}
	if _, err := system.Setsid(); err != nil {
		return fmt.Errorf("setsid %s", err)
	}
	if console != "" {
		if err := system.Setctty(); err != nil {
			return fmt.Errorf("setctty %s", err)
		}
	}
	if err := setupNetwork(container, context); err != nil {
		return fmt.Errorf("setup networking %s", err)
	}
	ns.logger.Println("setup mount namespace")
	if err := setupNewMountNamespace(rootfs, container.Mounts, console, container.ReadonlyFs, container.NoPivotRoot, container.Context["mount_label"]); err != nil {
		return fmt.Errorf("setup mount namespace %s", err)
	}
	if err := system.Sethostname(container.Hostname); err != nil {
		return fmt.Errorf("sethostname %s", err)
	}
	if err := finalizeNamespace(container); err != nil {
		return fmt.Errorf("finalize namespace %s", err)
	}

	if profile := container.Context["apparmor_profile"]; profile != "" {
		ns.logger.Printf("setting apparmor profile %s\n", profile)
		if err := apparmor.ApplyProfile(os.Getpid(), profile); err != nil {
			return err
		}
	}
	runtime.LockOSThread()
	if err := label.SetProcessLabel(container.Context["process_label"]); err != nil {
		return fmt.Errorf("SetProcessLabel label %s", err)
	}
	ns.logger.Printf("execing %s\n", args[0])
	return system.Execv(args[0], args[0:], container.Env)
}

func setupUser(container *libcontainer.Container) error {
	switch container.User {
	case "root", "":
		if err := system.Setgroups(nil); err != nil {
			return err
		}
		if err := system.Setresgid(0, 0, 0); err != nil {
			return err
		}
		if err := system.Setresuid(0, 0, 0); err != nil {
			return err
		}
	default:
		uid, gid, suppGids, err := user.GetUserGroupSupplementary(container.User, syscall.Getuid(), syscall.Getgid())
		if err != nil {
			return err
		}
		if err := system.Setgroups(suppGids); err != nil {
			return err
		}
		if err := system.Setgid(gid); err != nil {
			return err
		}
		if err := system.Setuid(uid); err != nil {
			return err
		}
	}
	return nil
}

// dupSlave dup2 the pty slave's fd into stdout and stdin and ensures that
// the slave's fd is 0, or stdin
func dupSlave(slave *os.File) error {
	if err := system.Dup2(slave.Fd(), 0); err != nil {
		return err
	}
	if err := system.Dup2(slave.Fd(), 1); err != nil {
		return err
	}
	if err := system.Dup2(slave.Fd(), 2); err != nil {
		return err
	}
	return nil
}

// setupVethNetwork uses the Network config if it is not nil to initialize
// the new veth interface inside the container for use by changing the name to eth0
// setting the MTU and IP address along with the default gateway
func setupNetwork(container *libcontainer.Container, context libcontainer.Context) error {
	for _, config := range container.Networks {
		strategy, err := network.GetStrategy(config.Type)
		if err != nil {
			return err
		}

		err1 := strategy.Initialize(config, context)
		if err1 != nil {
			return err1
		}
	}
	return nil
}

// finalizeNamespace drops the caps and sets the correct user
// and working dir before execing the command inside the namespace
func finalizeNamespace(container *libcontainer.Container) error {
	if err := capabilities.DropCapabilities(container); err != nil {
		return fmt.Errorf("drop capabilities %s", err)
	}
	if err := setupUser(container); err != nil {
		return fmt.Errorf("setup user %s", err)
	}
	if container.WorkingDir != "" {
		if err := system.Chdir(container.WorkingDir); err != nil {
			return fmt.Errorf("chdir to %s %s", container.WorkingDir, err)
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package modules

import (
	"fmt"
	"time"

	"github.com/pajlada/pajbot2/pkg"
	"github.com/pajlada/pajbot2/pkg/filters"
	"github.com/pajlada/pajbot2/pkg/utils"
)

type pajbot1BanphraseFilter struct {
	botChannel pkg.BotChannel

	server *server

	banphrases []pkg.Banphrase
}

func newPajbot1BanphraseFilter() pkg.Module {
	return &pajbot1BanphraseFilter{
		server: &_server,
	}
}

var pajbot1BanphraseSpec = moduleSpec{
	id:    "pajbot1_banphrase",
	name:  "pajbot1 banphrase",
	maker: newPajbot1BanphraseFilter,

	enabledByDefault: true,
}

func (m *pajbot1BanphraseFilter) addCustomBanphrase(phrase string) {
	m.banphrases = append(m.banphrases, &filters.Pajbot1Banphrase{
		ID:            -1,
		Name:          "Custom",
		Phrase:        phrase,
		Length:        600,
		Operator:      filters.OperatorContains,
		Permanent:     false,
		Warning:       false,
		Notify:        false,
		CaseSensitive: false,
		Enabled:       true,
		SubImmunity:   false,
		RemoveAccents: true,
	})
}

func (m *pajbot1BanphraseFilter) loadPajbot1Banphrases() error {
	const queryF = `SELECT * FROM tb_banphrase`

	session := m.server.oldSession

	rows, err := session.Query(queryF)
	if err != nil {
		return err
	}
	defer rows.Close()

	for rows.Next() {
		var bp filters.Pajbot1Banphrase
		err = bp.LoadScan(rows)
		if err != nil {
			return err
		}

		if bp.Enabled {
			m.banphrases = append(m.banphrases, &bp)
		}
	}
	return nil
}

func (m *pajbot1BanphraseFilter) Initialize(botChannel pkg.BotChannel, settings []byte) error {
	m.botChannel = botChannel

	// hard-coded banphrases
	m.addCustomBanphrase("n!66ger")

	m.addCustomBanphrase("negro")
	m.addCustomBanphrase("negr0")
	m.addCustomBanphrase("n3gro")
	m.addCustomBanphrase("n3gr0")

	m.addCustomBanphrase("nij1gger")

	m.addCustomBanphrase("nijgger")
	m.addCustomBanphrase("nijggger")
	m.addCustomBanphrase("nijgggger")
	m.addCustomBanphrase("nijggggger")
	m.addCustomBanphrase("nijg6er")
	m.addCustomBanphrase("nij6ger")
	m.addCustomBanphrase("nij66er")
	m.addCustomBanphrase("nijk6er")
	m.addCustomBanphrase("nijkger")
	m.addCustomBanphrase("nij6ker")
	m.addCustomBanphrase("nijgker")

	m.addCustomBanphrase("n1jgger")
	m.addCustomBanphrase("n1jg6er")
	m.addCustomBanphrase("n1j6ger")
	m.addCustomBanphrase("n1j66er")
	m.addCustomBanphrase("n1jk6er")
	m.addCustomBanphrase("n1jkger")
	m.addCustomBanphrase("n1j6ker")
	m.addCustomBanphrase("n1jgker")

	m.addCustomBanphrase("n!jgger")
	m.addCustomBanphrase("n!jg6er")
	m.addCustomBanphrase("n!j6ger")
	m.addCustomBanphrase("n!j66er")
	m.addCustomBanphrase("n!jk6er")
	m.addCustomBanphrase("n!jkger")
	m.addCustomBanphrase("n!j6ker")
	m.addCustomBanphrase("n!jgker")

	m.addCustomBanphrase("nij1gger")
	m.addCustomBanphrase("nij1g6er")
	m.addCustomBanphrase("nij16ger")
	m.addCustomBanphrase("nij166er")

	m.addCustomBanphrase("nij1k6er")
	m.addCustomBanphrase("nij1kger")
	m.addCustomBanphrase("nij16ker")
	m.addCustomBanphrase("nij1gker")

	m.addCustomBanphrase("n1jk6er")
	m.addCustomBanphrase("n1jkger")
	m.addCustomBanphrase("n1j6ker")
	m.addCustomBanphrase("n1jgker")

	m.addCustomBanphrase("nij1gger")

	m.addCustomBanphrase("ni@@er")
	m.addCustomBanphrase("nigger")
	m.addCustomBanphrase("niggger")
	m.addCustomBanphrase("nigggger")
	m.addCustomBanphrase("niggggger")
	m.addCustomBanphrase("nig6er")
	m.addCustomBanphrase("ni6ger")
	m.addCustomBanphrase("ni6grs")
	m.addCustomBanphrase("ni66er")
	m.addCustomBanphrase("nik6er")
	m.addCustomBanphrase("nikger")
	m.addCustomBanphrase("ni6ker")
	m.addCustomBanphrase("nigker")

	m.addCustomBanphrase("nl@@er")
	m.addCustomBanphrase("nlger")
	m.addCustomBanphrase("nlgger")
	m.addCustomBanphrase("nlggger")
	m.addCustomBanphrase("nlgggger")
	m.addCustomBanphrase("nlggggger")
	m.addCustomBanphrase("nlg6er")
	m.addCustomBanphrase("nl6ger")
	m.addCustomBanphrase("nl6grs")
	m.addCustomBanphrase("nl66er")
	m.addCustomBanphrase("nlk6er")
	m.addCustomBanphrase("nlker")
	m.addCustomBanphrase("nlkger")
	m.addCustomBanphrase("nl6ker")
	m.addCustomBanphrase("nlgker")

	m.addCustomBanphrase("n1gger")
	m.addCustomBanphrase("n1g6er")
	m.addCustomBanphrase("n16ger")
	m.addCustomBanphrase("n166er")
	m.addCustomBanphrase("n1k6er")
	m.addCustomBanphrase("n1kger")
	m.addCustomBanphrase("n16ker")
	m.addCustomBanphrase("n1gker")

	m.addCustomBanphrase("n!gger")
	m.addCustomBanphrase("n!g6er")
	m.addCustomBanphrase("n!6ger")
	m.addCustomBanphrase("n!66er")
	m.addCustomBanphrase("n!k6er")
	m.addCustomBanphrase("n!kger")
	m.addCustomBanphrase("n!6ker")
	m.addCustomBanphrase("n!gker")

	m.addCustomBanphrase("ni1gger")
	m.addCustomBanphrase("ni1g6er")
	m.addCustomBanphrase("ni16ger")
	m.addCustomBanphrase("ni166er")

	m.addCustomBanphrase("ni1k6er")
	m.addCustomBanphrase("ni1kger")
	m.addCustomBanphrase("ni16ker")
	m.addCustomBanphrase("ni1gker")

	m.addCustomBanphrase("n1k6er")
	m.addCustomBanphrase("n1kger")
	m.addCustomBanphrase("n16ker")
	m.addCustomBanphrase("n1gker")

	m.addCustomBanphrase("nek6er")
	m.addCustomBanphrase("nekger")
	m.addCustomBanphrase("ne6ker")
	m.addCustomBanphrase("negker")
	m.addCustomBanphrase("neg6er")
	m.addCustomBanphrase("negger")
	m.addCustomBanphrase("ne6ger")
	m.addCustomBanphrase("negger")

	m.addCustomBanphrase("ni1gg3r")

	m.addCustomBanphrase("nigg3r")
	m.addCustomBanphrase("nig63r")
	m.addCustomBanphrase("ni6g3r")
	m.addCustomBanphrase("ni663r")
	m.addCustomBanphrase("nik63r")
	m.addCustomBanphrase("nikg3r")
	m.addCustomBanphrase("ni6k3r")
	m.addCustomBanphrase("nigk3r")

	m.addCustomBanphrase("n1gg3r")
	m.addCustomBanphrase("n1g63r")
	m.addCustomBanphrase("n16g3r")
	m.addCustomBanphrase("n1663r")
	m.addCustomBanphrase("n1k63r")
	m.addCustomBanphrase("n1kg3r")
	m.addCustomBanphrase("n16k3r")
	m.addCustomBanphrase("n1gk3r")

	m.addCustomBanphrase("n!gg3r")
	m.addCustomBanphrase("n!g63r")
	m.addCustomBanphrase("n!6g3r")
	m.addCustomBanphrase("n!663r")
	m.addCustomBanphrase("n!k63r")
	m.addCustomBanphrase("n!kg3r")
	m.addCustomBanphrase("n!6k3r")
	m.addCustomBanphrase("n!gk3r")

	m.addCustomBanphrase("ni1gg3r")
	m.addCustomBanphrase("ni1g63r")
	m.addCustomBanphrase("ni16g3r")
	m.addCustomBanphrase("ni1663r")

	m.addCustomBanphrase("ni1k63r")
	m.addCustomBanphrase("ni1kg3r")
	m.addCustomBanphrase("ni16k3r")
	m.addCustomBanphrase("ni1gk3r")

	m.addCustomBanphrase("n1k63r")
	m.addCustomBanphrase("n1kg3r")
	m.addCustomBanphrase("n16k3r")
	m.addCustomBanphrase("n1gk3r")

	m.addCustomBanphrase("n3k63r")
	m.addCustomBanphrase("n3kg3r")
	m.addCustomBanphrase("n36k3r")
	m.addCustomBanphrase("n3gk3r")
	m.addCustomBanphrase("n3g63r")
	m.addCustomBanphrase("n3gg3r")
	m.addCustomBanphrase("n36g3r")
	m.addCustomBanphrase("n3gg3r")

	m.addCustomBanphrase("g63r")

	m.banphrases = append(m.banphrases, &filters.Pajbot1Banphrase{
		ID:            -1,
		Name:          "Custom",
		Phrase:        "b00ger",
		Length:        1,
		Operator:      filters.OperatorContains,
		Permanent:     false,
		Warning:       false,
		Notify:        false,
		CaseSensitive: false,
		Enabled:       true,
		SubImmunity:   false,
		RemoveAccents: true,
	})
	err := m.loadPajbot1Banphrases()
	if err != nil {
		return err
	}

	return nil
}

func (m *pajbot1BanphraseFilter) Disable() error {
	return nil
}

func (m *pajbot1BanphraseFilter) Spec() pkg.ModuleSpec {
	return &pajbot1BanphraseSpec
}

func (m *pajbot1BanphraseFilter) BotChannel() pkg.BotChannel {
	return m.botChannel
}

type TimeoutData struct {
	FullMessage string
	Banphrase   pkg.Banphrase
	Username    string
	Channel     string
	Timestamp   time.Time
}

func (m *pajbot1BanphraseFilter) OnWhisper(bot pkg.Sender, source pkg.User, message pkg.Message) error {
	return nil
}

func (m *pajbot1BanphraseFilter) check(bot pkg.Sender, source pkg.Channel, text string, action pkg.Action) error {
	originalVariations, lowercaseVariations, err := utils.MakeVariations(text, true)
	if err != nil {
		return err
	}

	for _, bp := range m.banphrases {
		var variations *[]string

		if !bp.IsCaseSensitive() {
			variations = &lowercaseVariations
		} else {
			variations = &originalVariations
		}

		for _, variation := range *variations {
			if bp.Triggers(variation) {
				// fmt.Printf("Banphrase triggered: %#v\n", bp)
				/*
					if bp.IsAdvanced() && source.GetChannel() == "forsen" {
						lol := TimeoutData{
							FullMessage: message.GetText(),
							Banphrase:   bp,
							Username:    user.GetName(),
							Channel:     source.GetChannel(),
							Timestamp:   time.Now().UTC(),
						}
						c := m.server.redis.Get()
						bytes, _ := json.Marshal(&lol)
						c.Do("LPUSH", "pajbot2:timeouts", bytes)
						c.Close()
					}
				*/

				if source.GetChannel() == "krakenbul" || bp.GetID() == -1 {
					reason := fmt.Sprintf("Matched banphrase with name '%s' and id '%d'", bp.GetName(), bp.GetID())
					action.Set(pkg.Timeout{bp.GetLength(), reason})
					action.SetNotifyModerator(bot.MakeUser("pajlada"))
					// fmt.Printf("Banphrase triggered: %#v for user %s", bp, user.GetName())
					return nil
				}
			}

			if !bp.IsAdvanced() {
				if bp.GetID() == -1 {
					fmt.Println("wtf")
				}
				break
			}
		}
	}

	return nil
}

func (m *pajbot1BanphraseFilter) OnMessage(bot pkg.Sender, source pkg.Channel, user pkg.User, message pkg.Message, action pkg.Action) error {
	if user.IsModerator() || user.IsBroadcaster(source) {
		return nil
	}

	if user.GetName() == "supibot" {
		return nil
	}

	m.check(bot, source, message.GetText(), action)
	m.check(bot, source, user.GetName(), action)

	return nil
}
<commit_msg>remove test banphrase<commit_after>package modules

import (
	"fmt"
	"time"

	"github.com/pajlada/pajbot2/pkg"
	"github.com/pajlada/pajbot2/pkg/filters"
	"github.com/pajlada/pajbot2/pkg/utils"
)

type pajbot1BanphraseFilter struct {
	botChannel pkg.BotChannel

	server *server

	banphrases []pkg.Banphrase
}

func newPajbot1BanphraseFilter() pkg.Module {
	return &pajbot1BanphraseFilter{
		server: &_server,
	}
}

var pajbot1BanphraseSpec = moduleSpec{
	id:    "pajbot1_banphrase",
	name:  "pajbot1 banphrase",
	maker: newPajbot1BanphraseFilter,

	enabledByDefault: true,
}

func (m *pajbot1BanphraseFilter) addCustomBanphrase(phrase string) {
	m.banphrases = append(m.banphrases, &filters.Pajbot1Banphrase{
		ID:            -1,
		Name:          "Custom",
		Phrase:        phrase,
		Length:        600,
		Operator:      filters.OperatorContains,
		Permanent:     false,
		Warning:       false,
		Notify:        false,
		CaseSensitive: false,
		Enabled:       true,
		SubImmunity:   false,
		RemoveAccents: true,
	})
}

func (m *pajbot1BanphraseFilter) loadPajbot1Banphrases() error {
	const queryF = `SELECT * FROM tb_banphrase`

	session := m.server.oldSession

	rows, err := session.Query(queryF)
	if err != nil {
		return err
	}
	defer rows.Close()

	for rows.Next() {
		var bp filters.Pajbot1Banphrase
		err = bp.LoadScan(rows)
		if err != nil {
			return err
		}

		if bp.Enabled {
			m.banphrases = append(m.banphrases, &bp)
		}
	}
	return nil
}

func (m *pajbot1BanphraseFilter) Initialize(botChannel pkg.BotChannel, settings []byte) error {
	m.botChannel = botChannel

	// hard-coded banphrases
	m.addCustomBanphrase("n!66ger")

	m.addCustomBanphrase("negro")
	m.addCustomBanphrase("negr0")
	m.addCustomBanphrase("n3gro")
	m.addCustomBanphrase("n3gr0")

	m.addCustomBanphrase("nij1gger")

	m.addCustomBanphrase("nijgger")
	m.addCustomBanphrase("nijggger")
	m.addCustomBanphrase("nijgggger")
	m.addCustomBanphrase("nijggggger")
	m.addCustomBanphrase("nijg6er")
	m.addCustomBanphrase("nij6ger")
	m.addCustomBanphrase("nij66er")
	m.addCustomBanphrase("nijk6er")
	m.addCustomBanphrase("nijkger")
	m.addCustomBanphrase("nij6ker")
	m.addCustomBanphrase("nijgker")

	m.addCustomBanphrase("n1jgger")
	m.addCustomBanphrase("n1jg6er")
	m.addCustomBanphrase("n1j6ger")
	m.addCustomBanphrase("n1j66er")
	m.addCustomBanphrase("n1jk6er")
	m.addCustomBanphrase("n1jkger")
	m.addCustomBanphrase("n1j6ker")
	m.addCustomBanphrase("n1jgker")

	m.addCustomBanphrase("n!jgger")
	m.addCustomBanphrase("n!jg6er")
	m.addCustomBanphrase("n!j6ger")
	m.addCustomBanphrase("n!j66er")
	m.addCustomBanphrase("n!jk6er")
	m.addCustomBanphrase("n!jkger")
	m.addCustomBanphrase("n!j6ker")
	m.addCustomBanphrase("n!jgker")

	m.addCustomBanphrase("nij1gger")
	m.addCustomBanphrase("nij1g6er")
	m.addCustomBanphrase("nij16ger")
	m.addCustomBanphrase("nij166er")

	m.addCustomBanphrase("nij1k6er")
	m.addCustomBanphrase("nij1kger")
	m.addCustomBanphrase("nij16ker")
	m.addCustomBanphrase("nij1gker")

	m.addCustomBanphrase("n1jk6er")
	m.addCustomBanphrase("n1jkger")
	m.addCustomBanphrase("n1j6ker")
	m.addCustomBanphrase("n1jgker")

	m.addCustomBanphrase("nij1gger")

	m.addCustomBanphrase("ni@@er")
	m.addCustomBanphrase("nigger")
	m.addCustomBanphrase("niggger")
	m.addCustomBanphrase("nigggger")
	m.addCustomBanphrase("niggggger")
	m.addCustomBanphrase("nig6er")
	m.addCustomBanphrase("ni6ger")
	m.addCustomBanphrase("ni6grs")
	m.addCustomBanphrase("ni66er")
	m.addCustomBanphrase("nik6er")
	m.addCustomBanphrase("nikger")
	m.addCustomBanphrase("ni6ker")
	m.addCustomBanphrase("nigker")

	m.addCustomBanphrase("nl@@er")
	m.addCustomBanphrase("nlger")
	m.addCustomBanphrase("nlgger")
	m.addCustomBanphrase("nlggger")
	m.addCustomBanphrase("nlgggger")
	m.addCustomBanphrase("nlggggger")
	m.addCustomBanphrase("nlg6er")
	m.addCustomBanphrase("nl6ger")
	m.addCustomBanphrase("nl6grs")
	m.addCustomBanphrase("nl66er")
	m.addCustomBanphrase("nlk6er")
	m.addCustomBanphrase("nlker")
	m.addCustomBanphrase("nlkger")
	m.addCustomBanphrase("nl6ker")
	m.addCustomBanphrase("nlgker")

	m.addCustomBanphrase("n1gger")
	m.addCustomBanphrase("n1g6er")
	m.addCustomBanphrase("n16ger")
	m.addCustomBanphrase("n166er")
	m.addCustomBanphrase("n1k6er")
	m.addCustomBanphrase("n1kger")
	m.addCustomBanphrase("n16ker")
	m.addCustomBanphrase("n1gker")

	m.addCustomBanphrase("n!gger")
	m.addCustomBanphrase("n!g6er")
	m.addCustomBanphrase("n!6ger")
	m.addCustomBanphrase("n!66er")
	m.addCustomBanphrase("n!k6er")
	m.addCustomBanphrase("n!kger")
	m.addCustomBanphrase("n!6ker")
	m.addCustomBanphrase("n!gker")

	m.addCustomBanphrase("ni1gger")
	m.addCustomBanphrase("ni1g6er")
	m.addCustomBanphrase("ni16ger")
	m.addCustomBanphrase("ni166er")

	m.addCustomBanphrase("ni1k6er")
	m.addCustomBanphrase("ni1kger")
	m.addCustomBanphrase("ni16ker")
	m.addCustomBanphrase("ni1gker")

	m.addCustomBanphrase("n1k6er")
	m.addCustomBanphrase("n1kger")
	m.addCustomBanphrase("n16ker")
	m.addCustomBanphrase("n1gker")

	m.addCustomBanphrase("nek6er")
	m.addCustomBanphrase("nekger")
	m.addCustomBanphrase("ne6ker")
	m.addCustomBanphrase("negker")
	m.addCustomBanphrase("neg6er")
	m.addCustomBanphrase("negger")
	m.addCustomBanphrase("ne6ger")
	m.addCustomBanphrase("negger")

	m.addCustomBanphrase("ni1gg3r")

	m.addCustomBanphrase("nigg3r")
	m.addCustomBanphrase("nig63r")
	m.addCustomBanphrase("ni6g3r")
	m.addCustomBanphrase("ni663r")
	m.addCustomBanphrase("nik63r")
	m.addCustomBanphrase("nikg3r")
	m.addCustomBanphrase("ni6k3r")
	m.addCustomBanphrase("nigk3r")

	m.addCustomBanphrase("n1gg3r")
	m.addCustomBanphrase("n1g63r")
	m.addCustomBanphrase("n16g3r")
	m.addCustomBanphrase("n1663r")
	m.addCustomBanphrase("n1k63r")
	m.addCustomBanphrase("n1kg3r")
	m.addCustomBanphrase("n16k3r")
	m.addCustomBanphrase("n1gk3r")

	m.addCustomBanphrase("n!gg3r")
	m.addCustomBanphrase("n!g63r")
	m.addCustomBanphrase("n!6g3r")
	m.addCustomBanphrase("n!663r")
	m.addCustomBanphrase("n!k63r")
	m.addCustomBanphrase("n!kg3r")
	m.addCustomBanphrase("n!6k3r")
	m.addCustomBanphrase("n!gk3r")

	m.addCustomBanphrase("ni1gg3r")
	m.addCustomBanphrase("ni1g63r")
	m.addCustomBanphrase("ni16g3r")
	m.addCustomBanphrase("ni1663r")

	m.addCustomBanphrase("ni1k63r")
	m.addCustomBanphrase("ni1kg3r")
	m.addCustomBanphrase("ni16k3r")
	m.addCustomBanphrase("ni1gk3r")

	m.addCustomBanphrase("n1k63r")
	m.addCustomBanphrase("n1kg3r")
	m.addCustomBanphrase("n16k3r")
	m.addCustomBanphrase("n1gk3r")

	m.addCustomBanphrase("n3k63r")
	m.addCustomBanphrase("n3kg3r")
	m.addCustomBanphrase("n36k3r")
	m.addCustomBanphrase("n3gk3r")
	m.addCustomBanphrase("n3g63r")
	m.addCustomBanphrase("n3gg3r")
	m.addCustomBanphrase("n36g3r")
	m.addCustomBanphrase("n3gg3r")

	m.addCustomBanphrase("g63r")

	err := m.loadPajbot1Banphrases()
	if err != nil {
		return err
	}

	return nil
}

func (m *pajbot1BanphraseFilter) Disable() error {
	return nil
}

func (m *pajbot1BanphraseFilter) Spec() pkg.ModuleSpec {
	return &pajbot1BanphraseSpec
}

func (m *pajbot1BanphraseFilter) BotChannel() pkg.BotChannel {
	return m.botChannel
}

type TimeoutData struct {
	FullMessage string
	Banphrase   pkg.Banphrase
	Username    string
	Channel     string
	Timestamp   time.Time
}

func (m *pajbot1BanphraseFilter) OnWhisper(bot pkg.Sender, source pkg.User, message pkg.Message) error {
	return nil
}

func (m *pajbot1BanphraseFilter) check(bot pkg.Sender, source pkg.Channel, text string, action pkg.Action) error {
	originalVariations, lowercaseVariations, err := utils.MakeVariations(text, true)
	if err != nil {
		return err
	}

	for _, bp := range m.banphrases {
		var variations *[]string

		if !bp.IsCaseSensitive() {
			variations = &lowercaseVariations
		} else {
			variations = &originalVariations
		}

		for _, variation := range *variations {
			if bp.Triggers(variation) {
				// fmt.Printf("Banphrase triggered: %#v\n", bp)
				/*
					if bp.IsAdvanced() && source.GetChannel() == "forsen" {
						lol := TimeoutData{
							FullMessage: message.GetText(),
							Banphrase:   bp,
							Username:    user.GetName(),
							Channel:     source.GetChannel(),
							Timestamp:   time.Now().UTC(),
						}
						c := m.server.redis.Get()
						bytes, _ := json.Marshal(&lol)
						c.Do("LPUSH", "pajbot2:timeouts", bytes)
						c.Close()
					}
				*/

				if source.GetChannel() == "krakenbul" || bp.GetID() == -1 {
					reason := fmt.Sprintf("Matched banphrase with name '%s' and id '%d'", bp.GetName(), bp.GetID())
					action.Set(pkg.Timeout{bp.GetLength(), reason})
					action.SetNotifyModerator(bot.MakeUser("pajlada"))
					// fmt.Printf("Banphrase triggered: %#v for user %s", bp, user.GetName())
					return nil
				}
			}

			if !bp.IsAdvanced() {
				if bp.GetID() == -1 {
					fmt.Println("wtf")
				}
				break
			}
		}
	}

	return nil
}

func (m *pajbot1BanphraseFilter) OnMessage(bot pkg.Sender, source pkg.Channel, user pkg.User, message pkg.Message, action pkg.Action) error {
	if user.IsModerator() || user.IsBroadcaster(source) {
		return nil
	}

	if user.GetName() == "supibot" {
		return nil
	}

	m.check(bot, source, message.GetText(), action)
	m.check(bot, source, user.GetName(), action)

	return nil
}
<|endoftext|>


<commit_before>package modules

import (
	"fmt"
	"time"

	"github.com/pajbot/pajbot2/pkg"
	"github.com/pajbot/pajbot2/pkg/filters"
	"github.com/pajbot/pajbot2/pkg/twitchactions"
	"github.com/pajbot/utils"
)

func init() {
	Register("pajbot1_banphrase", func() pkg.ModuleSpec {
		return &moduleSpec{
			id:   "pajbot1_banphrase",
			name: "pajbot1 banphrase",
			maker: func(b base) pkg.Module {
				m := newPajbot1BanphraseFilter(b)
				m.Initialize()
				return m
			},

			moduleType: pkg.ModuleTypeFilter,

			enabledByDefault: true,
		}
	})
}

type pajbot1BanphraseFilter struct {
	base

	banphrases []pkg.Banphrase
}

func newPajbot1BanphraseFilter(b base) *pajbot1BanphraseFilter {
	return &pajbot1BanphraseFilter{
		base: b,
	}
}

func (m *pajbot1BanphraseFilter) addCustomBanphrase(phrase string) {
	m.banphrases = append(m.banphrases, &filters.Pajbot1Banphrase{
		ID:            -1,
		Name:          "Custom",
		Phrase:        phrase,
		Length:        600,
		Operator:      filters.OperatorContains,
		Permanent:     false,
		Warning:       false,
		Notify:        false,
		CaseSensitive: false,
		Enabled:       true,
		SubImmunity:   false,
		RemoveAccents: true,
	})
}

func (m *pajbot1BanphraseFilter) loadPajbot1Banphrases() error {
	const queryF = `SELECT * FROM tb_banphrase`

	session := m.server.oldSession

	rows, err := session.Query(queryF)
	if err != nil {
		return err
	}
	defer rows.Close()

	for rows.Next() {
		var bp filters.Pajbot1Banphrase
		err = bp.LoadScan(rows)
		if err != nil {
			return err
		}

		if bp.Enabled {
			m.banphrases = append(m.banphrases, &bp)
		}
	}
	return nil
}

func (m *pajbot1BanphraseFilter) Initialize() {
	// hard-coded banphrases
	m.addCustomBanphrase("n!66ger")

	m.addCustomBanphrase("negro")
	m.addCustomBanphrase("negr0")
	m.addCustomBanphrase("n3gro")
	m.addCustomBanphrase("n3gr0")

	m.addCustomBanphrase("nij1gger")

	m.addCustomBanphrase("nijgger")
	m.addCustomBanphrase("nijggger")
	m.addCustomBanphrase("nijgggger")
	m.addCustomBanphrase("nijggggger")
	m.addCustomBanphrase("nijg6er")
	m.addCustomBanphrase("nij6ger")
	m.addCustomBanphrase("nij66er")
	m.addCustomBanphrase("nijk6er")
	m.addCustomBanphrase("nijkger")
	m.addCustomBanphrase("nij6ker")
	m.addCustomBanphrase("nijgker")

	m.addCustomBanphrase("n1jgger")
	m.addCustomBanphrase("n1jg6er")
	m.addCustomBanphrase("n1j6ger")
	m.addCustomBanphrase("n1j66er")
	m.addCustomBanphrase("n1jk6er")
	m.addCustomBanphrase("n1jkger")
	m.addCustomBanphrase("n1j6ker")
	m.addCustomBanphrase("n1jgker")

	m.addCustomBanphrase("n!jgger")
	m.addCustomBanphrase("n!jg6er")
	m.addCustomBanphrase("n!j6ger")
	m.addCustomBanphrase("n!j66er")
	m.addCustomBanphrase("n!jk6er")
	m.addCustomBanphrase("n!jkger")
	m.addCustomBanphrase("n!j6ker")
	m.addCustomBanphrase("n!jgker")

	m.addCustomBanphrase("nij1gger")
	m.addCustomBanphrase("nij1g6er")
	m.addCustomBanphrase("nij16ger")
	m.addCustomBanphrase("nij166er")

	m.addCustomBanphrase("nij1k6er")
	m.addCustomBanphrase("nij1kger")
	m.addCustomBanphrase("nij16ker")
	m.addCustomBanphrase("nij1gker")

	m.addCustomBanphrase("n1jk6er")
	m.addCustomBanphrase("n1jkger")
	m.addCustomBanphrase("n1j6ker")
	m.addCustomBanphrase("n1jgker")

	m.addCustomBanphrase("nij1gger")

	m.addCustomBanphrase("ni@@er")
	m.addCustomBanphrase("nigger")
	m.addCustomBanphrase("niggger")
	m.addCustomBanphrase("nigggger")
	m.addCustomBanphrase("niggggger")
	m.addCustomBanphrase("nig6er")
	m.addCustomBanphrase("ni6ger")
	m.addCustomBanphrase("ni6grs")
	m.addCustomBanphrase("ni66er")
	m.addCustomBanphrase("nik6er")
	m.addCustomBanphrase("nikger")
	m.addCustomBanphrase("ni6ker")
	m.addCustomBanphrase("nigker")

	m.addCustomBanphrase("nl@@er")
	m.addCustomBanphrase("nlger")
	m.addCustomBanphrase("nlgger")
	m.addCustomBanphrase("nlggger")
	m.addCustomBanphrase("nlgggger")
	m.addCustomBanphrase("nlggggger")
	m.addCustomBanphrase("nlg6er")
	m.addCustomBanphrase("nl6ger")
	m.addCustomBanphrase("nl6grs")
	m.addCustomBanphrase("nl66er")
	m.addCustomBanphrase("nlk6er")
	m.addCustomBanphrase("nlker")
	m.addCustomBanphrase("nlkger")
	m.addCustomBanphrase("nl6ker")
	m.addCustomBanphrase("nlgker")

	m.addCustomBanphrase("n1gger")
	m.addCustomBanphrase("n1g6er")
	m.addCustomBanphrase("n16ger")
	m.addCustomBanphrase("n166er")
	m.addCustomBanphrase("n1k6er")
	m.addCustomBanphrase("n1kger")
	m.addCustomBanphrase("n16ker")
	m.addCustomBanphrase("n1gker")

	m.addCustomBanphrase("n!gger")
	m.addCustomBanphrase("n!g6er")
	m.addCustomBanphrase("n!6ger")
	m.addCustomBanphrase("n!66er")
	m.addCustomBanphrase("n!k6er")
	m.addCustomBanphrase("n!kger")
	m.addCustomBanphrase("n!6ker")
	m.addCustomBanphrase("n!gker")

	m.addCustomBanphrase("ni1gger")
	m.addCustomBanphrase("ni1g6er")
	m.addCustomBanphrase("ni16ger")
	m.addCustomBanphrase("ni166er")

	m.addCustomBanphrase("ni1k6er")
	m.addCustomBanphrase("ni1kger")
	m.addCustomBanphrase("ni16ker")
	m.addCustomBanphrase("ni1gker")

	m.addCustomBanphrase("n1k6er")
	m.addCustomBanphrase("n1kger")
	m.addCustomBanphrase("n16ker")
	m.addCustomBanphrase("n1gker")

	m.addCustomBanphrase("nek6er")
	m.addCustomBanphrase("nekger")
	m.addCustomBanphrase("ne6ker")
	m.addCustomBanphrase("negker")
	m.addCustomBanphrase("neg6er")
	m.addCustomBanphrase("ne6ger")

	m.addCustomBanphrase("ni1gg3r")

	m.addCustomBanphrase("nigg3r")
	m.addCustomBanphrase("nig63r")
	m.addCustomBanphrase("ni6g3r")
	m.addCustomBanphrase("ni663r")
	m.addCustomBanphrase("nik63r")
	m.addCustomBanphrase("nikg3r")
	m.addCustomBanphrase("ni6k3r")
	m.addCustomBanphrase("nigk3r")

	m.addCustomBanphrase("n1gg3r")
	m.addCustomBanphrase("n1g63r")
	m.addCustomBanphrase("n16g3r")
	m.addCustomBanphrase("n1663r")
	m.addCustomBanphrase("n1k63r")
	m.addCustomBanphrase("n1kg3r")
	m.addCustomBanphrase("n16k3r")
	m.addCustomBanphrase("n1gk3r")

	m.addCustomBanphrase("n!gg3r")
	m.addCustomBanphrase("n!g63r")
	m.addCustomBanphrase("n!6g3r")
	m.addCustomBanphrase("n!663r")
	m.addCustomBanphrase("n!k63r")
	m.addCustomBanphrase("n!kg3r")
	m.addCustomBanphrase("n!6k3r")
	m.addCustomBanphrase("n!gk3r")

	m.addCustomBanphrase("ni1gg3r")
	m.addCustomBanphrase("ni1g63r")
	m.addCustomBanphrase("ni16g3r")
	m.addCustomBanphrase("ni1663r")

	m.addCustomBanphrase("ni1k63r")
	m.addCustomBanphrase("ni1kg3r")
	m.addCustomBanphrase("ni16k3r")
	m.addCustomBanphrase("ni1gk3r")

	m.addCustomBanphrase("n1k63r")
	m.addCustomBanphrase("n1kg3r")
	m.addCustomBanphrase("n16k3r")
	m.addCustomBanphrase("n1gk3r")

	m.addCustomBanphrase("n3k63r")
	m.addCustomBanphrase("n3kg3r")
	m.addCustomBanphrase("n36k3r")
	m.addCustomBanphrase("n3gk3r")
	m.addCustomBanphrase("n3g63r")
	m.addCustomBanphrase("n3gg3r")
	m.addCustomBanphrase("n36g3r")
	m.addCustomBanphrase("n3gg3r")

	m.addCustomBanphrase("g63r")

	err := m.loadPajbot1Banphrases()
	if err != nil {
		// return err
	}
}

type TimeoutData struct {
	FullMessage string
	Banphrase   pkg.Banphrase
	Username    string
	Channel     string
	Timestamp   time.Time
}

func (m *pajbot1BanphraseFilter) check(event pkg.MessageEvent, text string, actions pkg.Actions) error {
	originalVariations, lowercaseVariations, err := utils.MakeVariations(text, true)
	if err != nil {
		fmt.Println("Error making variations:", err)
		return err
	}

	for _, bp := range m.banphrases {
		var variations *[]string

		if !bp.IsCaseSensitive() {
			variations = &lowercaseVariations
		} else {
			variations = &originalVariations
		}

		for _, variation := range *variations {
			if bp.Triggers(variation) {
				// fmt.Printf("Banphrase triggered: %#v\n", bp)
				/*
					if bp.IsAdvanced() && source.GetName() == "forsen" {
						lol := TimeoutData{
							FullMessage: message.GetText(),
							Banphrase:   bp,
							Username:    user.GetName(),
							Channel:     source.GetName(),
							Timestamp:   time.Now().UTC(),
						}
						c := m.server.redis.Get()
						bytes, _ := json.Marshal(&lol)
						c.Do("LPUSH", "pajbot2:timeouts", bytes)
						c.Close()
					}
				*/

				if bp.GetID() == -1 {
					reason := fmt.Sprintf("Matched banphrase with name '%s' and id '%d'", bp.GetName(), bp.GetID())
					// FIXME
					actions.Timeout(event.User, bp.GetDuration()).SetReason(reason)
					// fmt.Printf("Banphrase triggered: %#v for user %s", bp, user.GetName())
					return nil
				}
			}

			if !bp.IsAdvanced() {
				if bp.GetID() == -1 {
					fmt.Println("wtf")
				}
				break
			}
		}
	}

	return nil
}

func (m *pajbot1BanphraseFilter) OnMessage(event pkg.MessageEvent) pkg.Actions {
	user := event.User
	message := event.Message

	if user.IsModerator() {
		return nil
	}

	if user.GetName() == "supibot" {
		return nil
	}

	actions := &twitchactions.Actions{}

	m.check(event, message.GetText(), actions)
	m.check(event, user.GetName(), actions)

	return actions
}
<commit_msg>clean up banphrase filter - removed some "often false positives"<commit_after>package modules

import (
	"fmt"
	"time"

	"github.com/pajbot/pajbot2/pkg"
	"github.com/pajbot/pajbot2/pkg/filters"
	"github.com/pajbot/pajbot2/pkg/twitchactions"
	"github.com/pajbot/utils"
)

func init() {
	Register("pajbot1_banphrase", func() pkg.ModuleSpec {
		return &moduleSpec{
			id:   "pajbot1_banphrase",
			name: "pajbot1 banphrase",
			maker: func(b base) pkg.Module {
				m := newPajbot1BanphraseFilter(b)
				m.Initialize()
				return m
			},

			moduleType: pkg.ModuleTypeFilter,

			enabledByDefault: true,
		}
	})
}

type pajbot1BanphraseFilter struct {
	base

	banphrases []pkg.Banphrase
}

func newPajbot1BanphraseFilter(b base) *pajbot1BanphraseFilter {
	return &pajbot1BanphraseFilter{
		base: b,
	}
}

func (m *pajbot1BanphraseFilter) addCustomBanphrase(phrase string) {
	m.banphrases = append(m.banphrases, &filters.Pajbot1Banphrase{
		ID:            -1,
		Name:          "Custom",
		Phrase:        phrase,
		Length:        600,
		Operator:      filters.OperatorContains,
		Permanent:     false,
		Warning:       false,
		Notify:        false,
		CaseSensitive: false,
		Enabled:       true,
		SubImmunity:   false,
		RemoveAccents: true,
	})
}

func (m *pajbot1BanphraseFilter) loadPajbot1Banphrases() error {
	const queryF = `SELECT * FROM tb_banphrase`

	session := m.server.oldSession

	rows, err := session.Query(queryF)
	if err != nil {
		return err
	}
	defer rows.Close()

	for rows.Next() {
		var bp filters.Pajbot1Banphrase
		err = bp.LoadScan(rows)
		if err != nil {
			return err
		}

		if bp.Enabled {
			m.banphrases = append(m.banphrases, &bp)
		}
	}
	return nil
}

func (m *pajbot1BanphraseFilter) Initialize() {
	// hard-coded banphrases
	m.addCustomBanphrase("n!66ger")

	// m.addCustomBanphrase("negro")
	m.addCustomBanphrase("negr0")
	m.addCustomBanphrase("n3gro")
	m.addCustomBanphrase("n3gr0")

	m.addCustomBanphrase("nij1gger")

	m.addCustomBanphrase("nijgger")
	m.addCustomBanphrase("nijggger")
	m.addCustomBanphrase("nijgggger")
	m.addCustomBanphrase("nijggggger")
	m.addCustomBanphrase("nijg6er")
	m.addCustomBanphrase("nij6ger")
	m.addCustomBanphrase("nij66er")
	m.addCustomBanphrase("nijk6er")
	m.addCustomBanphrase("nijkger")
	m.addCustomBanphrase("nij6ker")
	m.addCustomBanphrase("nijgker")

	m.addCustomBanphrase("n1jgger")
	m.addCustomBanphrase("n1jg6er")
	m.addCustomBanphrase("n1j6ger")
	m.addCustomBanphrase("n1j66er")
	m.addCustomBanphrase("n1jk6er")
	m.addCustomBanphrase("n1jkger")
	m.addCustomBanphrase("n1j6ker")
	m.addCustomBanphrase("n1jgker")

	m.addCustomBanphrase("n!jgger")
	m.addCustomBanphrase("n!jg6er")
	m.addCustomBanphrase("n!j6ger")
	m.addCustomBanphrase("n!j66er")
	m.addCustomBanphrase("n!jk6er")
	m.addCustomBanphrase("n!jkger")
	m.addCustomBanphrase("n!j6ker")
	m.addCustomBanphrase("n!jgker")

	m.addCustomBanphrase("nij1gger")
	m.addCustomBanphrase("nij1g6er")
	m.addCustomBanphrase("nij16ger")
	m.addCustomBanphrase("nij166er")

	m.addCustomBanphrase("nij1k6er")
	m.addCustomBanphrase("nij1kger")
	m.addCustomBanphrase("nij16ker")
	m.addCustomBanphrase("nij1gker")

	m.addCustomBanphrase("n1jk6er")
	m.addCustomBanphrase("n1jkger")
	m.addCustomBanphrase("n1j6ker")
	m.addCustomBanphrase("n1jgker")

	m.addCustomBanphrase("nij1gger")

	m.addCustomBanphrase("ni@@er")
	m.addCustomBanphrase("nigger")
	m.addCustomBanphrase("niggger")
	m.addCustomBanphrase("nigggger")
	m.addCustomBanphrase("niggggger")
	m.addCustomBanphrase("nig6er")
	m.addCustomBanphrase("ni6ger")
	m.addCustomBanphrase("ni6grs")
	m.addCustomBanphrase("ni66er")
	m.addCustomBanphrase("nik6er")
	m.addCustomBanphrase("nikger")
	m.addCustomBanphrase("ni6ker")
	m.addCustomBanphrase("nigker")

	m.addCustomBanphrase("nl@@er")
	m.addCustomBanphrase("nlger")
	m.addCustomBanphrase("nlgger")
	m.addCustomBanphrase("nlggger")
	m.addCustomBanphrase("nlgggger")
	m.addCustomBanphrase("nlggggger")
	m.addCustomBanphrase("nlg6er")
	m.addCustomBanphrase("nl6ger")
	m.addCustomBanphrase("nl6grs")
	m.addCustomBanphrase("nl66er")
	m.addCustomBanphrase("nlk6er")
	m.addCustomBanphrase("nlker")
	m.addCustomBanphrase("nlkger")
	m.addCustomBanphrase("nl6ker")
	m.addCustomBanphrase("nlgker")

	m.addCustomBanphrase("n1gger")
	m.addCustomBanphrase("n1g6er")
	m.addCustomBanphrase("n16ger")
	m.addCustomBanphrase("n166er")
	m.addCustomBanphrase("n1k6er")
	m.addCustomBanphrase("n1kger")
	m.addCustomBanphrase("n16ker")
	m.addCustomBanphrase("n1gker")

	m.addCustomBanphrase("n!gger")
	m.addCustomBanphrase("n!g6er")
	m.addCustomBanphrase("n!6ger")
	m.addCustomBanphrase("n!66er")
	m.addCustomBanphrase("n!k6er")
	m.addCustomBanphrase("n!kger")
	m.addCustomBanphrase("n!6ker")
	m.addCustomBanphrase("n!gker")

	m.addCustomBanphrase("ni1gger")
	m.addCustomBanphrase("ni1g6er")
	m.addCustomBanphrase("ni16ger")
	m.addCustomBanphrase("ni166er")

	m.addCustomBanphrase("ni1k6er")
	m.addCustomBanphrase("ni1kger")
	m.addCustomBanphrase("ni16ker")
	m.addCustomBanphrase("ni1gker")

	m.addCustomBanphrase("n1k6er")
	m.addCustomBanphrase("n1kger")
	m.addCustomBanphrase("n16ker")
	m.addCustomBanphrase("n1gker")

	m.addCustomBanphrase("nek6er")
	m.addCustomBanphrase("nekger")
	m.addCustomBanphrase("ne6ker")
	m.addCustomBanphrase("negker")
	m.addCustomBanphrase("neg6er")
	m.addCustomBanphrase("ne6ger")

	m.addCustomBanphrase("ni1gg3r")

	m.addCustomBanphrase("nigg3r")
	m.addCustomBanphrase("nig63r")
	m.addCustomBanphrase("ni6g3r")
	m.addCustomBanphrase("ni663r")
	m.addCustomBanphrase("nik63r")
	m.addCustomBanphrase("nikg3r")
	m.addCustomBanphrase("ni6k3r")
	m.addCustomBanphrase("nigk3r")

	m.addCustomBanphrase("n1gg3r")
	m.addCustomBanphrase("n1g63r")
	m.addCustomBanphrase("n16g3r")
	m.addCustomBanphrase("n1663r")
	m.addCustomBanphrase("n1k63r")
	m.addCustomBanphrase("n1kg3r")
	m.addCustomBanphrase("n16k3r")
	m.addCustomBanphrase("n1gk3r")

	m.addCustomBanphrase("n!gg3r")
	m.addCustomBanphrase("n!g63r")
	m.addCustomBanphrase("n!6g3r")
	m.addCustomBanphrase("n!663r")
	m.addCustomBanphrase("n!k63r")
	m.addCustomBanphrase("n!kg3r")
	m.addCustomBanphrase("n!6k3r")
	m.addCustomBanphrase("n!gk3r")

	m.addCustomBanphrase("ni1gg3r")
	m.addCustomBanphrase("ni1g63r")
	m.addCustomBanphrase("ni16g3r")
	m.addCustomBanphrase("ni1663r")

	m.addCustomBanphrase("ni1k63r")
	m.addCustomBanphrase("ni1kg3r")
	m.addCustomBanphrase("ni16k3r")
	m.addCustomBanphrase("ni1gk3r")

	m.addCustomBanphrase("n1k63r")
	m.addCustomBanphrase("n1kg3r")
	m.addCustomBanphrase("n16k3r")
	m.addCustomBanphrase("n1gk3r")

	m.addCustomBanphrase("n3k63r")
	m.addCustomBanphrase("n3kg3r")
	m.addCustomBanphrase("n36k3r")
	m.addCustomBanphrase("n3gk3r")
	m.addCustomBanphrase("n3g63r")
	m.addCustomBanphrase("n3gg3r")
	m.addCustomBanphrase("n36g3r")
	m.addCustomBanphrase("n3gg3r")

	// m.addCustomBanphrase("g63r")

	err := m.loadPajbot1Banphrases()
	if err != nil {
		// return err
	}
}

type TimeoutData struct {
	FullMessage string
	Banphrase   pkg.Banphrase
	Username    string
	Channel     string
	Timestamp   time.Time
}

func (m *pajbot1BanphraseFilter) check(event pkg.MessageEvent, text string, actions pkg.Actions) error {
	originalVariations, lowercaseVariations, err := utils.MakeVariations(text, true)
	if err != nil {
		fmt.Println("Error making variations:", err)
		return err
	}

	for _, bp := range m.banphrases {
		var variations *[]string

		if !bp.IsCaseSensitive() {
			variations = &lowercaseVariations
		} else {
			variations = &originalVariations
		}

		for _, variation := range *variations {
			if bp.Triggers(variation) {
				// fmt.Printf("Banphrase triggered: %#v\n", bp)
				/*
					if bp.IsAdvanced() && source.GetName() == "forsen" {
						lol := TimeoutData{
							FullMessage: message.GetText(),
							Banphrase:   bp,
							Username:    user.GetName(),
							Channel:     source.GetName(),
							Timestamp:   time.Now().UTC(),
						}
						c := m.server.redis.Get()
						bytes, _ := json.Marshal(&lol)
						c.Do("LPUSH", "pajbot2:timeouts", bytes)
						c.Close()
					}
				*/

				if bp.GetID() == -1 {
					reason := fmt.Sprintf("Matched banphrase with name '%s' and id '%d'", bp.GetName(), bp.GetID())
					// FIXME
					actions.Timeout(event.User, bp.GetDuration()).SetReason(reason)
					// fmt.Printf("Banphrase triggered: %#v for user %s", bp, user.GetName())
					return nil
				}
			}

			if !bp.IsAdvanced() {
				if bp.GetID() == -1 {
					fmt.Println("wtf")
				}
				break
			}
		}
	}

	return nil
}

func (m *pajbot1BanphraseFilter) OnMessage(event pkg.MessageEvent) pkg.Actions {
	user := event.User
	message := event.Message

	if user.IsModerator() {
		return nil
	}

	if user.GetName() == "supibot" {
		return nil
	}

	actions := &twitchactions.Actions{}

	m.check(event, message.GetText(), actions)
	m.check(event, user.GetName(), actions)

	return actions
}
<|endoftext|>


<commit_before>package build

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

	"github.com/nuclio/nuclio-sdk"
	"github.com/nuclio/nuclio/pkg/nuclio-build/eventhandlerparser"
	"github.com/nuclio/nuclio/pkg/nuclio-build/util"
	"github.com/pkg/errors"
	"github.com/spf13/viper"
)

type Options struct {
	Verbose         bool
	FunctionPath    string
	OutputType      string
	OutputName      string
	Version         string
	NuclioSourceDir string
	NuclioSourceURL string
	PushRegistry    string
}

type Builder struct {
	logger  nuclio.Logger
	options *Options
}

const (
	defaultBuilderImage     = "golang:1.8"
	processorConfigFileName = "processor.yaml"
	buildConfigFileName     = "build.yaml"
)

type config struct {
	Name    string `mapstructure:"name"`
	Handler string `mapstructure:"handler"`
	Build   struct {
		Image    string   `mapstructure:"image"`
		Packages []string `mapstructure:"packages"`
	} `mapstructure:"build"`
}

type buildStep struct {
	Message string
	Func    func() error
}

func NewBuilder(parentLogger nuclio.Logger, options *Options) *Builder {
	return &Builder{
		logger:  parentLogger.GetChild("builder").(nuclio.Logger),
		options: options,
	}
}

func (b *Builder) Build() error {
	config, err := b.readConfig(filepath.Join(b.options.FunctionPath, processorConfigFileName),
		filepath.Join(b.options.FunctionPath, buildConfigFileName))

	if err != nil {
		return errors.Wrap(err, "Unable to read Config")
	}

	b.logger.Info("Building run environment")

	env, err := newEnv(b.logger, config, b.options)
	if err != nil {
		return errors.Wrap(err, "Failed to create env")
	}

	if err := b.buildDockerSteps(env, b.options.OutputType == "docker"); err != nil {
		return err
	}

	if b.options.OutputType == "binary" {
		if err := util.CopyFile(env.getBinaryPath(), env.outputName); err != nil {
			return err
		}
	}

	b.logger.InfoWith("Outputting",
		"output_type", b.options.OutputType,
		"output_name", env.outputName)

	return nil
}

func (b *Builder) buildDockerSteps(env *env, outputToImage bool) error {
	b.logger.Debug("Creating docker helper")

	docker, err := newDockerHelper(b.logger, env)
	if err != nil {
		return errors.Wrap(err, "Error building docker helper")
	}

	defer docker.close()

	buildSteps := []buildStep{
		{Message: "Running docker onbuild",
			Func: docker.createOnBuildImage},
		{Message: "Running docker binary build",
			Func: docker.createBuilderImage},
	}

	if outputToImage {
		buildSteps = append(buildSteps, buildStep{
			Message: "Creating output container " + env.outputName,
			Func:    docker.createProcessorImage})
	}

	for _, step := range buildSteps {
		b.logger.InfoWith("Running build step", "message", step.Message)
		if err := step.Func(); err != nil {
			return errors.Wrap(err, "Error while "+step.Message)
		}
	}

	return nil
}

func (b *Builder) readConfigFile(c *config, key string, fileName string) error {
	b.logger.DebugWith("Reading config file", "path", fileName, "key", key)

	v := viper.New()
	v.SetConfigFile(fileName)
	if err := v.ReadInConfig(); err != nil {
		return errors.Wrapf(err, "Unable to read %q configuration", fileName)
	}

	if key != "" {
		v = v.Sub(key)

		if v == nil {
			return fmt.Errorf("Configuration file %s has no key %s", fileName, key)
		}
	}

	if err := v.Unmarshal(c); err != nil {
		return errors.Wrapf(err, "Unable to unmarshal %q configuration", fileName)
	}
	return nil
}

func (b *Builder) readProcessorConfigFile(c *config, fileName string) error {
	if _, err := os.Stat(fileName); os.IsNotExist(err) {
		c.Name = ""
		c.Handler = ""

		return nil
	}

	// try to read the configuration file
	return b.readConfigFile(c, "function", fileName)
}

func (b *Builder) readBuildConfigFile(c *config, fileName string) error {
	if _, err := os.Stat(fileName); os.IsNotExist(err) {
		c.Build.Image = defaultBuilderImage
		c.Build.Packages = []string{}

		return nil
	}

	// try to read the configuration file
	return b.readConfigFile(c, "", fileName)
}

func adjective(n int) string {
	switch n {
	case 0:
		return "no"
	case 1: // noop
	default:
		return "too many"
	}
	return "" // make compiler happy
}

func (b *Builder) populateEventHandlerInfo(cfg *config) error {
	parser := eventhandlerparser.NewEventHandlerParser(b.logger)
	pkgs, handlers, err := parser.ParseEventHandlers(b.options.FunctionPath)
	if err != nil {
		errors.Wrapf(err, "can't find handlers in %q", b.options.FunctionPath)
	}

	if len(handlers) != 1 {
		adj := adjective(len(handlers))
		return errors.Wrapf(err, "%s handlers found in %q", adj, b.options.FunctionPath)
	}

	if len(pkgs) != 1 {
		adj := adjective(len(pkgs))
		return errors.Wrapf(err, "%s packages found in %q", adj, b.options.FunctionPath)
	}

	if len(cfg.Handler) == 0 {
		cfg.Handler = handlers[0]
		b.logger.InfoWith("ParseHandler", "handler", cfg.Handler)
	}

	if len(cfg.Name) == 0 {
		cfg.Name = pkgs[0]
		b.logger.InfoWith("ParseHandler", "package", cfg.Name)
	}

	return nil
}

func (b *Builder) readConfig(processorConfigPath, buildFile string) (*config, error) {
	c := config{}
	if err := b.readProcessorConfigFile(&c, processorConfigPath); err != nil {
		return nil, err
	}

	if len(c.Handler) == 0 || len(c.Name) == 0 {
		if err := b.populateEventHandlerInfo(&c); err != nil {
			return nil, err
		}
	}

	if err := b.readBuildConfigFile(&c, buildFile); err != nil {
		return nil, err
	}
	return &c, nil
}
<commit_msg>Tweak a few logs (#98)<commit_after>package build

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

	"github.com/nuclio/nuclio-sdk"
	"github.com/nuclio/nuclio/pkg/nuclio-build/eventhandlerparser"
	"github.com/nuclio/nuclio/pkg/nuclio-build/util"
	"github.com/pkg/errors"
	"github.com/spf13/viper"
)

type Options struct {
	Verbose         bool
	FunctionPath    string
	OutputType      string
	OutputName      string
	Version         string
	NuclioSourceDir string
	NuclioSourceURL string
	PushRegistry    string
}

type Builder struct {
	logger  nuclio.Logger
	options *Options
}

const (
	defaultBuilderImage     = "golang:1.8"
	processorConfigFileName = "processor.yaml"
	buildConfigFileName     = "build.yaml"
)

type config struct {
	Name    string `mapstructure:"name"`
	Handler string `mapstructure:"handler"`
	Build   struct {
		Image    string   `mapstructure:"image"`
		Packages []string `mapstructure:"packages"`
	} `mapstructure:"build"`
}

type buildStep struct {
	Message string
	Func    func() error
}

func NewBuilder(parentLogger nuclio.Logger, options *Options) *Builder {
	return &Builder{
		logger:  parentLogger.GetChild("builder").(nuclio.Logger),
		options: options,
	}
}

func (b *Builder) Build() error {
	config, err := b.readConfig(filepath.Join(b.options.FunctionPath, processorConfigFileName),
		filepath.Join(b.options.FunctionPath, buildConfigFileName))

	if err != nil {
		return errors.Wrap(err, "Unable to read Config")
	}

	b.logger.Info("Building run environment")

	env, err := newEnv(b.logger, config, b.options)
	if err != nil {
		return errors.Wrap(err, "Failed to create env")
	}

	if err := b.buildDockerSteps(env, b.options.OutputType == "docker"); err != nil {
		return err
	}

	if b.options.OutputType == "binary" {
		if err := util.CopyFile(env.getBinaryPath(), env.outputName); err != nil {
			return err
		}
	}

	b.logger.InfoWith("Outputting",
		"output_type", b.options.OutputType,
		"output_name", env.outputName)

	return nil
}

func (b *Builder) buildDockerSteps(env *env, outputToImage bool) error {
	b.logger.Debug("Creating docker helper")

	docker, err := newDockerHelper(b.logger, env)
	if err != nil {
		return errors.Wrap(err, "Error building docker helper")
	}

	defer docker.close()

	buildSteps := []buildStep{
		{Message: "Running docker onbuild",
			Func: docker.createOnBuildImage},
		{Message: "Running docker binary build",
			Func: docker.createBuilderImage},
	}

	if outputToImage {
		buildSteps = append(buildSteps, buildStep{
			Message: "Creating output container " + env.outputName,
			Func:    docker.createProcessorImage})
	}

	for _, step := range buildSteps {
		b.logger.InfoWith("Running build step", "message", step.Message)
		if err := step.Func(); err != nil {
			return errors.Wrap(err, "Error while "+step.Message)
		}
	}

	return nil
}

func (b *Builder) readConfigFile(c *config, key string, fileName string) error {
	b.logger.DebugWith("Reading config file", "path", fileName, "key", key)

	v := viper.New()
	v.SetConfigFile(fileName)
	if err := v.ReadInConfig(); err != nil {
		return errors.Wrapf(err, "Unable to read %q configuration", fileName)
	}

	if key != "" {
		v = v.Sub(key)

		if v == nil {
			return fmt.Errorf("Configuration file %s has no key %s", fileName, key)
		}
	}

	if err := v.Unmarshal(c); err != nil {
		return errors.Wrapf(err, "Unable to unmarshal %q configuration", fileName)
	}
	return nil
}

func (b *Builder) readProcessorConfigFile(c *config, fileName string) error {
	if _, err := os.Stat(fileName); os.IsNotExist(err) {
		c.Name = ""
		c.Handler = ""

		return nil
	}

	// try to read the configuration file
	return b.readConfigFile(c, "function", fileName)
}

func (b *Builder) readBuildConfigFile(c *config, fileName string) error {
	if _, err := os.Stat(fileName); os.IsNotExist(err) {
		c.Build.Image = defaultBuilderImage
		c.Build.Packages = []string{}

		return nil
	}

	// try to read the configuration file
	return b.readConfigFile(c, "", fileName)
}

func adjective(n int) string {
	switch n {
	case 0:
		return "no"
	case 1: // noop
	default:
		return "too many"
	}
	return "" // make compiler happy
}

func (b *Builder) populateEventHandlerInfo(cfg *config) error {
	parser := eventhandlerparser.NewEventHandlerParser(b.logger)
	packages, handlers, err := parser.ParseEventHandlers(b.options.FunctionPath)
	if err != nil {
		errors.Wrapf(err, "can't find handlers in %q", b.options.FunctionPath)
	}

	b.logger.DebugWith("Parsed event handlers", "packages", packages, "handlers", handlers)

	if len(handlers) != 1 {
		adj := adjective(len(handlers))
		return errors.Wrapf(err, "%s handlers found in %q", adj, b.options.FunctionPath)
	}

	if len(packages) != 1 {
		adj := adjective(len(packages))
		return errors.Wrapf(err, "%s packages found in %q", adj, b.options.FunctionPath)
	}

	if len(cfg.Handler) == 0 {
		cfg.Handler = handlers[0]
		b.logger.DebugWith("Selected handler", "handler", cfg.Handler)
	}

	if len(cfg.Name) == 0 {
		cfg.Name = packages[0]
		b.logger.DebugWith("Selected package", "package", cfg.Name)
	}

	return nil
}

func (b *Builder) readConfig(processorConfigPath, buildFile string) (*config, error) {
	c := config{}
	if err := b.readProcessorConfigFile(&c, processorConfigPath); err != nil {
		return nil, err
	}

	if len(c.Handler) == 0 || len(c.Name) == 0 {
		if err := b.populateEventHandlerInfo(&c); err != nil {
			return nil, err
		}
	}

	if err := b.readBuildConfigFile(&c, buildFile); err != nil {
		return nil, err
	}
	return &c, nil
}
<|endoftext|>