<commit_before>package dbr

import (
	"github.com/corestoreio/csfw/util/bufferpool"
	"github.com/corestoreio/errors"
)

type alias struct {
	// Select used in cases where a sub-select is required.
	Select *Select
	// Expression can be any kind of SQL expression or a valid identifier.
	Expression string
	// Alias must be a valid identifier allowed for alias usage.
	Alias string
}

// MakeAlias creates a new alias expression
func MakeAlias(as ...string) alias {
	a := alias{
		Expression: as[0],
	}
	if len(as) > 1 {
		a.Alias = as[1]
	}
	return a
}

func (t alias) String() string {
	return Quoter.ExprAlias(t.Expression, t.Alias)
}

func (t alias) QuoteAs() string {
	return Quoter.QuoteAs(t.Expression, t.Alias)
}

// QuoteAsWriter writes the quote table and its maybe alias into w.
func (t alias) QuoteAsWriter(w queryWriter) (Arguments, error) {
	if t.Select != nil {
		w.WriteRune('(')
		args, err := t.Select.toSQL(w)
		w.WriteRune(')')
		w.WriteString(" AS ")
		Quoter.quote(w, t.Alias)
		return args, errors.Wrap(err, "[dbr] QuoteAsWriter.SubSelect")
	}
	Quoter.quoteAs(w, t.Expression, t.Alias)
	return nil, nil
}

// DefaultScopeNames specifies the name of the scopes used in all EAV* function
// to generate scope based hierarchical fall backs.
var DefaultScopeNames = [...]string{"Store", "Group", "Website", "Default"}

// EAVIfNull creates a nested IFNULL SQL statement when a scope based fall back
// hierarchy is required. Alias argument will be used as a prefix for the alias
// table name and as the final alias name.
// TODO: Migrate into EAV package
func EAVIfNull(alias, columnName, defaultVal string, scopeNames ...string) string {
	buf := bufferpool.Get()
	defer bufferpool.Put(buf)

	if len(scopeNames) == 0 {
		scopeNames = DefaultScopeNames[:]
	}

	brackets := 0
	for _, n := range scopeNames {
		buf.WriteString("IFNULL(")
		buf.WriteRune('`')
		buf.WriteString(alias)
		buf.WriteString(n)
		buf.WriteRune('`')
		buf.WriteRune('.')
		buf.WriteRune('`')
		buf.WriteString(columnName)
		buf.WriteRune('`')
		if brackets < len(scopeNames)-1 {
			buf.WriteRune(',')
		}
		brackets++
	}

	if defaultVal == "" {
		defaultVal = `''`
	}
	buf.WriteRune(',')
	buf.WriteString(defaultVal)
	for i := 0; i < brackets; i++ {
		buf.WriteRune(')')
	}
	buf.WriteString(" AS ")
	buf.WriteRune('`')
	buf.WriteString(alias)
	buf.WriteRune('`')
	return buf.String()
}
<commit_msg>storage/dbr: Add TODO for type aliases<commit_after>package dbr

import (
	"github.com/corestoreio/csfw/util/bufferpool"
	"github.com/corestoreio/errors"
)

type alias struct {
	// Select used in cases where a sub-select is required.
	Select *Select
	// Expression can be any kind of SQL expression or a valid identifier.
	Expression string
	// Alias must be a valid identifier allowed for alias usage.
	Alias string
}

// MakeAlias creates a new alias expression
func MakeAlias(as ...string) alias {
	a := alias{
		Expression: as[0],
	}
	if len(as) > 1 {
		a.Alias = as[1]
	}
	return a
}

func (t alias) String() string {
	return Quoter.ExprAlias(t.Expression, t.Alias)
}

func (t alias) QuoteAs() string {
	return Quoter.QuoteAs(t.Expression, t.Alias)
}

// QuoteAsWriter writes the quote table and its maybe alias into w.
func (t alias) QuoteAsWriter(w queryWriter) (Arguments, error) {
	if t.Select != nil {
		w.WriteRune('(')
		args, err := t.Select.toSQL(w)
		w.WriteRune(')')
		w.WriteString(" AS ")
		Quoter.quote(w, t.Alias)
		return args, errors.Wrap(err, "[dbr] QuoteAsWriter.SubSelect")
	}
	Quoter.quoteAs(w, t.Expression, t.Alias)
	return nil, nil
}

// TODO(CyS) if we need to distinguish between table name and the column or even need
// a sub select in the column list, then we can implement type aliases and replace
// all []string with type aliases. This costs some allocs but for modifying queries
// in dispatched events, it's getting easier ...
//type aliases []alias
//
//func makeAliasesFromStrings(columns ...string) aliases {
//
//}

// DefaultScopeNames specifies the name of the scopes used in all EAV* function
// to generate scope based hierarchical fall backs.
var DefaultScopeNames = [...]string{"Store", "Group", "Website", "Default"}

// EAVIfNull creates a nested IFNULL SQL statement when a scope based fall back
// hierarchy is required. Alias argument will be used as a prefix for the alias
// table name and as the final alias name.
// TODO: Migrate into EAV package
func EAVIfNull(alias, columnName, defaultVal string, scopeNames ...string) string {
	buf := bufferpool.Get()
	defer bufferpool.Put(buf)

	if len(scopeNames) == 0 {
		scopeNames = DefaultScopeNames[:]
	}

	brackets := 0
	for _, n := range scopeNames {
		buf.WriteString("IFNULL(")
		buf.WriteRune('`')
		buf.WriteString(alias)
		buf.WriteString(n)
		buf.WriteRune('`')
		buf.WriteRune('.')
		buf.WriteRune('`')
		buf.WriteString(columnName)
		buf.WriteRune('`')
		if brackets < len(scopeNames)-1 {
			buf.WriteRune(',')
		}
		brackets++
	}

	if defaultVal == "" {
		defaultVal = `''`
	}
	buf.WriteRune(',')
	buf.WriteString(defaultVal)
	for i := 0; i < brackets; i++ {
		buf.WriteRune(')')
	}
	buf.WriteString(" AS ")
	buf.WriteRune('`')
	buf.WriteString(alias)
	buf.WriteRune('`')
	return buf.String()
}
<|endoftext|>


<commit_before>// +build linux

package storage

import (
	"github.com/golang/glog"
	"os"
	"syscall"
	"time"
)

type WAL struct {
	fd   int
	mode string
}

func openWriteAheadFile(filename string, mode string) WAL {
	var file int
	var err error
	switch mode {
	case "osync":
		file, err = syscall.Open(filename, syscall.O_SYNC|os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
	case "dsync":
		file, err = syscall.Open(filename, syscall.O_DSYNC|os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
	case "direct":
		file, err = syscall.Open(filename, syscall.O_DIRECT|os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
	case "none", "fsync":
		file, err = syscall.Open(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
	default:
		glog.Fatal("PersistenceMode not reconised")
	}
	if err != nil {
		glog.Fatal(err)
	}
	// TOD0: remove hardcoded filesize
	err = syscall.Fallocate(file, 0, 0, int64(64*1000*1000)) // 64MB
	if err != nil {
		glog.Fatal(err)
	}
	return WAL{file, mode}
}

func (w WAL) writeAhead(bytes []byte) {
	startTime := time.Now()
	_, err := syscall.Write(w.fd, bytes)
	_,_ = syscall.Write(w.fd, byte[]('\n'))
	if err != nil {
		glog.Fatal(err)
	}
	if w.mode == "fsync" || w.mode == "direct" {
		err = syscall.Fdatasync(w.fd)
		if err != nil {
			glog.Fatal(err)
		}
	}
	if time.Since(startTime) > time.Millisecond {
		glog.Info(" bytes written & synced to persistent log in ", time.Since(startTime).String())
	}
	glog.V(1).Info(" bytes written & synced to persistent log in ", time.Since(startTime).String())
}
<commit_msg>fixing travis build in wal_linux<commit_after>// +build linux

package storage

import (
	"github.com/golang/glog"
	"os"
	"syscall"
	"time"
)

type WAL struct {
	fd   int
	mode string
}

func openWriteAheadFile(filename string, mode string) WAL {
	var file int
	var err error
	switch mode {
	case "osync":
		file, err = syscall.Open(filename, syscall.O_SYNC|os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
	case "dsync":
		file, err = syscall.Open(filename, syscall.O_DSYNC|os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
	case "direct":
		file, err = syscall.Open(filename, syscall.O_DIRECT|os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
	case "none", "fsync":
		file, err = syscall.Open(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
	default:
		glog.Fatal("PersistenceMode not reconised")
	}
	if err != nil {
		glog.Fatal(err)
	}
	// TOD0: remove hardcoded filesize
	err = syscall.Fallocate(file, 0, 0, int64(64*1000*1000)) // 64MB
	if err != nil {
		glog.Fatal(err)
	}
	return WAL{file, mode}
}

func (w WAL) writeAhead(bytes []byte) {
	startTime := time.Now()
	_, err := syscall.Write(w.fd, bytes)
	_,_ = syscall.Write(w.fd, []byte("\n"))
	if err != nil {
		glog.Fatal(err)
	}
	if w.mode == "fsync" || w.mode == "direct" {
		err = syscall.Fdatasync(w.fd)
		if err != nil {
			glog.Fatal(err)
		}
	}
	if time.Since(startTime) > time.Millisecond {
		glog.Info(" bytes written & synced to persistent log in ", time.Since(startTime).String())
	}
	glog.V(1).Info(" bytes written & synced to persistent log in ", time.Since(startTime).String())
}
<|endoftext|>


<commit_before>package streamtools

import (
	"container/heap"
	"github.com/bitly/go-simplejson"
	"log"
	"time"
)

func Count(inChan chan *simplejson.Json, ruleChan chan *simplejson.Json, queryChan chan stateQuery) {
	// block until we recieve a rule
	params = <-ruleChan
	windowSeconds, err := params.Get("window").Float64()
	if err != nil {
		log.Fatal(err.Error())
	}
	window := time.Duration(windowSeconds) * time.Second
	waitTimer := time.NewTimer(100 * time.Millisecond)

	pq := &PriorityQueue{}
	heap.Init(pq)

	emptyByte := make([]byte, 0)

	for {
		select {
		case params = <-ruleChan:
		case query = <-queryChan:
			out, err := simplejson.NewJson([]byte("{}"))
			if err != nil {
				log.Fatal(err.Error())
			}
			out.Set("count", len(*pq))
			query.responseChan <- out
		case <-inChan:
			queueMessage := &PQMessage{
				val: &emptyByte,
				t:   time.Now(),
			}
			if err != nil {
				log.Fatal(err.Error())
			}
			heap.Push(pq, queueMessage)
		case <-waitTimer.C:
		}
		for {
			pqMsg, diff := pq.PeekAndShift(time.Now(), window)
			if pqMsg == nil {
				// either the queue is empty, or it's not time to emit
				if diff == 0 {
					// then the queue is empty. Pause for 5 seconds before checking again
					diff = 5
				}
				waitTimer.Reset(diff)
				break
			}
		}
	}
}
<commit_msg>changed the delay from 5ns to 5s (oops)<commit_after>package streamtools

import (
	"container/heap"
	"github.com/bitly/go-simplejson"
	"log"
	"time"
)

func Count(inChan chan *simplejson.Json, ruleChan chan *simplejson.Json, queryChan chan stateQuery) {
	// block until we recieve a rule
	params = <-ruleChan
	windowSeconds, err := params.Get("window").Float64()
	if err != nil {
		log.Fatal(err.Error())
	}
	window := time.Duration(windowSeconds) * time.Second
	waitTimer := time.NewTimer(100 * time.Millisecond)

	pq := &PriorityQueue{}
	heap.Init(pq)

	emptyByte := make([]byte, 0)

	for {
		select {
		case params = <-ruleChan:
		case query = <-queryChan:
			out, err := simplejson.NewJson([]byte("{}"))
			if err != nil {
				log.Fatal(err.Error())
			}
			out.Set("count", len(*pq))
			query.responseChan <- out
		case <-inChan:
			queueMessage := &PQMessage{
				val: &emptyByte,
				t:   time.Now(),
			}
			if err != nil {
				log.Fatal(err.Error())
			}
			heap.Push(pq, queueMessage)
		case <-waitTimer.C:
		}
		for {
			pqMsg, diff := pq.PeekAndShift(time.Now(), window)
			if pqMsg == nil {
				// either the queue is empty, or it's not time to emit
				if diff == 0 {
					// then the queue is empty. Pause for 5 seconds before checking again
					diff = time.Duration(5)*time.Second
				}
				waitTimer.Reset(diff)
				break
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"gob"
	"encoding/binary"
	"os"
	"strings"
	"fmt"
	"log"
	"io"
	"sync"
)

func main() {
	s, err := Encode(os.Args[1])
	if err != nil {
		fmt.Printf("error: %v\n", err)
		return
	}
	fmt.Printf("encoded: %d bytes\n", len(s))

	fs, err := Decode(s)
	if err != nil {
		log.Exitf("decode: %v\n", err)
		return
	}
	fmt.Printf("all:\n")
	show(fs, "/")
}

func show(fs *FS, path string) {
	f, err := fs.Open(path)
	if err != nil {
		log.Printf("cannot open %s: %v\n", path, err)
		return
	}
	if f.IsDirectory() {
		fmt.Printf("d %s\n", path)
		names, err := f.Readdirnames()
		if err != nil {
			log.Printf("cannot get contents of %s: %v\n", path, err)
			return
		}
		for _, name := range names {
			show(fs, path+"/"+name)
		}
	}else{
		fmt.Printf("- %s\n", path)
		n, err := io.Copy(nullWriter{}, f)
		if err != nil {
			log.Printf("cannot read %s: %v\n", err)
			return
		}
		fmt.Printf("	%d bytes\n", n)
	}
}

type nullWriter struct {}
func (nullWriter) Write(data []byte) (int, os.Error) {
	return len(data), nil
}

// fsWriter represents file system while it's being encoded.
// The gob Encoder writes to the the bytes.Buffer.
type fsWriter struct {
	buf bytes.Buffer
	enc *gob.Encoder
}

// entry is the basic file system structure - it holds
// information on one directory entry.
type entry struct {
	name string		// name of entry.
	offset int			// start of information for this entry.
	dir bool			// is it a directory?
	len int			// length of file (only if it's a file)
}

// FS represents the file system and all its data.
type FS struct {
	mu sync.Mutex
	s string
	root uint32
	dec *gob.Decoder
	rd strings.Reader
}

// A File represents an entry in the file system.
type File struct {
	fs *FS
	rd strings.Reader
	entry *entry
}

// Encode recursively reads the directory at path
// and encodes it into a read only file system
// that can later be read with Decode.
func Encode(path string) (string, os.Error) {
	fs := &fsWriter{}
	fs.enc = gob.NewEncoder(&fs.buf)
	// make sure entry type is encoded first.
	fs.enc.Encode([]entry{})

	e, err := fs.write(path)
	if err != nil {
		return "", err
	}
	if !e.dir {
		return "", os.ErrorString("root must be a directory")
	}
	binary.Write(&fs.buf, binary.LittleEndian, uint32(e.offset))
	return string(fs.buf.Bytes()), nil
}

// write writes path and all its contents to the file system.
func (fs *fsWriter) write(path string) (*entry, os.Error) {
	f, err := os.Open(path, os.O_RDONLY, 0)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	info, err := f.Stat()
	if info == nil {
		return nil, err
	}
	if info.IsDirectory() {
		names, err := f.Readdirnames(-1)
		if err != nil {
			return nil, err
		}
		entries := make([]entry, len(names))
		for i, name := range names {
			ent, err := fs.write(path+"/"+name)
			if err != nil {
				return nil, err
			}
			ent.name = name
			entries[i] = *ent
		}
		off := len(fs.buf.Bytes())
		fs.enc.Encode(entries)
		return &entry{offset: off, dir: true}, nil
	}
	off := len(fs.buf.Bytes())
	buf := make([]byte, 8192)
	tot := 0
	for {
		n, _ := f.Read(buf)
		if n == 0 {
			break
		}
		fs.buf.Write(buf[0:n])
		tot += n
	}
	return &entry{offset: off, dir: false, len: tot}, nil
}

// Decode converts a file system as encoded by Encode
// into an FS.
func Decode(s string) (*FS, os.Error) {
	fs := new(FS)
	r := strings.NewReader(s[len(s)-4:])
	if err := binary.Read(r, binary.LittleEndian, &fs.root); err != nil {
		return nil, err
	}
	fs.s = s[0:len(s)-4]
	fs.dec = gob.NewDecoder(&fs.rd)

	// read dummy entry at start to prime the gob types.
	fs.rd = strings.Reader(fs.s)
	if err := fs.dec.Decode(new([]entry)); err != nil {
		return nil, err
	}

	return fs, nil
}

func isSlash(c int) bool {
	return c == '/'
}

// Open opens the named path within fs.
// Paths are slash-separated, with an optional
// slash prefix.
func (fs *FS) Open(path string) (*File, os.Error) {
	p := strings.FieldsFunc(path, isSlash)
	e := &entry{dir: true, offset: int(fs.root)}

	fs.mu.Lock()
	defer fs.mu.Unlock()
	for _, name := range p {
		var err os.Error
		e, err = fs.walk(e, name)
		if err != nil {
			return nil, err
		}
	}
	if e.dir {
		return &File{fs, "", e}, nil
	}
	return &File{
		fs,
		strings.Reader(fs.s[e.offset: e.offset+e.len]),
		e,
	}, nil
}

func (fs *FS) walk(e *entry, name string) (*entry, os.Error) {
	if !e.dir {
		return nil, os.ErrorString("not a directory")
	}
	contents, err := fs.contents(e)
	if err != nil {
		return nil, err
	}
	for i := range contents {
		if contents[i].name == name {
			return &contents[i], nil
		}
	}
	return nil, os.ErrorString("file not found")
}

// IsDirectory returns true if the file represents a directory.
func (f *File) IsDirectory() bool {
	return f.entry.dir
}

// Read reads from a file. It is invalid to call it on a directory.
func (f *File) Read(buf []byte) (int, os.Error) {
	if f.entry.dir {
		return 0, os.ErrorString("cannot read a directory")
	}
	return f.rd.Read(buf)
}

// contents returns all the entries inside a directory.
func (fs *FS) contents(e *entry) (entries []entry, err os.Error) {
	if !e.dir {
		return nil, os.ErrorString("not a directory")
	}
	fs.rd = strings.Reader(fs.s[e.offset:])
	err = fs.dec.Decode(&entries)
	return
}

// Readdirnames returns the names of all the files in
// the File, which must be a directory.
func (f *File) Readdirnames() ([]string, os.Error) {
	f.fs.mu.Unlock()
	defer f.fs.mu.Unlock()
	entries, err := f.fs.contents(f.entry)
	if err != nil {
		return nil, err
	}
	names := make([]string, len(entries))
	for i, e := range entries {
		names[i] = e.name
	}
	return names, nil
}
<commit_msg>added comments<commit_after>// The stringfs package provides a way to recursively encode the
// data in a directory as a string, and to extract the contents later.
package stringfs

import (
	"bytes"
	"encoding/binary"
	"gob"
	"os"
	"strings"
	"sync"
)

// The file system encoding uses gob to encode the
// metadata.
// It takes advantage of the fact that gob encodes all
// its types up front, which means we can decode gob
// package out of order as long as we know that the
// relevant types have been received first.
//
// The first item in the file system is a dummy type
// representing an array of directory entries.
// The final four bytes hold the offset of the start
// of the root directory (note that this uses regular
// non-variable-width encoding, so that we know
// exactly where it is).
// Each file entry is directly encoded as the bytes
// of the file, not using gob.
// Each directory entry is encoded as an array of
// entry types.

// entry is the basic file system structure - it holds
// information on one directory entry.
type entry struct {
	name string		// name of entry.
	offset int			// start of information for this entry.
	dir bool			// is it a directory?
	len int			// length of file (only if it's a file)
}

// fsWriter represents file system while it's being encoded.
// The gob Encoder writes to the the bytes.Buffer.
type fsWriter struct {
	buf bytes.Buffer
	enc *gob.Encoder
}

// FS represents the file system and all its data.
type FS struct {
	mu sync.Mutex
	s string
	root uint32			// offset of root directory.
	dec *gob.Decoder		// primed decoder, reading from &rd.
	rd strings.Reader
}

// A File represents an entry in the file system.
type File struct {
	fs *FS
	rd strings.Reader
	entry *entry
}

// Encode recursively reads the directory at path
// and encodes it into a read only file system
// that can later be read with Decode.
func Encode(path string) (string, os.Error) {
	fs := &fsWriter{}
	fs.enc = gob.NewEncoder(&fs.buf)
	// make sure entry type is encoded first.
	fs.enc.Encode([]entry{})

	e, err := fs.write(path)
	if err != nil {
		return "", err
	}
	if !e.dir {
		return "", os.ErrorString("root must be a directory")
	}
	binary.Write(&fs.buf, binary.LittleEndian, uint32(e.offset))
	return string(fs.buf.Bytes()), nil
}

// write writes path and all its contents to the file system.
func (fs *fsWriter) write(path string) (*entry, os.Error) {
	f, err := os.Open(path, os.O_RDONLY, 0)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	info, err := f.Stat()
	if info == nil {
		return nil, err
	}
	if info.IsDirectory() {
		names, err := f.Readdirnames(-1)
		if err != nil {
			return nil, err
		}
		entries := make([]entry, len(names))
		for i, name := range names {
			ent, err := fs.write(path+"/"+name)
			if err != nil {
				return nil, err
			}
			ent.name = name
			entries[i] = *ent
		}
		off := len(fs.buf.Bytes())
		fs.enc.Encode(entries)
		return &entry{offset: off, dir: true}, nil
	}
	off := len(fs.buf.Bytes())
	buf := make([]byte, 8192)
	tot := 0
	for {
		n, _ := f.Read(buf)
		if n == 0 {
			break
		}
		fs.buf.Write(buf[0:n])
		tot += n
	}
	return &entry{offset: off, dir: false, len: tot}, nil
}

// Decode converts a file system as encoded by Encode
// into an FS.
func Decode(s string) (*FS, os.Error) {
	fs := new(FS)
	r := strings.NewReader(s[len(s)-4:])
	if err := binary.Read(r, binary.LittleEndian, &fs.root); err != nil {
		return nil, err
	}
	fs.s = s[0:len(s)-4]
	fs.dec = gob.NewDecoder(&fs.rd)

	// read dummy entry at start to prime the gob types.
	fs.rd = strings.Reader(fs.s)
	if err := fs.dec.Decode(new([]entry)); err != nil {
		return nil, err
	}

	return fs, nil
}

func isSlash(c int) bool {
	return c == '/'
}

// Open opens the named path within fs.
// Paths are slash-separated, with an optional
// slash prefix.
func (fs *FS) Open(path string) (*File, os.Error) {
	p := strings.FieldsFunc(path, isSlash)
	e := &entry{dir: true, offset: int(fs.root)}

	fs.mu.Lock()
	defer fs.mu.Unlock()
	for _, name := range p {
		var err os.Error
		e, err = fs.walk(e, name)
		if err != nil {
			return nil, err
		}
	}
	if e.dir {
		return &File{fs, "", e}, nil
	}
	return &File{
		fs,
		strings.Reader(fs.s[e.offset: e.offset+e.len]),
		e,
	}, nil
}

func (fs *FS) walk(e *entry, name string) (*entry, os.Error) {
	if !e.dir {
		return nil, os.ErrorString("not a directory")
	}
	contents, err := fs.contents(e)
	if err != nil {
		return nil, err
	}
	for i := range contents {
		if contents[i].name == name {
			return &contents[i], nil
		}
	}
	return nil, os.ErrorString("file not found")
}

// IsDirectory returns true if the file represents a directory.
func (f *File) IsDirectory() bool {
	return f.entry.dir
}

// Read reads from a file. It is invalid to call it on a directory.
func (f *File) Read(buf []byte) (int, os.Error) {
	if f.entry.dir {
		return 0, os.ErrorString("cannot read a directory")
	}
	return f.rd.Read(buf)
}

// contents returns all the entries inside a directory.
func (fs *FS) contents(e *entry) (entries []entry, err os.Error) {
	if !e.dir {
		return nil, os.ErrorString("not a directory")
	}
	fs.rd = strings.Reader(fs.s[e.offset:])
	err = fs.dec.Decode(&entries)
	return
}

// Readdirnames returns the names of all the files in
// the File, which must be a directory.
func (f *File) Readdirnames() ([]string, os.Error) {
	f.fs.mu.Unlock()
	defer f.fs.mu.Unlock()
	entries, err := f.fs.contents(f.entry)
	if err != nil {
		return nil, err
	}
	names := make([]string, len(entries))
	for i, e := range entries {
		names[i] = e.name
	}
	return names, nil
}
<|endoftext|>


<commit_before>package supervisor

import (
	"fmt"
	"github.com/pborman/uuid"
	"time"
	"bytes"
	"strings"
	"encoding/json"
)

type UpdateOp int

const (
	STOPPED UpdateOp = iota
	OUTPUT
	RESTORE_KEY
)

type WorkerUpdate struct {
	Task      uuid.UUID
	Op        UpdateOp
	StoppedAt time.Time
	Output    string
}

func worker(id uint, work chan Task, updates chan WorkerUpdate) {
	for t := range work {
		fmt.Printf("worker %d received task %v\n", id, t.UUID.String())

		var output []string
		stderr := make(chan string)
		stdout := make(chan string)

		// drain stdout to the output[] array
		go func() {
			for {
				s, ok := <-stdout
				if !ok {
					break
				}
				output = append(output, s)
			}
		}()

		// relay messages on stderr to the updates
		// channel, wrapped in a WorkerUpdate struct
		go func() {
			for {
				s, ok := <-stderr
				if !ok {
					break
				}
				updates <- WorkerUpdate{
					Task:   t.UUID,
					Op:     OUTPUT,
					Output: s,
				}
			}
		}()

		// run the task...
		err := t.Run(stdout, stderr)
		if err != nil {
			fmt.Printf("oops: %s\n", err)
		}

		if t.Op == BACKUP {
			// parse JSON from standard output and get the restore key
			// (this might fail, we might not get a key, etc.)

			// FIXME: stop the drain goroutine for stdout.
			// FIXME: (geoff noticed some data races here, so that may just happen
			//         when he fixes those)
			v := struct {
				Key string
			}{}

			buf := bytes.NewBufferString(strings.Join(output, ""))
			dec := json.NewDecoder(buf)
			err := dec.Decode(&v)

			if err != nil {
				fmt.Printf("uh-oh: %s\n", err)

			} else {
				updates <- WorkerUpdate{
					Task:   t.UUID,
					Op:     RESTORE_KEY,
					Output: v.Key,
				}
			}
		}

		// signal to the supervisor that we finished
		updates <- WorkerUpdate{
			Task:      t.UUID,
			Op:        STOPPED,
			StoppedAt: time.Now(),
		}
	}
}

func (s *Supervisor) SpawnWorker() {
	s.nextWorker += 1
	go worker(s.nextWorker, s.workers, s.updates)
}
<commit_msg>Fix Data Race conditions in worker.go<commit_after>package supervisor

import (
	"fmt"
	"github.com/pborman/uuid"
	"time"
	"bytes"
	"strings"
	"encoding/json"
)

type UpdateOp int

const (
	STOPPED UpdateOp = iota
	OUTPUT
	RESTORE_KEY
)

type WorkerUpdate struct {
	Task      uuid.UUID
	Op        UpdateOp
	StoppedAt time.Time
	Output    string
}

func worker(id uint, work chan Task, updates chan WorkerUpdate) {
	for t := range work {
		fmt.Printf("worker %d received task %v\n", id, t.UUID.String())

		output := make(chan string)
		stderr := make(chan string)
		stdout := make(chan string)

		// drain stdout to the output[] array
		go func(out chan string, in chan string) {
			var b []string
			for {
				s, ok := <-in
				if !ok {
					break
				}
				b = append(b, s)
			}

			out <- strings.Join(b, "")
			close(out)
		}(output, stdout)

		// relay messages on stderr to the updates
		// channel, wrapped in a WorkerUpdate struct
		go func(t Task, in chan string) {
			for {
				s, ok := <-in
				if !ok {
					break
				}
				updates <- WorkerUpdate{
					Task:   t.UUID,
					Op:     OUTPUT,
					Output: s,
				}
			}
		}(t, stderr)

		// run the task...
		err := t.Run(stdout, stderr)
		if err != nil {
			fmt.Printf("oops: %s\n", err)
		}

		if t.Op == BACKUP {
			// parse JSON from standard output and get the restore key
			// (this might fail, we might not get a key, etc.)

			// FIXME: stop the drain goroutine for stdout.
			// FIXME: (geoff noticed some data races here, so that may just happen
			//         when he fixes those)
			v := struct {
				Key string
			}{}

			buf := bytes.NewBufferString(<-output)
			dec := json.NewDecoder(buf)
			err := dec.Decode(&v)

			if err != nil {
				fmt.Printf("uh-oh: %s\n", err)

			} else {
				updates <- WorkerUpdate{
					Task:   t.UUID,
					Op:     RESTORE_KEY,
					Output: v.Key,
				}
			}
		}

		// signal to the supervisor that we finished
		updates <- WorkerUpdate{
			Task:      t.UUID,
			Op:        STOPPED,
			StoppedAt: time.Now(),
		}
	}
}

func (s *Supervisor) SpawnWorker() {
	s.nextWorker += 1
	go worker(s.nextWorker, s.workers, s.updates)
}
<|endoftext|>


<commit_before>// Package router is a network/router selector
package router

import (
	"context"
	"net"
	"sort"
	"strconv"
	"sync"

	"github.com/micro/go-micro/client/selector"
	"github.com/micro/go-micro/network/router"
	"github.com/micro/go-micro/registry"
)

type routerSelector struct {
	opts selector.Options

	// the router
	r router.Router
}

type routerKey struct{}

func (r *routerSelector) Init(opts ...selector.Option) error {
	// no op
	return nil
}

func (r *routerSelector) Options() selector.Options {
	return r.opts
}

func (r *routerSelector) Select(service string, opts ...selector.SelectOption) (selector.Next, error) {
	// lookup router for routes for the service
	routes, err := r.r.Table().Lookup(router.NewQuery(
		router.QueryDestination(service),
	))

	if err != nil {
		return nil, err
	}

	// no routes return not found error
	if len(routes) == 0 {
		return nil, selector.ErrNotFound
	}

	// TODO: apply filters by pseudo constructing service

	// sort the routes based on metric
	sort.Slice(routes, func(i, j int) bool {
		return routes[i].Metric < routes[j].Metric
	})

	// roundrobin assuming routes are in metric preference order
	var i int
	var mtx sync.Mutex

	return func() (*registry.Node, error) {
		// get index and increment counter with every call to next
		mtx.Lock()
		idx := i
		i++
		mtx.Unlock()

		// get route based on idx
		route := routes[idx%len(routes)]

		// defaults to gateway and no port
		address := route.Gateway
		port := 0

		// check if its host:port
		host, pr, err := net.SplitHostPort(address)
		if err == nil {
			pp, _ := strconv.Atoi(pr)
			// set port
			port = pp
			// set address
			address = host
		}

		// return as a node
		return &registry.Node{
			// TODO: add id and metadata if we can
			Address: address,
			Port:    port,
		}, nil
	}, nil
}

func (r *routerSelector) Mark(service string, node *registry.Node, err error) {
	// TODO: pass back metrics or information to the router
	return
}

func (r *routerSelector) Reset(service string) {
	// TODO: reset the metrics or information at the router
	return
}

func (r *routerSelector) Close() error {
	// stop the router advertisements
	return r.r.Stop()
}

func (r *routerSelector) String() string {
	return "router"
}

// NewSelector returns a new router based selector
func NewSelector(opts ...selector.Option) selector.Selector {
	options := selector.Options{
		Context: context.Background(),
	}

	for _, o := range opts {
		o(&options)
	}

	// set default registry if not set
	if options.Registry == nil {
		options.Registry = registry.DefaultRegistry
	}

	// try get from the context
	r, ok := options.Context.Value(routerKey{}).(router.Router)
	if !ok {
		// TODO: Use router.DefaultRouter?
		r = router.NewRouter(
			router.Registry(options.Registry),
		)
	}

	// start the router advertisements
	r.Advertise()

	return &routerSelector{
		opts: options,
		r:    r,
	}
}

// WithRouter sets the router as an option
func WithRouter(r router.Router) selector.Option {
	return func(o *selector.Options) {
		if o.Context == nil {
			o.Context = context.Background()
		}
		o.Context = context.WithValue(o.Context, routerKey{}, r)
	}
}
<commit_msg>Add remote lookup via router selector<commit_after>// Package router is a network/router selector
package router

import (
	"context"
	"net"
	"os"
	"sort"
	"strconv"
	"sync"

	"github.com/micro/go-micro/client"
	"github.com/micro/go-micro/client/selector"
	"github.com/micro/go-micro/network/router"
	pb "github.com/micro/go-micro/network/router/proto"
	"github.com/micro/go-micro/registry"
)

type routerSelector struct {
	opts selector.Options

	// the router
	r router.Router

	// the client for the remote router
	c pb.RouterService

	// address of the remote router
	addr string

	// whether to use the remote router
	remote bool
}

type clientKey struct{}
type routerKey struct{}

// getRoutes returns the routes whether they are remote or local
func (r *routerSelector) getRoutes(service string) ([]router.Route, error) {
	if !r.remote {
		// lookup router for routes for the service
		return r.r.Table().Lookup(router.NewQuery(
			router.QueryDestination(service),
		))
	}

	// lookup the remote router

	var clientOpts []client.CallOption

	// set the remote address if specified
	if len(r.addr) > 0 {
		clientOpts = append(clientOpts, client.WithAddress(r.addr))
	}

	// call the router
	pbRoutes, err := r.c.Lookup(context.Background(), &pb.LookupRequest{
		Query: &pb.Query{
			Destination: service,
		},
	}, clientOpts...)
	if err != nil {
		return nil, err
	}

	var routes []router.Route

	// convert from pb to []*router.Route
	for _, r := range pbRoutes.Routes {
		routes = append(routes, router.Route{
			Destination: r.Destination,
			Gateway:     r.Gateway,
			Router:      r.Router,
			Network:     r.Network,
			Metric:      int(r.Metric),
		})
	}

	return routes, nil
}

func (r *routerSelector) Init(opts ...selector.Option) error {
	// no op
	return nil
}

func (r *routerSelector) Options() selector.Options {
	return r.opts
}

func (r *routerSelector) Select(service string, opts ...selector.SelectOption) (selector.Next, error) {
	// TODO: pull routes asynchronously and cache
	routes, err := r.getRoutes(service)
	if err != nil {
		return nil, err
	}

	// no routes return not found error
	if len(routes) == 0 {
		return nil, selector.ErrNotFound
	}

	// TODO: apply filters by pseudo constructing service

	// sort the routes based on metric
	sort.Slice(routes, func(i, j int) bool {
		return routes[i].Metric < routes[j].Metric
	})

	// roundrobin assuming routes are in metric preference order
	var i int
	var mtx sync.Mutex

	return func() (*registry.Node, error) {
		// get index and increment counter with every call to next
		mtx.Lock()
		idx := i
		i++
		mtx.Unlock()

		// get route based on idx
		route := routes[idx%len(routes)]

		// defaults to gateway and no port
		address := route.Gateway
		port := 0

		// check if its host:port
		host, pr, err := net.SplitHostPort(address)
		if err == nil {
			pp, _ := strconv.Atoi(pr)
			// set port
			port = pp
			// set address
			address = host
		}

		// return as a node
		return &registry.Node{
			// TODO: add id and metadata if we can
			Address: address,
			Port:    port,
		}, nil
	}, nil
}

func (r *routerSelector) Mark(service string, node *registry.Node, err error) {
	// TODO: pass back metrics or information to the router
	return
}

func (r *routerSelector) Reset(service string) {
	// TODO: reset the metrics or information at the router
	return
}

func (r *routerSelector) Close() error {
	// stop the router advertisements
	return r.r.Stop()
}

func (r *routerSelector) String() string {
	return "router"
}

// NewSelector returns a new router based selector
func NewSelector(opts ...selector.Option) selector.Selector {
	options := selector.Options{
		Context: context.Background(),
	}

	for _, o := range opts {
		o(&options)
	}

	// set default registry if not set
	if options.Registry == nil {
		options.Registry = registry.DefaultRegistry
	}

	// try get router from the context
	r, ok := options.Context.Value(routerKey{}).(router.Router)
	if !ok {
		// TODO: Use router.DefaultRouter?
		r = router.NewRouter(
			router.Registry(options.Registry),
		)
	}

	// try get client from the context
	c, ok := options.Context.Value(clientKey{}).(client.Client)
	if !ok {
		c = client.DefaultClient
	}

	// get the router from env vars if its a remote service
	remote := true
	routerName := os.Getenv("MICRO_ROUTER")
	routerAddress := os.Getenv("MICRO_ROUTER_ADDRESS")

	// start the router advertisements if we're running it locally
	if len(routerName) == 0 && len(routerAddress) == 0 {
		go r.Advertise()
		remote = false
	}

	return &routerSelector{
		opts: options,
		// set the internal router
		r: r,
		// set the client
		c: pb.NewRouterService(routerName, c),
		// address of router
		addr: routerAddress,
		// let ourselves know to use the remote router
		remote: remote,
	}
}

// WithClient sets the client for the request
func WithClient(c client.Client) selector.Option {
	return func(o *selector.Options) {
		if o.Context == nil {
			o.Context = context.Background()
		}
		o.Context = context.WithValue(o.Context, clientKey{}, c)
	}
}

// WithRouter sets the router as an option
func WithRouter(r router.Router) selector.Option {
	return func(o *selector.Options) {
		if o.Context == nil {
			o.Context = context.Background()
		}
		o.Context = context.WithValue(o.Context, routerKey{}, r)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Intel Corporation
//
// 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 (
	"errors"
	"fmt"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"unicode"
	"unicode/utf8"

	"github.com/urfave/cli"
)

// CommitConfig encapsulates the user configuration options, but is also
// used to pass some state between functions (FoundFixes).
type CommitConfig struct {
	// set when a fixes #XXX" commit is found
	FoundFixes bool

	// All commits must have a sign-off
	NeedSOBS bool

	// Atleast one commit must specify a bug that it fixes.
	NeedFixes bool

	MaxSubjectLineLength int
	MaxBodyLineLength    int

	SobString   string
	FixesString string

	FixesPattern *regexp.Regexp
	SobPattern   *regexp.Regexp
}

const (
	defaultSobString   = "Signed-off-by"
	defaultFixesString = "Fixes"

	defaultMaxSubjectLineLength = 75
	defaultMaxBodyLineLength    = 72
)

var (
	// Full path to git(1) command
	gitPath = ""
	verbose = false

	errNoCommit = errors.New("Need commit")
	errNoBranch = errors.New("Need branch")
	errNoConfig = errors.New("Need config")
)

func init() {
	var err error
	gitPath, err = exec.LookPath("git")
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: cannot find git in PATH\n")
		os.Exit(1)
	}
}

func checkCommitSubject(config *CommitConfig, commit, subject string) error {
	if config == nil {
		return errNoConfig
	}

	if commit == "" {
		return fmt.Errorf("Commit not specified")
	}

	if subject == "" {
		return fmt.Errorf("Commit %v: empty subject", commit)
	}

	if strings.TrimSpace(subject) == "" {
		return fmt.Errorf("Commit %v: pure whitespace subject", commit)
	}

	subsystemPattern := regexp.MustCompile(`^[^ ][^ ]*.*:`)
	matches := subsystemPattern.FindStringSubmatch(subject)
	if matches == nil {
		return fmt.Errorf("Commit %v: Failed to find subsystem in subject: %q",
			commit, subject)
	}

	length := len(subject)
	if length > config.MaxSubjectLineLength {
		return fmt.Errorf("commit %v: subject too long (max %v, got %v): %q",
			commit, config.MaxSubjectLineLength, length, subject)
	}

	if config.FixesString != "" && config.FixesPattern != nil {
		matches = config.FixesPattern.FindStringSubmatch(subject)

		if matches != nil {
			config.FoundFixes = true
		}
	}

	return nil
}

func checkCommitBodyLine(config *CommitConfig, commit string, line string,
	lineNum int, nonWhitespaceOnlyLine *int,
	sobPattern *regexp.Regexp, sobLine *int) error {
	if config == nil {
		return errNoConfig
	}

	if line == "" {
		return nil
	}

	if *nonWhitespaceOnlyLine == -1 {
		if strings.TrimSpace(line) != "" {
			*nonWhitespaceOnlyLine = lineNum
		}
	}

	// Check first character of line. If it's _not_
	// alphabetic, length limits don't apply.
	rune, _ := utf8.DecodeRune([]byte{line[0]})

	if !unicode.IsLetter(rune) {
		return nil
	}

	fixesMatches := config.FixesPattern.FindStringSubmatch(line)
	if fixesMatches != nil {
		config.FoundFixes = true
	}

	sobMatch := sobPattern.FindStringSubmatch(line)
	if sobMatch != nil {
		*sobLine = lineNum
	}

	// Note: SOB lines are *NOT* checked for max line
	// length: it isn't reasonable to penalise someone
	// people with long names ;)
	if *sobLine != -1 {
		return nil
	}

	length := len(line)
	if length > config.MaxBodyLineLength {
		return fmt.Errorf("commit %v: body line %d too long (max %v, got %v): %q",
			commit, 1+lineNum, config.MaxBodyLineLength, length, line)
	}

	return nil
}

func checkCommitBody(config *CommitConfig, commit string, body []string) error {
	if config == nil {
		return errNoConfig
	}

	if commit == "" {
		return fmt.Errorf("Commit not specified")
	}

	if body == nil {
		return fmt.Errorf("Commit %v: empty body", commit)
	}

	// note that sign-off lines must start in the first column
	sobPattern := regexp.MustCompile(fmt.Sprintf("^%s:", config.SobString))

	// line number which contains a sign-off line.
	sobLine := -1

	// line number containing only whitespace
	nonWhitespaceOnlyLine := -1

	for i, line := range body {
		err := checkCommitBodyLine(config, commit, line, i,
			&nonWhitespaceOnlyLine, sobPattern, &sobLine)
		if err != nil {
			return err
		}
	}

	if nonWhitespaceOnlyLine == -1 {
		return fmt.Errorf("Commit %v: pure whitespace body", commit)
	}

	if config.NeedSOBS && sobLine == -1 {
		return fmt.Errorf("Commit %v: no %v specified", commit, config.SobString)
	}

	if sobLine == nonWhitespaceOnlyLine {
		return fmt.Errorf("Commit %v: single-line %q body not permitted", commit, config.SobString)
	}

	return nil
}

func getCommitRange(commit, branch string) ([]string, error) {
	if commit == "" {
		return nil, errNoCommit
	}

	if branch == "" {
		return nil, errNoBranch
	}

	var args []string

	args = append(args, gitPath)
	args = append(args, "rev-list")
	args = append(args, "--no-merges")
	args = append(args, "--reverse")
	args = append(args, fmt.Sprintf("%s..", branch))

	cmdLine := exec.Command(args[0], args[1:]...)

	bytes, err := cmdLine.Output()
	if err != nil {
		return nil,
			fmt.Errorf("Failed to run command %v: %v",
				strings.Join(args, " "),
				err)
	}

	lines := strings.Split(string(bytes), "\n")

	// Remove last line if empty
	length := len(lines)
	last := lines[length-1]
	if last == "" {
		lines = lines[:length-1]
	}

	return lines, nil
}

func getCommitSubject(commit string) (string, error) {
	if commit == "" {
		return "", errNoCommit
	}

	var args []string

	args = append(args, gitPath)
	args = append(args, "log")
	args = append(args, "-1")
	args = append(args, "--pretty=%s")
	args = append(args, commit)

	cmdLine := exec.Command(args[0], args[1:]...)

	bytes, err := cmdLine.Output()
	if err != nil {
		return "",
			fmt.Errorf("Failed to run command %v: %v",
				strings.Join(args, " "), err)
	}

	return string(bytes), nil
}

func getCommitBody(commit string) ([]string, error) {
	if commit == "" {
		return []string{}, errNoCommit
	}

	var args []string

	args = append(args, gitPath)
	args = append(args, "log")
	args = append(args, "-1")
	args = append(args, "--pretty=%b")
	args = append(args, commit)

	cmdLine := exec.Command(args[0], args[1:]...)

	bytes, err := cmdLine.Output()
	if err != nil {
		return []string{},
			fmt.Errorf("Failed to run command %v: %v",
				strings.Join(args, " "), err)
	}

	lines := strings.Split(string(bytes), "\n")

	// Remove last line if empty
	length := len(lines)
	last := lines[length-1]
	if last == "" {
		lines = lines[:length-1]
	}

	return lines, nil
}

func checkCommitFull(config *CommitConfig, commit, subject string, body []string) error {
	if config == nil {
		return errNoConfig
	}

	if commit == "" {
		return errNoCommit
	}

	if subject == "" {
		return fmt.Errorf("Commit %v: empty subject", commit)
	}

	if body == nil {
		return fmt.Errorf("Commit %v: empty body", commit)
	}

	err := checkCommitSubject(config, commit, subject)
	if err != nil {
		return err
	}

	err = checkCommitBody(config, commit, body)
	return err
}

func checkCommit(config *CommitConfig, commit string) error {
	if config == nil {
		return errNoConfig
	}

	if commit == "" {
		return errNoCommit
	}

	subject, err := getCommitSubject(commit)
	if err != nil {
		return err
	}

	body, err := getCommitBody(commit)
	if err != nil {
		return err
	}

	return checkCommitFull(config, commit, subject, body)
}

// checkCommits performs checks on specified list of commits
func checkCommits(config *CommitConfig, commits []string) error {
	if config == nil {
		return errNoConfig
	}

	if commits == nil {
		return errNoCommit
	}

	config.FixesPattern = regexp.MustCompile(fmt.Sprintf("%s:* *#\\d+", config.FixesString))

	for _, commit := range commits {
		if verbose {
			fmt.Printf("Checking commit %s\n", commit)
		}
		err := checkCommit(config, commit)
		if err != nil {
			return err
		}
	}

	if config.NeedFixes && !config.FoundFixes {
		return fmt.Errorf("No %q found", config.FixesString)
	}

	return nil
}

// preChecks performs checks on the range of commits described by commit
// and branch.
func preChecks(config *CommitConfig, commit, branch string) error {
	if config == nil {
		return errNoConfig
	}

	if commit == "" {
		return errNoCommit
	}

	if branch == "" {
		branch = "master"
	}

	commits, err := getCommitRange(commit, branch)
	if err != nil {
		return err
	}

	if verbose {
		fmt.Printf("Found %d commits\n", len(commits))
	}

	return checkCommits(config, commits)
}

// NewCommitConfig creates a new CommitConfig object.
func NewCommitConfig(needFixes, needSignOffs bool, fixesPrefix, signoffPrefix string, bodyLength, subjectLength int) *CommitConfig {
	config := &CommitConfig{
		NeedSOBS:             needSignOffs,
		NeedFixes:            needFixes,
		MaxBodyLineLength:    bodyLength,
		MaxSubjectLineLength: subjectLength,
		SobString:            defaultSobString,
		FixesString:          defaultFixesString,
	}

	if config.MaxBodyLineLength == 0 {
		config.MaxBodyLineLength = defaultMaxBodyLineLength
	}

	if config.MaxSubjectLineLength == 0 {
		config.MaxSubjectLineLength = defaultMaxSubjectLineLength
	}

	if fixesPrefix != "" {
		config.FixesString = fixesPrefix
	}

	if signoffPrefix != "" {
		config.SobString = signoffPrefix
	}

	return config
}

func main() {
	app := cli.NewApp()
	app.Name = "commitchecks"
	app.Description = "perform checks on git commits"

	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "need-fixes, f",
			Usage: fmt.Sprintf("Ensure atleast one commit has a %q entry", defaultFixesString),
		},

		cli.BoolFlag{
			Name:  "need-sign-offs, s",
			Usage: fmt.Sprintf("Ensure all commits have a %q entry", defaultSobString),
		},

		cli.BoolFlag{
			Name:        "verbose",
			Usage:       "Display informational messages",
			EnvVar:      "CHECKCOMMITS_VERBOSE",
			Destination: &verbose,
		},

		cli.StringFlag{
			Name:  "fixes-prefix",
			Usage: fmt.Sprintf("Fixes prefix used as an alternative to %q", defaultFixesString),
		},

		cli.StringFlag{
			Name:  "sign-off-prefix",
			Usage: fmt.Sprintf("Sign-off prefix used as an alternative to %q", defaultSobString),
		},

		cli.UintFlag{
			Name:  "body-length",
			Usage: "Specify maximum body line length",
			Value: uint(defaultMaxBodyLineLength),
		},

		cli.UintFlag{
			Name:  "subject-length",
			Usage: "Specify maximum subject line length",
			Value: uint(defaultMaxSubjectLineLength),
		},
	}

	app.Action = func(c *cli.Context) error {
		var commit string
		var branch string

		count := c.NArg()

		if count < 1 || count > 2 {
			return fmt.Errorf("Usage: %s [options] <commit> [<branch>]", c.App.Name)
		}

		if count >= 1 {
			commit = c.Args().Get(0)
		}

		if count == 2 {
			branch = c.Args().Get(1)
		}

		config := NewCommitConfig(c.Bool("need-fixes"),
			c.Bool("need-sign-offs"),
			c.String("fixes-prefix"),
			c.String("sign-off-prefix"),
			int(c.Uint("body-length")),
			int(c.Uint("subject-length")))

		return preChecks(config, commit, branch)
	}

	err := app.Run(os.Args)
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: %v\n", err)
		os.Exit(1)
	}

	os.Exit(0)
}
<commit_msg>checkcommits: Improve verbose message.<commit_after>// Copyright (c) 2017 Intel Corporation
//
// 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 (
	"errors"
	"fmt"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"unicode"
	"unicode/utf8"

	"github.com/urfave/cli"
)

// CommitConfig encapsulates the user configuration options, but is also
// used to pass some state between functions (FoundFixes).
type CommitConfig struct {
	// set when a fixes #XXX" commit is found
	FoundFixes bool

	// All commits must have a sign-off
	NeedSOBS bool

	// Atleast one commit must specify a bug that it fixes.
	NeedFixes bool

	MaxSubjectLineLength int
	MaxBodyLineLength    int

	SobString   string
	FixesString string

	FixesPattern *regexp.Regexp
	SobPattern   *regexp.Regexp
}

const (
	defaultSobString   = "Signed-off-by"
	defaultFixesString = "Fixes"

	defaultMaxSubjectLineLength = 75
	defaultMaxBodyLineLength    = 72
)

var (
	// Full path to git(1) command
	gitPath = ""
	verbose = false

	errNoCommit = errors.New("Need commit")
	errNoBranch = errors.New("Need branch")
	errNoConfig = errors.New("Need config")
)

func init() {
	var err error
	gitPath, err = exec.LookPath("git")
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: cannot find git in PATH\n")
		os.Exit(1)
	}
}

func checkCommitSubject(config *CommitConfig, commit, subject string) error {
	if config == nil {
		return errNoConfig
	}

	if commit == "" {
		return fmt.Errorf("Commit not specified")
	}

	if subject == "" {
		return fmt.Errorf("Commit %v: empty subject", commit)
	}

	if strings.TrimSpace(subject) == "" {
		return fmt.Errorf("Commit %v: pure whitespace subject", commit)
	}

	subsystemPattern := regexp.MustCompile(`^[^ ][^ ]*.*:`)
	matches := subsystemPattern.FindStringSubmatch(subject)
	if matches == nil {
		return fmt.Errorf("Commit %v: Failed to find subsystem in subject: %q",
			commit, subject)
	}

	length := len(subject)
	if length > config.MaxSubjectLineLength {
		return fmt.Errorf("commit %v: subject too long (max %v, got %v): %q",
			commit, config.MaxSubjectLineLength, length, subject)
	}

	if config.FixesString != "" && config.FixesPattern != nil {
		matches = config.FixesPattern.FindStringSubmatch(subject)

		if matches != nil {
			config.FoundFixes = true
		}
	}

	return nil
}

func checkCommitBodyLine(config *CommitConfig, commit string, line string,
	lineNum int, nonWhitespaceOnlyLine *int,
	sobPattern *regexp.Regexp, sobLine *int) error {
	if config == nil {
		return errNoConfig
	}

	if line == "" {
		return nil
	}

	if *nonWhitespaceOnlyLine == -1 {
		if strings.TrimSpace(line) != "" {
			*nonWhitespaceOnlyLine = lineNum
		}
	}

	// Check first character of line. If it's _not_
	// alphabetic, length limits don't apply.
	rune, _ := utf8.DecodeRune([]byte{line[0]})

	if !unicode.IsLetter(rune) {
		return nil
	}

	fixesMatches := config.FixesPattern.FindStringSubmatch(line)
	if fixesMatches != nil {
		config.FoundFixes = true
	}

	sobMatch := sobPattern.FindStringSubmatch(line)
	if sobMatch != nil {
		*sobLine = lineNum
	}

	// Note: SOB lines are *NOT* checked for max line
	// length: it isn't reasonable to penalise someone
	// people with long names ;)
	if *sobLine != -1 {
		return nil
	}

	length := len(line)
	if length > config.MaxBodyLineLength {
		return fmt.Errorf("commit %v: body line %d too long (max %v, got %v): %q",
			commit, 1+lineNum, config.MaxBodyLineLength, length, line)
	}

	return nil
}

func checkCommitBody(config *CommitConfig, commit string, body []string) error {
	if config == nil {
		return errNoConfig
	}

	if commit == "" {
		return fmt.Errorf("Commit not specified")
	}

	if body == nil {
		return fmt.Errorf("Commit %v: empty body", commit)
	}

	// note that sign-off lines must start in the first column
	sobPattern := regexp.MustCompile(fmt.Sprintf("^%s:", config.SobString))

	// line number which contains a sign-off line.
	sobLine := -1

	// line number containing only whitespace
	nonWhitespaceOnlyLine := -1

	for i, line := range body {
		err := checkCommitBodyLine(config, commit, line, i,
			&nonWhitespaceOnlyLine, sobPattern, &sobLine)
		if err != nil {
			return err
		}
	}

	if nonWhitespaceOnlyLine == -1 {
		return fmt.Errorf("Commit %v: pure whitespace body", commit)
	}

	if config.NeedSOBS && sobLine == -1 {
		return fmt.Errorf("Commit %v: no %v specified", commit, config.SobString)
	}

	if sobLine == nonWhitespaceOnlyLine {
		return fmt.Errorf("Commit %v: single-line %q body not permitted", commit, config.SobString)
	}

	return nil
}

func getCommitRange(commit, branch string) ([]string, error) {
	if commit == "" {
		return nil, errNoCommit
	}

	if branch == "" {
		return nil, errNoBranch
	}

	var args []string

	args = append(args, gitPath)
	args = append(args, "rev-list")
	args = append(args, "--no-merges")
	args = append(args, "--reverse")
	args = append(args, fmt.Sprintf("%s..", branch))

	cmdLine := exec.Command(args[0], args[1:]...)

	bytes, err := cmdLine.Output()
	if err != nil {
		return nil,
			fmt.Errorf("Failed to run command %v: %v",
				strings.Join(args, " "),
				err)
	}

	lines := strings.Split(string(bytes), "\n")

	// Remove last line if empty
	length := len(lines)
	last := lines[length-1]
	if last == "" {
		lines = lines[:length-1]
	}

	return lines, nil
}

func getCommitSubject(commit string) (string, error) {
	if commit == "" {
		return "", errNoCommit
	}

	var args []string

	args = append(args, gitPath)
	args = append(args, "log")
	args = append(args, "-1")
	args = append(args, "--pretty=%s")
	args = append(args, commit)

	cmdLine := exec.Command(args[0], args[1:]...)

	bytes, err := cmdLine.Output()
	if err != nil {
		return "",
			fmt.Errorf("Failed to run command %v: %v",
				strings.Join(args, " "), err)
	}

	return string(bytes), nil
}

func getCommitBody(commit string) ([]string, error) {
	if commit == "" {
		return []string{}, errNoCommit
	}

	var args []string

	args = append(args, gitPath)
	args = append(args, "log")
	args = append(args, "-1")
	args = append(args, "--pretty=%b")
	args = append(args, commit)

	cmdLine := exec.Command(args[0], args[1:]...)

	bytes, err := cmdLine.Output()
	if err != nil {
		return []string{},
			fmt.Errorf("Failed to run command %v: %v",
				strings.Join(args, " "), err)
	}

	lines := strings.Split(string(bytes), "\n")

	// Remove last line if empty
	length := len(lines)
	last := lines[length-1]
	if last == "" {
		lines = lines[:length-1]
	}

	return lines, nil
}

func checkCommitFull(config *CommitConfig, commit, subject string, body []string) error {
	if config == nil {
		return errNoConfig
	}

	if commit == "" {
		return errNoCommit
	}

	if subject == "" {
		return fmt.Errorf("Commit %v: empty subject", commit)
	}

	if body == nil {
		return fmt.Errorf("Commit %v: empty body", commit)
	}

	err := checkCommitSubject(config, commit, subject)
	if err != nil {
		return err
	}

	err = checkCommitBody(config, commit, body)
	return err
}

func checkCommit(config *CommitConfig, commit string) error {
	if config == nil {
		return errNoConfig
	}

	if commit == "" {
		return errNoCommit
	}

	subject, err := getCommitSubject(commit)
	if err != nil {
		return err
	}

	body, err := getCommitBody(commit)
	if err != nil {
		return err
	}

	return checkCommitFull(config, commit, subject, body)
}

// checkCommits performs checks on specified list of commits
func checkCommits(config *CommitConfig, commits []string) error {
	if config == nil {
		return errNoConfig
	}

	if commits == nil {
		return errNoCommit
	}

	config.FixesPattern = regexp.MustCompile(fmt.Sprintf("%s:* *#\\d+", config.FixesString))

	for _, commit := range commits {
		if verbose {
			fmt.Printf("Checking commit %s\n", commit)
		}
		err := checkCommit(config, commit)
		if err != nil {
			return err
		}
	}

	if config.NeedFixes && !config.FoundFixes {
		return fmt.Errorf("No %q found", config.FixesString)
	}

	return nil
}

// preChecks performs checks on the range of commits described by commit
// and branch.
func preChecks(config *CommitConfig, commit, branch string) error {
	if config == nil {
		return errNoConfig
	}

	if commit == "" {
		return errNoCommit
	}

	if branch == "" {
		branch = "master"
	}

	commits, err := getCommitRange(commit, branch)
	if err != nil {
		return err
	}

	if verbose {
		fmt.Printf("Found %d commits between commit %v and branch %v\n",
			len(commits), commit, branch)
	}

	return checkCommits(config, commits)
}

// NewCommitConfig creates a new CommitConfig object.
func NewCommitConfig(needFixes, needSignOffs bool, fixesPrefix, signoffPrefix string, bodyLength, subjectLength int) *CommitConfig {
	config := &CommitConfig{
		NeedSOBS:             needSignOffs,
		NeedFixes:            needFixes,
		MaxBodyLineLength:    bodyLength,
		MaxSubjectLineLength: subjectLength,
		SobString:            defaultSobString,
		FixesString:          defaultFixesString,
	}

	if config.MaxBodyLineLength == 0 {
		config.MaxBodyLineLength = defaultMaxBodyLineLength
	}

	if config.MaxSubjectLineLength == 0 {
		config.MaxSubjectLineLength = defaultMaxSubjectLineLength
	}

	if fixesPrefix != "" {
		config.FixesString = fixesPrefix
	}

	if signoffPrefix != "" {
		config.SobString = signoffPrefix
	}

	return config
}

func main() {
	app := cli.NewApp()
	app.Name = "commitchecks"
	app.Description = "perform checks on git commits"

	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "need-fixes, f",
			Usage: fmt.Sprintf("Ensure atleast one commit has a %q entry", defaultFixesString),
		},

		cli.BoolFlag{
			Name:  "need-sign-offs, s",
			Usage: fmt.Sprintf("Ensure all commits have a %q entry", defaultSobString),
		},

		cli.BoolFlag{
			Name:        "verbose",
			Usage:       "Display informational messages",
			EnvVar:      "CHECKCOMMITS_VERBOSE",
			Destination: &verbose,
		},

		cli.StringFlag{
			Name:  "fixes-prefix",
			Usage: fmt.Sprintf("Fixes prefix used as an alternative to %q", defaultFixesString),
		},

		cli.StringFlag{
			Name:  "sign-off-prefix",
			Usage: fmt.Sprintf("Sign-off prefix used as an alternative to %q", defaultSobString),
		},

		cli.UintFlag{
			Name:  "body-length",
			Usage: "Specify maximum body line length",
			Value: uint(defaultMaxBodyLineLength),
		},

		cli.UintFlag{
			Name:  "subject-length",
			Usage: "Specify maximum subject line length",
			Value: uint(defaultMaxSubjectLineLength),
		},
	}

	app.Action = func(c *cli.Context) error {
		var commit string
		var branch string

		count := c.NArg()

		if count < 1 || count > 2 {
			return fmt.Errorf("Usage: %s [options] <commit> [<branch>]", c.App.Name)
		}

		if count >= 1 {
			commit = c.Args().Get(0)
		}

		if count == 2 {
			branch = c.Args().Get(1)
		}

		config := NewCommitConfig(c.Bool("need-fixes"),
			c.Bool("need-sign-offs"),
			c.String("fixes-prefix"),
			c.String("sign-off-prefix"),
			int(c.Uint("body-length")),
			int(c.Uint("subject-length")))

		return preChecks(config, commit, branch)
	}

	err := app.Run(os.Args)
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: %v\n", err)
		os.Exit(1)
	}

	os.Exit(0)
}
<|endoftext|>


<commit_before>package server

import (
	"io"
	"net"

	"github.com/hashicorp/scada-client/scada"
	"github.com/hashicorp/vault/version"
)

type SCADAListener struct {
	ln            net.Listener
	scadaProvider *scada.Provider
}

func (s *SCADAListener) Accept() (net.Conn, error) {
	return s.ln.Accept()
}

func (s *SCADAListener) Close() error {
	s.scadaProvider.Shutdown()
	return s.ln.Close()
}

func (s *SCADAListener) Addr() net.Addr {
	return s.ln.Addr()
}

func atlasListenerFactory(config map[string]string, logger io.Writer) (net.Listener, map[string]string, ReloadFunc, error) {
	scadaConfig := &scada.Config{
		Service:      "vault",
		Version:      version.GetVersion().VersionNumber(),
		ResourceType: "vault-cluster",
		Meta: map[string]string{
			"node_id": config["node_id"],
		},
		Atlas: scada.AtlasConfig{
			Endpoint:       config["endpoint"],
			Infrastructure: config["infrastructure"],
			Token:          config["token"],
		},
	}

	provider, list, err := scada.NewHTTPProvider(scadaConfig, logger)
	if err != nil {
		return nil, nil, nil, err
	}

	ln := &SCADAListener{
		ln:            list,
		scadaProvider: provider,
	}

	props := map[string]string{
		"addr":           "Atlas/SCADA",
		"infrastructure": scadaConfig.Atlas.Infrastructure,
	}

	return listenerWrapTLS(ln, props, config)
}
<commit_msg>Force tls_disable on scada connection inside outer TLS connection as it's not currently supported anyways<commit_after>package server

import (
	"io"
	"net"

	"github.com/hashicorp/scada-client/scada"
	"github.com/hashicorp/vault/version"
)

type SCADAListener struct {
	ln            net.Listener
	scadaProvider *scada.Provider
}

func (s *SCADAListener) Accept() (net.Conn, error) {
	return s.ln.Accept()
}

func (s *SCADAListener) Close() error {
	s.scadaProvider.Shutdown()
	return s.ln.Close()
}

func (s *SCADAListener) Addr() net.Addr {
	return s.ln.Addr()
}

func atlasListenerFactory(config map[string]string, logger io.Writer) (net.Listener, map[string]string, ReloadFunc, error) {
	scadaConfig := &scada.Config{
		Service:      "vault",
		Version:      version.GetVersion().VersionNumber(),
		ResourceType: "vault-cluster",
		Meta: map[string]string{
			"node_id": config["node_id"],
		},
		Atlas: scada.AtlasConfig{
			Endpoint:       config["endpoint"],
			Infrastructure: config["infrastructure"],
			Token:          config["token"],
		},
	}

	provider, list, err := scada.NewHTTPProvider(scadaConfig, logger)
	if err != nil {
		return nil, nil, nil, err
	}

	ln := &SCADAListener{
		ln:            list,
		scadaProvider: provider,
	}

	props := map[string]string{
		"addr":           "Atlas/SCADA",
		"infrastructure": scadaConfig.Atlas.Infrastructure,
	}

	// The outer connection is already TLS-enabled; this is just the listener
	// that reaches back inside that connection
	config["tls_disable"] = "1"

	return listenerWrapTLS(ln, props, config)
}
<|endoftext|>


<commit_before>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package perm

import (
	"regexp"
	"strings"

	"github.com/admpub/nging/application/registry/navigate"
)

type Map struct {
	V        map[string]*Map `json:",omitempty" xml:",omitempty"`
	Nav      *navigate.Item  `json:",omitempty" xml:",omitempty"`
	Behavior BehaviorPerms   `json:",omitempty" xml:",omitempty"`
}

//Import 导入菜单（用户缓存结果）
func (m *Map) Import(navList *navigate.List) *Map {
	if navList == nil {
		return m
	}
	for _, nav := range *navList {
		item := NewMap()
		item.Nav = nav
		if _, ok := m.V[nav.Action]; ok {
			panic(`The navigate name conflicts. Already existed name: ` + nav.Action)
		}
		m.V[nav.Action] = item
		item.Import(nav.Children)
	}
	return m
}

func BuildPermActions(values []string) string {
	var permActions string

	if len(values) > 0 && values[0] == `*` {
		permActions = `*`
		return permActions
	}
	var prefix string
	for _, v := range values {
		length := len(v)
		var suffix string
		if length > 2 {
			suffix = v[length-2:]
		}
		if suffix == `/*` {
			if len(prefix) > 0 {
				prefix += `|`
			}
			prefix += regexp.QuoteMeta(v[0 : length-2])
			if len(permActions) > 0 {
				permActions += `,`
			}
			permActions += v
			continue
		}
		if len(prefix) > 0 {
			re := regexp.MustCompile(`^(` + prefix + `)`)
			if re.MatchString(v) {
				continue
			}
		}
		if len(permActions) > 0 {
			permActions += `,`
		}
		permActions += v
	}
	return permActions
}

//Parse 解析用户获取的权限
func (m *Map) Parse(permActions string, navTree *Map) *Map {
	perms := strings.Split(permActions, `,`)
	for _, perm := range perms {
		arr := strings.Split(perm, `/`)
		tree := navTree
		result := m.V
		var spath string
		for _, a := range arr {
			if _, y := result[a]; !y {
				result[a] = NewMap()
			}
			if a == `*` { //"*"是最后一个字符
				break
			}
			if mp, y := tree.V[a]; y {
				result[a].Nav = mp.Nav
				spath = ``
				tree = mp
			} else {
				if len(spath) > 0 {
					spath += `/`
				}
				spath += a
				if mp, y := tree.V[spath]; y {
					result[a].Nav = mp.Nav
					spath = ``
					tree = mp
				}
			}
			result = result[a].V
		}
	}
	return m
}

func (m *Map) checkByNav(perm string) bool {
	if m.Nav != nil && m.Nav.Unlimited {
		return true
	}
	arr := strings.Split(perm, `/`)
	navResult := m.V
	var prefix string
	for _, a := range arr {
		key := prefix + a
		navV, hasNav := navResult[key]
		if !hasNav {
			prefix += key + `/`
			continue
		}
		prefix = ``
		if navV.Nav != nil && navV.Nav.Unlimited {
			return true
		}
		navResult = navV.V
	}
	return false
}

//Check 检测权限
//perm: /a/b/c
func (m *Map) Check(perm string, nav *Map) bool {
	if nav == nil || m == nav {
		return m.checkByNav(perm)
	}
	return m.checkByChecked(perm, nav)
}

func (m *Map) checkByChecked(perm string, nav *Map) bool {
	if m.Nav != nil && m.Nav.Unlimited {
		return true
	}
	arr := strings.Split(perm, `/`)
	result := m.V
	navResult := nav.V
	hasPerm := true
	var prefix string
	for _, a := range arr {
		key := prefix + a
		navV, hasNav := navResult[key]
		if !hasNav {
			if hasPerm {
				var v *Map
				v, hasPerm = result[a]
				if hasPerm {
					if v.Nav != nil && v.Nav.Unlimited {
						return true
					}
					if _, y := v.V[`*`]; y {
						return true
					}
					result = v.V
				}
			}
			prefix += key + `/`
			continue
		}
		prefix = ``
		if !hasPerm {
			if navV.Nav != nil && navV.Nav.Unlimited {
				return true
			}
			navResult = navV.V
			continue
		}
		var v *Map
		v, hasPerm = result[a]
		if hasPerm {
			if v.Nav != nil && v.Nav.Unlimited {
				return true
			}
			if _, y := v.V[`*`]; y {
				return true
			}
			result = v.V
		}
		if navV.Nav != nil && navV.Nav.Unlimited {
			return true
		}
		navResult = navV.V
	}
	return hasPerm
}

func NewMap() *Map {
	return &Map{V: map[string]*Map{}}
}
<commit_msg>update<commit_after>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package perm

import (
	"regexp"
	"strings"

	"github.com/admpub/nging/application/registry/navigate"
)

type Map struct {
	V   map[string]*Map `json:",omitempty" xml:",omitempty"`
	Nav *navigate.Item  `json:",omitempty" xml:",omitempty"`
}

//Import 导入菜单（用户缓存结果）
func (m *Map) Import(navList *navigate.List) *Map {
	if navList == nil {
		return m
	}
	for _, nav := range *navList {
		item := NewMap()
		item.Nav = nav
		if _, ok := m.V[nav.Action]; ok {
			panic(`The navigate name conflicts. Already existed name: ` + nav.Action)
		}
		m.V[nav.Action] = item
		item.Import(nav.Children)
	}
	return m
}

func BuildPermActions(values []string) string {
	var permActions string

	if len(values) > 0 && values[0] == `*` {
		permActions = `*`
		return permActions
	}
	var prefix string
	for _, v := range values {
		length := len(v)
		var suffix string
		if length > 2 {
			suffix = v[length-2:]
		}
		if suffix == `/*` {
			if len(prefix) > 0 {
				prefix += `|`
			}
			prefix += regexp.QuoteMeta(v[0 : length-2])
			if len(permActions) > 0 {
				permActions += `,`
			}
			permActions += v
			continue
		}
		if len(prefix) > 0 {
			re := regexp.MustCompile(`^(` + prefix + `)`)
			if re.MatchString(v) {
				continue
			}
		}
		if len(permActions) > 0 {
			permActions += `,`
		}
		permActions += v
	}
	return permActions
}

//Parse 解析用户获取的权限
func (m *Map) Parse(permActions string, navTree *Map) *Map {
	perms := strings.Split(permActions, `,`)
	for _, perm := range perms {
		arr := strings.Split(perm, `/`)
		tree := navTree
		result := m.V
		var spath string
		for _, a := range arr {
			if _, y := result[a]; !y {
				result[a] = NewMap()
			}
			if a == `*` { //"*"是最后一个字符
				break
			}
			if mp, y := tree.V[a]; y {
				result[a].Nav = mp.Nav
				spath = ``
				tree = mp
			} else {
				if len(spath) > 0 {
					spath += `/`
				}
				spath += a
				if mp, y := tree.V[spath]; y {
					result[a].Nav = mp.Nav
					spath = ``
					tree = mp
				}
			}
			result = result[a].V
		}
	}
	return m
}

func (m *Map) checkByNav(perm string) bool {
	if m.Nav != nil && m.Nav.Unlimited {
		return true
	}
	arr := strings.Split(perm, `/`)
	navResult := m.V
	var prefix string
	for _, a := range arr {
		key := prefix + a
		navV, hasNav := navResult[key]
		if !hasNav {
			prefix += key + `/`
			continue
		}
		prefix = ``
		if navV.Nav != nil && navV.Nav.Unlimited {
			return true
		}
		navResult = navV.V
	}
	return false
}

//Check 检测权限
//perm: /a/b/c
func (m *Map) Check(perm string, nav *Map) bool {
	if nav == nil || m == nav {
		return m.checkByNav(perm)
	}
	return m.checkByChecked(perm, nav)
}

func (m *Map) checkByChecked(perm string, nav *Map) bool {
	if m.Nav != nil && m.Nav.Unlimited {
		return true
	}
	arr := strings.Split(perm, `/`)
	result := m.V
	navResult := nav.V
	hasPerm := true
	var prefix string
	for _, a := range arr {
		key := prefix + a
		navV, hasNav := navResult[key]
		if !hasNav {
			if hasPerm {
				var v *Map
				v, hasPerm = result[a]
				if hasPerm {
					if v.Nav != nil && v.Nav.Unlimited {
						return true
					}
					if _, y := v.V[`*`]; y {
						return true
					}
					result = v.V
				}
			}
			prefix += key + `/`
			continue
		}
		prefix = ``
		if !hasPerm {
			if navV.Nav != nil && navV.Nav.Unlimited {
				return true
			}
			navResult = navV.V
			continue
		}
		var v *Map
		v, hasPerm = result[a]
		if hasPerm {
			if v.Nav != nil && v.Nav.Unlimited {
				return true
			}
			if _, y := v.V[`*`]; y {
				return true
			}
			result = v.V
		}
		if navV.Nav != nil && navV.Nav.Unlimited {
			return true
		}
		navResult = navV.V
	}
	return hasPerm
}

func NewMap() *Map {
	return &Map{V: map[string]*Map{}}
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Knative 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 knativeserving

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

	mf "github.com/jcrossley3/manifestival"
	servingv1alpha1 "github.com/knative/serving-operator/pkg/apis/serving/v1alpha1"
	"github.com/knative/serving-operator/pkg/controller/knativeserving/common"
	"github.com/knative/serving-operator/version"

	"github.com/operator-framework/operator-sdk/pkg/predicate"
	appsv1 "k8s.io/api/apps/v1"
	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/controller"
	"sigs.k8s.io/controller-runtime/pkg/handler"
	"sigs.k8s.io/controller-runtime/pkg/manager"
	"sigs.k8s.io/controller-runtime/pkg/reconcile"
	logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
	"sigs.k8s.io/controller-runtime/pkg/source"
)

const (
	operand = "knative-serving"
)

var (
	recursive = flag.Bool("recursive", false,
		"If filename is a directory, process all manifests recursively")
	log = logf.Log.WithName("controller_knativeserving")
	// Platform-specific behavior to affect the installation
	platforms common.Platforms
)

// Add creates a new KnativeServing Controller and adds it to the Manager. The Manager will set fields on the Controller
// and Start it when the Manager is Started.
func Add(mgr manager.Manager) error {
	return add(mgr, newReconciler(mgr))
}

// newReconciler returns a new reconcile.Reconciler
func newReconciler(mgr manager.Manager) reconcile.Reconciler {
	return &ReconcileKnativeServing{client: mgr.GetClient(), scheme: mgr.GetScheme()}
}

// add adds a new Controller to mgr with r as the reconcile.Reconciler
func add(mgr manager.Manager, r reconcile.Reconciler) error {
	// Create a new controller
	c, err := controller.New("knativeserving-controller", mgr, controller.Options{Reconciler: r})
	if err != nil {
		return err
	}

	// Watch for changes to primary resource KnativeServing
	err = c.Watch(&source.Kind{Type: &servingv1alpha1.KnativeServing{}}, &handler.EnqueueRequestForObject{}, predicate.GenerationChangedPredicate{})
	if err != nil {
		return err
	}

	// Watch child deployments for availability
	err = c.Watch(&source.Kind{Type: &appsv1.Deployment{}}, &handler.EnqueueRequestForOwner{
		IsController: true,
		OwnerType:    &servingv1alpha1.KnativeServing{},
	})
	if err != nil {
		return err
	}

	return nil
}

var _ reconcile.Reconciler = &ReconcileKnativeServing{}

// ReconcileKnativeServing reconciles a KnativeServing object
type ReconcileKnativeServing struct {
	// This client, initialized using mgr.Client() above, is a split client
	// that reads objects from the cache and writes to the apiserver
	client client.Client
	scheme *runtime.Scheme
	config mf.Manifest
}

// Create manifestival resources and KnativeServing, if necessary
func (r *ReconcileKnativeServing) InjectClient(c client.Client) error {
	koDataDir := os.Getenv("KO_DATA_PATH")
	m, err := mf.NewManifest(filepath.Join(koDataDir, "knative-serving-0.6.0.yaml"), *recursive, c)
	if err != nil {
		log.Error(err, "Failed to load manifest")
		return err
	}
	r.config = m
	return r.ensureKnativeServing()
}

// Reconcile reads that state of the cluster for a KnativeServing object and makes changes based on the state read
// and what is in the KnativeServing.Spec
// Note:
// The Controller will requeue the Request to be processed again if the returned error is non-nil or
// Result.Requeue is true, otherwise upon completion it will remove the work from the queue.
func (r *ReconcileKnativeServing) Reconcile(request reconcile.Request) (reconcile.Result, error) {
	reqLogger := log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name)
	reqLogger.Info("Reconciling KnativeServing")

	// Fetch the KnativeServing instance
	instance := &servingv1alpha1.KnativeServing{}
	if err := r.client.Get(context.TODO(), request.NamespacedName, instance); err != nil {
		if errors.IsNotFound(err) {
			if isInteresting(request) {
				r.config.DeleteAll()
			}
			return reconcile.Result{}, nil
		}
		return reconcile.Result{}, err
	}

	if !isInteresting(request) {
		return reconcile.Result{}, r.ignore(instance)
	}

	stages := []func(*servingv1alpha1.KnativeServing) error{
		r.initStatus,
		r.install,
		r.checkDeployments,
		r.deleteObsoleteResources,
	}

	for _, stage := range stages {
		if err := stage(instance); err != nil {
			return reconcile.Result{}, err
		}
	}
	return reconcile.Result{}, nil
}

// Initialize status conditions
func (r *ReconcileKnativeServing) initStatus(instance *servingv1alpha1.KnativeServing) error {
	if len(instance.Status.Conditions) == 0 {
		instance.Status.InitializeConditions()
		if err := r.updateStatus(instance); err != nil {
			return err
		}
	}
	return nil
}

// Update the status subresource
func (r *ReconcileKnativeServing) updateStatus(instance *servingv1alpha1.KnativeServing) error {

	// Account for https://github.com/kubernetes-sigs/controller-runtime/issues/406
	gvk := instance.GroupVersionKind()
	defer instance.SetGroupVersionKind(gvk)

	if err := r.client.Status().Update(context.TODO(), instance); err != nil {
		return err
	}
	return nil
}

// Apply the embedded resources
func (r *ReconcileKnativeServing) install(instance *servingv1alpha1.KnativeServing) error {
	if instance.Status.IsDeploying() {
		return nil
	}
	defer r.updateStatus(instance)

	extensions, err := platforms.Extend(r.client, r.scheme)
	if err != nil {
		return err
	}

	err = r.config.Transform(extensions.Transform(instance)...)
	if err == nil {
		err = extensions.PreInstall(instance)
		if err == nil {
			err = r.config.ApplyAll()
			if err == nil {
				err = extensions.PostInstall(instance)
			}
		}
	}
	if err != nil {
		instance.Status.MarkInstallFailed(err.Error())
		return err
	}

	// Update status
	instance.Status.Version = version.Version
	log.Info("Install succeeded", "version", version.Version)
	instance.Status.MarkInstallSucceeded()
	return nil
}

// Check for all deployments available
func (r *ReconcileKnativeServing) checkDeployments(instance *servingv1alpha1.KnativeServing) error {
	defer r.updateStatus(instance)
	available := func(d *appsv1.Deployment) bool {
		for _, c := range d.Status.Conditions {
			if c.Type == appsv1.DeploymentAvailable && c.Status == v1.ConditionTrue {
				return true
			}
		}
		return false
	}
	deployment := &appsv1.Deployment{}
	for _, u := range r.config.Resources {
		if u.GetKind() == "Deployment" {
			key := client.ObjectKey{Namespace: u.GetNamespace(), Name: u.GetName()}
			if err := r.client.Get(context.TODO(), key, deployment); err != nil {
				instance.Status.MarkDeploymentsNotReady()
				if errors.IsNotFound(err) {
					return nil
				}
				return err
			}
			if !available(deployment) {
				instance.Status.MarkDeploymentsNotReady()
				return nil
			}
		}
	}
	log.Info("All deployments are available")
	instance.Status.MarkDeploymentsAvailable()
	return nil
}

// Delete obsolete resources from previous versions
func (r *ReconcileKnativeServing) deleteObsoleteResources(instance *servingv1alpha1.KnativeServing) error {
	// istio-system resources from 0.3
	resource := &unstructured.Unstructured{}
	resource.SetNamespace("istio-system")
	resource.SetName("knative-ingressgateway")
	resource.SetAPIVersion("v1")
	resource.SetKind("Service")
	if err := r.config.Delete(resource); err != nil {
		return err
	}
	resource.SetAPIVersion("apps/v1")
	resource.SetKind("Deployment")
	if err := r.config.Delete(resource); err != nil {
		return err
	}
	resource.SetAPIVersion("autoscaling/v1")
	resource.SetKind("HorizontalPodAutoscaler")
	if err := r.config.Delete(resource); err != nil {
		return err
	}
	// config-controller from 0.5
	resource.SetNamespace(instance.GetNamespace())
	resource.SetName("config-controller")
	resource.SetAPIVersion("v1")
	resource.SetKind("ConfigMap")
	if err := r.config.Delete(resource); err != nil {
		return err
	}
	return nil
}

// Because it's effectively cluster-scoped, we only care about a
// single, named resource: knative-serving/knative-serving
func isInteresting(request reconcile.Request) bool {
	return request.Namespace == operand && request.Name == operand
}

// Reflect our ignorance in the KnativeServing status
func (r *ReconcileKnativeServing) ignore(instance *servingv1alpha1.KnativeServing) (err error) {
	err = r.initStatus(instance)
	if err == nil {
		msg := fmt.Sprintf("The only KnativeServing resource that matters is %s/%s", operand, operand)
		instance.Status.MarkIgnored(msg)
		err = r.updateStatus(instance)
	}
	return
}

// If we can't find knative-serving/knative-serving, create it
func (r *ReconcileKnativeServing) ensureKnativeServing() (err error) {
	const path = "config/crds/serving_v1alpha1_knativeserving_cr.yaml"
	instance := &servingv1alpha1.KnativeServing{}
	key := client.ObjectKey{Namespace: operand, Name: operand}
	if err = r.client.Get(context.TODO(), key, instance); err != nil {
		var manifest mf.Manifest
		manifest, err = mf.NewManifest(path, false, r.client)
		if err == nil {
			// create namespace
			err = manifest.Apply(&r.config.Resources[0])
		}
		if err == nil {
			err = manifest.Transform(mf.InjectNamespace(operand))
		}
		if err == nil {
			err = manifest.ApplyAll()
		}
	}
	return
}
<commit_msg>Use KO_DATA_PATH for custom resource (#37)<commit_after>/*
Copyright 2019 The Knative 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 knativeserving

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

	mf "github.com/jcrossley3/manifestival"
	servingv1alpha1 "github.com/knative/serving-operator/pkg/apis/serving/v1alpha1"
	"github.com/knative/serving-operator/pkg/controller/knativeserving/common"
	"github.com/knative/serving-operator/version"

	"github.com/operator-framework/operator-sdk/pkg/predicate"
	appsv1 "k8s.io/api/apps/v1"
	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/controller"
	"sigs.k8s.io/controller-runtime/pkg/handler"
	"sigs.k8s.io/controller-runtime/pkg/manager"
	"sigs.k8s.io/controller-runtime/pkg/reconcile"
	logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
	"sigs.k8s.io/controller-runtime/pkg/source"
)

const (
	operand = "knative-serving"
)

var (
	recursive = flag.Bool("recursive", false,
		"If filename is a directory, process all manifests recursively")
	log = logf.Log.WithName("controller_knativeserving")
	// Platform-specific behavior to affect the installation
	platforms common.Platforms
)

// Add creates a new KnativeServing Controller and adds it to the Manager. The Manager will set fields on the Controller
// and Start it when the Manager is Started.
func Add(mgr manager.Manager) error {
	return add(mgr, newReconciler(mgr))
}

// newReconciler returns a new reconcile.Reconciler
func newReconciler(mgr manager.Manager) reconcile.Reconciler {
	return &ReconcileKnativeServing{client: mgr.GetClient(), scheme: mgr.GetScheme()}
}

// add adds a new Controller to mgr with r as the reconcile.Reconciler
func add(mgr manager.Manager, r reconcile.Reconciler) error {
	// Create a new controller
	c, err := controller.New("knativeserving-controller", mgr, controller.Options{Reconciler: r})
	if err != nil {
		return err
	}

	// Watch for changes to primary resource KnativeServing
	err = c.Watch(&source.Kind{Type: &servingv1alpha1.KnativeServing{}}, &handler.EnqueueRequestForObject{}, predicate.GenerationChangedPredicate{})
	if err != nil {
		return err
	}

	// Watch child deployments for availability
	err = c.Watch(&source.Kind{Type: &appsv1.Deployment{}}, &handler.EnqueueRequestForOwner{
		IsController: true,
		OwnerType:    &servingv1alpha1.KnativeServing{},
	})
	if err != nil {
		return err
	}

	return nil
}

var _ reconcile.Reconciler = &ReconcileKnativeServing{}

// ReconcileKnativeServing reconciles a KnativeServing object
type ReconcileKnativeServing struct {
	// This client, initialized using mgr.Client() above, is a split client
	// that reads objects from the cache and writes to the apiserver
	client client.Client
	scheme *runtime.Scheme
	config mf.Manifest
}

// Create manifestival resources and KnativeServing, if necessary
func (r *ReconcileKnativeServing) InjectClient(c client.Client) error {
	koDataDir := os.Getenv("KO_DATA_PATH")
	m, err := mf.NewManifest(filepath.Join(koDataDir, "knative-serving-0.6.0.yaml"), *recursive, c)
	if err != nil {
		log.Error(err, "Failed to load manifest")
		return err
	}
	r.config = m
	return r.ensureKnativeServing()
}

// Reconcile reads that state of the cluster for a KnativeServing object and makes changes based on the state read
// and what is in the KnativeServing.Spec
// Note:
// The Controller will requeue the Request to be processed again if the returned error is non-nil or
// Result.Requeue is true, otherwise upon completion it will remove the work from the queue.
func (r *ReconcileKnativeServing) Reconcile(request reconcile.Request) (reconcile.Result, error) {
	reqLogger := log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name)
	reqLogger.Info("Reconciling KnativeServing")

	// Fetch the KnativeServing instance
	instance := &servingv1alpha1.KnativeServing{}
	if err := r.client.Get(context.TODO(), request.NamespacedName, instance); err != nil {
		if errors.IsNotFound(err) {
			if isInteresting(request) {
				r.config.DeleteAll()
			}
			return reconcile.Result{}, nil
		}
		return reconcile.Result{}, err
	}

	if !isInteresting(request) {
		return reconcile.Result{}, r.ignore(instance)
	}

	stages := []func(*servingv1alpha1.KnativeServing) error{
		r.initStatus,
		r.install,
		r.checkDeployments,
		r.deleteObsoleteResources,
	}

	for _, stage := range stages {
		if err := stage(instance); err != nil {
			return reconcile.Result{}, err
		}
	}
	return reconcile.Result{}, nil
}

// Initialize status conditions
func (r *ReconcileKnativeServing) initStatus(instance *servingv1alpha1.KnativeServing) error {
	if len(instance.Status.Conditions) == 0 {
		instance.Status.InitializeConditions()
		if err := r.updateStatus(instance); err != nil {
			return err
		}
	}
	return nil
}

// Update the status subresource
func (r *ReconcileKnativeServing) updateStatus(instance *servingv1alpha1.KnativeServing) error {

	// Account for https://github.com/kubernetes-sigs/controller-runtime/issues/406
	gvk := instance.GroupVersionKind()
	defer instance.SetGroupVersionKind(gvk)

	if err := r.client.Status().Update(context.TODO(), instance); err != nil {
		return err
	}
	return nil
}

// Apply the embedded resources
func (r *ReconcileKnativeServing) install(instance *servingv1alpha1.KnativeServing) error {
	if instance.Status.IsDeploying() {
		return nil
	}
	defer r.updateStatus(instance)

	extensions, err := platforms.Extend(r.client, r.scheme)
	if err != nil {
		return err
	}

	err = r.config.Transform(extensions.Transform(instance)...)
	if err == nil {
		err = extensions.PreInstall(instance)
		if err == nil {
			err = r.config.ApplyAll()
			if err == nil {
				err = extensions.PostInstall(instance)
			}
		}
	}
	if err != nil {
		instance.Status.MarkInstallFailed(err.Error())
		return err
	}

	// Update status
	instance.Status.Version = version.Version
	log.Info("Install succeeded", "version", version.Version)
	instance.Status.MarkInstallSucceeded()
	return nil
}

// Check for all deployments available
func (r *ReconcileKnativeServing) checkDeployments(instance *servingv1alpha1.KnativeServing) error {
	defer r.updateStatus(instance)
	available := func(d *appsv1.Deployment) bool {
		for _, c := range d.Status.Conditions {
			if c.Type == appsv1.DeploymentAvailable && c.Status == v1.ConditionTrue {
				return true
			}
		}
		return false
	}
	deployment := &appsv1.Deployment{}
	for _, u := range r.config.Resources {
		if u.GetKind() == "Deployment" {
			key := client.ObjectKey{Namespace: u.GetNamespace(), Name: u.GetName()}
			if err := r.client.Get(context.TODO(), key, deployment); err != nil {
				instance.Status.MarkDeploymentsNotReady()
				if errors.IsNotFound(err) {
					return nil
				}
				return err
			}
			if !available(deployment) {
				instance.Status.MarkDeploymentsNotReady()
				return nil
			}
		}
	}
	log.Info("All deployments are available")
	instance.Status.MarkDeploymentsAvailable()
	return nil
}

// Delete obsolete resources from previous versions
func (r *ReconcileKnativeServing) deleteObsoleteResources(instance *servingv1alpha1.KnativeServing) error {
	// istio-system resources from 0.3
	resource := &unstructured.Unstructured{}
	resource.SetNamespace("istio-system")
	resource.SetName("knative-ingressgateway")
	resource.SetAPIVersion("v1")
	resource.SetKind("Service")
	if err := r.config.Delete(resource); err != nil {
		return err
	}
	resource.SetAPIVersion("apps/v1")
	resource.SetKind("Deployment")
	if err := r.config.Delete(resource); err != nil {
		return err
	}
	resource.SetAPIVersion("autoscaling/v1")
	resource.SetKind("HorizontalPodAutoscaler")
	if err := r.config.Delete(resource); err != nil {
		return err
	}
	// config-controller from 0.5
	resource.SetNamespace(instance.GetNamespace())
	resource.SetName("config-controller")
	resource.SetAPIVersion("v1")
	resource.SetKind("ConfigMap")
	if err := r.config.Delete(resource); err != nil {
		return err
	}
	return nil
}

// Because it's effectively cluster-scoped, we only care about a
// single, named resource: knative-serving/knative-serving
func isInteresting(request reconcile.Request) bool {
	return request.Namespace == operand && request.Name == operand
}

// Reflect our ignorance in the KnativeServing status
func (r *ReconcileKnativeServing) ignore(instance *servingv1alpha1.KnativeServing) (err error) {
	err = r.initStatus(instance)
	if err == nil {
		msg := fmt.Sprintf("The only KnativeServing resource that matters is %s/%s", operand, operand)
		instance.Status.MarkIgnored(msg)
		err = r.updateStatus(instance)
	}
	return
}

// If we can't find knative-serving/knative-serving, create it
func (r *ReconcileKnativeServing) ensureKnativeServing() (err error) {
	koDataDir := os.Getenv("KO_DATA_PATH")
	const path = "serving_v1alpha1_knativeserving_cr.yaml"
	instance := &servingv1alpha1.KnativeServing{}
	key := client.ObjectKey{Namespace: operand, Name: operand}
	if err = r.client.Get(context.TODO(), key, instance); err != nil {
		var manifest mf.Manifest
		manifest, err = mf.NewManifest(filepath.Join(koDataDir, path), false, r.client)
		if err == nil {
			// create namespace
			err = manifest.Apply(&r.config.Resources[0])
		}
		if err == nil {
			err = manifest.Transform(mf.InjectNamespace(operand))
		}
		if err == nil {
			err = manifest.ApplyAll()
		}
	}
	return
}
<|endoftext|>


<commit_before>package native1

// 5.8 Protocols (from AdCOM spec 1.0)
//
// Options for the various bid response protocols that could be supported by an exchange.
//
// Dev note: this enum is copied to native package to allow requiring native/{request,response} in root openrtb package in future.
type Protocol int8

const (
	ProtocolVAST10         Protocol = 1  // VAST 1.0
	ProtocolVAST20         Protocol = 2  // VAST 2.0
	ProtocolVAST30         Protocol = 3  // VAST 3.0
	ProtocolVAST10Wrapper  Protocol = 4  // VAST 1.0 Wrapper
	ProtocolVAST20Wrapper  Protocol = 5  // VAST 2.0 Wrapper
	ProtocolVAST30Wrapper  Protocol = 6  // VAST 3.0 Wrapper
	ProtocolVAST40         Protocol = 7  // VAST 4.0
	ProtocolVAST40Wrapper  Protocol = 8  // VAST 4.0 Wrapper
	ProtocolDAAST10        Protocol = 9  // DAAST 1.0
	ProtocolDAAST10Wrapper Protocol = 10 // DAAST 1.0 Wrapper
	ProtocolVAST41         Protocol = 11 // VAST 4.1
	ProtocolVAST41Wrapper  Protocol = 11 // VAST 4.1 Wrapper
	ProtocolVAST42         Protocol = 11 // VAST 4.2
	ProtocolVAST42Wrapper  Protocol = 11 // VAST 4.2 Wrapper
)
<commit_msg>Protocol Enum Value Typo<commit_after>package native1

// 5.8 Protocols (from AdCOM spec 1.0)
//
// Options for the various bid response protocols that could be supported by an exchange.
//
// Dev note: this enum is copied to native package to allow requiring native/{request,response} in root openrtb package in future.
type Protocol int8

const (
	ProtocolVAST10         Protocol = 1  // VAST 1.0
	ProtocolVAST20         Protocol = 2  // VAST 2.0
	ProtocolVAST30         Protocol = 3  // VAST 3.0
	ProtocolVAST10Wrapper  Protocol = 4  // VAST 1.0 Wrapper
	ProtocolVAST20Wrapper  Protocol = 5  // VAST 2.0 Wrapper
	ProtocolVAST30Wrapper  Protocol = 6  // VAST 3.0 Wrapper
	ProtocolVAST40         Protocol = 7  // VAST 4.0
	ProtocolVAST40Wrapper  Protocol = 8  // VAST 4.0 Wrapper
	ProtocolDAAST10        Protocol = 9  // DAAST 1.0
	ProtocolDAAST10Wrapper Protocol = 10 // DAAST 1.0 Wrapper
	ProtocolVAST41         Protocol = 11 // VAST 4.1
	ProtocolVAST41Wrapper  Protocol = 12 // VAST 4.1 Wrapper
	ProtocolVAST42         Protocol = 13 // VAST 4.2
	ProtocolVAST42Wrapper  Protocol = 14 // VAST 4.2 Wrapper
)
<|endoftext|>


<commit_before>package naturalsort

import (
	"reflect"
	"sort"
	"testing"
)

func TestSortValid(t *testing.T) {
	cases := []struct {
		data, expected []string
	}{
		{
			nil,
			nil,
		},
		{
			[]string{},
			[]string{},
		},
		{
			[]string{"a"},
			[]string{"a"},
		},
		{
			[]string{"0"},
			[]string{"0"},
		},
		{
			[]string{"data", "data20", "data3"},
			[]string{"data", "data3", "data20"},
		},
		{
			[]string{"1", "2", "30", "22", "0", "00", "3"},
			[]string{"0", "00", "1", "2", "3", "22", "30"},
		},
		{
			[]string{"A1", "A0", "A21", "A11", "A111", "A2"},
			[]string{"A0", "A1", "A2", "A11", "A21", "A111"},
		},
		{
			[]string{"A1BA1", "A11AA1", "A2AB0", "B1AA1", "A1AA1"},
			[]string{"A1AA1", "A1BA1", "A2AB0", "A11AA1", "B1AA1"},
		},
		{
			[]string{"1ax10", "1a10", "1ax2", "1ax"},
			[]string{"1a10", "1ax", "1ax2", "1ax10"},
		},
		{
			[]string{"z1a10", "z1ax2", "z1ax"},
			[]string{"z1a10", "z1ax", "z1ax2"},
		},
		{
			// regression test for #8
			[]string{"a0000001", "a0001"},
			[]string{"a0001", "a0000001"},
		},
		{
			// regression test for #10 - Number sort before any symbols even if theyre lower on the ASCII table
			[]string{"#1", "1", "_1", "a"},
			[]string{"1", "#1", "_1", "a"},
		},
		{
			// regression test for #10 - Number sort before any symbols even if theyre lower on the ASCII table
			[]string{"#1", "1", "_1", "a"},
			[]string{"1", "#1", "_1", "a"},
		},
		{
			[]string{"1", " ", "0"},
			[]string{" ", "0", "1"},
		},
		{
			[]string{"1", " ", "0"},
			[]string{" ", "0", "1"},
		},
		{
			[]string{"1", "a", "0"},
			[]string{"0", "1", "a"},
		},
		{
			// regression test for #10
			[]string{"111111111111111111112", "111111111111111111113", "1111111111111111111120"},
			[]string{"111111111111111111112", "111111111111111111113", "1111111111111111111120"},
		},
	}

	for i, c := range cases {
		sort.Sort(NaturalSort(c.data))
		if !reflect.DeepEqual(c.data, c.expected) {
			t.Fatalf("Wrong order in test case #%d.\nExpected=%v\nGot=%v", i, c.expected, c.data)
		}
	}

}

func BenchmarkSort(b *testing.B) {
	var data = [...]string{"A1BA1", "A11AA1", "A2AB0", "B1AA1", "A1AA1"}
	for ii := 0; ii < b.N; ii++ {
		d := NaturalSort(data[:])
		sort.Sort(d)
	}
}
<commit_msg>Added a new test case to match OSX behavior<commit_after>package naturalsort

import (
	"reflect"
	"sort"
	"testing"
)

func TestSortValid(t *testing.T) {
	cases := []struct {
		data, expected []string
	}{
		{
			nil,
			nil,
		},
		{
			[]string{},
			[]string{},
		},
		{
			[]string{"a"},
			[]string{"a"},
		},
		{
			[]string{"0"},
			[]string{"0"},
		},
		{
			[]string{"data", "data20", "data3"},
			[]string{"data", "data3", "data20"},
		},
		{
			[]string{"1", "2", "30", "22", "0", "00", "3"},
			[]string{"0", "00", "1", "2", "3", "22", "30"},
		},
		{
			[]string{"A1", "A0", "A21", "A11", "A111", "A2"},
			[]string{"A0", "A1", "A2", "A11", "A21", "A111"},
		},
		{
			[]string{"A1BA1", "A11AA1", "A2AB0", "B1AA1", "A1AA1"},
			[]string{"A1AA1", "A1BA1", "A2AB0", "A11AA1", "B1AA1"},
		},
		{
			[]string{"1ax10", "1a10", "1ax2", "1ax"},
			[]string{"1a10", "1ax", "1ax2", "1ax10"},
		},
		{
			[]string{"z1a10", "z1ax2", "z1ax"},
			[]string{"z1a10", "z1ax", "z1ax2"},
		},
		{
			// regression test for #8
			[]string{"a0000001", "a0001"},
			[]string{"a0001", "a0000001"},
		},
		{
			// regression test for #10 - Number sort before any symbols even if theyre lower on the ASCII table
			[]string{"#1", "1", "_1", "a"},
			[]string{"1", "#1", "_1", "a"},
		},
		{
			// regression test for #10 - Number sort before any symbols even if theyre lower on the ASCII table
			[]string{"#1", "1", "_1", "a"},
			[]string{"1", "#1", "_1", "a"},
		},
		{	// test correct handling of space-only strings - This matches the Mac OSX sorting behavior
			[]string{"1", " ", "0"},
			[]string{" ", "0", "1"},
		},
		{
			[]string{"1", " ", " 1", "  "},
			[]string{" ", "  ", " 1", "1"},
		},
		{
			[]string{"1", "a", "0"},
			[]string{"0", "1", "a"},
		},
		{
			// regression test for #10
			[]string{"111111111111111111112", "111111111111111111113", "1111111111111111111120"},
			[]string{"111111111111111111112", "111111111111111111113", "1111111111111111111120"},
		},
	}

	for i, c := range cases {
		sort.Sort(NaturalSort(c.data))
		if !reflect.DeepEqual(c.data, c.expected) {
			t.Fatalf("Wrong order in test case #%d.\nExpected=%v\nGot=%v", i, c.expected, c.data)
		}
	}

}

func BenchmarkSort(b *testing.B) {
	var data = [...]string{"A1BA1", "A11AA1", "A2AB0", "B1AA1", "A1AA1"}
	for ii := 0; ii < b.N; ii++ {
		d := NaturalSort(data[:])
		sort.Sort(d)
	}
}
<|endoftext|>