<commit_before>package protomongo

import (
	"fmt"
	"reflect"
	"strconv"
	"strings"
	"sync"

	"github.com/golang/protobuf/descriptor"
	"github.com/golang/protobuf/proto"
	"go.mongodb.org/mongo-driver/bson/bsoncodec"
	"go.mongodb.org/mongo-driver/bson/bsonrw"
)

type protobufCodec struct {
	m            *sync.Mutex
	protoHelpers map[string]*protoHelper
}

// Returns a new instance of protobufCodec. protobufCodec is a MongoDB codec. It encodes protobuf objects using the protobuf
// field numbers as document keys. This means that stored protobufs can survive normal protobuf definition changes, e.g. renaming a field.
func NewProtobufCodec() *protobufCodec {
	return &protobufCodec{protoHelpers: make(map[string]*protoHelper), m: &sync.Mutex{}}
}

func (pc *protobufCodec) EncodeValue(ectx bsoncodec.EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
	origAsDescMsg := val.Interface().(descriptor.Message)
	for val.Kind() != reflect.Struct {
		val = val.Elem()
	}

	dw, err := vw.WriteDocument()
	if err != nil {
		return err
	}

	ph := pc.protoHelper(origAsDescMsg, val.Type())

	for _, prop := range ph.normalPropsByTag {
		fVal := val.FieldByName(prop.Name)
		if !fVal.IsZero() {
			if err := encodeField(ectx, dw, prop.Tag, fVal); err != nil {
				return err
			}
		}
	}

	for _, prop := range ph.oneofFieldWrapperProps {
		fVal := val.FieldByName(prop.Name)
		if !fVal.IsZero() {
			// Since this field is a oneof, we need to get the single Go value stored inside its oneof wrapper struct,
			// instead of simply using the value as-is.
			oneof := fVal.Elem().Elem()
			singleProp := proto.GetProperties(oneof.Type()).Prop[0]
			fVal = oneof.Field(0)
			if err := encodeField(ectx, dw, singleProp.Tag, fVal); err != nil {
				return err
			}
		}
	}

	return dw.WriteDocumentEnd()
}

func encodeField(ectx bsoncodec.EncodeContext, dw bsonrw.DocumentWriter, tag int, fVal reflect.Value) error {
	fvw, err := dw.WriteDocumentElement(TagToElementName(tag))
	if err != nil {
		return err
	}
	enc, err := ectx.LookupEncoder(fVal.Type())
	if err != nil {
		return err
	}
	return enc.EncodeValue(ectx, fvw, fVal)
}

func (pc *protobufCodec) DecodeValue(ectx bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
	origAsDescMsg := val.Interface().(descriptor.Message)
	if val.IsNil() {
		val.Set(reflect.New(val.Type().Elem()))
	}
	for val.Kind() != reflect.Struct {
		val = val.Elem()
	}

	dr, err := vr.ReadDocument()
	if err != nil {
		return err
	}

	ph := pc.protoHelper(origAsDescMsg, val.Type())
	for f, fvr, err := dr.ReadElement(); err != bsonrw.ErrEOD; f, fvr, err = dr.ReadElement() {
		if err != nil {
			return err
		}

		tag := elementNameToTag(f)
		prop, isNotOneOf := ph.normalPropsByTag[tag]
		oneof, isOneof := ph.oneofPropsByTag[tag]

		// Skip any field that we don't recognize.
		if !isNotOneOf && !isOneof {
			if err = vr.Skip(); err != nil {
				return err
			}
			continue
		}

		// Figure out what field we need to decode into.
		var fVal reflect.Value
		if isNotOneOf {
			fVal = val.FieldByName(prop.Name)
		} else if isOneof {
			oneofVal := reflect.New(oneof.Type.Elem())
			val.Field(oneof.Field).Set(oneofVal)
			fVal = oneofVal.Elem().Field(0)
		}

		// Actually decode the value.
		if err = lookupDecoderAndDecode(ectx, fvr, fVal); err != nil && isNotOneOf {
			// It's possible that this value was encoded as a repeated field and is now being decoded as non-repeated field,
			// or vice-versa. Since this would count as a valid protobuf change, we try to decode as the opposite type.
			// If this decoding attempt fails, we return the original decode error.
			if prop.Repeated {
				singleVal := reflect.New(fVal.Type().Elem()).Elem()
				if backupDecodeErr := lookupDecoderAndDecode(ectx, fvr, singleVal); backupDecodeErr != nil {
					return err
				}
				fVal.Set(reflect.Append(fVal, singleVal))
			} else {
				repeatedVal := reflect.New(reflect.SliceOf(fVal.Type())).Elem()
				if backupDecodeErr := lookupDecoderAndDecode(ectx, fvr, repeatedVal); backupDecodeErr != nil {
					return err
				}

				for i := 0; i < repeatedVal.Len(); i++ {
					singleVal := repeatedVal.Index(i)
					// Following the rules here at https://developers.google.com/protocol-buffers/docs/proto#updating,
					// repeated Message values must be merged into a single value.
					if _, fieldIsMessage := fVal.Interface().(proto.Message); fieldIsMessage {
						proto.Merge(fVal.Interface().(proto.Message), singleVal.Interface().(proto.Message))
					} else {
						fVal.Set(singleVal)
					}
				}
			}
		}
	}

	return nil
}

func lookupDecoderAndDecode(ectx bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
	enc, err := ectx.LookupDecoder(val.Type())
	if err != nil {
		return err
	}
	return enc.DecodeValue(ectx, vr, val)
}

type protoHelper struct {
	// Properties corresponding to 'normal' (non-oneof) protobuf fields.
	// Indexed by protobuf tag number (as a string).
	normalPropsByTag map[string]*proto.Properties
	// OneofProperties corresponding to oneof protobuf fields.
	// Indexed by protobuf tag number (as a string).
	oneofPropsByTag map[string]*proto.OneofProperties

	// Properties corresponding to Go wrapper types for protobuf oneof declarations.
	oneofFieldWrapperProps []*proto.Properties
}

func (pc *protobufCodec) protoHelper(pb descriptor.Message, t reflect.Type) *protoHelper {
	// Try to load a pre-existing protoHelper from cache, if it exists.
	messageName := proto.MessageName(pb)
	if ph, ok := pc.protoHelpers[messageName]; ok {
		return ph
	}

	// Find the names of all oneofs.
	_, msgDescriptor := descriptor.ForMessage(pb)
	oneofNames := make(map[string]bool)
	for _, oneof := range msgDescriptor.OneofDecl {
		oneofNames[*oneof.Name] = true
	}

	// Get the corresponding Go type's Properties, and divide them into three groups.
	// See comments on 'protoHelper' for details.
	props := proto.GetProperties(t)
	oneofFieldWrapperProps := make([]*proto.Properties, 0)
	normalPropsByTag := make(map[string]*proto.Properties)
	for _, prop := range props.Prop {
		if oneofNames[prop.OrigName] {
			oneofFieldWrapperProps = append(oneofFieldWrapperProps, prop)
		} else {
			normalPropsByTag[strconv.Itoa(prop.Tag)] = prop
		}
	}
	oneofPropsByTag := make(map[string]*proto.OneofProperties)
	for _, oneof := range props.OneofTypes {
		oneofPropsByTag[strconv.Itoa(oneof.Prop.Tag)] = oneof
	}
	ph := &protoHelper{normalPropsByTag, oneofPropsByTag, oneofFieldWrapperProps}

	pc.m.Lock()
	defer pc.m.Unlock()
	pc.protoHelpers[messageName] = ph

	return ph
}

const (
	tagPrefix = "PBTag_"
)

func TagToElementName(tag int) string {
	return fmt.Sprintf("%v%v", tagPrefix, tag)
}

func elementNameToTag(elementName string) string {
	return strings.Replace(elementName, tagPrefix, "", 1)
}
<commit_msg>Fix protomongo map access to be correctly locked for reads. (#740)<commit_after>package protomongo

import (
	"fmt"
	"reflect"
	"strconv"
	"strings"
	"sync"

	"github.com/golang/protobuf/descriptor"
	"github.com/golang/protobuf/proto"
	"go.mongodb.org/mongo-driver/bson/bsoncodec"
	"go.mongodb.org/mongo-driver/bson/bsonrw"
)

type protobufCodec struct {
	m            *sync.RWMutex
	protoHelpers map[string]*protoHelper
}

// Returns a new instance of protobufCodec. protobufCodec is a MongoDB codec. It encodes protobuf objects using the protobuf
// field numbers as document keys. This means that stored protobufs can survive normal protobuf definition changes, e.g. renaming a field.
func NewProtobufCodec() *protobufCodec {
	return &protobufCodec{protoHelpers: make(map[string]*protoHelper), m: &sync.RWMutex{}}
}

func (pc *protobufCodec) EncodeValue(ectx bsoncodec.EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
	origAsDescMsg := val.Interface().(descriptor.Message)
	for val.Kind() != reflect.Struct {
		val = val.Elem()
	}

	dw, err := vw.WriteDocument()
	if err != nil {
		return err
	}

	ph := pc.protoHelper(origAsDescMsg, val.Type())

	for _, prop := range ph.normalPropsByTag {
		fVal := val.FieldByName(prop.Name)
		if !fVal.IsZero() {
			if err := encodeField(ectx, dw, prop.Tag, fVal); err != nil {
				return err
			}
		}
	}

	for _, prop := range ph.oneofFieldWrapperProps {
		fVal := val.FieldByName(prop.Name)
		if !fVal.IsZero() {
			// Since this field is a oneof, we need to get the single Go value stored inside its oneof wrapper struct,
			// instead of simply using the value as-is.
			oneof := fVal.Elem().Elem()
			singleProp := proto.GetProperties(oneof.Type()).Prop[0]
			fVal = oneof.Field(0)
			if err := encodeField(ectx, dw, singleProp.Tag, fVal); err != nil {
				return err
			}
		}
	}

	return dw.WriteDocumentEnd()
}

func encodeField(ectx bsoncodec.EncodeContext, dw bsonrw.DocumentWriter, tag int, fVal reflect.Value) error {
	fvw, err := dw.WriteDocumentElement(TagToElementName(tag))
	if err != nil {
		return err
	}
	enc, err := ectx.LookupEncoder(fVal.Type())
	if err != nil {
		return err
	}
	return enc.EncodeValue(ectx, fvw, fVal)
}

func (pc *protobufCodec) DecodeValue(ectx bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
	origAsDescMsg := val.Interface().(descriptor.Message)
	if val.IsNil() {
		val.Set(reflect.New(val.Type().Elem()))
	}
	for val.Kind() != reflect.Struct {
		val = val.Elem()
	}

	dr, err := vr.ReadDocument()
	if err != nil {
		return err
	}

	ph := pc.protoHelper(origAsDescMsg, val.Type())
	for f, fvr, err := dr.ReadElement(); err != bsonrw.ErrEOD; f, fvr, err = dr.ReadElement() {
		if err != nil {
			return err
		}

		tag := elementNameToTag(f)
		prop, isNotOneOf := ph.normalPropsByTag[tag]
		oneof, isOneof := ph.oneofPropsByTag[tag]

		// Skip any field that we don't recognize.
		if !isNotOneOf && !isOneof {
			if err = vr.Skip(); err != nil {
				return err
			}
			continue
		}

		// Figure out what field we need to decode into.
		var fVal reflect.Value
		if isNotOneOf {
			fVal = val.FieldByName(prop.Name)
		} else if isOneof {
			oneofVal := reflect.New(oneof.Type.Elem())
			val.Field(oneof.Field).Set(oneofVal)
			fVal = oneofVal.Elem().Field(0)
		}

		// Actually decode the value.
		if err = lookupDecoderAndDecode(ectx, fvr, fVal); err != nil && isNotOneOf {
			// It's possible that this value was encoded as a repeated field and is now being decoded as non-repeated field,
			// or vice-versa. Since this would count as a valid protobuf change, we try to decode as the opposite type.
			// If this decoding attempt fails, we return the original decode error.
			if prop.Repeated {
				singleVal := reflect.New(fVal.Type().Elem()).Elem()
				if backupDecodeErr := lookupDecoderAndDecode(ectx, fvr, singleVal); backupDecodeErr != nil {
					return err
				}
				fVal.Set(reflect.Append(fVal, singleVal))
			} else {
				repeatedVal := reflect.New(reflect.SliceOf(fVal.Type())).Elem()
				if backupDecodeErr := lookupDecoderAndDecode(ectx, fvr, repeatedVal); backupDecodeErr != nil {
					return err
				}

				for i := 0; i < repeatedVal.Len(); i++ {
					singleVal := repeatedVal.Index(i)
					// Following the rules here at https://developers.google.com/protocol-buffers/docs/proto#updating,
					// repeated Message values must be merged into a single value.
					if _, fieldIsMessage := fVal.Interface().(proto.Message); fieldIsMessage {
						proto.Merge(fVal.Interface().(proto.Message), singleVal.Interface().(proto.Message))
					} else {
						fVal.Set(singleVal)
					}
				}
			}
		}
	}

	return nil
}

func lookupDecoderAndDecode(ectx bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
	enc, err := ectx.LookupDecoder(val.Type())
	if err != nil {
		return err
	}
	return enc.DecodeValue(ectx, vr, val)
}

type protoHelper struct {
	// Properties corresponding to 'normal' (non-oneof) protobuf fields.
	// Indexed by protobuf tag number (as a string).
	normalPropsByTag map[string]*proto.Properties
	// OneofProperties corresponding to oneof protobuf fields.
	// Indexed by protobuf tag number (as a string).
	oneofPropsByTag map[string]*proto.OneofProperties

	// Properties corresponding to Go wrapper types for protobuf oneof declarations.
	oneofFieldWrapperProps []*proto.Properties
}

func (pc *protobufCodec) protoHelper(pb descriptor.Message, t reflect.Type) *protoHelper {
	// Try to load a pre-existing protoHelper from cache, if it exists.
	messageName := proto.MessageName(pb)
	if ph, ok := pc.lockedGetProtoHelper(messageName); ok {
		return ph
	}

	// Find the names of all oneofs.
	_, msgDescriptor := descriptor.ForMessage(pb)
	oneofNames := make(map[string]bool)
	for _, oneof := range msgDescriptor.OneofDecl {
		oneofNames[*oneof.Name] = true
	}

	// Get the corresponding Go type's Properties, and divide them into three groups.
	// See comments on 'protoHelper' for details.
	props := proto.GetProperties(t)
	oneofFieldWrapperProps := make([]*proto.Properties, 0)
	normalPropsByTag := make(map[string]*proto.Properties)
	for _, prop := range props.Prop {
		if oneofNames[prop.OrigName] {
			oneofFieldWrapperProps = append(oneofFieldWrapperProps, prop)
		} else {
			normalPropsByTag[strconv.Itoa(prop.Tag)] = prop
		}
	}
	oneofPropsByTag := make(map[string]*proto.OneofProperties)
	for _, oneof := range props.OneofTypes {
		oneofPropsByTag[strconv.Itoa(oneof.Prop.Tag)] = oneof
	}
	ph := &protoHelper{normalPropsByTag, oneofPropsByTag, oneofFieldWrapperProps}
	pc.lockedSetProtoHelper(messageName, ph)
	return ph
}

func (pc *protobufCodec) lockedGetProtoHelper(messageName string) (*protoHelper, bool) {
	pc.m.RLock()
	defer pc.m.RUnlock()
	ph, ok := pc.protoHelpers[messageName]
	return ph, ok
}

func (pc *protobufCodec) lockedSetProtoHelper(messageName string, ph *protoHelper) {
	pc.m.Lock()
	defer pc.m.Unlock()
	pc.protoHelpers[messageName] = ph
}

const (
	tagPrefix = "PBTag_"
)

func TagToElementName(tag int) string {
	return fmt.Sprintf("%v%v", tagPrefix, tag)
}

func elementNameToTag(elementName string) string {
	return strings.Replace(elementName, tagPrefix, "", 1)
}
<|endoftext|>


<commit_before>// +build !windows

// This file contains a simple and incomplete implementation of the terminfo
// database. Information was taken from the ncurses manpages term(5) and
// terminfo(5). Currently, only the string capabilities for special keys and for
// functions without parameters are actually used. Colors are still done with
// ANSI escape sequences. Other special features that are not (yet?) supported
// are reading from ~/.terminfo, the TERMINFO_DIRS variable, Berkeley database
// format and extended capabilities.

package keyboard

import (
    "bytes"
    "encoding/binary"
    "os"
    "errors"
    "strings"
    "io/ioutil"
    "encoding/hex"
)

const (
    ti_header_length = 12
)

var (
    eterm_keys = []string{
        "\x1b[11~", "\x1b[12~", "\x1b[13~", "\x1b[14~", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[7~", "\x1b[8~", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C",
    }
    screen_keys = []string{
        "\x1bOP", "\x1bOQ", "\x1bOR", "\x1bOS", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[1~", "\x1b[4~", "\x1b[5~", "\x1b[6~", "\x1bOA", "\x1bOB", "\x1bOD", "\x1bOC",
    }
    xterm_keys = []string{
        "\x1bOP", "\x1bOQ", "\x1bOR", "\x1bOS", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1bOH", "\x1bOF", "\x1b[5~", "\x1b[6~", "\x1bOA", "\x1bOB", "\x1bOD", "\x1bOC",
    }
    rxvt_unicode_keys = []string{
        "\x1b[11~", "\x1b[12~", "\x1b[13~", "\x1b[14~", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[7~", "\x1b[8~", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C",
    }
    linux_keys = []string{
        "\x1b[[A", "\x1b[[B", "\x1b[[C", "\x1b[[D", "\x1b[[E", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[1~", "\x1b[4~", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C",
    }
    rxvt_256color_keys = []string{
        "\x1b[11~", "\x1b[12~", "\x1b[13~", "\x1b[14~", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[7~", "\x1b[8~", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C",
    }

    terms = []struct {
        name  string
        keys  []string
    }{
        {"Eterm", eterm_keys},
        {"screen", screen_keys},
        {"xterm", xterm_keys},
        {"rxvt-unicode", rxvt_unicode_keys},
        {"linux", linux_keys},
        {"rxvt-256color", rxvt_256color_keys},
    }
)

func load_terminfo() ([]byte, error) {
    var data []byte
    var err error

    term := os.Getenv("TERM")
    if term == "" {
        return nil, errors.New("termbox: TERM not set")
    }

    // The following behaviour follows the one described in terminfo(5) as
    // distributed by ncurses.

    terminfo := os.Getenv("TERMINFO")
    if terminfo != "" {
        // if TERMINFO is set, no other directory should be searched
        return ti_try_path(terminfo)
    }

    // next, consider ~/.terminfo
    home := os.Getenv("HOME")
    if home != "" {
        data, err = ti_try_path(home + "/.terminfo")
        if err == nil {
            return data, nil
        }
    }

    // next, TERMINFO_DIRS
    dirs := os.Getenv("TERMINFO_DIRS")
    if dirs != "" {
        for _, dir := range strings.Split(dirs, ":") {
            if dir == "" {
                // "" -> "/usr/share/terminfo"
                dir = "/usr/share/terminfo"
            }
            data, err = ti_try_path(dir)
            if err == nil {
                return data, nil
            }
        }
    }

    // fall back to /usr/share/terminfo
    return ti_try_path("/usr/share/terminfo")
}

func ti_try_path(path string) (data []byte, err error) {
    // load_terminfo already made sure it is set
    term := os.Getenv("TERM")

    // first try, the typical *nix path
    terminfo := path + "/" + term[0:1] + "/" + term
    data, err = ioutil.ReadFile(terminfo)
    if err == nil {
        return
    }

    // fallback to darwin specific dirs structure
    terminfo = path + "/" + hex.EncodeToString([]byte(term[:1])) + "/" + term
    data, err = ioutil.ReadFile(terminfo)
    return
}

func setup_term_builtin() error {
    name := os.Getenv("TERM")
    if name == "" {
        return errors.New("termbox: TERM environment variable not set")
    }

    for _, t := range terms {
        if t.name == name {
            keys = t.keys
            return nil
        }
    }

    compat_table := []struct {
        partial string
        keys    []string
    }{
        {"xterm", xterm_keys},
        {"rxvt", rxvt_unicode_keys},
        {"linux", linux_keys},
        {"Eterm", eterm_keys},
        {"screen", screen_keys},
        // let's assume that 'cygwin' is xterm compatible
        {"cygwin", xterm_keys},
        {"st", xterm_keys},
    }

    // try compatibility variants
    for _, it := range compat_table {
        if strings.Contains(name, it.partial) {
            keys = it.keys
            return nil
        }
    }

    return errors.New("termbox: unsupported terminal")
}

func ti_read_string(rd *bytes.Reader, str_off, table int16) (string, error) {
    var off int16

    _, err := rd.Seek(int64(str_off), 0)
    if err != nil {
        return "", err
    }
    err = binary.Read(rd, binary.LittleEndian, &off)
    if err != nil {
        return "", err
    }
    _, err = rd.Seek(int64(table+off), 0)
    if err != nil {
        return "", err
    }
    var bs []byte
    for {
        b, err := rd.ReadByte()
        if err != nil {
            return "", err
        }
        if b == byte(0x00) {
            break
        }
        bs = append(bs, b)
    }
    return string(bs), nil
}

func setup_term() (err error) {
    var data []byte
    var header [6]int16
    var str_offset, table_offset int16

    data, err = load_terminfo()
    if err != nil {
        return setup_term_builtin()
    }

    rd := bytes.NewReader(data)
    // 0: magic number, 1: size of names section, 2: size of boolean section, 3:
    // size of numbers section (in integers), 4: size of the strings section (in
    // integers), 5: size of the string table

    err = binary.Read(rd, binary.LittleEndian, header[:])
    if err != nil {
        return
    }

    if (header[1]+header[2])%2 != 0 {
        // old quirk to align everything on word boundaries
        header[2] += 1
    }
    str_offset = ti_header_length + header[1] + header[2] + 2*header[3]
    table_offset = str_offset + 2*header[4]

    // "Maps" the special keys constants from termbox.go to the number of the respective
    // string capability in the terminfo file. Taken from (ncurses) term.h.
    ti_keys := []int16{
        66, 68 /* apparently not a typo; 67 is F10 for whatever reason */, 69, 70,
        71, 72, 73, 74, 75, 67, 216, 217, 77, 59, 76, 164, 82, 81, 87, 61, 79, 83,
    }

    keys = make([]string, 0xFFFF-key_min)
    for i := range keys {
        keys[i], err = ti_read_string(rd, str_offset+2*ti_keys[i], table_offset)
        if err != nil {
            return
        }
    }
    return nil
}<commit_msg>Added support for xterm-256color (Ubuntu)<commit_after>// +build !windows

// This file contains a simple and incomplete implementation of the terminfo
// database. Information was taken from the ncurses manpages term(5) and
// terminfo(5). Currently, only the string capabilities for special keys and for
// functions without parameters are actually used. Colors are still done with
// ANSI escape sequences. Other special features that are not (yet?) supported
// are reading from ~/.terminfo, the TERMINFO_DIRS variable, Berkeley database
// format and extended capabilities.

package keyboard

import (
    "bytes"
    "encoding/binary"
    "os"
    "errors"
    "strings"
    "io/ioutil"
    "encoding/hex"
)

const (
    ti_header_length = 12
)

var (
    eterm_keys = []string{
        "\x1b[11~", "\x1b[12~", "\x1b[13~", "\x1b[14~", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[7~", "\x1b[8~", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C",
    }
    screen_keys = []string{
        "\x1bOP", "\x1bOQ", "\x1bOR", "\x1bOS", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[1~", "\x1b[4~", "\x1b[5~", "\x1b[6~", "\x1bOA", "\x1bOB", "\x1bOD", "\x1bOC",
    }
    xterm_keys = []string{
        "\x1bOP", "\x1bOQ", "\x1bOR", "\x1bOS", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1bOH", "\x1bOF", "\x1b[5~", "\x1b[6~", "\x1bOA", "\x1bOB", "\x1bOD", "\x1bOC",
    }
    xterm_256color_keys = []string{
        "\x1bOP", "\x1bOQ", "\x1bOR", "\x1bOS", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[H", "\x1b[F", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C",
    }
    rxvt_unicode_keys = []string{
        "\x1b[11~", "\x1b[12~", "\x1b[13~", "\x1b[14~", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[7~", "\x1b[8~", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C",
    }
    linux_keys = []string{
        "\x1b[[A", "\x1b[[B", "\x1b[[C", "\x1b[[D", "\x1b[[E", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[1~", "\x1b[4~", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C",
    }
    rxvt_256color_keys = []string{
        "\x1b[11~", "\x1b[12~", "\x1b[13~", "\x1b[14~", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[7~", "\x1b[8~", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C",
    }

    terms = []struct {
        name  string
        keys  []string
    }{
        {"Eterm", eterm_keys},
        {"screen", screen_keys},
        {"xterm", xterm_keys},
        {"xterm-256color", xterm_256color_keys},
        {"rxvt-unicode", rxvt_unicode_keys},
        {"linux", linux_keys},
        {"rxvt-256color", rxvt_256color_keys},
    }
)

func load_terminfo() ([]byte, error) {
    var data []byte
    var err error

    term := os.Getenv("TERM")
    if term == "" {
        return nil, errors.New("termbox: TERM not set")
    }

    // The following behaviour follows the one described in terminfo(5) as
    // distributed by ncurses.

    terminfo := os.Getenv("TERMINFO")
    if terminfo != "" {
        // if TERMINFO is set, no other directory should be searched
        return ti_try_path(terminfo)
    }

    // next, consider ~/.terminfo
    home := os.Getenv("HOME")
    if home != "" {
        data, err = ti_try_path(home + "/.terminfo")
        if err == nil {
            return data, nil
        }
    }

    // next, TERMINFO_DIRS
    dirs := os.Getenv("TERMINFO_DIRS")
    if dirs != "" {
        for _, dir := range strings.Split(dirs, ":") {
            if dir == "" {
                // "" -> "/usr/share/terminfo"
                dir = "/usr/share/terminfo"
            }
            data, err = ti_try_path(dir)
            if err == nil {
                return data, nil
            }
        }
    }

    // fall back to /usr/share/terminfo
    return ti_try_path("/usr/share/terminfo")
}

func ti_try_path(path string) (data []byte, err error) {
    // load_terminfo already made sure it is set
    term := os.Getenv("TERM")

    // first try, the typical *nix path
    terminfo := path + "/" + term[0:1] + "/" + term
    data, err = ioutil.ReadFile(terminfo)
    if err == nil {
        return
    }

    // fallback to darwin specific dirs structure
    terminfo = path + "/" + hex.EncodeToString([]byte(term[:1])) + "/" + term
    data, err = ioutil.ReadFile(terminfo)
    return
}

func setup_term_builtin() error {
    name := os.Getenv("TERM")
    if name == "" {
        return errors.New("termbox: TERM environment variable not set")
    }

    for _, t := range terms {
        if t.name == name {
            keys = t.keys
            return nil
        }
    }

    compat_table := []struct {
        partial string
        keys    []string
    }{
        {"xterm", xterm_keys},
        {"rxvt", rxvt_unicode_keys},
        {"linux", linux_keys},
        {"Eterm", eterm_keys},
        {"screen", screen_keys},
        // let's assume that 'cygwin' is xterm compatible
        {"cygwin", xterm_keys},
        {"st", xterm_keys},
    }

    // try compatibility variants
    for _, it := range compat_table {
        if strings.Contains(name, it.partial) {
            keys = it.keys
            return nil
        }
    }

    return errors.New("termbox: unsupported terminal")
}

func ti_read_string(rd *bytes.Reader, str_off, table int16) (string, error) {
    var off int16

    _, err := rd.Seek(int64(str_off), 0)
    if err != nil {
        return "", err
    }
    err = binary.Read(rd, binary.LittleEndian, &off)
    if err != nil {
        return "", err
    }
    _, err = rd.Seek(int64(table+off), 0)
    if err != nil {
        return "", err
    }
    var bs []byte
    for {
        b, err := rd.ReadByte()
        if err != nil {
            return "", err
        }
        if b == byte(0x00) {
            break
        }
        bs = append(bs, b)
    }
    return string(bs), nil
}

func setup_term() (err error) {
    var data []byte
    var header [6]int16
    var str_offset, table_offset int16

    data, err = load_terminfo()
    if err != nil {
        return setup_term_builtin()
    }

    rd := bytes.NewReader(data)
    // 0: magic number, 1: size of names section, 2: size of boolean section, 3:
    // size of numbers section (in integers), 4: size of the strings section (in
    // integers), 5: size of the string table

    err = binary.Read(rd, binary.LittleEndian, header[:])
    if err != nil {
        return
    }

    if (header[1]+header[2])%2 != 0 {
        // old quirk to align everything on word boundaries
        header[2] += 1
    }
    str_offset = ti_header_length + header[1] + header[2] + 2*header[3]
    table_offset = str_offset + 2*header[4]

    // "Maps" the special keys constants from termbox.go to the number of the respective
    // string capability in the terminfo file. Taken from (ncurses) term.h.
    ti_keys := []int16{
        66, 68 /* apparently not a typo; 67 is F10 for whatever reason */, 69, 70,
        71, 72, 73, 74, 75, 67, 216, 217, 77, 59, 76, 164, 82, 81, 87, 61, 79, 83,
    }

    keys = make([]string, 0xFFFF-key_min)
    for i := range keys {
        keys[i], err = ti_read_string(rd, str_offset+2*ti_keys[i], table_offset)
        if err != nil {
            return
        }
    }
    return nil
}<|endoftext|>


<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package local

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

	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/instance"
	"launchpad.net/juju-core/schema"
	"launchpad.net/juju-core/utils"
)

var checkIfRoot = func() bool {
	return os.Getuid() == 0
}

const (
	containerConfigKey = "container"
	containerDefault   = "lxc"
)

var (
	configFields = schema.Fields{
		"root-dir":            schema.String(),
		"bootstrap-ip":        schema.String(),
		"network-bridge":      schema.String(),
		containerConfigKey:    schema.String(),
		"storage-port":        schema.ForceInt(),
		"shared-storage-port": schema.ForceInt(),
	}
	// The port defaults below are not entirely arbitrary.  Local user web
	// frameworks often use 8000 or 8080, so I didn't want to use either of
	// these, but did want the familiarity of using something in the 8000
	// range.
	configDefaults = schema.Defaults{
		"root-dir":            "",
		"network-bridge":      "lxcbr0",
		containerConfigKey:    containerDefault,
		"bootstrap-ip":        schema.Omit,
		"storage-port":        8040,
		"shared-storage-port": 8041,
	}
)

type environConfig struct {
	*config.Config
	user          string
	attrs         map[string]interface{}
	runningAsRoot bool
}

func newEnvironConfig(config *config.Config, attrs map[string]interface{}) *environConfig {
	user := os.Getenv("USER")
	root := checkIfRoot()
	if root {
		sudo_user := os.Getenv("SUDO_USER")
		if sudo_user != "" {
			user = sudo_user
		}
	}
	return &environConfig{
		Config:        config,
		user:          user,
		attrs:         attrs,
		runningAsRoot: root,
	}
}

// Since it is technically possible for two different users on one machine to
// have the same local provider name, we need to have a simple way to
// namespace the file locations, but more importantly the containers.
func (c *environConfig) namespace() string {
	return fmt.Sprintf("%s-%s", c.user, c.Name())
}

func (c *environConfig) rootDir() string {
	return c.attrs["root-dir"].(string)
}

func (c *environConfig) container() instance.ContainerType {
	return instance.ContainerType(c.attrs["container"].(string))
}

func (c *environConfig) networkBridge() string {
	return c.attrs["network-bridge"].(string)
}

func (c *environConfig) sharedStorageDir() string {
	return filepath.Join(c.rootDir(), "shared-storage")
}

func (c *environConfig) storageDir() string {
	return filepath.Join(c.rootDir(), "storage")
}

func (c *environConfig) mongoDir() string {
	return filepath.Join(c.rootDir(), "db")
}

func (c *environConfig) logDir() string {
	return filepath.Join(c.rootDir(), "log")
}

// A config is bootstrapped if the bootstrap-ip address has been set.
func (c *environConfig) bootstrapped() bool {
	_, found := c.attrs["bootstrap-ip"]
	return found
}

func (c *environConfig) bootstrapIPAddress() string {
	addr, found := c.attrs["bootstrap-ip"]
	if found {
		return addr.(string)
	}
	return ""
}

func (c *environConfig) storagePort() int {
	return c.attrs["storage-port"].(int)
}

func (c *environConfig) sharedStoragePort() int {
	return c.attrs["shared-storage-port"].(int)
}

func (c *environConfig) storageAddr() string {
	return fmt.Sprintf("%s:%d", c.bootstrapIPAddress(), c.storagePort())
}

func (c *environConfig) sharedStorageAddr() string {
	return fmt.Sprintf("%s:%d", c.bootstrapIPAddress(), c.sharedStoragePort())
}

func (c *environConfig) configFile(filename string) string {
	return filepath.Join(c.rootDir(), filename)
}

func (c *environConfig) createDirs() error {
	for _, dirname := range []string{
		c.sharedStorageDir(),
		c.storageDir(),
		c.mongoDir(),
		c.logDir(),
	} {
		logger.Tracef("creating directory %s", dirname)
		if err := os.MkdirAll(dirname, 0755); err != nil {
			return err
		}
	}
	if c.runningAsRoot {
		// If we have SUDO_UID and SUDO_GID, start with rootDir(), and
		// change ownership of the directories.
		uid, gid, err := utils.SudoCallerIds()
		if err != nil {
			return err
		}
		if uid != 0 || gid != 0 {
			filepath.Walk(c.rootDir(),
				func(path string, info os.FileInfo, err error) error {
					if info != nil && info.IsDir() {
						if err := os.Chown(path, uid, gid); err != nil {
							return err
						}
					}
					return nil
				})
		}
	}
	return nil
}
<commit_msg>Add comment for the config keys as they are different from others.<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package local

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

	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/instance"
	"launchpad.net/juju-core/schema"
	"launchpad.net/juju-core/utils"
)

var checkIfRoot = func() bool {
	return os.Getuid() == 0
}

const (
	// These constants are defined here, and used in environprovider.go
	// to explicitly get from the config unknown params.
	containerConfigKey = "container"
	containerDefault   = "lxc"
)

var (
	configFields = schema.Fields{
		"root-dir":            schema.String(),
		"bootstrap-ip":        schema.String(),
		"network-bridge":      schema.String(),
		containerConfigKey:    schema.String(),
		"storage-port":        schema.ForceInt(),
		"shared-storage-port": schema.ForceInt(),
	}
	// The port defaults below are not entirely arbitrary.  Local user web
	// frameworks often use 8000 or 8080, so I didn't want to use either of
	// these, but did want the familiarity of using something in the 8000
	// range.
	configDefaults = schema.Defaults{
		"root-dir":            "",
		"network-bridge":      "lxcbr0",
		containerConfigKey:    containerDefault,
		"bootstrap-ip":        schema.Omit,
		"storage-port":        8040,
		"shared-storage-port": 8041,
	}
)

type environConfig struct {
	*config.Config
	user          string
	attrs         map[string]interface{}
	runningAsRoot bool
}

func newEnvironConfig(config *config.Config, attrs map[string]interface{}) *environConfig {
	user := os.Getenv("USER")
	root := checkIfRoot()
	if root {
		sudo_user := os.Getenv("SUDO_USER")
		if sudo_user != "" {
			user = sudo_user
		}
	}
	return &environConfig{
		Config:        config,
		user:          user,
		attrs:         attrs,
		runningAsRoot: root,
	}
}

// Since it is technically possible for two different users on one machine to
// have the same local provider name, we need to have a simple way to
// namespace the file locations, but more importantly the containers.
func (c *environConfig) namespace() string {
	return fmt.Sprintf("%s-%s", c.user, c.Name())
}

func (c *environConfig) rootDir() string {
	return c.attrs["root-dir"].(string)
}

func (c *environConfig) container() instance.ContainerType {
	return instance.ContainerType(c.attrs[containerConfigKey].(string))
}

func (c *environConfig) networkBridge() string {
	return c.attrs["network-bridge"].(string)
}

func (c *environConfig) sharedStorageDir() string {
	return filepath.Join(c.rootDir(), "shared-storage")
}

func (c *environConfig) storageDir() string {
	return filepath.Join(c.rootDir(), "storage")
}

func (c *environConfig) mongoDir() string {
	return filepath.Join(c.rootDir(), "db")
}

func (c *environConfig) logDir() string {
	return filepath.Join(c.rootDir(), "log")
}

// A config is bootstrapped if the bootstrap-ip address has been set.
func (c *environConfig) bootstrapped() bool {
	_, found := c.attrs["bootstrap-ip"]
	return found
}

func (c *environConfig) bootstrapIPAddress() string {
	addr, found := c.attrs["bootstrap-ip"]
	if found {
		return addr.(string)
	}
	return ""
}

func (c *environConfig) storagePort() int {
	return c.attrs["storage-port"].(int)
}

func (c *environConfig) sharedStoragePort() int {
	return c.attrs["shared-storage-port"].(int)
}

func (c *environConfig) storageAddr() string {
	return fmt.Sprintf("%s:%d", c.bootstrapIPAddress(), c.storagePort())
}

func (c *environConfig) sharedStorageAddr() string {
	return fmt.Sprintf("%s:%d", c.bootstrapIPAddress(), c.sharedStoragePort())
}

func (c *environConfig) configFile(filename string) string {
	return filepath.Join(c.rootDir(), filename)
}

func (c *environConfig) createDirs() error {
	for _, dirname := range []string{
		c.sharedStorageDir(),
		c.storageDir(),
		c.mongoDir(),
		c.logDir(),
	} {
		logger.Tracef("creating directory %s", dirname)
		if err := os.MkdirAll(dirname, 0755); err != nil {
			return err
		}
	}
	if c.runningAsRoot {
		// If we have SUDO_UID and SUDO_GID, start with rootDir(), and
		// change ownership of the directories.
		uid, gid, err := utils.SudoCallerIds()
		if err != nil {
			return err
		}
		if uid != 0 || gid != 0 {
			filepath.Walk(c.rootDir(),
				func(path string, info os.FileInfo, err error) error {
					if info != nil && info.IsDir() {
						if err := os.Chown(path, uid, gid); err != nil {
							return err
						}
					}
					return nil
				})
		}
	}
	return nil
}
<|endoftext|>


<commit_before><commit_msg>VA: Deprecate DNSResolvers field in config (#6493)<commit_after><|endoftext|>


<commit_before>package ui

import (
	"fmt"
	"net"
	"net/http"
	"net/url"
	"path/filepath"
	"runtime"
	"time"

	"github.com/getlantern/golog"
	"github.com/getlantern/tarfs"
	"github.com/getlantern/waitforserver"
	"github.com/skratchdot/open-golang/open"
)

const (
	LocalUIDir = "../../../lantern-ui/app"
)

var (
	log = golog.LoggerFor("flashlight.ui")

	l            net.Listener
	fs           *tarfs.FileSystem
	Translations *tarfs.FileSystem
	server       *http.Server
	uiaddr       string

	externalUrl    = "https://www.facebook.com/manototv/" // this string is going to be changed by Makefile
	openedExternal = false
	r              = http.NewServeMux()
)

func init() {
	// Assume the default directory containing UI assets is
	// a sibling directory to this file's directory.
	localResourcesPath := ""
	_, curDir, _, ok := runtime.Caller(1)
	if !ok {
		log.Errorf("Unable to determine caller directory")
	} else {
		localResourcesPath = filepath.Join(curDir, LocalUIDir)
		absLocalResourcesPath, err := filepath.Abs(localResourcesPath)
		if err != nil {
			absLocalResourcesPath = localResourcesPath
		}
		log.Debugf("Creating tarfs filesystem that prefers local resources at %v", absLocalResourcesPath)
	}

	var err error
	fs, err = tarfs.New(Resources, localResourcesPath)
	if err != nil {
		// Panicking here because this shouldn't happen at runtime unless the
		// resources were incorrectly embedded.
		panic(fmt.Errorf("Unable to open tarfs filesystem: %v", err))
	}
	Translations = fs.SubDir("locale")
}

func Handle(p string, handler http.Handler) string {
	r.Handle(p, handler)
	return uiaddr + p
}

func Start(addr string) error {
	var err error
	l, err = net.Listen("tcp", addr)
	if err != nil {
		return fmt.Errorf("Unable to listen at %v: %v", addr, l)
	}

	r.Handle("/", http.FileServer(fs))

	server = &http.Server{
		Handler:  r,
		ErrorLog: log.AsStdLogger(),
	}
	go func() {
		err := server.Serve(l)
		if err != nil {
			log.Errorf("Error serving: %v", err)
		}
	}()
	uiaddr = fmt.Sprintf("http://%v", l.Addr().String())
	log.Debugf("UI available at %v", uiaddr)

	return nil
}

// Show opens the UI in a browser. It will wait for the UI addr come up for at most 3 seconds
func Show() {
	go func() {
		addr, er := url.Parse(uiaddr)
		if er != nil {
			log.Errorf("Could not parse url `%v` with error `%v`", uiaddr, er)
			return
		}
		if err := waitforserver.WaitForServer("tcp", addr.Host, 10*time.Second); err != nil {
			log.Errorf("Error waiting for server: %v", err)
			return
		}
		err := open.Run(uiaddr)
		if err != nil {
			log.Errorf("Error opening page to `%v`: %v", uiaddr, err)
		}
		if externalUrl != "NO"+"_URL" && !openedExternal {
			time.Sleep(4 * time.Second)
			err = open.Run(externalUrl)
			if err != nil {
				log.Errorf("Error opening external page to `%v`: %v", uiaddr, err)
			}
			openedExternal = true
		}
	}()
}
<commit_msg>avoid redirect<commit_after>package ui

import (
	"fmt"
	"net"
	"net/http"
	"net/url"
	"path/filepath"
	"runtime"
	"time"

	"github.com/getlantern/golog"
	"github.com/getlantern/tarfs"
	"github.com/getlantern/waitforserver"
	"github.com/skratchdot/open-golang/open"
)

const (
	LocalUIDir = "../../../lantern-ui/app"
)

var (
	log = golog.LoggerFor("flashlight.ui")

	l            net.Listener
	fs           *tarfs.FileSystem
	Translations *tarfs.FileSystem
	server       *http.Server
	uiaddr       string

	externalUrl    = "https://www.facebook.com/manototv" // this string is going to be changed by Makefile
	openedExternal = false
	r              = http.NewServeMux()
)

func init() {
	// Assume the default directory containing UI assets is
	// a sibling directory to this file's directory.
	localResourcesPath := ""
	_, curDir, _, ok := runtime.Caller(1)
	if !ok {
		log.Errorf("Unable to determine caller directory")
	} else {
		localResourcesPath = filepath.Join(curDir, LocalUIDir)
		absLocalResourcesPath, err := filepath.Abs(localResourcesPath)
		if err != nil {
			absLocalResourcesPath = localResourcesPath
		}
		log.Debugf("Creating tarfs filesystem that prefers local resources at %v", absLocalResourcesPath)
	}

	var err error
	fs, err = tarfs.New(Resources, localResourcesPath)
	if err != nil {
		// Panicking here because this shouldn't happen at runtime unless the
		// resources were incorrectly embedded.
		panic(fmt.Errorf("Unable to open tarfs filesystem: %v", err))
	}
	Translations = fs.SubDir("locale")
}

func Handle(p string, handler http.Handler) string {
	r.Handle(p, handler)
	return uiaddr + p
}

func Start(addr string) error {
	var err error
	l, err = net.Listen("tcp", addr)
	if err != nil {
		return fmt.Errorf("Unable to listen at %v: %v", addr, l)
	}

	r.Handle("/", http.FileServer(fs))

	server = &http.Server{
		Handler:  r,
		ErrorLog: log.AsStdLogger(),
	}
	go func() {
		err := server.Serve(l)
		if err != nil {
			log.Errorf("Error serving: %v", err)
		}
	}()
	uiaddr = fmt.Sprintf("http://%v", l.Addr().String())
	log.Debugf("UI available at %v", uiaddr)

	return nil
}

// Show opens the UI in a browser. It will wait for the UI addr come up for at most 3 seconds
func Show() {
	go func() {
		addr, er := url.Parse(uiaddr)
		if er != nil {
			log.Errorf("Could not parse url `%v` with error `%v`", uiaddr, er)
			return
		}
		if err := waitforserver.WaitForServer("tcp", addr.Host, 10*time.Second); err != nil {
			log.Errorf("Error waiting for server: %v", err)
			return
		}
		err := open.Run(uiaddr)
		if err != nil {
			log.Errorf("Error opening page to `%v`: %v", uiaddr, err)
		}
		if externalUrl != "NO"+"_URL" && !openedExternal {
			time.Sleep(4 * time.Second)
			err = open.Run(externalUrl)
			if err != nil {
				log.Errorf("Error opening external page to `%v`: %v", uiaddr, err)
			}
			openedExternal = true
		}
	}()
}
<|endoftext|>


<commit_before>package ui

import (
	"fmt"
	"net"
	"net/http"
	"path"
	"path/filepath"
	"runtime"

	"github.com/getlantern/golog"
	"github.com/getlantern/open-golang/open"
	"github.com/getlantern/tarfs"
)

const (
	LocalUIDir = "../../../lantern-ui/app"
)

var (
	log = golog.LoggerFor("ui")

	l            net.Listener
	fs           *tarfs.FileSystem
	Translations *tarfs.FileSystem
	server       *http.Server
	uiaddr       string

	r = http.NewServeMux()
)

func init() {
	// Assume the default directory containing UI assets is
	// a sibling directory to this file's directory.
	localResourcesPath := ""
	_, curDir, _, ok := runtime.Caller(1)
	if !ok {
		log.Errorf("Unable to determine caller directory")
	} else {
		localResourcesPath = filepath.Join(curDir, LocalUIDir)
		absLocalResourcesPath, err := filepath.Abs(localResourcesPath)
		if err != nil {
			absLocalResourcesPath = localResourcesPath
		}
		log.Debugf("Creating tarfs filesystem that prefers local resources at %v", absLocalResourcesPath)
	}

	var err error
	fs, err = tarfs.New(Resources, localResourcesPath)
	if err != nil {
		panic(fmt.Errorf("Unable to open tarfs filesystem: %v", err))
	}
	Translations = fs.SubDir("locale")
}

func Handle(p string, handler http.Handler) string {
	r.Handle(p, handler)
	return path.Join(uiaddr, p)
}

func Start(addr string) error {
	var err error
	l, err = net.Listen("tcp", addr)
	if err != nil {
		return fmt.Errorf("Unable to listen at %v: %v", addr, l)
	}

	r.Handle("/", http.FileServer(fs))

	server = &http.Server{
		Handler: r,
	}
	go func() {
		err := server.Serve(l)
		if err != nil {
			log.Errorf("Error serving: %v", err)
		}
	}()
	uiaddr = fmt.Sprintf("http://%v", l.Addr().String())
	log.Debugf("UI available at %v", uiaddr)

	return nil
}

// Show opens the UI in a browser.
func Show() {
	open.Run(uiaddr)
}
<commit_msg>Switched back to using skratchdot/open-golang<commit_after>package ui

import (
	"fmt"
	"net"
	"net/http"
	"path"
	"path/filepath"
	"runtime"

	"github.com/getlantern/golog"
	"github.com/getlantern/tarfs"
	"github.com/skratchdot/open-golang/open"
)

const (
	LocalUIDir = "../../../lantern-ui/app"
)

var (
	log = golog.LoggerFor("ui")

	l            net.Listener
	fs           *tarfs.FileSystem
	Translations *tarfs.FileSystem
	server       *http.Server
	uiaddr       string

	r = http.NewServeMux()
)

func init() {
	// Assume the default directory containing UI assets is
	// a sibling directory to this file's directory.
	localResourcesPath := ""
	_, curDir, _, ok := runtime.Caller(1)
	if !ok {
		log.Errorf("Unable to determine caller directory")
	} else {
		localResourcesPath = filepath.Join(curDir, LocalUIDir)
		absLocalResourcesPath, err := filepath.Abs(localResourcesPath)
		if err != nil {
			absLocalResourcesPath = localResourcesPath
		}
		log.Debugf("Creating tarfs filesystem that prefers local resources at %v", absLocalResourcesPath)
	}

	var err error
	fs, err = tarfs.New(Resources, localResourcesPath)
	if err != nil {
		panic(fmt.Errorf("Unable to open tarfs filesystem: %v", err))
	}
	Translations = fs.SubDir("locale")
}

func Handle(p string, handler http.Handler) string {
	r.Handle(p, handler)
	return path.Join(uiaddr, p)
}

func Start(addr string) error {
	var err error
	l, err = net.Listen("tcp", addr)
	if err != nil {
		return fmt.Errorf("Unable to listen at %v: %v", addr, l)
	}

	r.Handle("/", http.FileServer(fs))

	server = &http.Server{
		Handler: r,
	}
	go func() {
		err := server.Serve(l)
		if err != nil {
			log.Errorf("Error serving: %v", err)
		}
	}()
	uiaddr = fmt.Sprintf("http://%v", l.Addr().String())
	log.Debugf("UI available at %v", uiaddr)

	return nil
}

// Show opens the UI in a browser.
func Show() {
	open.Run(uiaddr)
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package storage

import (
	"github.com/onsi/ginkgo"
	"k8s.io/kubernetes/test/e2e/storage/drivers"
	storageframework "k8s.io/kubernetes/test/e2e/storage/framework"
	"k8s.io/kubernetes/test/e2e/storage/testsuites"
	"k8s.io/kubernetes/test/e2e/storage/utils"
)

// List of testDrivers to be executed in below loop
var testDrivers = []func() storageframework.TestDriver{
	drivers.InitNFSDriver,
	drivers.InitGlusterFSDriver,
	drivers.InitISCSIDriver,
	drivers.InitRbdDriver,
	drivers.InitCephFSDriver,
	drivers.InitHostPathDriver,
	drivers.InitHostPathSymlinkDriver,
	drivers.InitEmptydirDriver,
	drivers.InitCinderDriver,
	drivers.InitGcePdDriver,
	drivers.InitWindowsGcePdDriver,
	drivers.InitVSphereDriver,
	drivers.InitAzureDiskDriver,
	drivers.InitAzureFileDriver,
	drivers.InitAwsDriver,
	drivers.InitLocalDriverWithVolumeType(utils.LocalVolumeDirectory),
	drivers.InitLocalDriverWithVolumeType(utils.LocalVolumeDirectoryLink),
	drivers.InitLocalDriverWithVolumeType(utils.LocalVolumeDirectoryBindMounted),
	drivers.InitLocalDriverWithVolumeType(utils.LocalVolumeDirectoryLinkBindMounted),
	drivers.InitLocalDriverWithVolumeType(utils.LocalVolumeTmpfs),
	drivers.InitLocalDriverWithVolumeType(utils.LocalVolumeBlock),
	drivers.InitLocalDriverWithVolumeType(utils.LocalVolumeBlockFS),
	drivers.InitLocalDriverWithVolumeType(utils.LocalVolumeGCELocalSSD),
}

// This executes testSuites for in-tree volumes.
var _ = utils.SIGDescribe("In-tree Volumes", func() {
	for _, initDriver := range testDrivers {
		curDriver := initDriver()

		ginkgo.Context(storageframework.GetDriverNameWithFeatureTags(curDriver), func() {
			storageframework.DefineTestSuites(curDriver, testsuites.BaseSuites)
		})
	}
})
<commit_msg>Disable Intree GCE PD tests by default<commit_after>/*
Copyright 2018 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package storage

import (
	"os"

	"github.com/onsi/ginkgo"
	"k8s.io/kubernetes/test/e2e/storage/drivers"
	storageframework "k8s.io/kubernetes/test/e2e/storage/framework"
	"k8s.io/kubernetes/test/e2e/storage/testsuites"
	"k8s.io/kubernetes/test/e2e/storage/utils"
)

// List of testDrivers to be executed in below loop
var testDrivers = []func() storageframework.TestDriver{
	drivers.InitNFSDriver,
	drivers.InitGlusterFSDriver,
	drivers.InitISCSIDriver,
	drivers.InitRbdDriver,
	drivers.InitCephFSDriver,
	drivers.InitHostPathDriver,
	drivers.InitHostPathSymlinkDriver,
	drivers.InitEmptydirDriver,
	drivers.InitCinderDriver,
	drivers.InitVSphereDriver,
	drivers.InitAzureDiskDriver,
	drivers.InitAzureFileDriver,
	drivers.InitAwsDriver,
	drivers.InitLocalDriverWithVolumeType(utils.LocalVolumeDirectory),
	drivers.InitLocalDriverWithVolumeType(utils.LocalVolumeDirectoryLink),
	drivers.InitLocalDriverWithVolumeType(utils.LocalVolumeDirectoryBindMounted),
	drivers.InitLocalDriverWithVolumeType(utils.LocalVolumeDirectoryLinkBindMounted),
	drivers.InitLocalDriverWithVolumeType(utils.LocalVolumeTmpfs),
	drivers.InitLocalDriverWithVolumeType(utils.LocalVolumeBlock),
	drivers.InitLocalDriverWithVolumeType(utils.LocalVolumeBlockFS),
	drivers.InitLocalDriverWithVolumeType(utils.LocalVolumeGCELocalSSD),
}

// This executes testSuites for in-tree volumes.
var _ = utils.SIGDescribe("In-tree Volumes", func() {
	if enableGcePD := os.Getenv("ENABLE_STORAGE_GCE_PD_DRIVER"); enableGcePD == "yes" {
		testDrivers = append(testDrivers, drivers.InitGcePdDriver)
		testDrivers = append(testDrivers, drivers.InitWindowsGcePdDriver)
	}
	for _, initDriver := range testDrivers {
		curDriver := initDriver()

		ginkgo.Context(storageframework.GetDriverNameWithFeatureTags(curDriver), func() {
			storageframework.DefineTestSuites(curDriver, testsuites.BaseSuites)
		})
	}
})
<|endoftext|>


<commit_before>package commonlog

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

	"github.com/gin-gonic/gin"
)

// Instances a Logger middleware that will write the logs to gin.DefaultWriter
// By default gin.DefaultWriter = os.Stdout
func New() gin.HandlerFunc {
	return NewWithWriter(gin.DefaultWriter)
}

// Instance a Logger middleware with the specified writter buffer.
// Example: os.Stdout, a file opened in write mode, a socket...
func NewWithWriter(out io.Writer) gin.HandlerFunc {
	pool := &sync.Pool{
		New: func() interface{} {
			buf := new(bytes.Buffer)
			return buf
		},
	}
	return func(c *gin.Context) {
		path := c.Request.URL.Path

		// Process request
		c.Next()

		//127.0.0.1 user-identifier frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326
		w := pool.Get().(*bytes.Buffer)
		w.Reset()
		w.WriteString(c.ClientIP())
		w.WriteString(" ")
		w.WriteString(time.Now().Format("[02/Jan/2006:15:04:05 -0700] "))
		w.WriteString("\"")
		w.WriteString(c.Request.Method)
		w.WriteString(" ")
		w.WriteString(path)
		w.WriteString(" ")
		w.WriteString(c.Request.Proto)
		w.WriteString("\" ")
		w.WriteString(strconv.Itoa(c.Writer.Status()))
		w.WriteString(" ")
		w.WriteString(strconv.Itoa(c.Writer.Size()))
		w.WriteString("\n")

		w.WriteTo(out)
		pool.Put(w)
	}
}
<commit_msg>Add missing user identifier part<commit_after>package commonlog

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

	"github.com/gin-gonic/gin"
)

// Instances a Logger middleware that will write the logs to gin.DefaultWriter
// By default gin.DefaultWriter = os.Stdout
func New() gin.HandlerFunc {
	return NewWithWriter(gin.DefaultWriter)
}

// Instance a Logger middleware with the specified writter buffer.
// Example: os.Stdout, a file opened in write mode, a socket...
func NewWithWriter(out io.Writer) gin.HandlerFunc {
	pool := &sync.Pool{
		New: func() interface{} {
			buf := new(bytes.Buffer)
			return buf
		},
	}
	return func(c *gin.Context) {
		// Process request
		c.Next()

		//127.0.0.1 user-identifier frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326
		w := pool.Get().(*bytes.Buffer)
		w.Reset()
		w.WriteString(c.ClientIP())
		w.WriteString(" - - ")
		w.WriteString(time.Now().Format("[02/Jan/2006:15:04:05 -0700] "))
		w.WriteString("\"")
		w.WriteString(c.Request.Method)
		w.WriteString(" ")
		w.WriteString(c.Request.URL.Path)
		w.WriteString(" ")
		w.WriteString(c.Request.Proto)
		w.WriteString("\" ")
		w.WriteString(strconv.Itoa(c.Writer.Status()))
		w.WriteString(" ")
		w.WriteString(strconv.Itoa(c.Writer.Size()))
		w.WriteString("\n")

		w.WriteTo(out)
		pool.Put(w)
	}
}
<|endoftext|>


<commit_before>package hammy

import (
	"fmt"
	"encoding/json"
	"github.com/couchbaselabs/go-couchbase"
	"github.com/dustin/gomemcached"
	"github.com/dustin/gomemcached/client"
)

type CouchbaseStateKeeper struct {
	Client *couchbase.Client
	Pool *couchbase.Pool
	Bucket *couchbase.Bucket
	Ttl int
}

func NewCouchbaseStateKeeper(cfg Config) (*CouchbaseStateKeeper, error) {
	tg := new(CouchbaseStateKeeper)

	c, err := couchbase.Connect(cfg.CouchbaseStates.ConnectTo)
	if err != nil {
		return nil, err
	}
	tg.Client = &c

	p, err := tg.Client.GetPool(cfg.CouchbaseStates.Pool)
	if err != nil {
		return nil, err
	}
	tg.Pool = &p

	b, err := tg.Pool.GetBucket(cfg.CouchbaseStates.Bucket)
	if err != nil {
		return nil, err
	}
	tg.Bucket = b

	tg.Ttl = cfg.CouchbaseStates.Ttl

	return tg, nil
}

func (sk *CouchbaseStateKeeper) Get(key string) StateKeeperAnswer {
	s := NewState()
	var cas uint64
	err := sk.Bucket.Gets(key, s, &cas)

	if err == nil {
		return StateKeeperAnswer{
			State: s,
			Cas: &cas,
			Err: nil,
		}
	} else {
		return StateKeeperAnswer{
			State: nil,
			Cas: nil,
			Err: err,
		}
	}
	panic("?!!")
}

func (sk *CouchbaseStateKeeper) MGet(keys []string) (states map[string]StateKeeperAnswer) {
	ans := sk.Bucket.GetBulk(keys)

	states = make(map[string]StateKeeperAnswer)
	for k, r := range ans {
		switch r.Status {
			case gomemcached.SUCCESS:
				s := NewState()
				err := json.Unmarshal(r.Body, &s)
				if err == nil {
					states[k] = StateKeeperAnswer{
						State: s,
						Cas: &r.Cas,
						Err: nil,
					}
				} else {
					states[k] = StateKeeperAnswer{
						State: nil,
						Cas: nil,
						Err: err,
					}
				}
			case gomemcached.KEY_ENOENT:
				states[k] = StateKeeperAnswer{
					State: NewState(),
					Cas: nil,
					Err: nil,
				}
			default:
				states[k] = StateKeeperAnswer{
					State: nil,
					Cas: nil,
					Err: fmt.Errorf("%s", r.Error()),
				}
		}
	}

	for _, k := range keys {
		if _, found := states[k]; !found {
			states[k] = StateKeeperAnswer{
				State: NewState(),
				Cas: nil,
				Err: nil,
			}
		}
	}

	return
}

func (sk *CouchbaseStateKeeper) Set(key string, data State, cas *uint64) (retry bool, err error) {
	err = sk.Bucket.Do(key, func(mc *memcached.Client, vb uint16) (e error) {
		buf, e := json.Marshal(data)
		if e != nil {
			return
		}
		req := &gomemcached.MCRequest{
			Opcode: gomemcached.SET,
			VBucket: vb,
			Key: []byte(key),
			Cas: 0,
			Opaque: 0,
			Extras: []byte{0, 0, 0, 0, 0, 0, 0, 0},
			Body: buf,
		}
		if cas != nil {
			req.Cas = *cas
		}

		resp, e := mc.Send(req)
		if e != nil {
			if resp != nil && resp.Status == gomemcached.KEY_EEXISTS {
				e = nil
				retry = true
			}
			return
		}

		switch resp.Status {
			case gomemcached.KEY_EEXISTS:
				retry = true
				return
			case gomemcached.SUCCESS:
				return
			default:
				return fmt.Errorf("CAS operation failed: %v", resp.Error())
		}
		panic("?!!")
	})
	if err != nil {
		return
	}

	return
}
<commit_msg>couchbase_state.go fixed<commit_after>package hammy

import (
	"fmt"
	"encoding/json"
	"github.com/couchbaselabs/go-couchbase"
	"github.com/dustin/gomemcached"
	"github.com/dustin/gomemcached/client"
)

type CouchbaseStateKeeper struct {
	Client *couchbase.Client
	Pool *couchbase.Pool
	Bucket *couchbase.Bucket
	Ttl int
}

func NewCouchbaseStateKeeper(cfg Config) (*CouchbaseStateKeeper, error) {
	tg := new(CouchbaseStateKeeper)

	c, err := couchbase.Connect(cfg.CouchbaseStates.ConnectTo)
	if err != nil {
		return nil, err
	}
	tg.Client = &c

	p, err := tg.Client.GetPool(cfg.CouchbaseStates.Pool)
	if err != nil {
		return nil, err
	}
	tg.Pool = &p

	b, err := tg.Pool.GetBucket(cfg.CouchbaseStates.Bucket)
	if err != nil {
		return nil, err
	}
	tg.Bucket = b

	tg.Ttl = cfg.CouchbaseStates.Ttl

	return tg, nil
}

func (sk *CouchbaseStateKeeper) Get(key string) StateKeeperAnswer {
	s := NewState()
	var cas uint64
	err := sk.Bucket.Gets(key, &s, &cas)

	if err == nil {
		return StateKeeperAnswer{
			State: s,
			Cas: &cas,
			Err: nil,
		}
	} else {
		return StateKeeperAnswer{
			State: nil,
			Cas: nil,
			Err: err,
		}
	}
	panic("?!!")
}

func (sk *CouchbaseStateKeeper) MGet(keys []string) (states map[string]StateKeeperAnswer) {
	ans := sk.Bucket.GetBulk(keys)

	states = make(map[string]StateKeeperAnswer)
	for k, r := range ans {
		switch r.Status {
			case gomemcached.SUCCESS:
				s := NewState()
				err := json.Unmarshal(r.Body, &s)
				if err == nil {
					states[k] = StateKeeperAnswer{
						State: s,
						Cas: &r.Cas,
						Err: nil,
					}
				} else {
					states[k] = StateKeeperAnswer{
						State: nil,
						Cas: nil,
						Err: err,
					}
				}
			case gomemcached.KEY_ENOENT:
				states[k] = StateKeeperAnswer{
					State: NewState(),
					Cas: nil,
					Err: nil,
				}
			default:
				states[k] = StateKeeperAnswer{
					State: nil,
					Cas: nil,
					Err: fmt.Errorf("%s", r.Error()),
				}
		}
	}

	for _, k := range keys {
		if _, found := states[k]; !found {
			states[k] = StateKeeperAnswer{
				State: NewState(),
				Cas: nil,
				Err: nil,
			}
		}
	}

	return
}

func (sk *CouchbaseStateKeeper) Set(key string, data State, cas *uint64) (retry bool, err error) {
	err = sk.Bucket.Do(key, func(mc *memcached.Client, vb uint16) (e error) {
		buf, e := json.Marshal(data)
		if e != nil {
			return
		}
		req := &gomemcached.MCRequest{
			Opcode: gomemcached.SET,
			VBucket: vb,
			Key: []byte(key),
			Cas: 0,
			Opaque: 0,
			Extras: []byte{0, 0, 0, 0, 0, 0, 0, 0},
			Body: buf,
		}
		if cas != nil {
			req.Cas = *cas
		}

		resp, e := mc.Send(req)
		if e != nil {
			if resp != nil && resp.Status == gomemcached.KEY_EEXISTS {
				e = nil
				retry = true
			}
			return
		}

		switch resp.Status {
			case gomemcached.KEY_EEXISTS:
				retry = true
				return
			case gomemcached.SUCCESS:
				return
			default:
				return fmt.Errorf("CAS operation failed: %v", resp.Error())
		}
		panic("?!!")
	})
	if err != nil {
		return
	}

	return
}
<|endoftext|>


<commit_before>package config

import (
	"fmt"
	"github.com/aws/aws-sdk-go/aws/arn"
	"github.com/mmmorris1975/aws-config/config"
	"github.com/mmmorris1975/aws-runas/lib/credentials"
	"os"
	"strings"
	"time"
)

const (
	// RegionEnvVar is the environment variable to define the AWS region to work in
	RegionEnvVar = "AWS_REGION"
	// DefaultRegionEnvVar is the environment variable to define the default AWS region (if AWS_REGION is not specified)
	DefaultRegionEnvVar = "AWS_DEFAULT_REGION"
	// SessionDurationEnvVar is the environment variable to define the Session Token credential lifetime
	SessionDurationEnvVar = "SESSION_TOKEN_DURATION"
	// RoleDurationEnvVar is the environment variable to define the Assume Role credential lifetime
	RoleDurationEnvVar = "CREDENTIALS_DURATION"
	// MfaSerialEnvVar is the environment variable to define the optional multi-factor authentication serial number or ARN to use to retrieve credentials
	MfaSerialEnvVar = "MFA_SERIAL"
	// ExternalIdEnvVar is the environment variable to define the optional External ID value when getting Assumed Role credentials
	ExternalIdEnvVar = "EXTERNAL_ID"
	// ProfileEnvVar is the environment variable to define the name of the configuration profile (or role ARN) to use to retrieve credentials
	ProfileEnvVar = "AWS_PROFILE"
	// DefaultProfileEnvVar is the environment variable to define the name of the default AWS profile, if different from the SDK default 'default'
	DefaultProfileEnvVar = "AWS_DEFAULT_PROFILE"
	sourceProfileKey     = "source_profile"
)

// ConfigResolver is the interface for retrieving AWS SDK configuration from a source
type ConfigResolver interface {
	ResolveConfig(string) (*AwsConfig, error)
}

// AwsConfig is the type used to hold the configuration details retrieved from a given source.
type AwsConfig struct {
	Region          string        `ini:"region"`
	SessionDuration time.Duration `ini:"session_token_duration"`
	RoleDuration    time.Duration `ini:"credentials_duration"`
	MfaSerial       string        `ini:"mfa_serial"`
	RoleArn         string        `ini:"role_arn"`
	ExternalID      string        `ini:"external_id"`
	SourceProfile   string        `ini:"source_profile"`
}

type configResolver struct {
	file          *config.AwsConfigFile
	defaultConfig *AwsConfig
	sourceConfig  *AwsConfig
	profileConfig *AwsConfig
	envConfig     *AwsConfig
	userConfig    *AwsConfig
}

// NewConfigResolver provides a default ConfigResolver which will consult the SDK config file ($HOME/.aws/config or
// value of AWS_CONFIG_FILE env var) as a source for configuration resolution, in addition to the provided user config
// data.
func NewConfigResolver(c *AwsConfig) (*configResolver, error) {
	r := new(configResolver)
	f, err := config.NewAwsConfigFile(nil)
	if err != nil {
		return nil, err
	}
	r.file = f

	if c == nil {
		r.userConfig = new(AwsConfig)
	} else {
		r.userConfig = c
	}

	return r, nil
}

// ResolveConfig will generate an AwsConfig object using a variety of sources.
// - First, the default section of the SDK config file is consulted
// - Next, if the profile argument is not a role ARN value, the value is looked up in the SDK config file,
//   additionally resolving any configuration from the profile set in the source_profile attribute
// - Then, apply any configuration settings provided by environment variables.
// - Finally, the above configurations, as well as any configuration specified in NewConfigResolver are merged
//   to provide a consolidated AwsConfig according to the following order of precedence (lowest to highest):
//   - Default config section, source_profile configuration, profile configuration, environment variables, user-supplied config
func (r *configResolver) ResolveConfig(profile string) (*AwsConfig, error) {
	// config file may not exist and config could be baked fully through env vars, so don't barf on errors
	r.ResolveDefaultConfig()

	a, err := arn.Parse(profile)
	if err != nil {
		// not a role arn, should be a profile name in the config file.  If profile not found, or other error,
		// fall through and allow possibility for config to be baked fully through env vars
		r.debug("profile is not a role ARN")
		p, err := r.file.Profile(profile)
		if err == nil {
			src := p.Key(sourceProfileKey).String()
			if len(src) > 0 {
				r.debug("resolving source_profile %s", src)
				// awscli allows a source_profile without a matching profile section in the config, in which case it will
				// only reference that profile name for the section name in the credentials file.  Mimic that behavior
				// by not error checking this call to ResolveProfileConfig()
				r.sourceConfig, _ = r.ResolveProfileConfig(src)
			}

			_, err = r.ResolveProfileConfig(profile)
			if err != nil {
				return nil, err
			}
		}
	} else {
		if strings.HasPrefix(a.Resource, "role/") {
			r.userConfig.RoleArn = a.String()
		} else {
			return nil, fmt.Errorf("invalid role arn format")
		}
	}

	_, err = r.ResolveEnvConfig()
	if err != nil {
		return nil, err
	}

	c := MergeConfig(r.defaultConfig, r.sourceConfig, r.profileConfig, r.envConfig, r.userConfig)
	if c.SessionDuration < 1 {
		c.SessionDuration = credentials.SessionTokenDefaultDuration
	}

	if c.RoleDuration < 1 {
		c.RoleDuration = credentials.AssumeRoleDefaultDuration
	}

	r.debug("MERGED CONFIG: %+v", c)
	return c, nil
}

// ResolveDefaultConfig will look up configuration information in the 'default' section of the AWS SDK configuration
// file.  The default section name can be overridden by setting the AWS_DEFAULT_PROFILE environment variable.  The config
// file location can be overridden by setting the AWS_CONFIG_FILE environment variable.  While any valid configuration
// property may be specified in the default section, this method will only return the settings for the 'region',
// 'session_token_duration', and 'credentials_duration' properties, to avoid possible conflict with role-specific configuration
func (r *configResolver) ResolveDefaultConfig() (*AwsConfig, error) {
	p := config.DefaultProfileName
	if v, ok := os.LookupEnv(DefaultProfileEnvVar); ok {
		p = v
	}

	s, err := r.file.Profile(p)
	if err != nil {
		return nil, err
	}

	// Unmarshal any valid ini token for the struct, but only actually set values we're allowing
	// For example, don't allow mfa_serial to be passed through from default config
	c := new(AwsConfig)
	if err := s.MapTo(c); err != nil {
		return nil, err
	}
	r.defaultConfig = &AwsConfig{Region: c.Region, SessionDuration: c.SessionDuration, RoleDuration: c.RoleDuration, SourceProfile: p}

	r.debug("DEFAULT CONFIG: %+v", r.defaultConfig)
	return r.defaultConfig, nil
}

// ResolveProfileConfig will resolve the configuration for the section specified by the profile argument, using the
// data mapping specified in the AwsConfig type fields.  This method will not recursively resolve configuration if
// the source_profile attribute is set.  If a source_profile is set for the provided named profile, a non-empty string
// value will be present in the returned AwsConfig.SourceProfile field, which can be used as the argument to another
// call to this method to resolve the source_profile configuration properties.
func (r *configResolver) ResolveProfileConfig(profile string) (*AwsConfig, error) {
	s, err := r.file.Profile(profile)
	if err != nil {
		return nil, err
	}

	c := new(AwsConfig)
	if err := s.MapTo(c); err != nil {
		return nil, err
	}
	r.profileConfig = c

	r.debug("PROFILE '%s' CONFIG: %+v", r.profileConfig)
	return r.profileConfig, nil
}

// Consult the following environment variables for setting configuration values:
// AWS_DEFAULT_REGION, AWS_REGION (will override AWS_DEFAULT_REGION), MFA_SERIAL, EXTERNAL_ID,
// SESSION_TOKEN_DURATION, CREDENTIALS_DURATION
func (r *configResolver) ResolveEnvConfig() (*AwsConfig, error) {
	c := new(AwsConfig)

	if v, ok := os.LookupEnv(DefaultRegionEnvVar); ok {
		c.Region = v
	}

	if v, ok := os.LookupEnv(RegionEnvVar); ok {
		c.Region = v
	}

	if v, ok := os.LookupEnv(MfaSerialEnvVar); ok {
		c.MfaSerial = v
	}

	if v, ok := os.LookupEnv(ExternalIdEnvVar); ok {
		c.ExternalID = v
	}

	if v, ok := os.LookupEnv(SessionDurationEnvVar); ok {
		d, err := time.ParseDuration(v)
		if err != nil {
			return nil, err
		}
		c.SessionDuration = d
	}

	if v, ok := os.LookupEnv(RoleDurationEnvVar); ok {
		d, err := time.ParseDuration(v)
		if err != nil {
			return nil, err
		}
		c.RoleDuration = d
	}

	r.envConfig = c
	r.debug("ENV CONFIG: %+v", r.envConfig)
	return r.envConfig, nil
}

// MergeConfig will merge the provided list of AwsConfig types to a single value.  Precedence is based on the order
// of the item in the list, with later items overriding values specified in earlier items.  Only non-nil AwsConfig types
// will be considered, and the field inside the AwsConfig item must be a non-zero value to override a prior setting
func MergeConfig(conf ...*AwsConfig) *AwsConfig {
	cfg := new(AwsConfig)

	for _, c := range conf {
		if c != nil {
			if len(c.Region) > 0 {
				cfg.Region = c.Region
			}

			if len(c.MfaSerial) > 0 {
				cfg.MfaSerial = c.MfaSerial
			}

			if len(c.RoleArn) > 0 {
				cfg.RoleArn = c.RoleArn
			}

			if len(c.ExternalID) > 0 {
				cfg.MfaSerial = c.MfaSerial
			}

			if len(c.SourceProfile) > 0 {
				cfg.SourceProfile = c.SourceProfile
			}

			if c.SessionDuration > 0 {
				cfg.SessionDuration = c.SessionDuration
			}

			if c.RoleDuration > 0 {
				cfg.RoleDuration = c.RoleDuration
			}
		}
	}

	return cfg
}

func (r *configResolver) debug(f string, v ...interface{}) {
	// fixme since we don't have an AWS client, this method won't work.  Need another way to communicate log level
	//if r.client != nil && r.client.ClientConfig("iam").Config.LogLevel.AtLeast(aws.LogDebug) {
	//	r.log.Log(fmt.Sprintf(f, v...))
	//}
}
<commit_msg>implement logger in config module<commit_after>package config

import (
	"fmt"
	"github.com/aws/aws-sdk-go/aws/arn"
	"github.com/mmmorris1975/aws-config/config"
	"github.com/mmmorris1975/aws-runas/lib/credentials"
	"github.com/mmmorris1975/simple-logger"
	"os"
	"strings"
	"time"
)

const (
	// RegionEnvVar is the environment variable to define the AWS region to work in
	RegionEnvVar = "AWS_REGION"
	// DefaultRegionEnvVar is the environment variable to define the default AWS region (if AWS_REGION is not specified)
	DefaultRegionEnvVar = "AWS_DEFAULT_REGION"
	// SessionDurationEnvVar is the environment variable to define the Session Token credential lifetime
	SessionDurationEnvVar = "SESSION_TOKEN_DURATION"
	// RoleDurationEnvVar is the environment variable to define the Assume Role credential lifetime
	RoleDurationEnvVar = "CREDENTIALS_DURATION"
	// MfaSerialEnvVar is the environment variable to define the optional multi-factor authentication serial number or ARN to use to retrieve credentials
	MfaSerialEnvVar = "MFA_SERIAL"
	// ExternalIdEnvVar is the environment variable to define the optional External ID value when getting Assumed Role credentials
	ExternalIdEnvVar = "EXTERNAL_ID"
	// ProfileEnvVar is the environment variable to define the name of the configuration profile (or role ARN) to use to retrieve credentials
	ProfileEnvVar = "AWS_PROFILE"
	// DefaultProfileEnvVar is the environment variable to define the name of the default AWS profile, if different from the SDK default 'default'
	DefaultProfileEnvVar = "AWS_DEFAULT_PROFILE"
	sourceProfileKey     = "source_profile"
)

// ConfigResolver is the interface for retrieving AWS SDK configuration from a source
type ConfigResolver interface {
	ResolveConfig(string) (*AwsConfig, error)
}

// AwsConfig is the type used to hold the configuration details retrieved from a given source.
type AwsConfig struct {
	Region          string        `ini:"region"`
	SessionDuration time.Duration `ini:"session_token_duration"`
	RoleDuration    time.Duration `ini:"credentials_duration"`
	MfaSerial       string        `ini:"mfa_serial"`
	RoleArn         string        `ini:"role_arn"`
	ExternalID      string        `ini:"external_id"`
	SourceProfile   string        `ini:"source_profile"`
}

type configResolver struct {
	file          *config.AwsConfigFile
	defaultConfig *AwsConfig
	sourceConfig  *AwsConfig
	profileConfig *AwsConfig
	envConfig     *AwsConfig
	userConfig    *AwsConfig
	log           *simple_logger.Logger
}

// NewConfigResolver provides a default ConfigResolver which will consult the SDK config file ($HOME/.aws/config or
// value of AWS_CONFIG_FILE env var) as a source for configuration resolution, in addition to the provided user config
// data.
func NewConfigResolver(c *AwsConfig) (*configResolver, error) {
	r := new(configResolver)
	f, err := config.NewAwsConfigFile(nil)
	if err != nil {
		return nil, err
	}
	r.file = f

	if c == nil {
		r.userConfig = new(AwsConfig)
	} else {
		r.userConfig = c
	}

	return r, nil
}

func (r *configResolver) WithLogger(l *simple_logger.Logger) *configResolver {
	r.log = l
	return r
}

// ResolveConfig will generate an AwsConfig object using a variety of sources.
// - First, the default section of the SDK config file is consulted
// - Next, if the profile argument is not a role ARN value, the value is looked up in the SDK config file,
//   additionally resolving any configuration from the profile set in the source_profile attribute
// - Then, apply any configuration settings provided by environment variables.
// - Finally, the above configurations, as well as any configuration specified in NewConfigResolver are merged
//   to provide a consolidated AwsConfig according to the following order of precedence (lowest to highest):
//   - Default config section, source_profile configuration, profile configuration, environment variables, user-supplied config
func (r *configResolver) ResolveConfig(profile string) (*AwsConfig, error) {
	// config file may not exist and config could be baked fully through env vars, so don't barf on errors
	r.ResolveDefaultConfig()

	a, err := arn.Parse(profile)
	if err != nil {
		// not a role arn, should be a profile name in the config file.  If profile not found, or other error,
		// fall through and allow possibility for config to be baked fully through env vars
		r.debug("profile is not a role ARN")
		p, err := r.file.Profile(profile)
		if err == nil {
			src := p.Key(sourceProfileKey).String()
			if len(src) > 0 {
				r.debug("resolving source_profile %s", src)
				// awscli allows a source_profile without a matching profile section in the config, in which case it will
				// only reference that profile name for the section name in the credentials file.  Mimic that behavior
				// by not error checking this call to ResolveProfileConfig()
				r.sourceConfig, _ = r.ResolveProfileConfig(src)
			}

			_, err = r.ResolveProfileConfig(profile)
			if err != nil {
				return nil, err
			}
		}
	} else {
		if strings.HasPrefix(a.Resource, "role/") {
			r.userConfig.RoleArn = a.String()
		} else {
			return nil, fmt.Errorf("invalid role arn format")
		}
	}

	_, err = r.ResolveEnvConfig()
	if err != nil {
		return nil, err
	}

	c := MergeConfig(r.defaultConfig, r.sourceConfig, r.profileConfig, r.envConfig, r.userConfig)
	if c.SessionDuration < 1 {
		c.SessionDuration = credentials.SessionTokenDefaultDuration
	}

	if c.RoleDuration < 1 {
		c.RoleDuration = credentials.AssumeRoleDefaultDuration
	}

	r.debug("MERGED CONFIG: %+v", c)
	return c, nil
}

// ResolveDefaultConfig will look up configuration information in the 'default' section of the AWS SDK configuration
// file.  The default section name can be overridden by setting the AWS_DEFAULT_PROFILE environment variable.  The config
// file location can be overridden by setting the AWS_CONFIG_FILE environment variable.  While any valid configuration
// property may be specified in the default section, this method will only return the settings for the 'region',
// 'session_token_duration', and 'credentials_duration' properties, to avoid possible conflict with role-specific configuration
func (r *configResolver) ResolveDefaultConfig() (*AwsConfig, error) {
	p := config.DefaultProfileName
	if v, ok := os.LookupEnv(DefaultProfileEnvVar); ok {
		p = v
	}

	s, err := r.file.Profile(p)
	if err != nil {
		return nil, err
	}

	// Unmarshal any valid ini token for the struct, but only actually set values we're allowing
	// For example, don't allow mfa_serial to be passed through from default config
	c := new(AwsConfig)
	if err := s.MapTo(c); err != nil {
		return nil, err
	}
	r.defaultConfig = &AwsConfig{Region: c.Region, SessionDuration: c.SessionDuration, RoleDuration: c.RoleDuration, SourceProfile: p}

	r.debug("DEFAULT CONFIG: %+v", r.defaultConfig)
	return r.defaultConfig, nil
}

// ResolveProfileConfig will resolve the configuration for the section specified by the profile argument, using the
// data mapping specified in the AwsConfig type fields.  This method will not recursively resolve configuration if
// the source_profile attribute is set.  If a source_profile is set for the provided named profile, a non-empty string
// value will be present in the returned AwsConfig.SourceProfile field, which can be used as the argument to another
// call to this method to resolve the source_profile configuration properties.
func (r *configResolver) ResolveProfileConfig(profile string) (*AwsConfig, error) {
	s, err := r.file.Profile(profile)
	if err != nil {
		return nil, err
	}

	c := new(AwsConfig)
	if err := s.MapTo(c); err != nil {
		return nil, err
	}
	r.profileConfig = c

	r.debug("PROFILE '%s' CONFIG: %+v", r.profileConfig)
	return r.profileConfig, nil
}

// Consult the following environment variables for setting configuration values:
// AWS_DEFAULT_REGION, AWS_REGION (will override AWS_DEFAULT_REGION), MFA_SERIAL, EXTERNAL_ID,
// SESSION_TOKEN_DURATION, CREDENTIALS_DURATION
func (r *configResolver) ResolveEnvConfig() (*AwsConfig, error) {
	c := new(AwsConfig)

	if v, ok := os.LookupEnv(DefaultRegionEnvVar); ok {
		c.Region = v
	}

	if v, ok := os.LookupEnv(RegionEnvVar); ok {
		c.Region = v
	}

	if v, ok := os.LookupEnv(MfaSerialEnvVar); ok {
		c.MfaSerial = v
	}

	if v, ok := os.LookupEnv(ExternalIdEnvVar); ok {
		c.ExternalID = v
	}

	if v, ok := os.LookupEnv(SessionDurationEnvVar); ok {
		d, err := time.ParseDuration(v)
		if err != nil {
			return nil, err
		}
		c.SessionDuration = d
	}

	if v, ok := os.LookupEnv(RoleDurationEnvVar); ok {
		d, err := time.ParseDuration(v)
		if err != nil {
			return nil, err
		}
		c.RoleDuration = d
	}

	r.envConfig = c
	r.debug("ENV CONFIG: %+v", r.envConfig)
	return r.envConfig, nil
}

// MergeConfig will merge the provided list of AwsConfig types to a single value.  Precedence is based on the order
// of the item in the list, with later items overriding values specified in earlier items.  Only non-nil AwsConfig types
// will be considered, and the field inside the AwsConfig item must be a non-zero value to override a prior setting
func MergeConfig(conf ...*AwsConfig) *AwsConfig {
	cfg := new(AwsConfig)

	for _, c := range conf {
		if c != nil {
			if len(c.Region) > 0 {
				cfg.Region = c.Region
			}

			if len(c.MfaSerial) > 0 {
				cfg.MfaSerial = c.MfaSerial
			}

			if len(c.RoleArn) > 0 {
				cfg.RoleArn = c.RoleArn
			}

			if len(c.ExternalID) > 0 {
				cfg.MfaSerial = c.MfaSerial
			}

			if len(c.SourceProfile) > 0 {
				cfg.SourceProfile = c.SourceProfile
			}

			if c.SessionDuration > 0 {
				cfg.SessionDuration = c.SessionDuration
			}

			if c.RoleDuration > 0 {
				cfg.RoleDuration = c.RoleDuration
			}
		}
	}

	return cfg
}

func (r *configResolver) debug(f string, v ...interface{}) {
	if r.log != nil {
		r.log.Debugf(f, v)
	}
}
<|endoftext|>


<commit_before>package main

import "fmt"
import "net/http"
import "strings"
import "database/sql"
import _ "github.com/go-sql-driver/mysql"

func getAverageLen(addrs []string)(int){
	numEle := len(addrs)
	numChar := 0
	for i := range addrs{
		numChar += len([]rune(addrs[i]))
	}
	return numChar/numEle
}

func main(){
	// Connecting to the DB
	db, err := sql.Open("mysql", "bloom:test@/unsubscribed")
	if err != nil {     panic(err.Error()) // Just for example purpose. You should use proper error handling instead of panic
	}

	// Closing the connection at the end
	defer db.Close()

	// testing the connection
	err = db.Ping()
	if err != nil {     panic(err.Error()) // Just for example purpose. You should use proper error handling instead of panic
	}

	// Populating the DB (run once)
	// _, err = db.Exec("insert into unsub_0 (user_id, email) values (180, ?)", "vlam321@gamil.com")

	// Querying the DB
	rows, err := db.Query("SELECT user_id, email FROM unsub_0;")
	if err != nil {     panic(err.Error()) // Just for example purpose. You should use proper error handling instead of panic
	}

	// Printing the results
	for rows.Next(){
		var userid int
		var email string
		err = rows.Scan(&userid, &email)
		if err != nil{
			panic(err.Error())
		}
		fmt.Printf("%d, %s\n", userid, email)
	}

	// Check for errors in rows
	err = rows.Err()
	if err != nil{
		panic(err.Error())
	}
	fmt.Println("Success!")

	// net/http stuffs
	http.HandleFunc("/hello", sayhelloName) // set router
	err = http.ListenAndServe(":9090", nil) // set listen port
	if err != nil { panic(err.Error()) }
}

// func used for http stuffs
func sayhelloName(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()  // parse arguments, you have to call this by yourself
	fmt.Println(r.Form)  // print form information in server side
	fmt.Println("path", r.URL.Path)
	fmt.Println("scheme", r.URL.Scheme)
	fmt.Println(r.Form["url_long"])
	for k, v := range r.Form {
		fmt.Println("key:", k)
		fmt.Println("val:", strings.Join(v, ""))
	}
	fmt.Fprintf(w, "Hello astaxie!") // send data to client side
}

<commit_msg>Deleted main.go<commit_after><|endoftext|>


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

package main

import (
	"flag"
	"fmt"
	"log/syslog"
	"os"
	"time"

	"github.com/coreos/ignition/src/exec"
	"github.com/coreos/ignition/src/exec/stages"
	_ "github.com/coreos/ignition/src/exec/stages/prepivot"
	"github.com/coreos/ignition/src/log"
	"github.com/coreos/ignition/src/oem"
	"github.com/coreos/ignition/src/providers"
	_ "github.com/coreos/ignition/src/providers/cmdline"

	"github.com/coreos/ignition/Godeps/_workspace/src/github.com/coreos/go-semver/semver"
)

const versionString = "0.0.0+git"

var version = *semver.Must(semver.NewVersion(versionString))

func main() {
	flags := struct {
		configCache  string
		fetchTimeout time.Duration
		oem          oem.Name
		providers    providers.List
		root         string
		stage        stages.Name
		version      bool
	}{}

	flag.StringVar(&flags.configCache, "config-cache", "/tmp/ignition.json", "where to cache the config")
	flag.DurationVar(&flags.fetchTimeout, "fetchtimeout", exec.DefaultFetchTimeout, "")
	flag.Var(&flags.oem, "oem", fmt.Sprintf("current oem. %v", oem.Names()))
	flag.Var(&flags.providers, "provider", fmt.Sprintf("provider of config. can be specified multiple times. %v", providers.Names()))
	flag.StringVar(&flags.root, "root", "/", "root of the filesystem")
	flag.Var(&flags.stage, "stage", fmt.Sprintf("execution stage. %v", stages.Names()))
	flag.BoolVar(&flags.version, "version", false, "print the version and exit")

	flag.Parse()

	if config, ok := oem.Get(flags.oem.String()); ok {
		for k, v := range config.Flags() {
			flag.Set(k, v)
		}
	}

	if flags.version {
		fmt.Printf("ignition %s\n", versionString)
		return
	}

	if flags.stage == "" {
		fmt.Fprint(os.Stderr, "'--stage' must be provided\n")
		os.Exit(2)
	}

	var logger log.Logger
	if slogger, err := syslog.New(syslog.LOG_DEBUG, "ignition"); err == nil {
		defer slogger.Close()
		logger = slogger
	} else {
		logger = log.Stdout{}
		logger.Err(fmt.Sprintf("unable to open syslog: %v", err))
	}
	engine := exec.Engine{
		Root:         flags.root,
		FetchTimeout: flags.fetchTimeout,
		Logger:       logger,
		ConfigCache:  flags.configCache,
	}
	for _, name := range flags.providers {
		engine.AddProvider(providers.Get(name).Create(logger))
	}

	if !engine.Run(flags.stage.String()) {
		os.Exit(1)
	}
}
<commit_msg>main: introduce --clear-cache flag<commit_after>// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"flag"
	"fmt"
	"log/syslog"
	"os"
	"time"

	"github.com/coreos/ignition/src/exec"
	"github.com/coreos/ignition/src/exec/stages"
	_ "github.com/coreos/ignition/src/exec/stages/prepivot"
	"github.com/coreos/ignition/src/log"
	"github.com/coreos/ignition/src/oem"
	"github.com/coreos/ignition/src/providers"
	_ "github.com/coreos/ignition/src/providers/cmdline"

	"github.com/coreos/ignition/Godeps/_workspace/src/github.com/coreos/go-semver/semver"
)

const versionString = "0.0.0+git"

var version = *semver.Must(semver.NewVersion(versionString))

func main() {
	flags := struct {
		clearCache   bool
		configCache  string
		fetchTimeout time.Duration
		oem          oem.Name
		providers    providers.List
		root         string
		stage        stages.Name
		version      bool
	}{}

	flag.BoolVar(&flags.clearCache, "clear-cache", false, "clear any cached config")
	flag.StringVar(&flags.configCache, "config-cache", "/tmp/ignition.json", "where to cache the config")
	flag.DurationVar(&flags.fetchTimeout, "fetchtimeout", exec.DefaultFetchTimeout, "")
	flag.Var(&flags.oem, "oem", fmt.Sprintf("current oem. %v", oem.Names()))
	flag.Var(&flags.providers, "provider", fmt.Sprintf("provider of config. can be specified multiple times. %v", providers.Names()))
	flag.StringVar(&flags.root, "root", "/", "root of the filesystem")
	flag.Var(&flags.stage, "stage", fmt.Sprintf("execution stage. %v", stages.Names()))
	flag.BoolVar(&flags.version, "version", false, "print the version and exit")

	flag.Parse()

	if config, ok := oem.Get(flags.oem.String()); ok {
		for k, v := range config.Flags() {
			flag.Set(k, v)
		}
	}

	if flags.version {
		fmt.Printf("ignition %s\n", versionString)
		return
	}

	if flags.stage == "" {
		fmt.Fprint(os.Stderr, "'--stage' must be provided\n")
		os.Exit(2)
	}

	var logger log.Logger
	if slogger, err := syslog.New(syslog.LOG_DEBUG, "ignition"); err == nil {
		defer slogger.Close()
		logger = slogger
	} else {
		logger = log.Stdout{}
		logger.Err(fmt.Sprintf("unable to open syslog: %v", err))
	}

	if flags.clearCache {
		if err := os.Remove(flags.configCache); err != nil {
			logger.Err(fmt.Sprintf("unable to clear cache: %v", err))
		}
	}

	engine := exec.Engine{
		Root:         flags.root,
		FetchTimeout: flags.fetchTimeout,
		Logger:       logger,
		ConfigCache:  flags.configCache,
	}
	for _, name := range flags.providers {
		engine.AddProvider(providers.Get(name).Create(logger))
	}

	if !engine.Run(flags.stage.String()) {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"path/filepath"
)

type Config struct {
	FactorioDir        string `json:"factorio_dir"`
	FactorioSavesDir   string `json:"saves_dir"`
	FactorioModsDir    string `json:"mods_dir"`
	FactorioConfigFile string `json:"config_file"`
	FactorioLog        string `json:"logfile"`
	FactorioBinary     string `json:"factorio_binary"`
	ServerIP           string `json:"server_ip"`
	ServerPort         string `json:"server_port"`
	MaxUploadSize      int64  `json:"max_upload_size"`
	Username           string `json:"username"`
	Password           string `json:"password"`
	DatabaseFile       string `json:"database_file"`
	ConfFile           string
}

var (
	config       Config
	FactorioServ *FactorioServer
	Auth         *AuthHTTP
)

func failOnError(err error, msg string) {
	if err != nil {
		log.Printf("%s: %s", msg, err)
		panic(fmt.Sprintf("%s: %s", msg, err))
	}
}

// Loads server configuration files
// JSON config file contains default values,
// config file will overwrite any provided flags
func loadServerConfig(f string) {
	file, err := os.Open(f)
	failOnError(err, "Error loading config file.")

	decoder := json.NewDecoder(file)
	err = decoder.Decode(&config)
}

func parseFlags() {
	confFile := flag.String("conf", "./conf.json", "Specify location of Factorio Server Manager config file.")
	factorioDir := flag.String("dir", "./", "Specify location of Factorio directory.")
	factorioIP := flag.String("host", "0.0.0.0", "Specify IP for webserver to listen on.")
	factorioPort := flag.String("port", "8080", "Specify a port for the server.")
	factorioConfigFile := flag.String("config", "config/config.ini", "Specify location of Factorio config.ini file")
	factorioMaxUpload := flag.Int64("max-upload", 1024*1024*20, "Maximum filesize for uploaded files (default 20MB).")
	factorioBinary := flag.String("bin", "bin/x64/factorio", "Location of Factorio Server binary file")

	flag.Parse()

	config.ConfFile = *confFile
	config.FactorioDir = *factorioDir
	config.ServerIP = *factorioIP
	config.ServerPort = *factorioPort
	config.FactorioSavesDir = filepath.Join(config.FactorioDir, "saves")
	config.FactorioModsDir = filepath.Join(config.FactorioDir, "mods")
	config.FactorioConfigFile = filepath.Join(config.FactorioDir, *factorioConfigFile)
	config.FactorioBinary = filepath.Join(config.FactorioDir, *factorioBinary)
	config.FactorioLog = filepath.Join(config.FactorioDir, "factorio-current.log")
	config.MaxUploadSize = *factorioMaxUpload
}

func main() {
	parseFlags()
	loadServerConfig(config.ConfFile)

	// Initialize Factorio Server struct
	FactorioServ = initFactorio()

	// Initialize authentication system
	Auth = initAuth()
	Auth.createAuthDb(config.DatabaseFile)
	Auth.createRoles()
	err := Auth.createInitialUser(config.Username, config.Password, "admin", "")
	if err != nil {
		log.Printf("Error creating user: %s", err)
	}

	router := NewRouter()
	createModPackDir()

	fmt.Printf("Starting server on: %s:%s", config.ServerIP, config.ServerPort)
	log.Fatal(http.ListenAndServe(config.ServerIP+":"+config.ServerPort, router))
}
<commit_msg>Fix file path to factorio-current.log on windows.<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
)

type Config struct {
	FactorioDir        string `json:"factorio_dir"`
	FactorioSavesDir   string `json:"saves_dir"`
	FactorioModsDir    string `json:"mods_dir"`
	FactorioConfigFile string `json:"config_file"`
	FactorioLog        string `json:"logfile"`
	FactorioBinary     string `json:"factorio_binary"`
	ServerIP           string `json:"server_ip"`
	ServerPort         string `json:"server_port"`
	MaxUploadSize      int64  `json:"max_upload_size"`
	Username           string `json:"username"`
	Password           string `json:"password"`
	DatabaseFile       string `json:"database_file"`
	ConfFile           string
}

var (
	config       Config
	FactorioServ *FactorioServer
	Auth         *AuthHTTP
)

func failOnError(err error, msg string) {
	if err != nil {
		log.Printf("%s: %s", msg, err)
		panic(fmt.Sprintf("%s: %s", msg, err))
	}
}

// Loads server configuration files
// JSON config file contains default values,
// config file will overwrite any provided flags
func loadServerConfig(f string) {
	file, err := os.Open(f)
	failOnError(err, "Error loading config file.")

	decoder := json.NewDecoder(file)
	err = decoder.Decode(&config)
}

func parseFlags() {
	confFile := flag.String("conf", "./conf.json", "Specify location of Factorio Server Manager config file.")
	factorioDir := flag.String("dir", "./", "Specify location of Factorio directory.")
	factorioIP := flag.String("host", "0.0.0.0", "Specify IP for webserver to listen on.")
	factorioPort := flag.String("port", "8080", "Specify a port for the server.")
	factorioConfigFile := flag.String("config", "config/config.ini", "Specify location of Factorio config.ini file")
	factorioMaxUpload := flag.Int64("max-upload", 1024*1024*20, "Maximum filesize for uploaded files (default 20MB).")
	factorioBinary := flag.String("bin", "bin/x64/factorio", "Location of Factorio Server binary file")

	flag.Parse()

	config.ConfFile = *confFile
	config.FactorioDir = *factorioDir
	config.ServerIP = *factorioIP
	config.ServerPort = *factorioPort
	config.FactorioSavesDir = filepath.Join(config.FactorioDir, "saves")
	config.FactorioModsDir = filepath.Join(config.FactorioDir, "mods")
	config.FactorioConfigFile = filepath.Join(config.FactorioDir, *factorioConfigFile)
	config.FactorioBinary = filepath.Join(config.FactorioDir, *factorioBinary)
	config.MaxUploadSize = *factorioMaxUpload

    if runtime.GOOS == "windows" {
        appdata := os.Getenv("APPDATA")
        config.FactorioLog = filepath.Join(appdata, "Factorio", "factorio-current.log")
    } else {
        config.FactorioLog = filepath.Join(config.FactorioDir, "factorio-current.log")
    }
}

func main() {
	parseFlags()
	loadServerConfig(config.ConfFile)

	// Initialize Factorio Server struct
	FactorioServ = initFactorio()

	// Initialize authentication system
	Auth = initAuth()
	Auth.createAuthDb(config.DatabaseFile)
	Auth.createRoles()
	err := Auth.createInitialUser(config.Username, config.Password, "admin", "")
	if err != nil {
		log.Printf("Error creating user: %s", err)
	}

	router := NewRouter()
	createModPackDir()

	fmt.Printf("Starting server on: %s:%s", config.ServerIP, config.ServerPort)
	log.Fatal(http.ListenAndServe(config.ServerIP+":"+config.ServerPort, router))
}
<|endoftext|>