<commit_before>package server

import (
	"fmt"
	"github.com/Aptomi/aptomi/pkg/engine"
	"github.com/Aptomi/aptomi/pkg/engine/apply"
	"github.com/Aptomi/aptomi/pkg/engine/diff"
	"github.com/Aptomi/aptomi/pkg/engine/resolve"
	"github.com/Aptomi/aptomi/pkg/event"
	"github.com/Aptomi/aptomi/pkg/runtime"
	log "github.com/Sirupsen/logrus"
	"time"
)

func logError(err interface{}) {
	log.Errorf("Error while enforcing policy: %s", err)
}

func (server *Server) enforceLoop() error {
	for {
		err := server.enforce()
		if err != nil {
			logError(err)
		}
		time.Sleep(server.cfg.Enforcer.Interval)
	}
}

func (server *Server) enforce() error {
	server.enforcementIdx++

	defer func() {
		if err := recover(); err != nil {
			logError(err)
		}
	}()

	// todo think about initial state when there is no revision at all
	currRevision, err := server.store.GetRevision(runtime.LastGen)
	if err != nil {
		return fmt.Errorf("unable to get curr revision: %s", err)
	}

	// Mark last Revision as failed if it wasn't completed
	if currRevision != nil && currRevision.Status == engine.RevisionStatusInProgress {
		currRevision.Status = engine.RevisionStatusError
		currRevision.AppliedAt = time.Now()
		revErr := server.store.UpdateRevision(currRevision)
		if revErr != nil {
			log.Warnf("(enforce-%d) Error while setting current revision that is in progress to error state: %s", server.enforcementIdx, revErr)
		}
		log.Infof("(enforce-%d) Current revision that is in progress was reset to error state", server.enforcementIdx)
	}

	desiredPolicy, desiredPolicyGen, err := server.store.GetPolicy(runtime.LastGen)
	if err != nil {
		return fmt.Errorf("error while getting desiredPolicy: %s", err)
	}

	// if policy is not found, it means it somehow was not initialized correctly. let's return error
	if desiredPolicy == nil {
		return fmt.Errorf("desiredPolicy is nil, does not exist in the store")
	}

	actualState, err := server.store.GetActualState()
	if err != nil {
		return fmt.Errorf("error while getting actual state: %s", err)
	}

	eventLog := event.NewLog(fmt.Sprintf("enforce-%d-resolve", server.enforcementIdx), true)
	resolver := resolve.NewPolicyResolver(desiredPolicy, server.externalData, eventLog)
	desiredState, err := resolver.ResolveAllDependencies()
	if err != nil {
		// todo save eventlog
		server.saveErrRevision(currRevision, desiredPolicyGen)

		return fmt.Errorf("cannot resolve desiredPolicy: %s", err)
	}

	stateDiff := diff.NewPolicyResolutionDiff(desiredState, actualState)

	nextRevision, err := server.store.NewRevision(desiredPolicyGen)
	if err != nil {
		return fmt.Errorf("unable to get next revision: %s", err)
	}

	// policy changed while no actions needed to achieve desired state
	if len(stateDiff.Actions) <= 0 && currRevision != nil && currRevision.Policy == nextRevision.Policy {
		log.Infof("(enforce-%d) No changes, policy gen %d", server.enforcementIdx, desiredPolicyGen)
		return nil
	}
	log.Infof("(enforce-%d) New revision %d, policy gen %d, %d actions need to be applied", server.enforcementIdx, nextRevision.GetGeneration(), desiredPolicyGen, len(stateDiff.Actions))

	// todo save eventlog (if there were changes?)

	// todo if policy gen changed, we still need to save revision but with progress == done

	// Save revision
	err = server.store.SaveRevision(nextRevision)
	if err != nil {
		return fmt.Errorf("error while saving new revision: %s", err)
	}

	if server.cfg.Enforcer.Noop {
		log.Infof("(enforce-%d) Applying changes in noop mode (sleep per action = %d seconds)", server.enforcementIdx, server.cfg.Enforcer.NoopSleep)
	} else {
		log.Infof("(enforce-%d) Applying changes", server.enforcementIdx)
	}

	pluginRegistry := server.pluginRegistryFactory()
	eventLog = event.NewLog(fmt.Sprintf("enforce-%d-apply", server.enforcementIdx), true)
	applier := apply.NewEngineApply(desiredPolicy, desiredState, actualState, server.store.GetActualStateUpdater(), server.externalData, pluginRegistry, stateDiff.Actions, eventLog, server.store.GetRevisionProgressUpdater(nextRevision))
	_, err = applier.Apply()

	// todo save eventlog

	if err != nil {
		return fmt.Errorf("error while applying new revision: %s", err)
	}
	log.Infof("(enforce-%d) New revision %d successfully applied, %d component instances", server.enforcementIdx, nextRevision.GetGeneration(), len(desiredState.GetComponentProcessingOrder()))

	return nil
}

func (server *Server) saveErrRevision(currRevision *engine.Revision, desiredPolicyGen runtime.Generation) {
	if currRevision == nil || currRevision.Policy != desiredPolicyGen || currRevision.Status != engine.RevisionStatusError {
		rev, revErr := server.store.NewRevision(desiredPolicyGen)
		if revErr != nil {
			log.Warnf("(enforce-%d) Error while creating revision to record resolution error: %s", server.enforcementIdx, revErr)
		}

		rev.Status = engine.RevisionStatusError
		revErr = server.store.SaveRevision(rev)
		if revErr != nil {
			log.Warnf("(enforce-%d) Error while saving revision to record resolution error: %s", server.enforcementIdx, revErr)
		}
	}
}
<commit_msg>Fix logging of the enforcer noop sleep config<commit_after>package server

import (
	"fmt"
	"github.com/Aptomi/aptomi/pkg/engine"
	"github.com/Aptomi/aptomi/pkg/engine/apply"
	"github.com/Aptomi/aptomi/pkg/engine/diff"
	"github.com/Aptomi/aptomi/pkg/engine/resolve"
	"github.com/Aptomi/aptomi/pkg/event"
	"github.com/Aptomi/aptomi/pkg/runtime"
	log "github.com/Sirupsen/logrus"
	"time"
)

func logError(err interface{}) {
	log.Errorf("Error while enforcing policy: %s", err)
}

func (server *Server) enforceLoop() error {
	for {
		err := server.enforce()
		if err != nil {
			logError(err)
		}
		time.Sleep(server.cfg.Enforcer.Interval)
	}
}

func (server *Server) enforce() error {
	server.enforcementIdx++

	defer func() {
		if err := recover(); err != nil {
			logError(err)
		}
	}()

	// todo think about initial state when there is no revision at all
	currRevision, err := server.store.GetRevision(runtime.LastGen)
	if err != nil {
		return fmt.Errorf("unable to get curr revision: %s", err)
	}

	// Mark last Revision as failed if it wasn't completed
	if currRevision != nil && currRevision.Status == engine.RevisionStatusInProgress {
		currRevision.Status = engine.RevisionStatusError
		currRevision.AppliedAt = time.Now()
		revErr := server.store.UpdateRevision(currRevision)
		if revErr != nil {
			log.Warnf("(enforce-%d) Error while setting current revision that is in progress to error state: %s", server.enforcementIdx, revErr)
		}
		log.Infof("(enforce-%d) Current revision that is in progress was reset to error state", server.enforcementIdx)
	}

	desiredPolicy, desiredPolicyGen, err := server.store.GetPolicy(runtime.LastGen)
	if err != nil {
		return fmt.Errorf("error while getting desiredPolicy: %s", err)
	}

	// if policy is not found, it means it somehow was not initialized correctly. let's return error
	if desiredPolicy == nil {
		return fmt.Errorf("desiredPolicy is nil, does not exist in the store")
	}

	actualState, err := server.store.GetActualState()
	if err != nil {
		return fmt.Errorf("error while getting actual state: %s", err)
	}

	eventLog := event.NewLog(fmt.Sprintf("enforce-%d-resolve", server.enforcementIdx), true)
	resolver := resolve.NewPolicyResolver(desiredPolicy, server.externalData, eventLog)
	desiredState, err := resolver.ResolveAllDependencies()
	if err != nil {
		// todo save eventlog
		server.saveErrRevision(currRevision, desiredPolicyGen)

		return fmt.Errorf("cannot resolve desiredPolicy: %s", err)
	}

	stateDiff := diff.NewPolicyResolutionDiff(desiredState, actualState)

	nextRevision, err := server.store.NewRevision(desiredPolicyGen)
	if err != nil {
		return fmt.Errorf("unable to get next revision: %s", err)
	}

	// policy changed while no actions needed to achieve desired state
	if len(stateDiff.Actions) <= 0 && currRevision != nil && currRevision.Policy == nextRevision.Policy {
		log.Infof("(enforce-%d) No changes, policy gen %d", server.enforcementIdx, desiredPolicyGen)
		return nil
	}
	log.Infof("(enforce-%d) New revision %d, policy gen %d, %d actions need to be applied", server.enforcementIdx, nextRevision.GetGeneration(), desiredPolicyGen, len(stateDiff.Actions))

	// todo save eventlog (if there were changes?)

	// todo if policy gen changed, we still need to save revision but with progress == done

	// Save revision
	err = server.store.SaveRevision(nextRevision)
	if err != nil {
		return fmt.Errorf("error while saving new revision: %s", err)
	}

	if server.cfg.Enforcer.Noop {
		log.Infof("(enforce-%d) Applying changes in noop mode (sleep per action = %s)", server.enforcementIdx, server.cfg.Enforcer.NoopSleep)
	} else {
		log.Infof("(enforce-%d) Applying changes", server.enforcementIdx)
	}

	pluginRegistry := server.pluginRegistryFactory()
	eventLog = event.NewLog(fmt.Sprintf("enforce-%d-apply", server.enforcementIdx), true)
	applier := apply.NewEngineApply(desiredPolicy, desiredState, actualState, server.store.GetActualStateUpdater(), server.externalData, pluginRegistry, stateDiff.Actions, eventLog, server.store.GetRevisionProgressUpdater(nextRevision))
	_, err = applier.Apply()

	// todo save eventlog

	if err != nil {
		return fmt.Errorf("error while applying new revision: %s", err)
	}
	log.Infof("(enforce-%d) New revision %d successfully applied, %d component instances", server.enforcementIdx, nextRevision.GetGeneration(), len(desiredState.GetComponentProcessingOrder()))

	return nil
}

func (server *Server) saveErrRevision(currRevision *engine.Revision, desiredPolicyGen runtime.Generation) {
	if currRevision == nil || currRevision.Policy != desiredPolicyGen || currRevision.Status != engine.RevisionStatusError {
		rev, revErr := server.store.NewRevision(desiredPolicyGen)
		if revErr != nil {
			log.Warnf("(enforce-%d) Error while creating revision to record resolution error: %s", server.enforcementIdx, revErr)
		}

		rev.Status = engine.RevisionStatusError
		revErr = server.store.SaveRevision(rev)
		if revErr != nil {
			log.Warnf("(enforce-%d) Error while saving revision to record resolution error: %s", server.enforcementIdx, revErr)
		}
	}
}
<|endoftext|>


<commit_before>package gol
<commit_msg>add gollog test<commit_after>package gol

import (
	"reflect"
	"testing"

	"github.com/philchia/gol/adapter"
)

var _logger = NewLogger(DEBUG)
var _loggerAdapter = new(fakeReadWriter)

func init() {

	_logger.AddLogAdapter("fake", _loggerAdapter)
	_logger.RemoveAdapter(CONSOLELOGGER)
	_logger.SetOption(LogOption(0))
}

func Test_gollog_Debug(t *testing.T) {
	type args struct {
		i []interface{}
	}
	tests := []struct {
		name string
		args args
		want []byte
	}{
		{
			"case1",
			args{
				[]interface{}{"Hello world"},
			},
			[]byte("\033[32m[DEBUG]\033[0m Hello world\n"),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			_logger.Debug(tt.args.i...)
			if got := _loggerAdapter.Read(); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("Debug() = %s, want %s", string(got), string(tt.want))
			}
		})
	}
}

func Test_gollog_Debugf(t *testing.T) {
	type args struct {
		format string
		i      []interface{}
	}
	tests := []struct {
		name string
		args args
		want []byte
	}{
		{
			"case1",
			args{
				"%s",
				[]interface{}{"Hello world"},
			},
			[]byte("\033[32m[DEBUG]\033[0m Hello world\n"),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			_logger.Debugf(tt.args.format, tt.args.i...)
			if got := _loggerAdapter.Read(); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("Debugf() = %s, want %s", string(got), string(tt.want))
			}
		})
	}
}

func Test_gollog_Info(t *testing.T) {
	type args struct {
		i []interface{}
	}
	tests := []struct {
		name string
		args args
		want []byte
	}{
		{
			"case1",
			args{
				[]interface{}{"Hello world"},
			},
			[]byte("\033[34m[INFO]\033[0m Hello world\n"),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			_logger.Info(tt.args.i...)
			if got := _loggerAdapter.Read(); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("Info() = %s, want %s", string(got), string(tt.want))
			}
		})
	}
}

func Test_gollog_Infof(t *testing.T) {
	type args struct {
		format string
		i      []interface{}
	}
	tests := []struct {
		name string
		args args
		want []byte
	}{
		{
			"case1",
			args{
				"%s",
				[]interface{}{"Hello world"},
			},
			[]byte("\033[34m[INFO]\033[0m Hello world\n"),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			_logger.Infof(tt.args.format, tt.args.i...)
			if got := _loggerAdapter.Read(); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("Infof() = %s, want %s", string(got), string(tt.want))
			}
		})
	}
}

func Test_gollog_Warn(t *testing.T) {
	type args struct {
		i []interface{}
	}
	tests := []struct {
		name string
		args args
		want []byte
	}{
		{
			"case1",
			args{
				[]interface{}{"Hello world"},
			},
			[]byte("\033[33m[WARN]\033[0m Hello world\n"),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			_logger.Warn(tt.args.i...)
			if got := _loggerAdapter.Read(); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("Warn() = %s, want %s", string(got), string(tt.want))
			}
		})
	}
}

func Test_gollog_Warnf(t *testing.T) {
	type args struct {
		format string
		i      []interface{}
	}
	tests := []struct {
		name string
		args args
		want []byte
	}{
		{
			"case1",
			args{
				"%s",
				[]interface{}{"Hello world"},
			},
			[]byte("\033[33m[WARN]\033[0m Hello world\n"),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			_logger.Warnf(tt.args.format, tt.args.i...)
			if got := _loggerAdapter.Read(); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("Warnf() = %s, want %s", string(got), string(tt.want))
			}
		})
	}
}

func Test_gollog_Error(t *testing.T) {
	type args struct {
		i []interface{}
	}
	tests := []struct {
		name string
		args args
		want []byte
	}{
		{
			"case1",
			args{
				[]interface{}{"Hello world"},
			},
			[]byte("\033[31m[ERROR]\033[0m Hello world\n"),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			_logger.Error(tt.args.i...)
			if got := _loggerAdapter.Read(); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("Error() = %s, want %s", string(got), string(tt.want))
			}
		})
	}
}

func Test_gollog_Errorf(t *testing.T) {
	type args struct {
		format string
		i      []interface{}
	}
	tests := []struct {
		name string
		args args
		want []byte
	}{
		{
			"case1",
			args{
				"%s",
				[]interface{}{"Hello world"},
			},
			[]byte("\033[31m[ERROR]\033[0m Hello world\n"),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			_logger.Errorf(tt.args.format, tt.args.i...)
			if got := _loggerAdapter.Read(); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("Errorf() = %s, want %s", string(got), string(tt.want))
			}
		})
	}
}

func Test_gollog_Critical(t *testing.T) {
	type args struct {
		i []interface{}
	}
	tests := []struct {
		name string
		args args
		want []byte
	}{
		{
			"case1",
			args{
				[]interface{}{"Hello world"},
			},
			[]byte("\033[35m[CRITICAL]\033[0m Hello world\n"),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			_logger.Critical(tt.args.i...)
			if got := _loggerAdapter.Read(); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("Critical() = %s, want %s", string(got), string(tt.want))
			}
		})
	}
}

func Test_gollog_Criticalf(t *testing.T) {
	type args struct {
		format string
		i      []interface{}
	}
	tests := []struct {
		name string
		args args
		want []byte
	}{
		{
			"case1",
			args{
				"%s",
				[]interface{}{"Hello world"},
			},
			[]byte("\033[35m[CRITICAL]\033[0m Hello world\n"),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			_logger.Criticalf(tt.args.format, tt.args.i...)
			if got := _loggerAdapter.Read(); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("Criticalf() = %s, want %s", string(got), string(tt.want))
			}
		})
	}
}

func Test_gollog_SetLevel(t *testing.T) {
	type args struct {
		level LogLevel
	}
	tests := []struct {
		name string
		args args
		want LogLevel
	}{
		{
			"case1",
			args{
				DEBUG,
			},
			DEBUG,
		},
		{
			"case2",
			args{
				WARN,
			},
			WARN,
		},
		{
			"case2",
			args{
				ERROR,
			},
			ERROR,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			_logger.SetLevel(tt.args.level)
			if got := _logger.(*gollog).level; got != tt.want {
				t.Errorf("SetLevel(level) = %d, want %d", got, tt.want)
			}
		})
	}
}

func Test_gollog_SetOption(t *testing.T) {
	type args struct {
		option LogOption
	}
	tests := []struct {
		name string
		args args
		want LogOption
	}{
		{
			"case1",
			args{
				Lmicroseconds,
			},
			Lmicroseconds,
		},
		{
			"case2",
			args{
				Ltime,
			},
			Ltime,
		},
		{
			"case3",
			args{
				Ltime | Ldate,
			},
			Ltime | Ldate,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			_logger.SetOption(tt.args.option)
			if got := _logger.(*gollog).option; got != tt.want {
				t.Errorf("SetOption(option) = %d, want %d", got, tt.want)
			}
		})
	}
}

func Test_gollog_AddLogAdapter(t *testing.T) {
	type args struct {
		name    string
		adapter adapter.Adapter
	}
	tests := []struct {
		name    string
		args    args
		wantErr bool
	}{
		{
			"case1",
			args{
				"fake1",
				new(fakeReadWriter),
			},
			false,
		},
		{
			"case2",
			args{
				"fake",
				new(fakeReadWriter),
			},
			true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := _logger.AddLogAdapter(tt.args.name, tt.args.adapter); (err != nil) != tt.wantErr {
				t.Errorf("AddLogAdapter() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func Test_gollog_RemoveAdapter(t *testing.T) {
	defer AddLogAdapter("fake", _loggerAdapter)

	type args struct {
		name string
	}
	tests := []struct {
		name    string
		args    args
		wantErr bool
	}{
		{
			"case1",
			args{
				"fake2",
			},
			true,
		},
		{
			"case2",
			args{
				"fake",
			},
			false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := _logger.RemoveAdapter(tt.args.name); (err != nil) != tt.wantErr {
				t.Errorf("RemoveAdapter() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func Test_gollog_Flush(t *testing.T) {
	tests := []struct {
		name string
		want bool
	}{
		{
			"case1",
			true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			_logger.Flush()
		})
	}
}
<|endoftext|>


<commit_before>package terminal

import (
	"fmt"
	"os"
	"reflect"
	"strconv"
	"strings"
	"text/tabwriter"

	"github.com/go-delve/delve/pkg/config"
)

func configureCmd(t *Term, ctx callContext, args string) error {
	switch args {
	case "-list":
		return configureList(t)
	case "-save":
		return config.SaveConfig(t.conf)
	case "":
		return fmt.Errorf("wrong number of arguments to \"config\"")
	default:
		err := configureSet(t, args)
		if err != nil {
			return err
		}
		if t.client != nil { // only happens in tests
			lcfg := t.loadConfig()
			t.client.SetReturnValuesLoadConfig(&lcfg)
		}
		return nil
	}
}

type configureIterator struct {
	cfgValue reflect.Value
	cfgType  reflect.Type
	i        int
}

func iterateConfiguration(conf *config.Config) *configureIterator {
	cfgValue := reflect.ValueOf(conf).Elem()
	cfgType := cfgValue.Type()

	return &configureIterator{cfgValue, cfgType, -1}
}

func (it *configureIterator) Next() bool {
	it.i++
	return it.i < it.cfgValue.NumField()
}

func (it *configureIterator) Field() (name string, field reflect.Value) {
	name = it.cfgType.Field(it.i).Tag.Get("yaml")
	if comma := strings.Index(name, ","); comma >= 0 {
		name = name[:comma]
	}
	field = it.cfgValue.Field(it.i)
	return
}

func configureFindFieldByName(conf *config.Config, name string) reflect.Value {
	it := iterateConfiguration(conf)
	for it.Next() {
		fieldName, field := it.Field()
		if fieldName == name {
			return field
		}
	}
	return reflect.ValueOf(nil)
}

func configureList(t *Term) error {
	w := new(tabwriter.Writer)
	w.Init(os.Stdout, 0, 8, 1, ' ', 0)

	it := iterateConfiguration(t.conf)
	for it.Next() {
		fieldName, field := it.Field()
		if fieldName == "" {
			continue
		}

		if field.Kind() == reflect.Ptr {
			if !field.IsNil() {
				fmt.Fprintf(w, "%s\t%v\n", fieldName, field.Elem())
			} else {
				fmt.Fprintf(w, "%s\t<not defined>\n", fieldName)
			}
		} else {
			fmt.Fprintf(w, "%s\t%v\n", fieldName, field)
		}
	}
	return w.Flush()
}

func configureSet(t *Term, args string) error {
	v := split2PartsBySpace(args)

	cfgname := v[0]
	var rest string
	if len(v) == 2 {
		rest = v[1]
	}

	if cfgname == "alias" {
		return configureSetAlias(t, rest)
	}

	field := configureFindFieldByName(t.conf, cfgname)
	if !field.CanAddr() {
		return fmt.Errorf("%q is not a configuration parameter", cfgname)
	}

	if field.Kind() == reflect.Slice && field.Type().Elem().Name() == "SubstitutePathRule" {
		return configureSetSubstitutePath(t, rest)
	}

	simpleArg := func(typ reflect.Type) (reflect.Value, error) {
		switch typ.Kind() {
		case reflect.Int:
			n, err := strconv.Atoi(rest)
			if err != nil {
				return reflect.ValueOf(nil), fmt.Errorf("argument to %q must be a number", cfgname)
			}
			if n < 0 {
				return reflect.ValueOf(nil), fmt.Errorf("argument to %q must be a number greater than zero", cfgname)
			}
			return reflect.ValueOf(&n), nil
		case reflect.Bool:
			v := rest == "true"
			return reflect.ValueOf(&v), nil
		case reflect.String:
			return reflect.ValueOf(&rest), nil
		default:
			return reflect.ValueOf(nil), fmt.Errorf("unsupported type for configuration key %q", cfgname)
		}
	}

	if field.Kind() == reflect.Ptr {
		val, err := simpleArg(field.Type().Elem())
		if err != nil {
			return err
		}
		field.Set(val)
	} else {
		val, err := simpleArg(field.Type())
		if err != nil {
			return err
		}
		field.Set(val.Elem())
	}
	return nil
}

func configureSetSubstitutePath(t *Term, rest string) error {
	argv := config.SplitQuotedFields(rest, '"')
	switch len(argv) {
	case 1: // delete substitute-path rule
		for i := range t.conf.SubstitutePath {
			if t.conf.SubstitutePath[i].From == argv[0] {
				copy(t.conf.SubstitutePath[i:], t.conf.SubstitutePath[i+1:])
				t.conf.SubstitutePath = t.conf.SubstitutePath[:len(t.conf.SubstitutePath)-1]
				return nil
			}
		}
		return fmt.Errorf("could not find rule for %q", argv[0])
	case 2: // add substitute-path rule
		for i := range t.conf.SubstitutePath {
			if t.conf.SubstitutePath[i].From == argv[0] {
				t.conf.SubstitutePath[i].To = argv[1]
				return nil
			}
		}
		t.conf.SubstitutePath = append(t.conf.SubstitutePath, config.SubstitutePathRule{From: argv[0], To: argv[1]})
	default:
		return fmt.Errorf("too many arguments to \"config substitute-path\"")
	}
	return nil
}

func configureSetAlias(t *Term, rest string) error {
	argv := config.SplitQuotedFields(rest, '"')
	switch len(argv) {
	case 1: // delete alias rule
		for k := range t.conf.Aliases {
			v := t.conf.Aliases[k]
			for i := range v {
				if v[i] == argv[0] {
					copy(v[i:], v[i+1:])
					t.conf.Aliases[k] = v[:len(v)-1]
				}
			}
		}
	case 2: // add alias rule
		alias, cmd := argv[1], argv[0]
		if t.conf.Aliases == nil {
			t.conf.Aliases = make(map[string][]string)
		}
		t.conf.Aliases[cmd] = append(t.conf.Aliases[cmd], alias)
	}
	t.cmds.Merge(t.conf.Aliases)
	return nil
}
<commit_msg>terminal: config -list should print strings in quotes (#2605)<commit_after>package terminal

import (
	"fmt"
	"os"
	"reflect"
	"strconv"
	"strings"
	"text/tabwriter"

	"github.com/go-delve/delve/pkg/config"
)

func configureCmd(t *Term, ctx callContext, args string) error {
	switch args {
	case "-list":
		return configureList(t)
	case "-save":
		return config.SaveConfig(t.conf)
	case "":
		return fmt.Errorf("wrong number of arguments to \"config\"")
	default:
		err := configureSet(t, args)
		if err != nil {
			return err
		}
		if t.client != nil { // only happens in tests
			lcfg := t.loadConfig()
			t.client.SetReturnValuesLoadConfig(&lcfg)
		}
		return nil
	}
}

type configureIterator struct {
	cfgValue reflect.Value
	cfgType  reflect.Type
	i        int
}

func iterateConfiguration(conf *config.Config) *configureIterator {
	cfgValue := reflect.ValueOf(conf).Elem()
	cfgType := cfgValue.Type()

	return &configureIterator{cfgValue, cfgType, -1}
}

func (it *configureIterator) Next() bool {
	it.i++
	return it.i < it.cfgValue.NumField()
}

func (it *configureIterator) Field() (name string, field reflect.Value) {
	name = it.cfgType.Field(it.i).Tag.Get("yaml")
	if comma := strings.Index(name, ","); comma >= 0 {
		name = name[:comma]
	}
	field = it.cfgValue.Field(it.i)
	return
}

func configureFindFieldByName(conf *config.Config, name string) reflect.Value {
	it := iterateConfiguration(conf)
	for it.Next() {
		fieldName, field := it.Field()
		if fieldName == name {
			return field
		}
	}
	return reflect.ValueOf(nil)
}

func configureList(t *Term) error {
	w := new(tabwriter.Writer)
	w.Init(os.Stdout, 0, 8, 1, ' ', 0)

	it := iterateConfiguration(t.conf)
	for it.Next() {
		fieldName, field := it.Field()
		if fieldName == "" {
			continue
		}

		switch field.Kind() {
		case reflect.Ptr:
			if !field.IsNil() {
				fmt.Fprintf(w, "%s\t%v\n", fieldName, field.Elem())
			} else {
				fmt.Fprintf(w, "%s\t<not defined>\n", fieldName)
			}
		case reflect.String:
			fmt.Fprintf(w, "%s\t%q\n", fieldName, field)
		default:
			fmt.Fprintf(w, "%s\t%v\n", fieldName, field)
		}
	}
	return w.Flush()
}

func configureSet(t *Term, args string) error {
	v := split2PartsBySpace(args)

	cfgname := v[0]
	var rest string
	if len(v) == 2 {
		rest = v[1]
	}

	if cfgname == "alias" {
		return configureSetAlias(t, rest)
	}

	field := configureFindFieldByName(t.conf, cfgname)
	if !field.CanAddr() {
		return fmt.Errorf("%q is not a configuration parameter", cfgname)
	}

	if field.Kind() == reflect.Slice && field.Type().Elem().Name() == "SubstitutePathRule" {
		return configureSetSubstitutePath(t, rest)
	}

	simpleArg := func(typ reflect.Type) (reflect.Value, error) {
		switch typ.Kind() {
		case reflect.Int:
			n, err := strconv.Atoi(rest)
			if err != nil {
				return reflect.ValueOf(nil), fmt.Errorf("argument to %q must be a number", cfgname)
			}
			if n < 0 {
				return reflect.ValueOf(nil), fmt.Errorf("argument to %q must be a number greater than zero", cfgname)
			}
			return reflect.ValueOf(&n), nil
		case reflect.Bool:
			v := rest == "true"
			return reflect.ValueOf(&v), nil
		case reflect.String:
			return reflect.ValueOf(&rest), nil
		default:
			return reflect.ValueOf(nil), fmt.Errorf("unsupported type for configuration key %q", cfgname)
		}
	}

	if field.Kind() == reflect.Ptr {
		val, err := simpleArg(field.Type().Elem())
		if err != nil {
			return err
		}
		field.Set(val)
	} else {
		val, err := simpleArg(field.Type())
		if err != nil {
			return err
		}
		field.Set(val.Elem())
	}
	return nil
}

func configureSetSubstitutePath(t *Term, rest string) error {
	argv := config.SplitQuotedFields(rest, '"')
	switch len(argv) {
	case 1: // delete substitute-path rule
		for i := range t.conf.SubstitutePath {
			if t.conf.SubstitutePath[i].From == argv[0] {
				copy(t.conf.SubstitutePath[i:], t.conf.SubstitutePath[i+1:])
				t.conf.SubstitutePath = t.conf.SubstitutePath[:len(t.conf.SubstitutePath)-1]
				return nil
			}
		}
		return fmt.Errorf("could not find rule for %q", argv[0])
	case 2: // add substitute-path rule
		for i := range t.conf.SubstitutePath {
			if t.conf.SubstitutePath[i].From == argv[0] {
				t.conf.SubstitutePath[i].To = argv[1]
				return nil
			}
		}
		t.conf.SubstitutePath = append(t.conf.SubstitutePath, config.SubstitutePathRule{From: argv[0], To: argv[1]})
	default:
		return fmt.Errorf("too many arguments to \"config substitute-path\"")
	}
	return nil
}

func configureSetAlias(t *Term, rest string) error {
	argv := config.SplitQuotedFields(rest, '"')
	switch len(argv) {
	case 1: // delete alias rule
		for k := range t.conf.Aliases {
			v := t.conf.Aliases[k]
			for i := range v {
				if v[i] == argv[0] {
					copy(v[i:], v[i+1:])
					t.conf.Aliases[k] = v[:len(v)-1]
				}
			}
		}
	case 2: // add alias rule
		alias, cmd := argv[1], argv[0]
		if t.conf.Aliases == nil {
			t.conf.Aliases = make(map[string][]string)
		}
		t.conf.Aliases[cmd] = append(t.conf.Aliases[cmd], alias)
	}
	t.cmds.Merge(t.conf.Aliases)
	return nil
}
<|endoftext|>


<commit_before>package tracing

import (
	"io"
	"strings"

	"github.com/grafana/grafana/pkg/log"
	"github.com/grafana/grafana/pkg/setting"

	opentracing "github.com/opentracing/opentracing-go"
	jaegercfg "github.com/uber/jaeger-client-go/config"
	ini "gopkg.in/ini.v1"
)

var (
	logger log.Logger = log.New("tracing")
)

type TracingSettings struct {
	Enabled      bool
	Address      string
	CustomTags   map[string]string
	SamplerType  string
	SamplerParam float64
}

func Init(file *ini.File) (io.Closer, error) {
	settings := parseSettings(file)
	return internalInit(settings)
}

func parseSettings(file *ini.File) *TracingSettings {
	settings := &TracingSettings{}

	var section, err = setting.Cfg.GetSection("tracing.jaeger")
	if err != nil {
		return settings
	}

	settings.Address = section.Key("address").MustString("")
	if settings.Address != "" {
		settings.Enabled = true
	}

	settings.CustomTags = splitTagSettings(section.Key("always_included_tag").MustString(""))
	settings.SamplerType = section.Key("sampler_type").MustString("")
	settings.SamplerParam = section.Key("sampler_param").MustFloat64(1)

	return settings
}

func internalInit(settings *TracingSettings) (io.Closer, error) {
	if !settings.Enabled {
		return &nullCloser{}, nil
	}

	cfg := jaegercfg.Configuration{
		Disabled: !settings.Enabled,
		Sampler: &jaegercfg.SamplerConfig{
			Type:  settings.SamplerType,
			Param: settings.SamplerParam,
		},
		Reporter: &jaegercfg.ReporterConfig{
			LogSpans:           false,
			LocalAgentHostPort: settings.Address,
		},
	}

	jLogger := &jaegerLogWrapper{logger: log.New("jaeger")}

	options := []jaegercfg.Option{}
	options = append(options, jaegercfg.Logger(jLogger))

	for tag, value := range settings.CustomTags {
		options = append(options, jaegercfg.Tag(tag, value))
	}

	tracer, closer, err := cfg.New("grafana", options...)
	if err != nil {
		return nil, err
	}

	opentracing.InitGlobalTracer(tracer)
	logger.Info("Initializing jaeger tracer", "address", settings.Address)
	return closer, nil
}

func splitTagSettings(input string) map[string]string {
	res := map[string]string{}

	tags := strings.Split(input, ",")
	for _, v := range tags {
		kv := strings.Split(v, ":")
		if len(kv) > 1 {
			res[kv[0]] = kv[1]
		}
	}

	return res
}

type jaegerLogWrapper struct {
	logger log.Logger
}

func (jlw *jaegerLogWrapper) Error(msg string) {
	jlw.logger.Error(msg)
}

func (jlw *jaegerLogWrapper) Infof(msg string, args ...interface{}) {
	jlw.logger.Info(msg, args)
}

type nullCloser struct{}

func (*nullCloser) Close() error { return nil }
<commit_msg>jaeger: capitalize tracer name<commit_after>package tracing

import (
	"io"
	"strings"

	"github.com/grafana/grafana/pkg/log"
	"github.com/grafana/grafana/pkg/setting"

	opentracing "github.com/opentracing/opentracing-go"
	jaegercfg "github.com/uber/jaeger-client-go/config"
	ini "gopkg.in/ini.v1"
)

var (
	logger log.Logger = log.New("tracing")
)

type TracingSettings struct {
	Enabled      bool
	Address      string
	CustomTags   map[string]string
	SamplerType  string
	SamplerParam float64
}

func Init(file *ini.File) (io.Closer, error) {
	settings := parseSettings(file)
	return internalInit(settings)
}

func parseSettings(file *ini.File) *TracingSettings {
	settings := &TracingSettings{}

	var section, err = setting.Cfg.GetSection("tracing.jaeger")
	if err != nil {
		return settings
	}

	settings.Address = section.Key("address").MustString("")
	if settings.Address != "" {
		settings.Enabled = true
	}

	settings.CustomTags = splitTagSettings(section.Key("always_included_tag").MustString(""))
	settings.SamplerType = section.Key("sampler_type").MustString("")
	settings.SamplerParam = section.Key("sampler_param").MustFloat64(1)

	return settings
}

func internalInit(settings *TracingSettings) (io.Closer, error) {
	if !settings.Enabled {
		return &nullCloser{}, nil
	}

	cfg := jaegercfg.Configuration{
		Disabled: !settings.Enabled,
		Sampler: &jaegercfg.SamplerConfig{
			Type:  settings.SamplerType,
			Param: settings.SamplerParam,
		},
		Reporter: &jaegercfg.ReporterConfig{
			LogSpans:           false,
			LocalAgentHostPort: settings.Address,
		},
	}

	jLogger := &jaegerLogWrapper{logger: log.New("jaeger")}

	options := []jaegercfg.Option{}
	options = append(options, jaegercfg.Logger(jLogger))

	for tag, value := range settings.CustomTags {
		options = append(options, jaegercfg.Tag(tag, value))
	}

	tracer, closer, err := cfg.New("grafana", options...)
	if err != nil {
		return nil, err
	}

	opentracing.InitGlobalTracer(tracer)
	logger.Info("Initializing Jaeger tracer", "address", settings.Address)
	return closer, nil
}

func splitTagSettings(input string) map[string]string {
	res := map[string]string{}

	tags := strings.Split(input, ",")
	for _, v := range tags {
		kv := strings.Split(v, ":")
		if len(kv) > 1 {
			res[kv[0]] = kv[1]
		}
	}

	return res
}

type jaegerLogWrapper struct {
	logger log.Logger
}

func (jlw *jaegerLogWrapper) Error(msg string) {
	jlw.logger.Error(msg)
}

func (jlw *jaegerLogWrapper) Infof(msg string, args ...interface{}) {
	jlw.logger.Info(msg, args)
}

type nullCloser struct{}

func (*nullCloser) Close() error { return nil }
<|endoftext|>


<commit_before>// Copyright 2014-2017 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build linux

// Package util contains various u-root utility functions.
package util

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"runtime"
	"syscall"
)

const (
	// Not all these paths may be populated or even exist but OTOH they might.
	PATHHEAD = "/ubin"
	PATHMID  = "/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/bin:/usr/local/sbin"
	PATHTAIL = "/buildbin"
	CmdsPath = "github.com/u-root/u-root/cmds"
)

type Creator interface {
	Create() error
	fmt.Stringer
}

type Dir struct {
	Name string
	Mode os.FileMode
}

func (d Dir) Create() error {
	return os.MkdirAll(d.Name, d.Mode)
}

func (d Dir) String() string {
	return fmt.Sprintf("dir %q (mode %#o)", d.Name, d.Mode)
}

type File struct {
	Name     string
	Contents string
	Mode     os.FileMode
}

func (f File) Create() error {
	return ioutil.WriteFile(f.Name, []byte(f.Contents), f.Mode)
}

func (f File) String() string {
	return fmt.Sprintf("file %q (mode %#o)", f.Name, f.Mode)
}

type Symlink struct {
	Target  string
	NewPath string
}

func (s Symlink) Create() error {
	os.Remove(s.NewPath)
	return os.Symlink(s.Target, s.NewPath)
}

func (s Symlink) String() string {
	return fmt.Sprintf("symlink %q -> %q", s.NewPath, s.Target)
}

type Link struct {
	OldPath string
	NewPath string
}

func (s Link) Create() error {
	os.Remove(s.NewPath)
	return os.Link(s.OldPath, s.NewPath)
}

func (s Link) String() string {
	return fmt.Sprintf("link %q -> %q", s.NewPath, s.OldPath)
}

type Dev struct {
	Name string
	Mode uint32
	Dev  int
}

func (d Dev) Create() error {
	os.Remove(d.Name)
	return syscall.Mknod(d.Name, d.Mode, d.Dev)
}

func (d Dev) String() string {
	return fmt.Sprintf("dev %q (mode %#o; magic %d)", d.Name, d.Mode, d.Dev)
}

type Mount struct {
	Source string
	Target string
	FSType string
	Flags  uintptr
	Opts   string
}

func (m Mount) Create() error {
	return syscall.Mount(m.Source, m.Target, m.FSType, m.Flags, m.Opts)
}

func (m Mount) String() string {
	return fmt.Sprintf("mount -t %q -o %s %q %q flags %#x", m.FSType, m.Opts, m.Source, m.Target, m.Flags)
}

var (
	namespace = []Creator{
		Dir{Name: "/buildbin", Mode: 0777},
		Dir{Name: "/ubin", Mode: 0777},
		Dir{Name: "/tmp", Mode: 0777},
		Dir{Name: "/env", Mode: 0777},
		Dir{Name: "/tcz", Mode: 0777},
		Dir{Name: "/lib", Mode: 0777},
		Dir{Name: "/usr/lib", Mode: 0777},
		Dir{Name: "/go/pkg/linux_amd64", Mode: 0777},

		Dir{Name: "/etc", Mode: 0777},
		File{Name: "/etc/resolv.conf", Contents: `nameserver 8.8.8.8`, Mode: 0644},

		Dir{Name: "/proc", Mode: 0555},
		Mount{Target: "/proc", FSType: "proc"},
		Mount{Target: "/tmp", FSType: "tmpfs"},

		Dir{Name: "/dev", Mode: 0777},
		Dev{Name: "/dev/tty", Mode: syscall.S_IFCHR | 0666, Dev: 0x0500},
		Dev{Name: "/dev/urandom", Mode: syscall.S_IFCHR | 0444, Dev: 0x0109},
		Dev{Name: "/dev/port", Mode: syscall.S_IFCHR | 0640, Dev: 0x0104},

		// Kernel must be compiled with CONFIG_DEVTMPFS.
		Mount{Target: "/dev", FSType: "devtmpfs"},
		Dir{Name: "/dev/pts", Mode: 0777},
		Mount{Target: "/dev/pts", FSType: "devpts", Opts: "newinstance,ptmxmode=666,gid=5,mode=620"},
		Symlink{NewPath: "/dev/ptmx", Target: "/dev/pts/ptmx"},

		Dir{Name: "/sys", Mode: 0555},
		Mount{Source: "sys", Target: "/sys", FSType: "sysfs"},
		Mount{Source: "cgroup", Target: "/sys/fs/cgroup", FSType: "tmpfs"},
		Dir{Name: "/sys/fs/cgroup/memory", Mode: 0555},
		Dir{Name: "/sys/fs/cgroup/freezer", Mode: 0555},
		Dir{Name: "/sys/fs/cgroup/devices", Mode: 0555},
		Dir{Name: "/sys/fs/cgroup/cpu,cpuacct", Mode: 0555},
		Symlink{NewPath: "/sys/fs/cgroup/cpu", Target: "/sys/fs/cgroup/cpu,cpuacct"},
		Symlink{NewPath: "/sys/fs/cgroup/cpuacct", Target: "/sys/fs/cgroup/cpu,cpuacct"},
		Mount{Source: "cgroup", Target: "/sys/fs/cgroup/memory", FSType: "cgroup", Opts: "memory"},
		Mount{Source: "cgroup", Target: "/sys/fs/cgroup/freezer", FSType: "cgroup", Opts: "freezer"},
		Mount{Source: "cgroup", Target: "/sys/fs/cgroup/devices", FSType: "cgroup", Opts: "devices"},
		Mount{Source: "cgroup", Target: "/sys/fs/cgroup/cpu,cpuacct", FSType: "cgroup", Opts: "cpu,cpuacct"},
	}

	Env = map[string]string{
		"LD_LIBRARY_PATH": "/usr/local/lib",
		"GOROOT":          "/go",
		"GOPATH":          "/",
		"GOBIN":           "/ubin",
		"CGO_ENABLED":     "0",
	}
)

func GoBin() string {
	return fmt.Sprintf("/go/bin/%s_%s:/go/bin:/go/pkg/tool/%s_%s", runtime.GOOS, runtime.GOARCH, runtime.GOOS, runtime.GOARCH)
}

// build the root file system.
func Rootfs() {
	Env["PATH"] = fmt.Sprintf("%v:%v:%v:%v", GoBin(), PATHHEAD, PATHMID, PATHTAIL)
	for k, v := range Env {
		os.Setenv(k, v)
	}

	for _, c := range namespace {
		if err := c.Create(); err != nil {
			log.Printf("Error creating %s: %v", c, err)
		} else {
			log.Printf("Created %v", c)
		}
	}
}
<commit_msg>chrome: mount tmpfs on /dev/shm<commit_after>// Copyright 2014-2017 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build linux

// Package util contains various u-root utility functions.
package util

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"runtime"
	"syscall"
)

const (
	// Not all these paths may be populated or even exist but OTOH they might.
	PATHHEAD = "/ubin"
	PATHMID  = "/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/bin:/usr/local/sbin"
	PATHTAIL = "/buildbin"
	CmdsPath = "github.com/u-root/u-root/cmds"
)

type Creator interface {
	Create() error
	fmt.Stringer
}

type Dir struct {
	Name string
	Mode os.FileMode
}

func (d Dir) Create() error {
	return os.MkdirAll(d.Name, d.Mode)
}

func (d Dir) String() string {
	return fmt.Sprintf("dir %q (mode %#o)", d.Name, d.Mode)
}

type File struct {
	Name     string
	Contents string
	Mode     os.FileMode
}

func (f File) Create() error {
	return ioutil.WriteFile(f.Name, []byte(f.Contents), f.Mode)
}

func (f File) String() string {
	return fmt.Sprintf("file %q (mode %#o)", f.Name, f.Mode)
}

type Symlink struct {
	Target  string
	NewPath string
}

func (s Symlink) Create() error {
	os.Remove(s.NewPath)
	return os.Symlink(s.Target, s.NewPath)
}

func (s Symlink) String() string {
	return fmt.Sprintf("symlink %q -> %q", s.NewPath, s.Target)
}

type Link struct {
	OldPath string
	NewPath string
}

func (s Link) Create() error {
	os.Remove(s.NewPath)
	return os.Link(s.OldPath, s.NewPath)
}

func (s Link) String() string {
	return fmt.Sprintf("link %q -> %q", s.NewPath, s.OldPath)
}

type Dev struct {
	Name string
	Mode uint32
	Dev  int
}

func (d Dev) Create() error {
	os.Remove(d.Name)
	return syscall.Mknod(d.Name, d.Mode, d.Dev)
}

func (d Dev) String() string {
	return fmt.Sprintf("dev %q (mode %#o; magic %d)", d.Name, d.Mode, d.Dev)
}

type Mount struct {
	Source string
	Target string
	FSType string
	Flags  uintptr
	Opts   string
}

func (m Mount) Create() error {
	return syscall.Mount(m.Source, m.Target, m.FSType, m.Flags, m.Opts)
}

func (m Mount) String() string {
	return fmt.Sprintf("mount -t %q -o %s %q %q flags %#x", m.FSType, m.Opts, m.Source, m.Target, m.Flags)
}

var (
	namespace = []Creator{
		Dir{Name: "/buildbin", Mode: 0777},
		Dir{Name: "/ubin", Mode: 0777},
		Dir{Name: "/tmp", Mode: 0777},
		Dir{Name: "/env", Mode: 0777},
		Dir{Name: "/tcz", Mode: 0777},
		Dir{Name: "/lib", Mode: 0777},
		Dir{Name: "/usr/lib", Mode: 0777},
		Dir{Name: "/go/pkg/linux_amd64", Mode: 0777},

		Dir{Name: "/etc", Mode: 0777},
		File{Name: "/etc/resolv.conf", Contents: `nameserver 8.8.8.8`, Mode: 0644},

		Dir{Name: "/proc", Mode: 0555},
		Mount{Target: "/proc", FSType: "proc"},
		Mount{Target: "/tmp", FSType: "tmpfs"},

		Dir{Name: "/dev", Mode: 0777},
		Dev{Name: "/dev/tty", Mode: syscall.S_IFCHR | 0666, Dev: 0x0500},
		Dev{Name: "/dev/urandom", Mode: syscall.S_IFCHR | 0444, Dev: 0x0109},
		Dev{Name: "/dev/port", Mode: syscall.S_IFCHR | 0640, Dev: 0x0104},

		// Kernel must be compiled with CONFIG_DEVTMPFS.
		// Note that things kind of work even if this mount fails.
		// TODO: move the Dir commands above below this line?
		Mount{Target: "/dev", FSType: "devtmpfs"},

		Dir{Name: "/dev/pts", Mode: 0777},
		Mount{Target: "/dev/pts", FSType: "devpts", Opts: "newinstance,ptmxmode=666,gid=5,mode=620"},
		Symlink{NewPath: "/dev/ptmx", Target: "/dev/pts/ptmx"},

		// Note: shm is required at least for Chrome. If you don't mount
		// it chrome throws a bogus "out of memory" error, not the more
		// useful "I can't open /dev/shm/whatever". SAD!
		Dir{Name: "/dev/shm", Mode: 0777},
		Mount{Source: "tmpfs", Target: "/dev/shm", FSType: "tmpfs"},

		Dir{Name: "/sys", Mode: 0555},
		Mount{Source: "sys", Target: "/sys", FSType: "sysfs"},
		Mount{Source: "cgroup", Target: "/sys/fs/cgroup", FSType: "tmpfs"},
		Dir{Name: "/sys/fs/cgroup/memory", Mode: 0555},
		Dir{Name: "/sys/fs/cgroup/freezer", Mode: 0555},
		Dir{Name: "/sys/fs/cgroup/devices", Mode: 0555},
		Dir{Name: "/sys/fs/cgroup/cpu,cpuacct", Mode: 0555},
		Symlink{NewPath: "/sys/fs/cgroup/cpu", Target: "/sys/fs/cgroup/cpu,cpuacct"},
		Symlink{NewPath: "/sys/fs/cgroup/cpuacct", Target: "/sys/fs/cgroup/cpu,cpuacct"},
		Mount{Source: "cgroup", Target: "/sys/fs/cgroup/memory", FSType: "cgroup", Opts: "memory"},
		Mount{Source: "cgroup", Target: "/sys/fs/cgroup/freezer", FSType: "cgroup", Opts: "freezer"},
		Mount{Source: "cgroup", Target: "/sys/fs/cgroup/devices", FSType: "cgroup", Opts: "devices"},
		Mount{Source: "cgroup", Target: "/sys/fs/cgroup/cpu,cpuacct", FSType: "cgroup", Opts: "cpu,cpuacct"},
	}

	Env = map[string]string{
		"LD_LIBRARY_PATH": "/usr/local/lib",
		"GOROOT":          "/go",
		"GOPATH":          "/",
		"GOBIN":           "/ubin",
		"CGO_ENABLED":     "0",
	}
)

func GoBin() string {
	return fmt.Sprintf("/go/bin/%s_%s:/go/bin:/go/pkg/tool/%s_%s", runtime.GOOS, runtime.GOARCH, runtime.GOOS, runtime.GOARCH)
}

// build the root file system.
func Rootfs() {
	Env["PATH"] = fmt.Sprintf("%v:%v:%v:%v", GoBin(), PATHHEAD, PATHMID, PATHTAIL)
	for k, v := range Env {
		os.Setenv(k, v)
	}

	for _, c := range namespace {
		if err := c.Create(); err != nil {
			log.Printf("Error creating %s: %v", c, err)
		} else {
			log.Printf("Created %v", c)
		}
	}
}
<|endoftext|>


<commit_before>package graph

import (
	"fmt"
	"log"
	"strings"
	"sync"
)

// Use Pointer when we need to update the struct with receiver
// https://golang.org/doc/faq#methods_on_values_or_pointers

// Data contains graph data, represented in adjacency list and slice.
type Data struct {
	Vertices []*Vertex

	sync.Mutex

	// OutEdges maps each Vertex to its outgoing edges
	OutEdges map[*Vertex][]Edge

	// InEdges maps each Vertex to its incoming edges
	InEdges map[*Vertex][]Edge

	// to prevent duplicating vertex IDs
	vertexIDs map[string]bool
}

// Vertex is a vertex(node) in Graph.
type Vertex struct {
	// ID of Vertex is assumed to be unique between vertices.
	ID string

	// Color is used for graph traversal.
	Color string

	sync.Mutex

	// Stamp stores stamp records for several graph algorithms.
	Stamp map[string]float64
}

// Edge is an edge(arc) in a graph that has direction from one to another vertex.
type Edge struct {
	// Vtx can be either source or destination
	Vtx *Vertex

	// Weight contains the weight value in float64.
	// Note that `Weight` is a single floating value.
	// Define with []float64 if we want duplicate edge values.
	Weight float64
}

// NewData returns a new Data.
func NewData() *Data {
	return &Data{
		Vertices:  []*Vertex{},
		OutEdges:  make(map[*Vertex][]Edge),
		InEdges:   make(map[*Vertex][]Edge),
		vertexIDs: make(map[string]bool),
	}
}

// NewVertex returns a new Vertex.
func NewVertex(id string) *Vertex {
	return &Vertex{
		ID:    id,
		Color: "",
		Stamp: make(map[string]float64),
	}
}

// AddVertex adds a vertex to a graph Data.
func (d *Data) AddVertex(vtx *Vertex) (bool, error) {
	if _, ok := d.vertexIDs[vtx.ID]; ok {
		return false, fmt.Errorf("`%s` already exists", vtx.ID)
	}
	d.Mutex.Lock()
	d.vertexIDs[vtx.ID] = true
	d.Mutex.Unlock()
	d.Vertices = append(d.Vertices, vtx)
	return true, nil
}

// Connect adds an edge from src to dst Vertex, to a graph Data.
func (d *Data) Connect(src, dst *Vertex, weight float64) {
	isAdded, _ := d.AddVertex(src)
	if !isAdded {
		log.Printf("`%s` was previously added to Data\n", src.ID)
		src = d.FindVertexByID(src.ID)
	} else {
		log.Printf("`%s` is added to Data\n", src.ID)
	}
	isAdded, _ = d.AddVertex(dst)
	if !isAdded {
		log.Printf("`%s` was previously added to Data\n", dst.ID)
		dst = d.FindVertexByID(dst.ID)
	} else {
		log.Printf("`%s` is added to Data\n", dst.ID)
	}
	edgeSrc := Edge{
		Vtx:    src,
		Weight: weight,
	}
	edgeDst := Edge{
		Vtx:    dst,
		Weight: weight,
	}
	d.Mutex.Lock()
	// update Outgoing Edges
	if _, ok := d.OutEdges[src]; !ok {
		d.OutEdges[src] = []Edge{edgeDst}
	} else {
		// if OutEdges already exists
		isDuplicate := false
		for idx, edge := range d.OutEdges[src] {
			// if there is a duplicate(parallel) edge
			if edge.Vtx == dst {
				log.Println("Duplicate(Parallel) Edge Found. Overwriting the Weight value.")
				log.Printf("%v --> %v + %v\n", edge.Weight, edge.Weight, weight)
				edge.Weight += weight
				d.OutEdges[src][idx] = edge
				isDuplicate = true
				break
			}
		}
		// if this is just another edge from `src` Vertex
		if !isDuplicate {
			d.OutEdges[src] = append(d.OutEdges[src], edgeDst)
		}
	}
	// update Incoming Edges
	if _, ok := d.InEdges[dst]; !ok {
		d.InEdges[dst] = []Edge{edgeSrc}
	} else {
		// if InEdges already exists
		isDuplicate := false
		for idx, edge := range d.InEdges[dst] {
			// if there is a duplicate(parallel) edge
			if edge.Vtx == src {
				log.Println("Duplicate(Parallel) Edge Found. Overwriting the Weight value.")
				log.Printf("%v --> %v + %v\n", edge.Weight, edge.Weight, weight)
				edge.Weight += weight

				// `range` iterates over values
				// Make sure to overwrite with assignment
				d.InEdges[dst][idx] = edge
				isDuplicate = true
				break
			}
		}
		// if this is just another edge to `dst` Vertex
		if !isDuplicate {
			d.InEdges[dst] = append(d.InEdges[dst], edgeSrc)
		}
	}
	d.Mutex.Unlock()
}

// Init initializes the graph Data.
func (d *Data) Init() {
	// (X) d = NewData()
	// this only updates the pointer
	//
	// Do this.
	*d = *NewData()
}

// GetVertexSize returns the size of Vertex of the graph Data.
func (d Data) GetVertexSize() int64 {
	return int64(len(d.Vertices))
}

// String describes the graph Data.
func (d Data) String() string {
	if d.GetVertexSize() == 0 {
		return "Graph is empty."
	}
	slice := []string{}
	for _, vtx := range d.Vertices {
		vtxLabel := fmt.Sprintf("Vertex: %s | ", vtx.ID)
		if _, ok := d.OutEdges[vtx]; !ok {
			slice = append(slice, fmt.Sprintf(vtxLabel+"Outgoing Edges: [%s] -- none", vtx.ID))
		} else {
			for _, edge := range d.OutEdges[vtx] {
				slice = append(slice, fmt.Sprintf(vtxLabel+"Outgoing Edges: [%s] -- %.3f --> [%s]", vtx.ID, edge.Weight, edge.Vtx.ID))
			}
		}
		if _, ok := d.InEdges[vtx]; !ok {
			slice = append(slice, fmt.Sprintf(vtxLabel+"Incoming Edges: none --> [%s]", vtx.ID))
		} else {
			for _, edge := range d.InEdges[vtx] {
				slice = append(slice, fmt.Sprintf(vtxLabel+"Incoming Edges: [%s] -- %.3f --> [%s]", edge.Vtx.ID, edge.Weight, vtx.ID))
			}
		}
	}
	return strings.Join(slice, "\n")
}

// FindVertexByID finds a Vertex by ID.
func (d Data) FindVertexByID(id string) *Vertex {
	for _, vtx := range d.Vertices {
		if vtx.ID == id {
			return vtx
		}
	}
	return nil
}

// DeleteVertex deletes a Vertex from the graph Data.
func (d *Data) DeleteVertex(vtx *Vertex) {
	// delete from d.Vertices
	for idx, elem := range d.Vertices {
		if elem == vtx {
			copy(d.Vertices[idx:], d.Vertices[idx+1:])
			d.Vertices[len(d.Vertices)-1] = nil // zero value of type or nil
			d.Vertices = d.Vertices[:len(d.Vertices)-1 : len(d.Vertices)-1]
			break
		}
	}
	// delete edges from neighbor vertex's outgoing, incoming edges
	for _, edge1 := range d.OutEdges[vtx] {
		for idx, edge2 := range d.OutEdges[edge1.Vtx] {
			if edge2.Vtx == vtx {
				copy(d.OutEdges[edge1.Vtx][idx:], d.OutEdges[edge1.Vtx][idx+1:])
				d.OutEdges[edge1.Vtx][len(d.OutEdges[edge1.Vtx])-1] = Edge{}
				d.OutEdges[edge1.Vtx] = d.OutEdges[edge1.Vtx][:len(d.OutEdges[edge1.Vtx])-1 : len(d.OutEdges[edge1.Vtx])-1]
				break
			}
		}
		for idx, edge2 := range d.InEdges[edge1.Vtx] {
			if edge2.Vtx == vtx {
				copy(d.InEdges[edge1.Vtx][idx:], d.InEdges[edge1.Vtx][idx+1:])
				d.InEdges[edge1.Vtx][len(d.InEdges[edge1.Vtx])-1] = Edge{}
				d.InEdges[edge1.Vtx] = d.InEdges[edge1.Vtx][:len(d.InEdges[edge1.Vtx])-1 : len(d.InEdges[edge1.Vtx])-1]
				break
			}
		}
	}
	for _, edge1 := range d.InEdges[vtx] {
		for idx, edge2 := range d.OutEdges[edge1.Vtx] {
			if edge2.Vtx == vtx {
				copy(d.OutEdges[edge1.Vtx][idx:], d.OutEdges[edge1.Vtx][idx+1:])
				d.OutEdges[edge1.Vtx][len(d.OutEdges[edge1.Vtx])-1] = Edge{}
				d.OutEdges[edge1.Vtx] = d.OutEdges[edge1.Vtx][:len(d.OutEdges[edge1.Vtx])-1 : len(d.OutEdges[edge1.Vtx])-1]
				break
			}
		}
		for idx, edge2 := range d.InEdges[edge1.Vtx] {
			if edge2.Vtx == vtx {
				copy(d.InEdges[edge1.Vtx][idx:], d.InEdges[edge1.Vtx][idx+1:])
				d.InEdges[edge1.Vtx][len(d.InEdges[edge1.Vtx])-1] = Edge{}
				d.InEdges[edge1.Vtx] = d.InEdges[edge1.Vtx][:len(d.InEdges[edge1.Vtx])-1 : len(d.InEdges[edge1.Vtx])-1]
				break
			}
		}
	}

	// delete from maps
	d.Mutex.Lock()
	delete(d.OutEdges, vtx)
	delete(d.InEdges, vtx)
	delete(d.vertexIDs, vtx.ID)
	d.Mutex.Unlock()
}

// DeleteEdge deletes an Edge from src to dst from the graph Data.
// This does not delete Vertices.
func (d *Data) DeleteEdge(src, dst *Vertex) {
	// delete an edge from OutEdges
	for idx, edge := range d.OutEdges[src] {
		if edge.Vtx == dst {
			copy(d.OutEdges[src][idx:], d.OutEdges[src][idx+1:])
			// d.OutEdges[src][len(d.OutEdges[src])-1] = nil // zero value of type or nil
			d.OutEdges[src][len(d.OutEdges[src])-1] = Edge{}
			d.OutEdges[src] = d.OutEdges[src][:len(d.OutEdges[src])-1 : len(d.OutEdges[src])-1]
			break
		}
	}
	// delete an edge from InEdges
	for idx, edge := range d.InEdges[dst] {
		if edge.Vtx == src {
			copy(d.InEdges[dst][idx:], d.InEdges[dst][idx+1:])
			d.InEdges[dst][len(d.InEdges[dst])-1] = Edge{}
			d.InEdges[dst] = d.InEdges[dst][:len(d.InEdges[dst])-1 : len(d.InEdges[dst])-1]
			break
		}
	}
}

// GetEdgeWeight returns the weight value of an edge from src to dst Vertex.
func (d Data) GetEdgeWeight(src, dst *Vertex) float64 {
	for _, edge := range d.OutEdges[src] {
		if edge.Vtx == dst {
			return edge.Weight
		}
	}
	return 0.0
}

// UpdateEdgeWeight overwrites an Edge's weight value.
func (d *Data) UpdateEdgeWeight(src, dst *Vertex, weight float64) {
	// `range` iterates over values
	// Make sure to overwrite with assignment
	for idx, edge := range d.OutEdges[src] {
		if edge.Vtx == dst {
			edge.Weight = weight
			d.OutEdges[src][idx] = edge
			break
		}
	}
}
<commit_msg>Update canonical import path<commit_after>package graph // import "github.com/gyuho/goraph/graph"

import (
	"fmt"
	"log"
	"strings"
	"sync"
)

// Use Pointer when we need to update the struct with receiver
// https://golang.org/doc/faq#methods_on_values_or_pointers

// Data contains graph data, represented in adjacency list and slice.
type Data struct {
	Vertices []*Vertex

	sync.Mutex

	// OutEdges maps each Vertex to its outgoing edges
	OutEdges map[*Vertex][]Edge

	// InEdges maps each Vertex to its incoming edges
	InEdges map[*Vertex][]Edge

	// to prevent duplicating vertex IDs
	vertexIDs map[string]bool
}

// Vertex is a vertex(node) in Graph.
type Vertex struct {
	// ID of Vertex is assumed to be unique between vertices.
	ID string

	// Color is used for graph traversal.
	Color string

	sync.Mutex

	// Stamp stores stamp records for several graph algorithms.
	Stamp map[string]float64
}

// Edge is an edge(arc) in a graph that has direction from one to another vertex.
type Edge struct {
	// Vtx can be either source or destination
	Vtx *Vertex

	// Weight contains the weight value in float64.
	// Note that `Weight` is a single floating value.
	// Define with []float64 if we want duplicate edge values.
	Weight float64
}

// NewData returns a new Data.
func NewData() *Data {
	return &Data{
		Vertices:  []*Vertex{},
		OutEdges:  make(map[*Vertex][]Edge),
		InEdges:   make(map[*Vertex][]Edge),
		vertexIDs: make(map[string]bool),
	}
}

// NewVertex returns a new Vertex.
func NewVertex(id string) *Vertex {
	return &Vertex{
		ID:    id,
		Color: "",
		Stamp: make(map[string]float64),
	}
}

// AddVertex adds a vertex to a graph Data.
func (d *Data) AddVertex(vtx *Vertex) (bool, error) {
	if _, ok := d.vertexIDs[vtx.ID]; ok {
		return false, fmt.Errorf("`%s` already exists", vtx.ID)
	}
	d.Mutex.Lock()
	d.vertexIDs[vtx.ID] = true
	d.Mutex.Unlock()
	d.Vertices = append(d.Vertices, vtx)
	return true, nil
}

// Connect adds an edge from src to dst Vertex, to a graph Data.
func (d *Data) Connect(src, dst *Vertex, weight float64) {
	isAdded, _ := d.AddVertex(src)
	if !isAdded {
		log.Printf("`%s` was previously added to Data\n", src.ID)
		src = d.FindVertexByID(src.ID)
	} else {
		log.Printf("`%s` is added to Data\n", src.ID)
	}
	isAdded, _ = d.AddVertex(dst)
	if !isAdded {
		log.Printf("`%s` was previously added to Data\n", dst.ID)
		dst = d.FindVertexByID(dst.ID)
	} else {
		log.Printf("`%s` is added to Data\n", dst.ID)
	}
	edgeSrc := Edge{
		Vtx:    src,
		Weight: weight,
	}
	edgeDst := Edge{
		Vtx:    dst,
		Weight: weight,
	}
	d.Mutex.Lock()
	// update Outgoing Edges
	if _, ok := d.OutEdges[src]; !ok {
		d.OutEdges[src] = []Edge{edgeDst}
	} else {
		// if OutEdges already exists
		isDuplicate := false
		for idx, edge := range d.OutEdges[src] {
			// if there is a duplicate(parallel) edge
			if edge.Vtx == dst {
				log.Println("Duplicate(Parallel) Edge Found. Overwriting the Weight value.")
				log.Printf("%v --> %v + %v\n", edge.Weight, edge.Weight, weight)
				edge.Weight += weight
				d.OutEdges[src][idx] = edge
				isDuplicate = true
				break
			}
		}
		// if this is just another edge from `src` Vertex
		if !isDuplicate {
			d.OutEdges[src] = append(d.OutEdges[src], edgeDst)
		}
	}
	// update Incoming Edges
	if _, ok := d.InEdges[dst]; !ok {
		d.InEdges[dst] = []Edge{edgeSrc}
	} else {
		// if InEdges already exists
		isDuplicate := false
		for idx, edge := range d.InEdges[dst] {
			// if there is a duplicate(parallel) edge
			if edge.Vtx == src {
				log.Println("Duplicate(Parallel) Edge Found. Overwriting the Weight value.")
				log.Printf("%v --> %v + %v\n", edge.Weight, edge.Weight, weight)
				edge.Weight += weight

				// `range` iterates over values
				// Make sure to overwrite with assignment
				d.InEdges[dst][idx] = edge
				isDuplicate = true
				break
			}
		}
		// if this is just another edge to `dst` Vertex
		if !isDuplicate {
			d.InEdges[dst] = append(d.InEdges[dst], edgeSrc)
		}
	}
	d.Mutex.Unlock()
}

// Init initializes the graph Data.
func (d *Data) Init() {
	// (X) d = NewData()
	// this only updates the pointer
	//
	// Do this.
	*d = *NewData()
}

// GetVertexSize returns the size of Vertex of the graph Data.
func (d Data) GetVertexSize() int64 {
	return int64(len(d.Vertices))
}

// String describes the graph Data.
func (d Data) String() string {
	if d.GetVertexSize() == 0 {
		return "Graph is empty."
	}
	slice := []string{}
	for _, vtx := range d.Vertices {
		vtxLabel := fmt.Sprintf("Vertex: %s | ", vtx.ID)
		if _, ok := d.OutEdges[vtx]; !ok {
			slice = append(slice, fmt.Sprintf(vtxLabel+"Outgoing Edges: [%s] -- none", vtx.ID))
		} else {
			for _, edge := range d.OutEdges[vtx] {
				slice = append(slice, fmt.Sprintf(vtxLabel+"Outgoing Edges: [%s] -- %.3f --> [%s]", vtx.ID, edge.Weight, edge.Vtx.ID))
			}
		}
		if _, ok := d.InEdges[vtx]; !ok {
			slice = append(slice, fmt.Sprintf(vtxLabel+"Incoming Edges: none --> [%s]", vtx.ID))
		} else {
			for _, edge := range d.InEdges[vtx] {
				slice = append(slice, fmt.Sprintf(vtxLabel+"Incoming Edges: [%s] -- %.3f --> [%s]", edge.Vtx.ID, edge.Weight, vtx.ID))
			}
		}
	}
	return strings.Join(slice, "\n")
}

// FindVertexByID finds a Vertex by ID.
func (d Data) FindVertexByID(id string) *Vertex {
	for _, vtx := range d.Vertices {
		if vtx.ID == id {
			return vtx
		}
	}
	return nil
}

// DeleteVertex deletes a Vertex from the graph Data.
func (d *Data) DeleteVertex(vtx *Vertex) {
	// delete from d.Vertices
	for idx, elem := range d.Vertices {
		if elem == vtx {
			copy(d.Vertices[idx:], d.Vertices[idx+1:])
			d.Vertices[len(d.Vertices)-1] = nil // zero value of type or nil
			d.Vertices = d.Vertices[:len(d.Vertices)-1 : len(d.Vertices)-1]
			break
		}
	}
	// delete edges from neighbor vertex's outgoing, incoming edges
	for _, edge1 := range d.OutEdges[vtx] {
		for idx, edge2 := range d.OutEdges[edge1.Vtx] {
			if edge2.Vtx == vtx {
				copy(d.OutEdges[edge1.Vtx][idx:], d.OutEdges[edge1.Vtx][idx+1:])
				d.OutEdges[edge1.Vtx][len(d.OutEdges[edge1.Vtx])-1] = Edge{}
				d.OutEdges[edge1.Vtx] = d.OutEdges[edge1.Vtx][:len(d.OutEdges[edge1.Vtx])-1 : len(d.OutEdges[edge1.Vtx])-1]
				break
			}
		}
		for idx, edge2 := range d.InEdges[edge1.Vtx] {
			if edge2.Vtx == vtx {
				copy(d.InEdges[edge1.Vtx][idx:], d.InEdges[edge1.Vtx][idx+1:])
				d.InEdges[edge1.Vtx][len(d.InEdges[edge1.Vtx])-1] = Edge{}
				d.InEdges[edge1.Vtx] = d.InEdges[edge1.Vtx][:len(d.InEdges[edge1.Vtx])-1 : len(d.InEdges[edge1.Vtx])-1]
				break
			}
		}
	}
	for _, edge1 := range d.InEdges[vtx] {
		for idx, edge2 := range d.OutEdges[edge1.Vtx] {
			if edge2.Vtx == vtx {
				copy(d.OutEdges[edge1.Vtx][idx:], d.OutEdges[edge1.Vtx][idx+1:])
				d.OutEdges[edge1.Vtx][len(d.OutEdges[edge1.Vtx])-1] = Edge{}
				d.OutEdges[edge1.Vtx] = d.OutEdges[edge1.Vtx][:len(d.OutEdges[edge1.Vtx])-1 : len(d.OutEdges[edge1.Vtx])-1]
				break
			}
		}
		for idx, edge2 := range d.InEdges[edge1.Vtx] {
			if edge2.Vtx == vtx {
				copy(d.InEdges[edge1.Vtx][idx:], d.InEdges[edge1.Vtx][idx+1:])
				d.InEdges[edge1.Vtx][len(d.InEdges[edge1.Vtx])-1] = Edge{}
				d.InEdges[edge1.Vtx] = d.InEdges[edge1.Vtx][:len(d.InEdges[edge1.Vtx])-1 : len(d.InEdges[edge1.Vtx])-1]
				break
			}
		}
	}

	// delete from maps
	d.Mutex.Lock()
	delete(d.OutEdges, vtx)
	delete(d.InEdges, vtx)
	delete(d.vertexIDs, vtx.ID)
	d.Mutex.Unlock()
}

// DeleteEdge deletes an Edge from src to dst from the graph Data.
// This does not delete Vertices.
func (d *Data) DeleteEdge(src, dst *Vertex) {
	// delete an edge from OutEdges
	for idx, edge := range d.OutEdges[src] {
		if edge.Vtx == dst {
			copy(d.OutEdges[src][idx:], d.OutEdges[src][idx+1:])
			// d.OutEdges[src][len(d.OutEdges[src])-1] = nil // zero value of type or nil
			d.OutEdges[src][len(d.OutEdges[src])-1] = Edge{}
			d.OutEdges[src] = d.OutEdges[src][:len(d.OutEdges[src])-1 : len(d.OutEdges[src])-1]
			break
		}
	}
	// delete an edge from InEdges
	for idx, edge := range d.InEdges[dst] {
		if edge.Vtx == src {
			copy(d.InEdges[dst][idx:], d.InEdges[dst][idx+1:])
			d.InEdges[dst][len(d.InEdges[dst])-1] = Edge{}
			d.InEdges[dst] = d.InEdges[dst][:len(d.InEdges[dst])-1 : len(d.InEdges[dst])-1]
			break
		}
	}
}

// GetEdgeWeight returns the weight value of an edge from src to dst Vertex.
func (d Data) GetEdgeWeight(src, dst *Vertex) float64 {
	for _, edge := range d.OutEdges[src] {
		if edge.Vtx == dst {
			return edge.Weight
		}
	}
	return 0.0
}

// UpdateEdgeWeight overwrites an Edge's weight value.
func (d *Data) UpdateEdgeWeight(src, dst *Vertex, weight float64) {
	// `range` iterates over values
	// Make sure to overwrite with assignment
	for idx, edge := range d.OutEdges[src] {
		if edge.Vtx == dst {
			edge.Weight = weight
			d.OutEdges[src][idx] = edge
			break
		}
	}
}
<|endoftext|>


<commit_before>package captcha_test

import (
	"github.com/leocbs/2captcha/captcha"
	"github.com/leocbs/2captcha/captcha/httpmock"
	"net/http"
	"strconv"
	"testing"
)

const testKey = "testKey"

func setUp() {
	http.DefaultTransport = httpmock.DefaultTransport
}

func TestShouldValidateEmptyKey(t *testing.T) {
	_, err := captcha.New("")
	if err == nil {
		t.Error("new captcha don't valid empty key")
	}
}

func TestShouldValidateEmptyBase64(t *testing.T) {
	twocaptcha, _ := captcha.New(testKey)
	_, err := twocaptcha.UploadBase64Image("")
	if err == nil {
		t.Error("new captcha don't valid empty base64 image")
	}
}

func TestShouldUploadBase64Image(t *testing.T) {
	setUp()
	httpmock.DefaultTransport.RegisterResponder("POST", "http://2captcha.com/in.php",
		func(req *http.Request) (*http.Response, error) {
			return &http.Response{
				Status:     strconv.Itoa(200),
				StatusCode: 200,
				Body:       httpmock.NewRespBodyFromString("OK|captchaID"),
				Header:     http.Header{},
			}, nil

		})

	twocaptcha, _ := captcha.New(testKey)
	captchaID, err := twocaptcha.UploadBase64Image("dHdvY2FwdGNoYQ==")
	if err != nil {
		t.Errorf("upload response not OK: %s", err)
	}
	if captchaID != "captchaID" {
		t.Error("upload image don't return captcha id correctly")
	}
}
<commit_msg>add tests todo<commit_after>package captcha_test

import (
	"github.com/leocbs/2captcha/captcha"
	"github.com/leocbs/2captcha/captcha/httpmock"
	"net/http"
	"strconv"
	"testing"
)

const testKey = "testKey"

func setUp() {
	http.DefaultTransport = httpmock.DefaultTransport
}

func TestShouldValidateEmptyKey(t *testing.T) {
	_, err := captcha.New("")
	if err == nil {
		t.Error("new captcha don't valid empty key")
	}
}

func TestShouldValidateEmptyBase64(t *testing.T) {
	twocaptcha, _ := captcha.New(testKey)
	_, err := twocaptcha.UploadBase64Image("")
	if err == nil {
		t.Error("new captcha don't valid empty base64 image")
	}
}

func TestShouldUploadBase64Image(t *testing.T) {
	setUp()
	httpmock.DefaultTransport.RegisterResponder("POST", "http://2captcha.com/in.php",
		func(req *http.Request) (*http.Response, error) {
			return &http.Response{
				Status:     strconv.Itoa(200),
				StatusCode: 200,
				Body:       httpmock.NewRespBodyFromString("OK|captchaID"),
				Header:     http.Header{},
			}, nil

		})

	twocaptcha, _ := captcha.New(testKey)
	captchaID, err := twocaptcha.UploadBase64Image("dHdvY2FwdGNoYQ==")
	if err != nil {
		t.Errorf("upload response not OK: %s", err)
	}
	if captchaID != "captchaID" {
		t.Error("upload image don't return captcha id correctly")
	}
}

//test nil params
//test captcha solution
//test status code different 200<|endoftext|>


<commit_before>// +build !windows

package main

import (
	"encoding/json"
	"fmt"
	"log"
	"os"
	"os/exec"
	"runtime"
	"strings"

	"github.com/taskcluster/generic-worker/process"
	"github.com/taskcluster/shell"
)

type OSUser struct {
	HomeDir  string
	Name     string
	Password string
}

type TaskContext struct {
	TaskDir string
	User    *OSUser
}

func immediateShutdown(cause string) {
	if config.ShutdownMachineOnInternalError {
		cmd := exec.Command("shutdown", "now", cause)
		err := cmd.Run()
		if err != nil {
			log.Fatal(err)
		}
	}
	os.Exit(64)
}

// we put this in init() instead of startup() as we want tests to be able to change
// it - note we shouldn't have these nasty global vars, I can only apologise, and
// say taskcluster-worker will be much nicer
func init() {
	pwd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	taskContext = &TaskContext{
		TaskDir: pwd,
	}
}

func (task *TaskRun) prepareCommand(index int) error {
	return nil
}

func (task *TaskRun) generateCommand(index int) error {
	var err error
	task.Commands[index], err = process.NewCommand(task.Payload.Command[index], taskContext.TaskDir, task.EnvVars())
	if err != nil {
		return err
	}
	task.Commands[index].DirectOutput(task.logWriter)
	return nil
}

func taskCleanup() error {
	deleteTaskDirs()
	return nil
}

func install(arguments map[string]interface{}) (err error) {
	return nil
}

func (task *TaskRun) EnvVars() []string {
	workerEnv := os.Environ()
	taskEnv := map[string]string{}
	taskEnvArray := []string{}
	for _, j := range workerEnv {
		if !strings.HasPrefix(j, "TASKCLUSTER_ACCESS_TOKEN=") {
			spl := strings.SplitN(j, "=", 2)
			if len(spl) != 2 {
				panic(fmt.Errorf("Could not interpret string %q as `key=value`", j))
			}
			taskEnv[spl[0]] = spl[1]
		}
	}
	if task.Payload.Env != nil {
		err := json.Unmarshal(task.Payload.Env, &taskEnv)
		if err != nil {
			panic(err)
		}
	}
	taskEnv["TASK_ID"] = task.TaskID
	for i, j := range taskEnv {
		taskEnvArray = append(taskEnvArray, i+"="+j)
	}
	log.Printf("Environment: %#v", taskEnvArray)
	return taskEnvArray
}

func makeDirReadable(dir string) error {
	return os.Chmod(dir, 0777)
}

func makeDirUnreadable(dir string) error {
	return os.Chmod(dir, 0700)
}

func RenameCrossDevice(oldpath, newpath string) error {
	// TODO: here we should be able to rename when oldpath and newpath are on
	// different partitions - for now this will cover 99% of cases, and we
	// currently don't have non-windows platforms in production, so not
	// currently high priority
	return os.Rename(oldpath, newpath)
}

func (task *TaskRun) addGroupsToUser(groups []string) error {
	if len(groups) == 0 {
		return nil
	}
	return fmt.Errorf("Not able to add groups %v to user on platform %v - feature not supported.", groups, runtime.GOOS)
}

func (task *TaskRun) formatCommand(index int) string {
	return shell.Escape(task.Payload.Command[index]...)
}

func prepareTaskUser(username string) {
}

func deleteTaskDir(path string) error {
	log.Print("Removing home directory '" + path + "'...")
	err := os.RemoveAll(path)
	if err != nil {
		log.Print("WARNING: could not delete directory '" + path + "'")
		log.Printf("%v", err)
		return err
	}
	return nil
}
<commit_msg>fix for linux, darwin<commit_after>// +build !windows

package main

import (
	"encoding/json"
	"fmt"
	"log"
	"os"
	"os/exec"
	"runtime"
	"strings"

	"github.com/taskcluster/generic-worker/process"
	"github.com/taskcluster/shell"
)

type OSUser struct {
	HomeDir  string
	Name     string
	Password string
}

type TaskContext struct {
	TaskDir string
	User    *OSUser
}

func immediateShutdown(cause string) {
	if config.ShutdownMachineOnInternalError {
		cmd := exec.Command("shutdown", "now", cause)
		err := cmd.Run()
		if err != nil {
			log.Fatal(err)
		}
	}
	os.Exit(64)
}

// we put this in init() instead of startup() as we want tests to be able to change
// it - note we shouldn't have these nasty global vars, I can only apologise, and
// say taskcluster-worker will be much nicer
func init() {
	pwd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	taskContext = &TaskContext{
		TaskDir: pwd,
	}
}

func (task *TaskRun) prepareCommand(index int) error {
	return nil
}

func (task *TaskRun) generateCommand(index int) error {
	var err error
	task.Commands[index], err = process.NewCommand(task.Payload.Command[index], taskContext.TaskDir, task.EnvVars())
	if err != nil {
		return err
	}
	task.Commands[index].DirectOutput(task.logWriter)
	return nil
}

func taskCleanup() error {
	if config.CleanUpTaskDirs {
		deleteTaskDirs()
	}
	return nil
}

func install(arguments map[string]interface{}) (err error) {
	return nil
}

func (task *TaskRun) EnvVars() []string {
	workerEnv := os.Environ()
	taskEnv := map[string]string{}
	taskEnvArray := []string{}
	for _, j := range workerEnv {
		if !strings.HasPrefix(j, "TASKCLUSTER_ACCESS_TOKEN=") {
			spl := strings.SplitN(j, "=", 2)
			if len(spl) != 2 {
				panic(fmt.Errorf("Could not interpret string %q as `key=value`", j))
			}
			taskEnv[spl[0]] = spl[1]
		}
	}
	if task.Payload.Env != nil {
		err := json.Unmarshal(task.Payload.Env, &taskEnv)
		if err != nil {
			panic(err)
		}
	}
	taskEnv["TASK_ID"] = task.TaskID
	for i, j := range taskEnv {
		taskEnvArray = append(taskEnvArray, i+"="+j)
	}
	log.Printf("Environment: %#v", taskEnvArray)
	return taskEnvArray
}

func makeDirReadable(dir string) error {
	return os.Chmod(dir, 0777)
}

func makeDirUnreadable(dir string) error {
	return os.Chmod(dir, 0700)
}

func RenameCrossDevice(oldpath, newpath string) error {
	// TODO: here we should be able to rename when oldpath and newpath are on
	// different partitions - for now this will cover 99% of cases, and we
	// currently don't have non-windows platforms in production, so not
	// currently high priority
	return os.Rename(oldpath, newpath)
}

func (task *TaskRun) addGroupsToUser(groups []string) error {
	if len(groups) == 0 {
		return nil
	}
	return fmt.Errorf("Not able to add groups %v to user on platform %v - feature not supported.", groups, runtime.GOOS)
}

func (task *TaskRun) formatCommand(index int) string {
	return shell.Escape(task.Payload.Command[index]...)
}

func prepareTaskUser(username string) {
}

func deleteTaskDir(path string) error {
	log.Print("Removing task directory '" + path + "'...")
	err := os.RemoveAll(path)
	if err != nil {
		log.Print("WARNING: could not delete directory '" + path + "'")
		log.Printf("%v", err)
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net"
	"net/http"
	"bufio"
	"io/ioutil"
	"strings"
)

const (
	EDGE_SERVER = "localhost:3091"
	BRIDGE_SERVER = "localhost:3093"
)

func writeErrorPage(w http.ResponseWriter) bool {
	fmt.Fprint(w, "ERROR")
	return false
}

func askBridgeForBundle(url string, w http.ResponseWriter) bool {
	remoteAddr, _ := net.ResolveTCPAddr("tcp", BRIDGE_SERVER)
	conn, err := net.DialTCP("tcp", nil, remoteAddr)
	readyMSG := []byte("READY\n")
	endMSG := []byte("END\n")
	if err != nil {
		fmt.Println("Could not establish connection to bridge server at " + BRIDGE_SERVER)
		return false // Failed to get new bundle
	}
	reader := bufio.NewReader(conn)
	conn.Write([]byte("BUNDLE " + url + "\n"))
	result, _ := reader.ReadString('\n')
	if !strings.HasPrefix(result, "COMPLETE") {
		fmt.Println("Bridge server not adhering to protocol.")
		fmt.Println("In response to BUNDLE, sent " + result)
		conn.Write(endMSG)
		conn.Close()
		return false
	}
	conn.Write(readyMSG)
	bundle, _ := ioutil.ReadAll(reader)
	w.Write(bundle)
	conn.Close()
	return true
}

func requestNewBundle(url string, w http.ResponseWriter) bool {
	success := askBridgeForBundle(url, w)
	if !success {
		return writeErrorPage(w)
	}
	return success
}

// Check if a bundle has already been cached and, if so, write it to the ResponseWriter
func readFromCache(url string, w http.ResponseWriter) bool {
	remoteAddr, _ := net.ResolveTCPAddr("tcp", EDGE_SERVER)
	conn, err := net.DialTCP("tcp", nil, remoteAddr)
	okayMSG := []byte("OKAY\n")
	readyMSG := []byte("READY\n")
	if err != nil {
		fmt.Println("Could not establish connection to edge server at " + EDGE_SERVER)
		return false // Failed to lookup
	}
	reader := bufio.NewReader(conn)
	conn.Write([]byte("LOOKUP " + url + "\n"))
	result, _ := reader.ReadString('\n')
	if !strings.HasPrefix(result, "RESULT") {
		fmt.Println("Edge server not adhering to protocol.")
		fmt.Println("In response to LOOKUP, sent " + result)
		conn.Write(okayMSG)
		conn.Close()
		return false
	}
	fmt.Println(result)
	if strings.HasSuffix(result, "not found\n") {
		fmt.Println("No bundle found in cache")
		conn.Write(okayMSG)
		conn.Close()
		return false
	} else if strings.HasSuffix(result, "found\n") {
		// TODO
		// Find a way to pipe the output from existing connection right into responseWriter
		conn.Write(readyMSG)
		bundle, _ := ioutil.ReadAll(reader)
		w.Write(bundle)
		conn.Close()
		return true
	}
	fmt.Println("Unrecognized RESULT status received from edge server")
	return false
}

// Handle requests for URLs by looking for cached bundles or requesting new ones
// be made by a bridge/transport server.
func proxyHandler(w http.ResponseWriter, r *http.Request) {
	requestedURL := r.URL.String()
	//succeeded := readFromCache(requestedURL, w)
	succeeded := requestNewBundle(requestedURL, w)
	if succeeded {
		fmt.Println("Successfully served bundle")
	} else {
		fmt.Println("Could not find bundle")
	}
}

// Create an HTTP proxy server to listen on port 3090
// TODO
// Serve a "please wait" page and store bundles for a certain amount of time
// until they are re-requested or a timeout occurs
func main() {
	http.HandleFunc("/", proxyHandler)
	fmt.Println("CeNo proxy server listening at http://localhost:3090")
	http.ListenAndServe(":3090", nil)
}<commit_msg>Implemented asynchronous bundle-fetching with memory storage for retrieved bundles waiting to be served<commit_after>package main

import (
	"fmt"
	"net"
	"net/http"
	"bufio"
	"io/ioutil"
	"strings"
	"bytes"
)

const (
	EDGE_SERVER = "localhost:3091"
	BRIDGE_SERVER = "localhost:3093"
	ERROR_MSG = "The page you requested could not be fetched at this time.\nPlease try again in a moment.\n"
)

type Process struct {
	Clients map[string]bool
	Bundle  []byte
	URL     string
}

type Request struct {
	URL    string
	Writer http.ResponseWriter
	Source string
}

func pleaseWait(url string) []byte {
	content, _ := ioutil.ReadFile("views/wait.html")
	return bytes.Replace(content, []byte("{{REDIRECT}}"), []byte(url), 1)
}

func writeErrorPage(w http.ResponseWriter) bool {
	fmt.Fprintln(w, "Unfortunately, the page you have requested cannot be fetched at this time.")
	fmt.Fprintln(w, "Please try again in a moment.")
	return false
}

// Have the Transport Server create a new bundle
func askBridgeForBundle(url string, reportCompletion chan Process) bool {
	remoteAddr, _ := net.ResolveTCPAddr("tcp", BRIDGE_SERVER)
	conn, err := net.DialTCP("tcp", nil, remoteAddr)
	readyMSG := []byte("READY\n")
	endMSG := []byte("END\n")
	if err != nil {
		fmt.Println("Could not establish connection to bridge server at " + BRIDGE_SERVER)
		return false // Failed to get new bundle
	}
	reader := bufio.NewReader(conn)
	conn.Write([]byte("BUNDLE " + url + "\n"))
	result, _ := reader.ReadString('\n')
	if !strings.HasPrefix(result, "COMPLETE") {
		fmt.Println("Bridge server not adhering to protocol.")
		fmt.Println("In response to BUNDLE, sent " + result)
		conn.Write(endMSG)
		conn.Close()
		return false
	}
	conn.Write(readyMSG)
	bundle, _ := ioutil.ReadAll(reader)
	reportCompletion <- Process { Clients: nil, Bundle: bundle, URL: url }
	conn.Close()
	return true
}

func requestNewBundle(url string, reportCompletion chan Process) bool {
	success := askBridgeForBundle(url, reportCompletion)
	if !success {
		reportCompletion <- Process { Clients: nil, Bundle: []byte(ERROR_MSG), URL: url }
	}
	return success
}

// Check if a bundle has already been cached and, if so, write it to the ResponseWriter
func readFromCache(url string, reportCompletion chan Process) bool {
	remoteAddr, _ := net.ResolveTCPAddr("tcp", EDGE_SERVER)
	conn, err := net.DialTCP("tcp", nil, remoteAddr)
	okayMSG := []byte("OKAY\n")
	readyMSG := []byte("READY\n")
	if err != nil {
		fmt.Println("Could not establish connection to edge server at " + EDGE_SERVER)
		return false // Failed to lookup
	}
	reader := bufio.NewReader(conn)
	conn.Write([]byte("LOOKUP " + url + "\n"))
	result, _ := reader.ReadString('\n')
	if !strings.HasPrefix(result, "RESULT") {
		fmt.Println("Edge server not adhering to protocol.")
		fmt.Println("In response to LOOKUP, sent " + result)
		conn.Write(okayMSG)
		conn.Close()
		return false
	}
	fmt.Println(result)
	if strings.HasSuffix(result, "not found\n") {
		fmt.Println("No bundle found in cache")
		conn.Write(okayMSG)
		conn.Close()
		return false
	} else if strings.HasSuffix(result, "found\n") {
		conn.Write(readyMSG)
		bundle, _ := ioutil.ReadAll(reader)
		reportCompletion <- Process { Clients: nil, Bundle: bundle, URL: url }
		conn.Close()
		return true
	}
	fmt.Println("Unrecognized RESULT status received from edge server")
	return false
}

func getBundle(url string, reportCompletion chan Process) {
	foundInCache := readFromCache(url, reportCompletion)
	if !foundInCache {
		producedBundle := requestNewBundle(url, reportCompletion)
		if !producedBundle {
			fmt.Println("Error; Could not produce new bundle")
		}
	}
}

func issueBundles(requests chan Request) {
	processes := make(map[string]Process)
	// Have the cache lookup and transport communicator routines commuicate when
	// new bundles have been found or produced through the this channel
	finishedProcesses := make(chan Process)
	for {
		select {
		case request := <-requests:
			_, exists := processes[request.URL]
			if exists { // We have already started processing a lookup or bundling for this URL
				if len(processes[request.URL].Bundle) > 0 { //The bundle has been prepared
					request.Writer.Write(processes[request.URL].Bundle)
					_, hasRequested := processes[request.URL].Clients[request.Source]
					if hasRequested {
						// Remove the source of the request from the set of clients
						// so we can get closer to removing the bundle from memory
						delete(processes[request.URL].Clients, request.Source)
					}
					if len(processes[request.URL].Clients) == 0 {
						// Remove the process from memory since no one is waiting on it
						delete(processes, request.URL)
					}
				} else {
					request.Writer.Write(pleaseWait(request.URL))
					_, hasRequested := processes[request.URL].Clients[request.Source]
					if !hasRequested {
						// Add the new source to the set of clients waiting for the bundle
						processes[request.URL].Clients[request.Source] = true
					}
				}
			} else {
				// Start a new process for the requested URL's bundle
				firstClient := make(map[string]bool)
				firstClient[request.Source] = true
				processes[request.URL] = Process { Clients: firstClient, Bundle: []byte(""), URL: request.URL }
				go getBundle(request.URL, finishedProcesses)
			}
		case finished := <-finishedProcesses:
			// When either a successful cache lookup completes or a new bundle is produced,
			// store the bundle's contents in an existing process to be fetched by clients
			_, stillWorking := processes[finished.URL]
			if stillWorking {
				// Cannot assign directly to a map's struct value so use this workaround
				tempProc := processes[finished.URL]
				copy(tempProc.Bundle, finished.Bundle)
				processes[finished.URL] = tempProc
			}
		}
	}
}

func makeProxyHandler(toDealer chan Request) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		// Leave it to the bundle dealer to serve the bundle or please wait page.
		// This avoids duplicating bundles in memory through a channel.
		toDealer <- Request { r.RequestURI, w, r.RemoteAddr }
	}
}

// Create an HTTP proxy server to listen on port 3090
func main() {
	toBundleDealer := make(chan Request)
	// Read requests for bundles for given URLs from toBundleDealer, serve through frBundleDealer
	go issueBundles(toBundleDealer)
	http.HandleFunc("/", makeProxyHandler(toBundleDealer))
	fmt.Println("CeNo proxy server listening at http://localhost:3090")
	http.ListenAndServe(":3090", nil)
}<|endoftext|>


<commit_before><commit_msg>Accept short aliases such as ts for timestamp<commit_after><|endoftext|>


<commit_before>// dainit is a simple init system for Linux intended for non-server uses
// (ie. for a programmer's home Linux system.)
//
// It aims to be easy to use.
package main

import (
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
	"github.com/rhaamo/lutrainit/shared/ipc"
	"github.com/go-clog/clog"
)

var (
	// LutraVersion should match the one in lutractl/main.go
	LutraVersion = "0.1"

	// StartupServices is the in-memory map list of processes started on a full-start boot
	StartupServices = make(map[ServiceType][]*Service)

	// LoadedServices is the list of services loaded, with last known state
	LoadedServices = make(map[ipc.ServiceName]*ipc.LoadedService)

	// NetFs design the list of known network file systems to be avoided mounted at boot
	NetFs = []string{"nfs", "nfs4", "smbfs", "cifs", "codafs", "ncpfs", "shfs", "fuse", "fuseblk", "glusterfs", "davfs", "fuse.glusterfs"}
	// VirtFs design the list of known virtual file systems to avoid unmounting at shutdown
	VirtFs = []string{"proc", "sysfs", "tmpfs", "devtmpfs", "devpts"}

	// Theses two last should only filled by LDFLAGS, see Makefile

	// LutraBuildTime is the time of the build
	LutraBuildTime string
	// LutraBuildGitHash is the git sha1 of the commit based on
	LutraBuildGitHash string

)

// Runs a command, setting up Stdin/Stdout/Stderr to be the standard OS
// ones, and not /dev/null. This will block until the command finishes.
func run(cmd string, args ...string) error {
	c := exec.Command(cmd, args...)
	c.Stdout = os.Stdout
	c.Stdin = os.Stdin
	c.Stderr = os.Stderr
	return c.Run()
}

// Runs a command and waits for it to finish.
func runquiet(cmd string, args ...string) error {
	c := exec.Command(cmd, args...)
	return c.Run()
}

// SetHostname set the hostname
func SetHostname(hostname []byte) {
	proc, err := os.Create("/proc/sys/kernel/hostname")
	if err != nil {
		clog.Error(2, err.Error())
		return
	}
	defer proc.Close()

	_, err = proc.Write(hostname)
	if err != nil {
		clog.Error(2, err.Error())
		return
	}
}

func main() {
	err := setupLogging(false); if err != nil {
		println("[lutra] Error: This is going bad, could not setup logging", err.Error())
		// we have no choice
		// PANIC PANIC PANIC
		os.Exit(-1)
	}

	// First of first, who are we ?
	clog.Info("~~ LutraInit %s starting...", LutraVersion)
	clog.Info("~~ Build commit %s", LutraBuildGitHash)
	clog.Info("~~ Build time %s", LutraBuildTime)

	if !thePidOne() {
		clog.Warn("[lutra] I'm sorry but I'm supposed to be run as an init.")
		os.Exit(-1)
	}

	// First of all, we need to be sure we have a correct PATH setted
	// This is usefull if we use lutrainit in an initramfs since PATH would be unset
	curEnvPath := os.Getenv("PATH")
	if len(strings.TrimSpace(curEnvPath)) == 0 {
		os.Setenv("PATH", "/usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin")
		clog.Info("[lutra] Empty $PATH, fixed.")
	}
	clog.Info("[lutra] Current $PATH is: %s", os.Getenv("PATH"))

	// Remount root as rw.
	//
	// This should be handled by mount -a according to mount(8), since the flags that
	// / is mounted with don't match /etc/fstab, but for some reason it's not remounting
	// root as rw even though it's not ro in /etc/fstab. TODO: Look into this..
	clog.Info("[lutra] Remounting root filesystem")
	Remount("/")

	// Start socket in background
	go socketInitctl()

	// Mount local filesytems
	clog.Info("[lutra] Mounting local file systems")
	MountAllExcept(NetFs)

	// Activate swap partitions, mount -a doesn't do this since they aren't really mounted anywhere
	run("swapon", "-a")

	// Set the hostname for getty to be happy.
	if hostname, err := ioutil.ReadFile("/etc/hostname"); err == nil {
		SetHostname(hostname)
	} else {
		clog.Error(2, "[lutra] Error setting hostname: %s", err.Error())
	}

	// There's a little (dare I say, a lot?) of black magic that seems to
	// happen on a modern Linux systems for filesystems.
	//
	// Time was, everything would go into /etc/fstab.
	//
	// If you read "Demystifying the init system" (https://felipec.wordpress.com/2013/11/04/init/)
	// he manually mounts /proc, /sys, /run, etc.
	//
	// When I do that on my Debian system, I get an "already mounted" error
	// despite it not being in /etc/fstab, so I don't mount them here (either
	// the kernel is doing it, or Debian is lying about init being the first
	// process.)
	//
	// However, /dev/shm is neither automounted, nor in fstab, and without it
	// Chromium won't start, so it's done manually here.
	//
	// (It should probably just go into my fstab to be honest, but then it seems
	// that I'd need to manually add it every time I install a new system..)
	Mount("tmpfs", "shm", "/dev/shm", "mode=1777,nosuid,nodev")

	// Parse Main configuration
	if err = ParseSetupConfig("/etc/lutrainit/lutra.conf"); err != nil {
		clog.Warn("[lutra] Cannot parse configuration file: %s", err.Error())
	}

	// Parse all the configs in /etc/dainit. Finally!
	err = ParseServiceConfigs("/etc/lutrainit/lutra.d", false)
	if err != nil {
		clog.Error(2, "[lutra] Cannot parse service configs: %s", err.Error())
	}

	// We finally have a filesystem mounted and the configuration is parsed
	if err := setupLogging(true); err != nil {
		clog.Error(2, "Failed to add file logging to logger: %s", err.Error())
	}
	// Start all services from StartupServices in the right Needs/Provide order
	StartServices()

	// Kick Zombies out in the background
	go reapChildren()

	Gettys(MainConfig.Autologins, MainConfig.Persist)

	// The tty exited. Kill processes, unmount filesystems and halt the system.
	doShutdown(false)
}

func thePidOne() bool {
	if os.Getpid() == 1 {
		return true
	}

	return false
}

func setupLogging(withFile bool) (err error) {
	err = clog.New(clog.CONSOLE, clog.ConsoleConfig{
		Level: clog.TRACE, // record all logs
		BufferSize: 100,     // log async, 0 is sync
	})
	if err != nil {
		println("Whoops, cannot initialize logging to console:", err.Error())
		return err
	}

	if withFile {
		err = clog.New(clog.FILE, clog.FileConfig{
			Level:      clog.TRACE,
			BufferSize: MainConfig.Log.BufferLen,
			Filename:   MainConfig.Log.Filename,
			FileRotationConfig: clog.FileRotationConfig{
				Rotate:   MainConfig.Log.Rotate,
				Daily:    MainConfig.Log.Daily,
				MaxSize:  1 << uint(MainConfig.Log.MaxSize),
				MaxLines: MainConfig.Log.MaxLines,
				MaxDays:  MainConfig.Log.MaxDays,
			},
		})
		if err != nil {
			clog.Error(2, "Cannot initialize log to file: %s", err.Error())
		}
	}
	return err
}
<commit_msg>Useless comment<commit_after>// dainit is a simple init system for Linux intended for non-server uses
// (ie. for a programmer's home Linux system.)
//
// It aims to be easy to use.
package main

import (
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
	"github.com/rhaamo/lutrainit/shared/ipc"
	"github.com/go-clog/clog"
)

var (
	// LutraVersion should match the one in lutractl/main.go
	LutraVersion = "0.1"

	// Should only be used for the FIRST startup
	// StartupServices is the in-memory map list of processes started on a full-start boot
	StartupServices = make(map[ServiceType][]*Service)

	// Used for any other actions, start, stop, etc.
	// LoadedServices is the list of services loaded, with last known state
	LoadedServices = make(map[ipc.ServiceName]*ipc.LoadedService)

	// NetFs design the list of known network file systems to be avoided mounted at boot
	NetFs = []string{"nfs", "nfs4", "smbfs", "cifs", "codafs", "ncpfs", "shfs", "fuse", "fuseblk", "glusterfs", "davfs", "fuse.glusterfs"}
	// VirtFs design the list of known virtual file systems to avoid unmounting at shutdown
	VirtFs = []string{"proc", "sysfs", "tmpfs", "devtmpfs", "devpts"}

	// Theses two last should only filled by LDFLAGS, see Makefile

	// LutraBuildTime is the time of the build
	LutraBuildTime string
	// LutraBuildGitHash is the git sha1 of the commit based on
	LutraBuildGitHash string

)

// Runs a command, setting up Stdin/Stdout/Stderr to be the standard OS
// ones, and not /dev/null. This will block until the command finishes.
func run(cmd string, args ...string) error {
	c := exec.Command(cmd, args...)
	c.Stdout = os.Stdout
	c.Stdin = os.Stdin
	c.Stderr = os.Stderr
	return c.Run()
}

// Runs a command and waits for it to finish.
func runquiet(cmd string, args ...string) error {
	c := exec.Command(cmd, args...)
	return c.Run()
}

// SetHostname set the hostname
func SetHostname(hostname []byte) {
	proc, err := os.Create("/proc/sys/kernel/hostname")
	if err != nil {
		clog.Error(2, err.Error())
		return
	}
	defer proc.Close()

	_, err = proc.Write(hostname)
	if err != nil {
		clog.Error(2, err.Error())
		return
	}
}

func main() {
	err := setupLogging(false); if err != nil {
		println("[lutra] Error: This is going bad, could not setup logging", err.Error())
		// we have no choice
		// PANIC PANIC PANIC
		os.Exit(-1)
	}

	// First of first, who are we ?
	clog.Info("~~ LutraInit %s starting...", LutraVersion)
	clog.Info("~~ Build commit %s", LutraBuildGitHash)
	clog.Info("~~ Build time %s", LutraBuildTime)

	if !thePidOne() {
		clog.Warn("[lutra] I'm sorry but I'm supposed to be run as an init.")
		os.Exit(-1)
	}

	// First of all, we need to be sure we have a correct PATH setted
	// This is usefull if we use lutrainit in an initramfs since PATH would be unset
	curEnvPath := os.Getenv("PATH")
	if len(strings.TrimSpace(curEnvPath)) == 0 {
		os.Setenv("PATH", "/usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin")
		clog.Info("[lutra] Empty $PATH, fixed.")
	}
	clog.Info("[lutra] Current $PATH is: %s", os.Getenv("PATH"))

	// Remount root as rw.
	//
	// This should be handled by mount -a according to mount(8), since the flags that
	// / is mounted with don't match /etc/fstab, but for some reason it's not remounting
	// root as rw even though it's not ro in /etc/fstab. TODO: Look into this..
	clog.Info("[lutra] Remounting root filesystem")
	Remount("/")

	// Start socket in background
	go socketInitctl()

	// Mount local filesytems
	clog.Info("[lutra] Mounting local file systems")
	MountAllExcept(NetFs)

	// Activate swap partitions, mount -a doesn't do this since they aren't really mounted anywhere
	run("swapon", "-a")

	// Set the hostname for getty to be happy.
	if hostname, err := ioutil.ReadFile("/etc/hostname"); err == nil {
		SetHostname(hostname)
	} else {
		clog.Error(2, "[lutra] Error setting hostname: %s", err.Error())
	}

	// There's a little (dare I say, a lot?) of black magic that seems to
	// happen on a modern Linux systems for filesystems.
	//
	// Time was, everything would go into /etc/fstab.
	//
	// If you read "Demystifying the init system" (https://felipec.wordpress.com/2013/11/04/init/)
	// he manually mounts /proc, /sys, /run, etc.
	//
	// When I do that on my Debian system, I get an "already mounted" error
	// despite it not being in /etc/fstab, so I don't mount them here (either
	// the kernel is doing it, or Debian is lying about init being the first
	// process.)
	//
	// However, /dev/shm is neither automounted, nor in fstab, and without it
	// Chromium won't start, so it's done manually here.
	//
	// (It should probably just go into my fstab to be honest, but then it seems
	// that I'd need to manually add it every time I install a new system..)
	Mount("tmpfs", "shm", "/dev/shm", "mode=1777,nosuid,nodev")

	// Parse Main configuration
	if err = ParseSetupConfig("/etc/lutrainit/lutra.conf"); err != nil {
		clog.Warn("[lutra] Cannot parse configuration file: %s", err.Error())
	}

	// Parse all the configs in /etc/dainit. Finally!
	err = ParseServiceConfigs("/etc/lutrainit/lutra.d", false)
	if err != nil {
		clog.Error(2, "[lutra] Cannot parse service configs: %s", err.Error())
	}

	// We finally have a filesystem mounted and the configuration is parsed
	if err := setupLogging(true); err != nil {
		clog.Error(2, "Failed to add file logging to logger: %s", err.Error())
	}
	// Start all services from StartupServices in the right Needs/Provide order
	StartServices()

	// Kick Zombies out in the background
	go reapChildren()

	Gettys(MainConfig.Autologins, MainConfig.Persist)

	// The tty exited. Kill processes, unmount filesystems and halt the system.
	doShutdown(false)
}

func thePidOne() bool {
	if os.Getpid() == 1 {
		return true
	}

	return false
}

func setupLogging(withFile bool) (err error) {
	err = clog.New(clog.CONSOLE, clog.ConsoleConfig{
		Level: clog.TRACE, // record all logs
		BufferSize: 100,     // log async, 0 is sync
	})
	if err != nil {
		println("Whoops, cannot initialize logging to console:", err.Error())
		return err
	}

	if withFile {
		err = clog.New(clog.FILE, clog.FileConfig{
			Level:      clog.TRACE,
			BufferSize: MainConfig.Log.BufferLen,
			Filename:   MainConfig.Log.Filename,
			FileRotationConfig: clog.FileRotationConfig{
				Rotate:   MainConfig.Log.Rotate,
				Daily:    MainConfig.Log.Daily,
				MaxSize:  1 << uint(MainConfig.Log.MaxSize),
				MaxLines: MainConfig.Log.MaxLines,
				MaxDays:  MainConfig.Log.MaxDays,
			},
		})
		if err != nil {
			clog.Error(2, "Cannot initialize log to file: %s", err.Error())
		}
	}
	return err
}
<|endoftext|>