<commit_before>package core

import (
	"fmt"
	"reflect"
	"strings"
	"time"
)

const (
	TWOSIDES = iota + 1
	ONLYTODB
	ONLYFROMDB
)

// database column
type Column struct {
	Name            string
	TableName       string
	FieldName       string
	SQLType         SQLType
	Length          int
	Length2         int
	Nullable        bool
	Default         string
	Indexes         map[string]bool
	IsPrimaryKey    bool
	IsAutoIncrement bool
	MapType         int
	IsCreated       bool
	IsUpdated       bool
	IsDeleted       bool
	IsCascade       bool
	IsVersion       bool
	fieldPath       []string
	DefaultIsEmpty  bool
	EnumOptions     map[string]int
	SetOptions      map[string]int
	DisableTimeZone bool
	TimeZone        *time.Location // column specified time zone
}

func NewColumn(name, fieldName string, sqlType SQLType, len1, len2 int, nullable bool) *Column {
	return &Column{
		Name:            name,
		TableName:       "",
		FieldName:       fieldName,
		SQLType:         sqlType,
		Length:          len1,
		Length2:         len2,
		Nullable:        nullable,
		Default:         "",
		Indexes:         make(map[string]bool),
		IsPrimaryKey:    false,
		IsAutoIncrement: false,
		MapType:         TWOSIDES,
		IsCreated:       false,
		IsUpdated:       false,
		IsDeleted:       false,
		IsCascade:       false,
		IsVersion:       false,
		fieldPath:       nil,
		DefaultIsEmpty:  false,
		EnumOptions:     make(map[string]int),
	}
}

// generate column description string according dialect
func (col *Column) String(d Dialect) string {
	sql := d.QuoteStr() + col.Name + d.QuoteStr() + " "

	sql += d.SqlType(col) + " "

	if col.IsPrimaryKey {
		sql += "PRIMARY KEY "
		if col.IsAutoIncrement {
			sql += d.AutoIncrStr() + " "
		}
	}

	if d.ShowCreateNull() {
		if col.Nullable {
			sql += "NULL "
		} else {
			sql += "NOT NULL "
		}
	}

	if col.Default != "" {
		sql += "DEFAULT " + col.Default + " "
	}

	return sql
}

func (col *Column) StringNoPk(d Dialect) string {
	sql := d.QuoteStr() + col.Name + d.QuoteStr() + " "

	sql += d.SqlType(col) + " "

	if d.ShowCreateNull() {
		if col.Nullable {
			sql += "NULL "
		} else {
			sql += "NOT NULL "
		}
	}

	if col.Default != "" {
		sql += "DEFAULT " + col.Default + " "
	}

	return sql
}

// return col's filed of struct's value
func (col *Column) ValueOf(bean interface{}) (*reflect.Value, error) {
	dataStruct := reflect.Indirect(reflect.ValueOf(bean))
	return col.ValueOfV(&dataStruct)
}

func (col *Column) ValueOfV(dataStruct *reflect.Value) (*reflect.Value, error) {
	var fieldValue reflect.Value
	if col.fieldPath == nil {
		col.fieldPath = strings.Split(col.FieldName, ".")
	}

	if dataStruct.Type().Kind() == reflect.Map {
		keyValue := reflect.ValueOf(col.fieldPath[len(col.fieldPath)-1])
		fieldValue = dataStruct.MapIndex(keyValue)
		return &fieldValue, nil
	} else if dataStruct.Type().Kind() == reflect.Interface {
		structValue := reflect.ValueOf(dataStruct.Interface())
		dataStruct = &structValue
	}

	level := len(col.fieldPath)
	fieldValue = dataStruct.FieldByName(col.fieldPath[0])
	for i := 0; i < level-1; i++ {
		if !fieldValue.IsValid() {
			break
		}
		if fieldValue.Kind() == reflect.Struct {
			fieldValue = fieldValue.FieldByName(col.fieldPath[i+1])
		} else if fieldValue.Kind() == reflect.Ptr {
			if fieldValue.IsNil() {
				fieldValue.Set(reflect.New(fieldValue.Type().Elem()))
			}
			fieldValue = fieldValue.Elem().FieldByName(col.fieldPath[i+1])
		} else {
			return nil, fmt.Errorf("field  %v is not valid", col.FieldName)
		}
	}

	if !fieldValue.IsValid() {
		return nil, fmt.Errorf("field  %v is not valid", col.FieldName)
	}

	return &fieldValue, nil
}
<commit_msg>bug fixed<commit_after>package core

import (
	"fmt"
	"reflect"
	"strings"
	"time"
)

const (
	TWOSIDES = iota + 1
	ONLYTODB
	ONLYFROMDB
)

// database column
type Column struct {
	Name            string
	TableName       string
	FieldName       string
	SQLType         SQLType
	Length          int
	Length2         int
	Nullable        bool
	Default         string
	Indexes         map[string]int
	IsPrimaryKey    bool
	IsAutoIncrement bool
	MapType         int
	IsCreated       bool
	IsUpdated       bool
	IsDeleted       bool
	IsCascade       bool
	IsVersion       bool
	fieldPath       []string
	DefaultIsEmpty  bool
	EnumOptions     map[string]int
	SetOptions      map[string]int
	DisableTimeZone bool
	TimeZone        *time.Location // column specified time zone
}

func NewColumn(name, fieldName string, sqlType SQLType, len1, len2 int, nullable bool) *Column {
	return &Column{
		Name:            name,
		TableName:       "",
		FieldName:       fieldName,
		SQLType:         sqlType,
		Length:          len1,
		Length2:         len2,
		Nullable:        nullable,
		Default:         "",
		Indexes:         make(map[string]int),
		IsPrimaryKey:    false,
		IsAutoIncrement: false,
		MapType:         TWOSIDES,
		IsCreated:       false,
		IsUpdated:       false,
		IsDeleted:       false,
		IsCascade:       false,
		IsVersion:       false,
		fieldPath:       nil,
		DefaultIsEmpty:  false,
		EnumOptions:     make(map[string]int),
	}
}

// generate column description string according dialect
func (col *Column) String(d Dialect) string {
	sql := d.QuoteStr() + col.Name + d.QuoteStr() + " "

	sql += d.SqlType(col) + " "

	if col.IsPrimaryKey {
		sql += "PRIMARY KEY "
		if col.IsAutoIncrement {
			sql += d.AutoIncrStr() + " "
		}
	}

	if d.ShowCreateNull() {
		if col.Nullable {
			sql += "NULL "
		} else {
			sql += "NOT NULL "
		}
	}

	if col.Default != "" {
		sql += "DEFAULT " + col.Default + " "
	}

	return sql
}

func (col *Column) StringNoPk(d Dialect) string {
	sql := d.QuoteStr() + col.Name + d.QuoteStr() + " "

	sql += d.SqlType(col) + " "

	if d.ShowCreateNull() {
		if col.Nullable {
			sql += "NULL "
		} else {
			sql += "NOT NULL "
		}
	}

	if col.Default != "" {
		sql += "DEFAULT " + col.Default + " "
	}

	return sql
}

// return col's filed of struct's value
func (col *Column) ValueOf(bean interface{}) (*reflect.Value, error) {
	dataStruct := reflect.Indirect(reflect.ValueOf(bean))
	return col.ValueOfV(&dataStruct)
}

func (col *Column) ValueOfV(dataStruct *reflect.Value) (*reflect.Value, error) {
	var fieldValue reflect.Value
	if col.fieldPath == nil {
		col.fieldPath = strings.Split(col.FieldName, ".")
	}

	if dataStruct.Type().Kind() == reflect.Map {
		keyValue := reflect.ValueOf(col.fieldPath[len(col.fieldPath)-1])
		fieldValue = dataStruct.MapIndex(keyValue)
		return &fieldValue, nil
	} else if dataStruct.Type().Kind() == reflect.Interface {
		structValue := reflect.ValueOf(dataStruct.Interface())
		dataStruct = &structValue
	}

	level := len(col.fieldPath)
	fieldValue = dataStruct.FieldByName(col.fieldPath[0])
	for i := 0; i < level-1; i++ {
		if !fieldValue.IsValid() {
			break
		}
		if fieldValue.Kind() == reflect.Struct {
			fieldValue = fieldValue.FieldByName(col.fieldPath[i+1])
		} else if fieldValue.Kind() == reflect.Ptr {
			if fieldValue.IsNil() {
				fieldValue.Set(reflect.New(fieldValue.Type().Elem()))
			}
			fieldValue = fieldValue.Elem().FieldByName(col.fieldPath[i+1])
		} else {
			return nil, fmt.Errorf("field  %v is not valid", col.FieldName)
		}
	}

	if !fieldValue.IsValid() {
		return nil, fmt.Errorf("field  %v is not valid", col.FieldName)
	}

	return &fieldValue, nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"os"
	"os/signal"
	"runtime/pprof"
	"sync/atomic"
	"syscall"
	"time"
)

var (
	Log = NewLogger(os.Stderr, LOG_DEBUG, 10*time.Second)
	// For input sentence or message "errors"
	AisLog = NewLogger(os.Stdout, LOG_DEBUG, 0)
)

var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")

func main() {
	flag.Parse()
	signalChan := make(chan os.Signal, 1)
	// Intercept ^C and `timeout`s.
	// Catching SIGPIPE has no effect if it was what Log wrote to that broke, as it's, well, broken.
	signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGPIPE)

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			Log.Fatal(err.Error())
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	merger := make(chan Message, 200)
	go Merge(merger)

	Log.AddPeriodicLogger("from_main", 120*time.Second, func(l *Logger, _ time.Duration) {
		c := l.Compose(LOG_DEBUG)
		c.Writeln("waiting to be merged: %d/%d", len(merger), cap(merger))
		c.Writeln("source connections: %d", atomic.LoadInt32(&Listener_connections))
		c.Close()
	})

	Read("ECC", "http://aishub.ais.ecc.no/raw", 5*time.Second, merger)
	Read("kystverket", "tcp://153.44.253.27:5631", 5*time.Second, merger)
	//Read("http_timeout", "http://127.0.0.1:12340", 8*time.Second, merger)
	//Read("tcp_timeout", "tcp://127.0.0.1:12341", 2*time.Second, merger)
	//Read("redirect", "http://localhost:12342", 0*time.Second, merger)
	//Read("redirect_loop", "http://localhost:12343", 0*time.Second, merger)
	//Read("http_flood", "http://localhost:12344", 2*time.Second, merger)
	//Read("tcp_flood", "tcp://localhost:12345", 2*time.Second, merger)
	//Read("file", "minute_ecc.log", 0*time.Second, merger)

	// Here we wait for CTRL-C or some other kill signal
	_ = <-signalChan
	Log.Info("\n...Stopping...")
	Log.RunPeriodicLoggers(time.Now().Add(1 * time.Hour))
	AisLog.RunPeriodicLoggers(time.Now().Add(1 * time.Hour))
}
<commit_msg>Move all signal handling code to the end of main()<commit_after>package main

import (
	"flag"
	"os"
	"os/signal"
	"runtime/pprof"
	"sync/atomic"
	"syscall"
	"time"
)

var (
	Log = NewLogger(os.Stderr, LOG_DEBUG, 10*time.Second)
	// For input sentence or message "errors"
	AisLog = NewLogger(os.Stdout, LOG_DEBUG, 0)
)

var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")

func main() {
	flag.Parse()
	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			Log.Fatal(err.Error())
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	merger := make(chan Message, 200)
	go Merge(merger)

	Log.AddPeriodicLogger("from_main", 120*time.Second, func(l *Logger, _ time.Duration) {
		c := l.Compose(LOG_DEBUG)
		c.Writeln("waiting to be merged: %d/%d", len(merger), cap(merger))
		c.Writeln("source connections: %d", atomic.LoadInt32(&Listener_connections))
		c.Close()
	})

	Read("ECC", "http://aishub.ais.ecc.no/raw", 5*time.Second, merger)
	Read("kystverket", "tcp://153.44.253.27:5631", 5*time.Second, merger)
	//Read("http_timeout", "http://127.0.0.1:12340", 8*time.Second, merger)
	//Read("tcp_timeout", "tcp://127.0.0.1:12341", 2*time.Second, merger)
	//Read("redirect", "http://localhost:12342", 0*time.Second, merger)
	//Read("redirect_loop", "http://localhost:12343", 0*time.Second, merger)
	//Read("http_flood", "http://localhost:12344", 2*time.Second, merger)
	//Read("tcp_flood", "tcp://localhost:12345", 2*time.Second, merger)
	//Read("file", "minute_ecc.log", 0*time.Second, merger)

	signalChan := make(chan os.Signal, 1)
	// Intercept ^C and `timeout`s.
	// Catching SIGPIPE has no effect if it was what Log wrote to that broke, as it's, well, broken.
	signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGPIPE)
	// Here we wait for CTRL-C or some other kill signal
	_ = <-signalChan
	Log.Info("\n...Stopping...")
	Log.RunPeriodicLoggers(time.Now().Add(1 * time.Hour))
	AisLog.RunPeriodicLoggers(time.Now().Add(1 * time.Hour))
}
<|endoftext|>


<commit_before>// +build !appengine

package memcache

import (
	"github.com/rainycape/memcache"
	"gnd.la/cache/driver"
	"gnd.la/config"
	"strings"
	"time"
)

type memcacheDriver struct {
	*memcache.Client
}

func (c *memcacheDriver) Set(key string, b []byte, timeout int) error {
	item := memcache.Item{Key: key, Value: b, Expiration: int32(timeout)}
	return c.Client.Set(&item)
}

func (c *memcacheDriver) Get(key string) ([]byte, error) {
	item, err := c.Client.Get(key)
	if err != nil && err != memcache.ErrCacheMiss {
		return nil, err
	}
	if item != nil {
		return item.Value, nil
	}
	return nil, nil
}

func (c *memcacheDriver) GetMulti(keys []string) (map[string][]byte, error) {
	results, err := c.Client.GetMulti(keys)
	if err != nil && err != memcache.ErrCacheMiss {
		return nil, err
	}
	value := make(map[string][]byte, len(results))
	for k, v := range results {
		value[k] = v.Value
	}
	return value, nil
}

func (c *memcacheDriver) Delete(key string) error {
	err := c.Client.Delete(key)
	if err != nil && err != memcache.ErrCacheMiss {
		return err
	}
	return nil
}

func (c *memcacheDriver) Connection() interface{} {
	return c.Client
}

func memcacheOpener(url *config.URL) (driver.Driver, error) {
	hosts := strings.Split(url.Value, ",")
	conns := make([]string, len(hosts))
	for ii, v := range hosts {
		conns[ii] = driver.DefaultPort(v, 11211)
	}
	client := memcache.New(conns...)
	if tm, ok := url.Fragment.Int("timeout"); ok {
		client.SetTimeout(time.Millisecond * time.Duration(tm))
	}
	if maxIdle, ok := url.Fragment.Int("max_idle"); ok {
		client.SetMaxIdleConnsPerAddr(maxIdle)
	}
	return &memcacheDriver{Client: client}, nil
}

func init() {
	driver.Register("memcache", memcacheOpener)
}
<commit_msg>Don't report memcache timeouts as errors<commit_after>// +build !appengine

package memcache

import (
	"github.com/rainycape/memcache"
	"gnd.la/cache/driver"
	"gnd.la/config"
	"net"
	"strings"
	"time"
)

type memcacheDriver struct {
	*memcache.Client
}

func (c *memcacheDriver) Set(key string, b []byte, timeout int) error {
	item := memcache.Item{Key: key, Value: b, Expiration: int32(timeout)}
	return c.error(c.Client.Set(&item))
}

func (c *memcacheDriver) Get(key string) ([]byte, error) {
	item, err := c.Client.Get(key)
	if err != nil {
		return nil, c.error(err)
	}
	if item != nil {
		return item.Value, nil
	}
	return nil, nil
}

func (c *memcacheDriver) GetMulti(keys []string) (map[string][]byte, error) {
	results, err := c.Client.GetMulti(keys)
	if err != nil {
		return nil, c.error(err)
	}
	value := make(map[string][]byte, len(results))
	for k, v := range results {
		value[k] = v.Value
	}
	return value, nil
}

func (c *memcacheDriver) Delete(key string) error {
	return c.error(c.Client.Delete(key))
}

func (c *memcacheDriver) Connection() interface{} {
	return c.Client
}

func (c *memcacheDriver) error(err error) error {
	if err != nil {
		if err == memcache.ErrCacheMiss {
			return nil
		}
		if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
			// Don't log these errors since they're so frequent
			// in memcache that they end up generating a lot
			// of logs
			return nil
		}
	}
	return err
}

func memcacheOpener(url *config.URL) (driver.Driver, error) {
	hosts := strings.Split(url.Value, ",")
	conns := make([]string, len(hosts))
	for ii, v := range hosts {
		conns[ii] = driver.DefaultPort(v, 11211)
	}
	client := memcache.New(conns...)
	if tm, ok := url.Fragment.Int("timeout"); ok {
		client.SetTimeout(time.Millisecond * time.Duration(tm))
	}
	if maxIdle, ok := url.Fragment.Int("max_idle"); ok {
		client.SetMaxIdleConnsPerAddr(maxIdle)
	}
	return &memcacheDriver{Client: client}, nil
}

func init() {
	driver.Register("memcache", memcacheOpener)
}
<|endoftext|>


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

// +build appengine

package build

import (
	"net/http"
	"strings"

	"appengine"
)

func handleFunc(path string, h http.HandlerFunc) {
	for _, d := range dashboards {
		http.HandleFunc(d.Prefix+path, h)
	}
}

// Dashboard describes a unique build dashboard.
type Dashboard struct {
	Name      string     // This dashboard's name (eg, "Go")
	Namespace string     // This dashboard's namespace (eg, "" (default), "Git")
	Prefix    string     // The path prefix (no trailing /)
	Packages  []*Package // The project's packages to build
}

// dashboardForRequest returns the appropriate dashboard for a given URL path.
func dashboardForRequest(r *http.Request) *Dashboard {
	for _, d := range dashboards[1:] {
		if d.Prefix == "" {
			panic("prefix can be empty only for the first dashboard")
		}
		if strings.HasPrefix(r.URL.Path, d.Prefix) {
			return d
		}
	}
	if dashboards[0].Prefix != "" {
		panic("prefix for the first dashboard should be empty")
	}
	return dashboards[0]
}

// Context returns a namespaced context for this dashboard, or panics if it
// fails to create a new context.
func (d *Dashboard) Context(c appengine.Context) appengine.Context {
	if d.Namespace == "" {
		return c
	}
	n, err := appengine.Namespace(c, d.Namespace)
	if err != nil {
		panic(err)
	}
	return n
}

// The currently known dashboards.
// The first one should have an empty prefix and
// the other ones a non empty prefix.
var dashboards = []*Dashboard{goDash, gccgoDash}

// goDash is the dashboard for the main go repository.
var goDash = &Dashboard{
	Name:      "Go",
	Namespace: "Git",
	Prefix:    "",
	Packages:  goPackages,
}

// goPackages is a list of all of the packages built by the main go repository.
var goPackages = []*Package{
	{
		Kind: "go",
		Name: "Go",
	},
	{
		Kind: "subrepo",
		Name: "arch",
		Path: "golang.org/x/arch",
	},
	{
		Kind: "subrepo",
		Name: "blog",
		Path: "golang.org/x/blog",
	},
	{
		Kind: "subrepo",
		Name: "crypto",
		Path: "golang.org/x/crypto",
	},
	{
		Kind: "subrepo",
		Name: "exp",
		Path: "golang.org/x/exp",
	},
	{
		Kind: "subrepo",
		Name: "image",
		Path: "golang.org/x/image",
	},
	{
		Kind: "subrepo",
		Name: "mobile",
		Path: "golang.org/x/mobile",
	},
	{
		Kind: "subrepo",
		Name: "net",
		Path: "golang.org/x/net",
	},
	{
		Kind: "subrepo",
		Name: "oauth2",
		Path: "golang.org/x/oauth2",
	},
	{
		Kind: "subrepo",
		Name: "review",
		Path: "golang.org/x/review",
	},
	{
		Kind: "subrepo",
		Name: "sync",
		Path: "golang.org/x/sync",
	},
	{
		Kind: "subrepo",
		Name: "sys",
		Path: "golang.org/x/sys",
	},
	{
		Kind: "subrepo",
		Name: "talks",
		Path: "golang.org/x/talks",
	},
	{
		Kind: "subrepo",
		Name: "term",
		Path: "golang.org/x/term",
	},
	{
		Kind: "subrepo",
		Name: "text",
		Path: "golang.org/x/text",
	},
	{
		Kind: "subrepo",
		Name: "time",
		Path: "golang.org/x/time",
	},
	{
		Kind: "subrepo",
		Name: "tools",
		Path: "golang.org/x/tools",
	},
	{
		Kind: "subrepo",
		Name: "tour",
		Path: "golang.org/x/tour",
	},
}

// gccgoDash is the dashboard for gccgo.
var gccgoDash = &Dashboard{
	Name:      "Gccgo",
	Namespace: "Gccgo",
	Prefix:    "/gccgo",
	Packages: []*Package{
		{
			Kind: "gccgo",
			Name: "Gccgo",
		},
	},
}

// hiddenBranches specifies branches that
// should not be displayed on the build dashboard.
// This also prevents the builder infrastructure
// from testing sub-repos against these branches.
var hiddenBranches = map[string]bool{
	"release-branch.go1.4": true,
}
<commit_msg>app: redirect from HTTP to HTTPS<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build appengine

package build

import (
	"net/http"
	"strings"

	"appengine"
)

func handleFunc(path string, h http.HandlerFunc) {
	for _, d := range dashboards {
		http.Handle(d.Prefix+path, httpsOnlyHandler{h})
	}
}

// httpsOnlyHandler redirects requests to "http://example.com/foo?bar"
// to "https://example.com/foo?bar"
type httpsOnlyHandler struct {
	fn http.HandlerFunc
}

func (h httpsOnlyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if !appengine.IsDevAppServer() && r.TLS == nil {
		r.URL.Scheme = "https"
		r.URL.Host = r.Host
		http.Redirect(w, r, r.URL.String(), http.StatusFound)
		return
	}
	h.fn(w, r)
}

// Dashboard describes a unique build dashboard.
type Dashboard struct {
	Name      string     // This dashboard's name (eg, "Go")
	Namespace string     // This dashboard's namespace (eg, "" (default), "Git")
	Prefix    string     // The path prefix (no trailing /)
	Packages  []*Package // The project's packages to build
}

// dashboardForRequest returns the appropriate dashboard for a given URL path.
func dashboardForRequest(r *http.Request) *Dashboard {
	for _, d := range dashboards[1:] {
		if d.Prefix == "" {
			panic("prefix can be empty only for the first dashboard")
		}
		if strings.HasPrefix(r.URL.Path, d.Prefix) {
			return d
		}
	}
	if dashboards[0].Prefix != "" {
		panic("prefix for the first dashboard should be empty")
	}
	return dashboards[0]
}

// Context returns a namespaced context for this dashboard, or panics if it
// fails to create a new context.
func (d *Dashboard) Context(c appengine.Context) appengine.Context {
	if d.Namespace == "" {
		return c
	}
	n, err := appengine.Namespace(c, d.Namespace)
	if err != nil {
		panic(err)
	}
	return n
}

// The currently known dashboards.
// The first one should have an empty prefix and
// the other ones a non empty prefix.
var dashboards = []*Dashboard{goDash, gccgoDash}

// goDash is the dashboard for the main go repository.
var goDash = &Dashboard{
	Name:      "Go",
	Namespace: "Git",
	Prefix:    "",
	Packages:  goPackages,
}

// goPackages is a list of all of the packages built by the main go repository.
var goPackages = []*Package{
	{
		Kind: "go",
		Name: "Go",
	},
	{
		Kind: "subrepo",
		Name: "arch",
		Path: "golang.org/x/arch",
	},
	{
		Kind: "subrepo",
		Name: "blog",
		Path: "golang.org/x/blog",
	},
	{
		Kind: "subrepo",
		Name: "crypto",
		Path: "golang.org/x/crypto",
	},
	{
		Kind: "subrepo",
		Name: "exp",
		Path: "golang.org/x/exp",
	},
	{
		Kind: "subrepo",
		Name: "image",
		Path: "golang.org/x/image",
	},
	{
		Kind: "subrepo",
		Name: "mobile",
		Path: "golang.org/x/mobile",
	},
	{
		Kind: "subrepo",
		Name: "net",
		Path: "golang.org/x/net",
	},
	{
		Kind: "subrepo",
		Name: "oauth2",
		Path: "golang.org/x/oauth2",
	},
	{
		Kind: "subrepo",
		Name: "review",
		Path: "golang.org/x/review",
	},
	{
		Kind: "subrepo",
		Name: "sync",
		Path: "golang.org/x/sync",
	},
	{
		Kind: "subrepo",
		Name: "sys",
		Path: "golang.org/x/sys",
	},
	{
		Kind: "subrepo",
		Name: "talks",
		Path: "golang.org/x/talks",
	},
	{
		Kind: "subrepo",
		Name: "term",
		Path: "golang.org/x/term",
	},
	{
		Kind: "subrepo",
		Name: "text",
		Path: "golang.org/x/text",
	},
	{
		Kind: "subrepo",
		Name: "time",
		Path: "golang.org/x/time",
	},
	{
		Kind: "subrepo",
		Name: "tools",
		Path: "golang.org/x/tools",
	},
	{
		Kind: "subrepo",
		Name: "tour",
		Path: "golang.org/x/tour",
	},
}

// gccgoDash is the dashboard for gccgo.
var gccgoDash = &Dashboard{
	Name:      "Gccgo",
	Namespace: "Gccgo",
	Prefix:    "/gccgo",
	Packages: []*Package{
		{
			Kind: "gccgo",
			Name: "Gccgo",
		},
	},
}

// hiddenBranches specifies branches that
// should not be displayed on the build dashboard.
// This also prevents the builder infrastructure
// from testing sub-repos against these branches.
var hiddenBranches = map[string]bool{
	"release-branch.go1.4": true,
}
<|endoftext|>


<commit_before>package server

import (
	"net"
	"strings"

	"github.com/hashicorp/serf/serf"
)

const (
	// StatusReap is used to update the status of a node if we
	// are handling a EventMemberReap
	StatusReap = serf.MemberStatus(-1)

	// kappaEventPrefix is pre-pended to a kappa event to distinguish it
	kappaEventPrefix = "kappa-event:"
)

// kappaEventName computes the name of a kappa event
func kappaEventName(name string) string {
	return kappaEventPrefix + name
}

// isKappaEvent checks if a serf event is a Kappa event
func isKappaEvent(name string) bool {
	return strings.HasPrefix(name, kappaEventPrefix)
}

// rawKappaEventName is used to get the raw kappa event name
func rawKappaEventName(name string) string {
	return strings.TrimPrefix(name, kappaEventPrefix)
}

// serfEventHandler is used to handle events from the Serf cluster
func (s *Server) serfEventHandler() error {
	for {
		select {
		case e := <-s.serfEventCh:
			switch e.EventType() {
			case serf.EventMemberJoin:
				s.nodeJoin(e.(serf.MemberEvent))
				s.localMemberEvent(e.(serf.MemberEvent))

			case serf.EventMemberLeave, serf.EventMemberFailed:
				s.nodeFailed(e.(serf.MemberEvent))
				s.localMemberEvent(e.(serf.MemberEvent))

			case serf.EventMemberReap:
				s.localMemberEvent(e.(serf.MemberEvent))
			case serf.EventUser:
				s.localEvent(e.(serf.UserEvent))
			case serf.EventMemberUpdate: // Ignore
			case serf.EventQuery: // Ignore
			default:
				s.logger.Warn("kappa: unhandled Serf Event: %#v", e)
			}

		case <-s.t.Dying():
			return nil
		}
	}
}

// localMemberEvent is used to reconcile Serf events with the strongly
// consistent store if we are the current leader
func (s *Server) localMemberEvent(me serf.MemberEvent) {
	// Do nothing if we are not the leader
	if !s.IsLeader() {
		return
	}

	// Check if this is a reap event
	isReap := me.EventType() == serf.EventMemberReap

	// Queue the members for reconciliation
	for _, m := range me.Members {
		// Change the status if this is a reap event
		if isReap {
			m.Status = StatusReap
		}
		select {
		case s.reconcileCh <- m:
		default:
		}
	}
}

// localEvent is called when we receive an event on the local Serf
func (s *Server) localEvent(event serf.UserEvent) {

	// Handle only consul events
	if !strings.HasPrefix(event.Name, KappaServiceName+":") {
		return
	}

	switch name := event.Name; {
	case name == LeaderEventName:
		s.logger.Info("kappa: New leader elected: %s", event.Payload)

	case isKappaEvent(name):
		event.Name = rawKappaEventName(name)
		s.logger.Debug("kappa: user event: %s", event.Name)

		// Send event to processing channel
		s.kappaEventCh <- event

	default:
		s.logger.Warn("kappa: Unhandled local event: %v", event)
	}
}

// nodeJoin is used to handle join events on the both serf clusters
func (s *Server) nodeJoin(me serf.MemberEvent) {
	for _, m := range me.Members {
		details, err := getKappaServer(m)
		if err != nil {
			continue
		}
		s.logger.Info("kappa: adding server %s", details)

		// Add to the local list as well
		if details.Cluster == s.config.ClusterName {
			s.localLock.Lock()
			s.localKappas[details.Addr.String()] = details
			s.localLock.Unlock()
		}

		// If we still expecting to bootstrap, may need to handle this
		if s.config.BootstrapExpect != 0 {
			s.maybeBootstrap()
		}
	}
}

// maybeBootsrap is used to handle bootstrapping when a new consul server joins
func (s *Server) maybeBootstrap() {
	// // TODO: Requires Raft!
	// index, err := s.raftStore.LastIndex()
	// if err != nil {
	// 	s.logger.Error("kappa: failed to read last raft index: %v", err)
	// 	return
	// }
	// // Bootstrap can only be done if there are no committed logs,
	// // remove our expectations of bootstrapping
	// if index != 0 {
	// 	s.config.BootstrapExpect = 0
	// 	return
	// }

	// Scan for all the known servers
	members := s.serf.Members()
	addrs := make([]string, 0)
	for _, member := range members {
		details, err := getKappaServer(member)
		if err != nil {
			continue
		}
		if details.Cluster != s.config.ClusterName {
			s.logger.Error("kappa: Member %v has a conflicting datacenter, ignoring", member)
			continue
		}
		if details.Expect != 0 && details.Expect != s.config.BootstrapExpect {
			s.logger.Error("kappa: Member %v has a conflicting expect value. All nodes should expect the same number.", member)
			return
		}
		if details.Bootstrap {
			s.logger.Error("kappa: Member %v has bootstrap mode. Expect disabled.", member)
			return
		}
		addr := &net.TCPAddr{IP: member.Addr, Port: details.SSHPort}
		addrs = append(addrs, addr.String())
	}

	// Skip if we haven't met the minimum expect count
	if len(addrs) < s.config.BootstrapExpect {
		return
	}

	// Update the peer set
	// TODO: Requires Raft!
	// s.logger.Info("kappa: Attempting bootstrap with nodes: %v", addrs)
	// if err := s.raft.SetPeers(addrs).Error(); err != nil {
	// 	s.logger.Error("kappa: failed to bootstrap peers: %v", err)
	// }

	// Bootstrapping complete, don't enter this again
	s.config.BootstrapExpect = 0
}

// nodeFailed is used to handle fail events on both the serf clusters
func (s *Server) nodeFailed(me serf.MemberEvent) {
	s.localLock.Lock()
	for _, m := range me.Members {
		details, err := getKappaServer(m)
		if err != nil {
			continue
		}
		s.logger.Info("kappa: removing server %s", details)

		// Remove from the local list as well
		delete(s.localKappas, details.Addr.String())
	}
	s.localLock.Unlock()
}
<commit_msg>Update logging for serf<commit_after>package server

import (
	"net"
	"strings"

	"github.com/hashicorp/serf/serf"
)

const (
	// StatusReap is used to update the status of a node if we
	// are handling a EventMemberReap
	StatusReap = serf.MemberStatus(-1)

	// kappaEventPrefix is pre-pended to a kappa event to distinguish it
	kappaEventPrefix = "kappa-event:"
)

// kappaEventName computes the name of a kappa event
func kappaEventName(name string) string {
	return kappaEventPrefix + name
}

// isKappaEvent checks if a serf event is a Kappa event
func isKappaEvent(name string) bool {
	return strings.HasPrefix(name, kappaEventPrefix)
}

// rawKappaEventName is used to get the raw kappa event name
func rawKappaEventName(name string) string {
	return strings.TrimPrefix(name, kappaEventPrefix)
}

// serfEventHandler is used to handle events from the Serf cluster
func (s *Server) serfEventHandler() error {
	for {
		select {
		case e := <-s.serfEventCh:
			s.logger.Info("Received event:", "evt", e.String())
			switch e.EventType() {
			case serf.EventMemberJoin:
				s.nodeJoin(e.(serf.MemberEvent))
				s.localMemberEvent(e.(serf.MemberEvent))

			case serf.EventMemberLeave, serf.EventMemberFailed:
				s.nodeFailed(e.(serf.MemberEvent))
				s.localMemberEvent(e.(serf.MemberEvent))

			case serf.EventMemberReap:
				s.localMemberEvent(e.(serf.MemberEvent))
			case serf.EventUser:
				s.localEvent(e.(serf.UserEvent))
			case serf.EventMemberUpdate: // Ignore
			case serf.EventQuery: // Ignore
			default:
				s.logger.Warn("kappa: unhandled Serf Event: %#v", e)
			}

		case <-s.t.Dying():
			return nil
		}
	}
}

// localMemberEvent is used to reconcile Serf events with the strongly
// consistent store if we are the current leader
func (s *Server) localMemberEvent(me serf.MemberEvent) {
	// Do nothing if we are not the leader
	if !s.IsLeader() {
		return
	}

	// Check if this is a reap event
	isReap := me.EventType() == serf.EventMemberReap

	// Queue the members for reconciliation
	for _, m := range me.Members {
		// Change the status if this is a reap event
		if isReap {
			m.Status = StatusReap
		}
		select {
		case s.reconcileCh <- m:
		default:
		}
	}
}

// localEvent is called when we receive an event on the local Serf
func (s *Server) localEvent(event serf.UserEvent) {

	// Handle only consul events
	if !strings.HasPrefix(event.Name, KappaServiceName+":") {
		return
	}

	switch name := event.Name; {
	case name == LeaderEventName:
		s.logger.Info("kappa: New leader elected: %s", event.Payload)

	case isKappaEvent(name):
		event.Name = rawKappaEventName(name)
		s.logger.Debug("kappa: user event: %s", event.Name)

		// Send event to processing channel
		s.kappaEventCh <- event

	default:
		s.logger.Warn("kappa: Unhandled local event: %v", event)
	}
}

// nodeJoin is used to handle join events on the both serf clusters
func (s *Server) nodeJoin(me serf.MemberEvent) {
	for _, m := range me.Members {
		details, err := getKappaServer(m)
		if err != nil {
			s.logger.Warn("kappa: error adding server", err)
			continue
		}
		s.logger.Info("kappa: adding server", details.String())

		// Add to the local list as well
		if details.Cluster == s.config.ClusterName {
			s.localLock.Lock()
			s.localKappas[details.Addr.String()] = details
			s.localLock.Unlock()
		}

		// If we still expecting to bootstrap, may need to handle this
		if s.config.BootstrapExpect != 0 {
			s.maybeBootstrap()
		}
	}
}

// maybeBootsrap is used to handle bootstrapping when a new consul server joins
func (s *Server) maybeBootstrap() {
	// // TODO: Requires Raft!
	// index, err := s.raftStore.LastIndex()
	// if err != nil {
	// 	s.logger.Error("kappa: failed to read last raft index: %v", err)
	// 	return
	// }
	// // Bootstrap can only be done if there are no committed logs,
	// // remove our expectations of bootstrapping
	// if index != 0 {
	// 	s.config.BootstrapExpect = 0
	// 	return
	// }

	// Scan for all the known servers
	members := s.serf.Members()
	addrs := make([]string, 0)
	for _, member := range members {
		details, err := getKappaServer(member)
		if err != nil {
			continue
		}
		if details.Cluster != s.config.ClusterName {
			s.logger.Warn("kappa: Member %v has a conflicting datacenter, ignoring", member)
			continue
		}
		if details.Expect != 0 && details.Expect != s.config.BootstrapExpect {
			s.logger.Warn("kappa: Member %v has a conflicting expect value. All nodes should expect the same number.", member)
			return
		}
		if details.Bootstrap {
			s.logger.Warn("kappa: Member %v has bootstrap mode. Expect disabled.", member)
			return
		}
		addr := &net.TCPAddr{IP: member.Addr, Port: details.SSHPort}
		addrs = append(addrs, addr.String())
	}

	// Skip if we haven't met the minimum expect count
	if len(addrs) < s.config.BootstrapExpect {
		return
	}

	// Update the peer set
	// TODO: Requires Raft!
	// s.logger.Info("kappa: Attempting bootstrap with nodes: %v", addrs)
	// if err := s.raft.SetPeers(addrs).Error(); err != nil {
	// 	s.logger.Error("kappa: failed to bootstrap peers: %v", err)
	// }

	// Bootstrapping complete, don't enter this again
	s.config.BootstrapExpect = 0
}

// nodeFailed is used to handle fail events on both the serf clusters
func (s *Server) nodeFailed(me serf.MemberEvent) {
	s.localLock.Lock()
	for _, m := range me.Members {
		details, err := getKappaServer(m)
		if err != nil {
			continue
		}
		s.logger.Info("kappa: removing server %s", details)

		// Remove from the local list as well
		delete(s.localKappas, details.Addr.String())
	}
	s.localLock.Unlock()
}
<|endoftext|>


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

package git

import (
	"bufio"
	"container/list"
	"fmt"
	"net/http"
	"strconv"
	"strings"

	"github.com/mcuadros/go-version"
)

// Commit represents a git commit.
type Commit struct {
	Tree
	ID            sha1 // The ID of this commit object
	Author        *Signature
	Committer     *Signature
	CommitMessage string

	parents        []sha1 // SHA1 strings
	submoduleCache *objectCache
}

// Message returns the commit message. Same as retrieving CommitMessage directly.
func (c *Commit) Message() string {
	return c.CommitMessage
}

// Summary returns first line of commit message.
func (c *Commit) Summary() string {
	return strings.Split(c.CommitMessage, "\n")[0]
}

// ParentID returns oid of n-th parent (0-based index).
// It returns nil if no such parent exists.
func (c *Commit) ParentID(n int) (sha1, error) {
	if n >= len(c.parents) {
		return sha1{}, ErrNotExist{"", ""}
	}
	return c.parents[n], nil
}

// Parent returns n-th parent (0-based index) of the commit.
func (c *Commit) Parent(n int) (*Commit, error) {
	id, err := c.ParentID(n)
	if err != nil {
		return nil, err
	}
	parent, err := c.repo.getCommit(id)
	if err != nil {
		return nil, err
	}
	return parent, nil
}

// ParentCount returns number of parents of the commit.
// 0 if this is the root commit,  otherwise 1,2, etc.
func (c *Commit) ParentCount() int {
	return len(c.parents)
}

func isImageFile(data []byte) (string, bool) {
	contentType := http.DetectContentType(data)
	if strings.Index(contentType, "image/") != -1 {
		return contentType, true
	}
	return contentType, false
}

func (c *Commit) IsImageFile(name string) bool {
	blob, err := c.GetBlobByPath(name)
	if err != nil {
		return false
	}

	dataRc, err := blob.Data()
	if err != nil {
		return false
	}
	buf := make([]byte, 1024)
	n, _ := dataRc.Read(buf)
	if n > 0 {
		buf = buf[:n]
	}
	_, isImage := isImageFile(buf)
	return isImage
}

// GetCommitByPath return the commit of relative path object.
func (c *Commit) GetCommitByPath(relpath string) (*Commit, error) {
	return c.repo.getCommitByPathWithID(c.ID, relpath)
}

// AddAllChanges marks local changes to be ready for commit.
func AddChanges(repoPath string, all bool, files ...string) error {
	cmd := NewCommand("add")
	if all {
		cmd.AddArguments("--all")
	}
	_, err := cmd.AddArguments(files...).RunInDir(repoPath)
	return err
}

// CommitChanges commits local changes with given message and author.
func CommitChanges(repoPath, message string, author *Signature) error {
	cmd := NewCommand("commit", "-m", message)
	if author != nil {
		cmd.AddArguments(fmt.Sprintf("--author='%s <%s>'", author.Name, author.Email))
	}
	_, err := cmd.RunInDir(repoPath)

	// No stderr but exit status 1 means nothing to commit.
	if err != nil && err.Error() == "exit status 1" {
		return nil
	}
	return err
}

func commitsCount(repoPath, revision, relpath string) (int64, error) {
	var cmd *Command
	isFallback := false
	if version.Compare(gitVersion, "1.8.0", "<") {
		isFallback = true
		cmd = NewCommand("log", "--pretty=format:''")
	} else {
		cmd = NewCommand("rev-list", "--count")
	}
	cmd.AddArguments(revision)
	if len(relpath) > 0 {
		cmd.AddArguments("--", relpath)
	}

	stdout, err := cmd.RunInDir(repoPath)
	if err != nil {
		return 0, err
	}

	if isFallback {
		return int64(len(strings.Split(stdout, "\n"))), nil
	}
	return strconv.ParseInt(strings.TrimSpace(stdout), 10, 64)
}

// CommitsCount returns number of total commits of until given revision.
func CommitsCount(repoPath, revision string) (int64, error) {
	return commitsCount(repoPath, revision, "")
}

func (c *Commit) CommitsCount() (int64, error) {
	return CommitsCount(c.repo.Path, c.ID.String())
}

func (c *Commit) CommitsByRange(page int) (*list.List, error) {
	return c.repo.commitsByRange(c.ID, page)
}

func (c *Commit) CommitsBefore() (*list.List, error) {
	return c.repo.getCommitsBefore(c.ID)
}

func (c *Commit) CommitsBeforeLimit(num int) (*list.List, error) {
	return c.repo.getCommitsBeforeLimit(c.ID, num)
}

func (c *Commit) CommitsBeforeUntil(commitID string) (*list.List, error) {
	endCommit, err := c.repo.GetCommit(commitID)
	if err != nil {
		return nil, err
	}
	return c.repo.CommitsBetween(c, endCommit)
}

func (c *Commit) SearchCommits(keyword string) (*list.List, error) {
	return c.repo.searchCommits(c.ID, keyword)
}

func (c *Commit) GetFilesChangedSinceCommit(pastCommit string) ([]string, error) {
	return c.repo.getFilesChanged(pastCommit, c.ID.String())
}

func (c *Commit) GetSubModules() (*objectCache, error) {
	if c.submoduleCache != nil {
		return c.submoduleCache, nil
	}

	entry, err := c.GetTreeEntryByPath(".gitmodules")
	if err != nil {
		return nil, err
	}
	rd, err := entry.Blob().Data()
	if err != nil {
		return nil, err
	}

	scanner := bufio.NewScanner(rd)
	c.submoduleCache = newObjectCache()
	var ismodule bool
	var path string
	for scanner.Scan() {
		if strings.HasPrefix(scanner.Text(), "[submodule") {
			ismodule = true
			continue
		}
		if ismodule {
			fields := strings.Split(scanner.Text(), "=")
			k := strings.TrimSpace(fields[0])
			if k == "path" {
				path = strings.TrimSpace(fields[1])
			} else if k == "url" {
				c.submoduleCache.Set(path, &SubModule{path, strings.TrimSpace(fields[1])})
				ismodule = false
			}
		}
	}

	return c.submoduleCache, nil
}

func (c *Commit) GetSubModule(entryname string) (*SubModule, error) {
	modules, err := c.GetSubModules()
	if err != nil {
		return nil, err
	}

	module, has := modules.Get(entryname)
	if has {
		return module.(*SubModule), nil
	}
	return nil, nil
}
<commit_msg>Avoid creating an array for the sole purpose of counting elements<commit_after>// Copyright 2015 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package git

import (
	"bufio"
	"container/list"
	"fmt"
	"net/http"
	"strconv"
	"strings"

	"github.com/mcuadros/go-version"
)

// Commit represents a git commit.
type Commit struct {
	Tree
	ID            sha1 // The ID of this commit object
	Author        *Signature
	Committer     *Signature
	CommitMessage string

	parents        []sha1 // SHA1 strings
	submoduleCache *objectCache
}

// Message returns the commit message. Same as retrieving CommitMessage directly.
func (c *Commit) Message() string {
	return c.CommitMessage
}

// Summary returns first line of commit message.
func (c *Commit) Summary() string {
	return strings.Split(c.CommitMessage, "\n")[0]
}

// ParentID returns oid of n-th parent (0-based index).
// It returns nil if no such parent exists.
func (c *Commit) ParentID(n int) (sha1, error) {
	if n >= len(c.parents) {
		return sha1{}, ErrNotExist{"", ""}
	}
	return c.parents[n], nil
}

// Parent returns n-th parent (0-based index) of the commit.
func (c *Commit) Parent(n int) (*Commit, error) {
	id, err := c.ParentID(n)
	if err != nil {
		return nil, err
	}
	parent, err := c.repo.getCommit(id)
	if err != nil {
		return nil, err
	}
	return parent, nil
}

// ParentCount returns number of parents of the commit.
// 0 if this is the root commit,  otherwise 1,2, etc.
func (c *Commit) ParentCount() int {
	return len(c.parents)
}

func isImageFile(data []byte) (string, bool) {
	contentType := http.DetectContentType(data)
	if strings.Index(contentType, "image/") != -1 {
		return contentType, true
	}
	return contentType, false
}

func (c *Commit) IsImageFile(name string) bool {
	blob, err := c.GetBlobByPath(name)
	if err != nil {
		return false
	}

	dataRc, err := blob.Data()
	if err != nil {
		return false
	}
	buf := make([]byte, 1024)
	n, _ := dataRc.Read(buf)
	if n > 0 {
		buf = buf[:n]
	}
	_, isImage := isImageFile(buf)
	return isImage
}

// GetCommitByPath return the commit of relative path object.
func (c *Commit) GetCommitByPath(relpath string) (*Commit, error) {
	return c.repo.getCommitByPathWithID(c.ID, relpath)
}

// AddAllChanges marks local changes to be ready for commit.
func AddChanges(repoPath string, all bool, files ...string) error {
	cmd := NewCommand("add")
	if all {
		cmd.AddArguments("--all")
	}
	_, err := cmd.AddArguments(files...).RunInDir(repoPath)
	return err
}

// CommitChanges commits local changes with given message and author.
func CommitChanges(repoPath, message string, author *Signature) error {
	cmd := NewCommand("commit", "-m", message)
	if author != nil {
		cmd.AddArguments(fmt.Sprintf("--author='%s <%s>'", author.Name, author.Email))
	}
	_, err := cmd.RunInDir(repoPath)

	// No stderr but exit status 1 means nothing to commit.
	if err != nil && err.Error() == "exit status 1" {
		return nil
	}
	return err
}

func commitsCount(repoPath, revision, relpath string) (int64, error) {
	var cmd *Command
	isFallback := false
	if version.Compare(gitVersion, "1.8.0", "<") {
		isFallback = true
		cmd = NewCommand("log", "--pretty=format:''")
	} else {
		cmd = NewCommand("rev-list", "--count")
	}
	cmd.AddArguments(revision)
	if len(relpath) > 0 {
		cmd.AddArguments("--", relpath)
	}

	stdout, err := cmd.RunInDir(repoPath)
	if err != nil {
		return 0, err
	}

	if isFallback {
		return int64(strings.Count(stdout, "\n")), nil
	}
	return strconv.ParseInt(strings.TrimSpace(stdout), 10, 64)
}

// CommitsCount returns number of total commits of until given revision.
func CommitsCount(repoPath, revision string) (int64, error) {
	return commitsCount(repoPath, revision, "")
}

func (c *Commit) CommitsCount() (int64, error) {
	return CommitsCount(c.repo.Path, c.ID.String())
}

func (c *Commit) CommitsByRange(page int) (*list.List, error) {
	return c.repo.commitsByRange(c.ID, page)
}

func (c *Commit) CommitsBefore() (*list.List, error) {
	return c.repo.getCommitsBefore(c.ID)
}

func (c *Commit) CommitsBeforeLimit(num int) (*list.List, error) {
	return c.repo.getCommitsBeforeLimit(c.ID, num)
}

func (c *Commit) CommitsBeforeUntil(commitID string) (*list.List, error) {
	endCommit, err := c.repo.GetCommit(commitID)
	if err != nil {
		return nil, err
	}
	return c.repo.CommitsBetween(c, endCommit)
}

func (c *Commit) SearchCommits(keyword string) (*list.List, error) {
	return c.repo.searchCommits(c.ID, keyword)
}

func (c *Commit) GetFilesChangedSinceCommit(pastCommit string) ([]string, error) {
	return c.repo.getFilesChanged(pastCommit, c.ID.String())
}

func (c *Commit) GetSubModules() (*objectCache, error) {
	if c.submoduleCache != nil {
		return c.submoduleCache, nil
	}

	entry, err := c.GetTreeEntryByPath(".gitmodules")
	if err != nil {
		return nil, err
	}
	rd, err := entry.Blob().Data()
	if err != nil {
		return nil, err
	}

	scanner := bufio.NewScanner(rd)
	c.submoduleCache = newObjectCache()
	var ismodule bool
	var path string
	for scanner.Scan() {
		if strings.HasPrefix(scanner.Text(), "[submodule") {
			ismodule = true
			continue
		}
		if ismodule {
			fields := strings.Split(scanner.Text(), "=")
			k := strings.TrimSpace(fields[0])
			if k == "path" {
				path = strings.TrimSpace(fields[1])
			} else if k == "url" {
				c.submoduleCache.Set(path, &SubModule{path, strings.TrimSpace(fields[1])})
				ismodule = false
			}
		}
	}

	return c.submoduleCache, nil
}

func (c *Commit) GetSubModule(entryname string) (*SubModule, error) {
	modules, err := c.GetSubModules()
	if err != nil {
		return nil, err
	}

	module, has := modules.Get(entryname)
	if has {
		return module.(*SubModule), nil
	}
	return nil, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strings"
)

const (
	PLUGIN_MANAGER_URL string = "/pluginManager/api/xml?depth=1"
)

func iAccessPluginManagement() error {
	pluginsResp, err := httpClient.Get(getUrl(PLUGIN_MANAGER_URL))

	if err != nil {
		return err
	}

	body, _ = getBodyString(pluginsResp)
	return nil
}

func allThePluginsAreInstalled() error {
	if !strings.Contains(body, "<shortName>cucumber-reports</shortName>") {
		return fmt.Errorf("expected %s to contain 'cucumber-reports'", body)
	}
	return nil
}
<commit_msg>Extended plugin test to test for all expected plugins<commit_after>package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
)

const (
	PLUGIN_MANAGER_URL string = "/pluginManager/api/json?depth=1&tree=plugins[shortName,version]"
)

type Plugins struct {
	Plugins []Plugin
}

type Plugin struct {
	Name    string `json:"shortName"`
	Version string `json:"version"`
}

func iAccessPluginManagement() error {
	pluginsResp, err := httpClient.Get(getUrl(PLUGIN_MANAGER_URL))

	if err != nil {
		return err
	}

	body, _ = getBodyString(pluginsResp)
	return nil
}

func createPluginArray(plugins Plugins) map[string]string {
	a := make(map[string]string)

	for _, plugin := range plugins.Plugins {
		a[plugin.Name] = plugin.Version
	}
	return a
}

func getAllInstalledPlugins() (Plugins, error) {
	var plugins Plugins
	json.Unmarshal([]byte(body), &plugins)

	if len(plugins.Plugins) == 0 {
		return plugins, fmt.Errorf("%s", "No plugins installed")
	}

	return plugins, nil
}

func getAllExpectedPlugins() (Plugins, error) {
	var plugins Plugins
	filePath, _ := os.Getwd()

	p, err := ioutil.ReadFile(filePath + "/../../../src/jenkins/plugins.txt")

	if err != nil {
		return Plugins{}, fmt.Errorf("%s", err)
	}

	scanner := bufio.NewScanner(strings.NewReader(fmt.Sprintf("%s", p)))
	for scanner.Scan() {
		pluginLine := scanner.Text()
		splitPlugin := strings.Split(pluginLine, ":")
		plugin := Plugin{Name: splitPlugin[0], Version: splitPlugin[1]}
		plugins.Plugins = append(plugins.Plugins, plugin)
	}

	if len(plugins.Plugins) == 0 {
		return plugins, fmt.Errorf("%s", "No expected plugins")
	}

	return plugins, nil
}

func allThePluginsAreInstalled() error {
	installedPlugins, err := getAllInstalledPlugins()
	if err != nil {
		return fmt.Errorf("%s", err)
	}
	installedPluginsArray := createPluginArray(installedPlugins)
	expectedPlugins, err := getAllExpectedPlugins()
	if err != nil {
		return fmt.Errorf("%s", err)
	}

	for _, v := range expectedPlugins.Plugins {
		if installedPluginsArray[v.Name] == "" {
			return fmt.Errorf("Expected plugin %s is not installed", v.Name)
		}
		if installedPluginsArray[v.Name] != v.Version {
			return fmt.Errorf("Unexpected plugin version %s for %s (should be version %s)", installedPluginsArray[v.Name], v.Name, v.Version)
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package ts3

// ServerMethods groups server methods.
type ServerMethods struct {
	*Client
}

// Instance represents basic information for a TeamSpeak 3 instance.
type Instance struct {
	DatabaseVersion             int    `ms:"serverinstance_database_version"`
	FileTransferPort            int    `ms:"serverinstance_filetransfer_port"`
	MaxTotalDownloadBandwidth   uint64 `ms:"serverinstance_max_download_total_bandwidth"`
	MaxTotalUploadBandwidth     uint64 `ms:"serverinstance_max_upload_total_bandwidth"`
	GuestServerQueryGroup       int    `ms:"serverinstance_guest_serverquery_group"`
	ServerQueryFloodCommands    int    `ms:"serverinstance_serverquery_flood_commands"`
	ServerQueryFloodTime        int    `ms:"serverinstance_serverquery_flood_time"`
	ServerQueryBanTime          int    `ms:"serverinstance_serverquery_ban_time"`
	TemplateServerAdminGroup    int    `ms:"serverinstance_template_serveradmin_group"`
	TemplateServerDefaultGroup  int    `ms:"serverinstance_template_serverdefault_group"`
	TemplateChannelAdminGroup   int    `ms:"serverinstance_template_channeladmin_group"`
	TemplateChannelDefaultGroup int    `ms:"serverinstance_template_channeldefault_group"`
	PermissionsVersion          int    `ms:"serverinstance_permissions_version"`
	PendingConnectionsPerIP     int    `ms:"serverinstance_pending_connections_per_ip"`
}

// ServerConnectionInfo represents the connection info for a TeamSpeak 3 instance.
type ServerConnectionInfo struct {
	FileTransferBandwidthSent     uint64  `ms:"connection_filetransfer_bandwidth_sent"`
	FileTransferBandwidthReceived uint64  `ms:"connection_filetransfer_bandwidth_received"`
	FileTransferTotalSent         uint64  `ms:"connection_filetransfer_bytes_sent_total"`
	FileTransferTotalReceived     uint64  `ms:"connection_filetransfer_bytes_received_total"`
	PacketsSentTotal              uint64  `ms:"connection_packets_sent_total"`
	PacketsReceivedTotal          uint64  `ms:"connection_packets_received_total"`
	BytesSentTotal                uint64  `ms:"connection_bytes_sent_total"`
	BytesReceivedTotal            uint64  `ms:"connection_bytes_received_total"`
	BandwidthSentLastSecond       uint64  `ms:"connection_bandwidth_sent_last_second_total"`
	BandwidthReceivedLastSecond   uint64  `ms:"connection_bandwidth_received_last_second_total"`
	BandwidthSentLastMinute       uint64  `ms:"connection_bandwidth_sent_last_minute_total"`
	BandwidthReceivedLastMinute   uint64  `ms:"connection_bandwidth_received_last_minute_total"`
	ConnectedTime                 uint32  `ms:"connection_connected_time"`
	PacketLossTotalAvg            float32 `ms:"connection_packetloss_total"`
	PingTotalAvg                  float32 `ms:"connection_ping"`
}

// Server represents a TeamSpeak 3 virtual server.
type Server struct {
	AntiFloodPointsNeededCommandBlock      int     `ms:"virtualserver_antiflood_points_needed_command_block"`
	AntiFloodPointsNeededIPBlock           int     `ms:"virtualserver_antiflood_points_needed_ip_block"`
	AntiFloodPointsTickReduce              int     `ms:"virtualserver_antiflood_points_tick_reduce"`
	ChannelsOnline                         int     `ms:"virtualserver_channelsonline"`
	ClientsOnline                          int     `ms:"virtualserver_clientsonline"`
	CodecEncryptionMode                    int     `ms:"virtualserver_codec_encryption_mode"`
	ComplainAutoBanCount                   int     `ms:"virtualserver_complain_autoban_count"`
	ComplainAutoBanTime                    int     `ms:"virtualserver_complain_autoban_time"`
	ComplainRemoveTime                     int     `ms:"virtualserver_complain_remove_time"`
	Created                                int     `ms:"virtualserver_created"`
	DefaultChannelAdminGroup               int     `ms:"virtualserver_default_channel_admin_group"`
	DefaultChannelGroup                    int     `ms:"virtualserver_default_channel_group"`
	DefaultServerGroup                     int     `ms:"virtualserver_default_server_group"`
	HostBannerGFXInterval                  int     `ms:"virtualserver_hostbanner_gfx_interval"`
	HostMessageMode                        int     `ms:"virtualserver_hostmessage_mode"`
	ID                                     int     `ms:"virtualserver_id"`
	MachineID                              string  `ms:"virtualserver_machine_id"`
	MaxClients                             int     `ms:"virtualserver_maxclients"`
	MinClientsInChannelBeforeForcedSilence int     `ms:"virtualserver_min_clients_in_channel_before_forced_silence"`
	NeededIdentitySecurityLevel            int     `ms:"virtualserver_needed_identity_security_level"`
	Port                                   int     `ms:"virtualserver_port"`
	QueryClientsOnline                     int     `ms:"virtualserver_queryclientsonline"`
	Uptime                                 int     `ms:"virtualserver_uptime"` // TODO(steve): use time.Duration
	AskForPrivilegeKey                     bool    `ms:"virtualserver_ask_for_privilegekey"`
	AutoStart                              bool    `ms:"virtualserver_autostart"`
	FlagPassword                           bool    `ms:"virtualserver_flag_password"`
	LogChannel                             bool    `ms:"virtualserver_log_channel"`
	LogClient                              bool    `ms:"virtualserver_log_client"`
	LogFileTransfer                        bool    `ms:"virtualserver_log_filetransfer"`
	LogPermissions                         bool    `ms:"virtualserver_log_permissions"`
	LogQuery                               bool    `ms:"virtualserver_log_client"`
	LogServer                              bool    `ms:"virtualserver_log_server"`
	WebListEnabled                         bool    `ms:"virtualserver_web_list_enabled"`
	PrioritySpeakerDimmModificator         float32 `ms:"virtualserver_priority_speaker_dimm_modificator"`
	BandwidthReceivedLastMinuteTotal       int     `ms:"virtualserver_bandwidth_received_last_minute_total"`
	BandwidthReceivedLastSecondTotal       int     `ms:"virtualserver_bandwidth_received_last_second_total"`
	BandwidthSentLastMinuteTotal           int     `ms:"virtualserver_bandwidth_sent_last_minute_total"`
	BandwidthSentLastSecondTotal           int     `ms:"virtualserver_bandwidth_sent_last_second_total"`
	ChannelTempDeleteDelayDefault          int     `ms:"virtualserver_channel_temp_delete_delay_default"`
	HostBannerMode                         int     `ms:"virtualserver_hostbanner_mode"`
	IconID                                 int     `ms:"virtualserver_icon_id"`
	MinAndroidVersion                      int     `ms:"virtualserver_min_android_version"`
	MinClientVersion                       int     `ms:"virtualserver_min_client_version"`
	MiniOSVersion                          int     `ms:"virtualserver_min_ios_version"`
	ReservedSlots                          int     `ms:"virtualserver_reserved_slots"`
	TotalPing                              float32 `ms:"virtualserver_total_ping"`
	MaxDownloadTotalBandwidth              uint64  `ms:"virtualserver_max_download_total_bandwidth"`
	MaxUploadTotalBandwidth                uint64  `ms:"virtualserver_max_upload_total_bandwidth"`
	MonthBytesDownloaded                   int64   `ms:"virtualserver_MonthBytesDownloaded"`
	MonthBytesUploaded                     int64   `ms:"virtualserver_MonthBytesUploaded"`
	TotalBytesDownloaded                   int64   `ms:"virtualserver_TotalBytesDownloaded"`
	TotalBytesUploaded                     int64   `ms:"virtualserver_TotalBytesUploaded"`
	TotalPacketLossControl                 int64   `ms:"virtualserver_total_packet_loss_control"`
	TotalPacketLossKeepalive               int64   `ms:"virtualserver_total_packet_loss_keepalive"`
	TotalPacketLossSpeech                  int64   `ms:"virtualserver_total_packet_loss_speech"`
	TotalPacketLossTotal                   int64   `ms:"virtualserver_total_packet_loss_total"`
	VirtualServerDownloadQuota             int64   `ms:"virtualserver_virtualserver_download_quota"`
	VirtualServerUploadQuota               int64   `ms:"virtualserver_virtualserver_Upload_quota"`
	FileBase                               string  `ms:"virtualserver_filebase"`
	HostBannerGFXURL                       string  `ms:"virtualserver_hostbanner_gfx_url"`
	HostBannerURL                          string  `ms:"virtualserver_hostbanner_url"`
	HostButtonGFXURL                       string  `ms:"virtualserver_hostbutton_gfx_url"`
	HostButtonToolTip                      string  `ms:"virtualserver_hostbutton_tooltip"`
	HostButtonURL                          string  `ms:"virtualserver_hostbutton_url"`
	HostMessage                            string  `ms:"virtualserver_hostmessage"`
	Name                                   string  `ms:"virtualserver_name"`
	NamePhonetic                           string  `ms:"virtualserver_name_phonetic"`
	Password                               string  `ms:"virtualserver_password"`
	Platform                               string  `ms:"virtualserver_platform"`
	Status                                 string  `ms:"virtualserver_status"`
	UniqueIdentifier                       string  `ms:"virtualserver_unique_identifier"`
	Version                                string  `ms:"virtualserver_version"`
	WelcomeMessage                         string  `ms:"virtualserver_welcomemessage"`
}

// List lists virtual servers.
func (s *ServerMethods) List(options ...string) ([]*Server, error) {
	var servers []*Server
	if _, err := s.ExecCmd(NewCmd("serverlist").WithOptions(options...).WithResponse(&servers)); err != nil {
		return nil, err
	}

	return servers, nil
}

// IDGetByPort returns the database id of the virtual server running on UDP port.
func (s *ServerMethods) IDGetByPort(port uint16) (int, error) {
	r := struct {
		ID int `ms:"server_id"`
	}{}
	_, err := s.ExecCmd(NewCmd("serveridgetbyport").WithArgs(NewArg("virtualserver_port", port)).WithResponse(&r))
	return r.ID, err
}

// Info returns detailed configuration information about the selected server.
func (s *ServerMethods) Info() (*Server, error) {
	r := &Server{}
	if _, err := s.ExecCmd(NewCmd("serverinfo").WithResponse(&r)); err != nil {
		return nil, err
	}

	return r, nil
}

// InstanceInfo returns detailed information about the selected instance.
func (s *ServerMethods) InstanceInfo() (*Instance, error) {
	r := &Instance{}
	if _, err := s.ExecCmd(NewCmd("instanceinfo").WithResponse(&r)); err != nil {
		return nil, err
	}

	return r, nil
}

// ServerConnectionInfo returns detailed bandwidth and transfer information about the selected instance.
func (s *ServerMethods) ServerConnectionInfo() (*ServerConnectionInfo, error) {
	r := &ServerConnectionInfo{}
	if _, err := s.ExecCmd(NewCmd("serverrequestconnectioninfo").WithResponse(&r)); err != nil {
		return nil, err
	}

	return r, nil

}

// Edit changes the selected virtual servers configuration using the given args.
func (s *ServerMethods) Edit(args ...CmdArg) error {
	_, err := s.ExecCmd(NewCmd("serveredit").WithArgs(args...))
	return err
}

// Delete deletes the virtual server specified by id.
// Only virtual server in a stopped state can be deleted.
func (s *ServerMethods) Delete(id int) error {
	_, err := s.ExecCmd(NewCmd("serverdelete").WithArgs(NewArg("sid", id)))
	return err
}

// CreatedServer is the details returned by a server create.
type CreatedServer struct {
	ID    int    `ms:"sid"`
	Port  uint16 `ms:"virtualserver_port"`
	Token string
}

// Create creates a new virtual server using the given properties and returns
// its ID, port and initial administrator privilege key.
// If virtualserver_port arg is not specified, the server will use the first unused
// UDP port.
func (s *ServerMethods) Create(name string, args ...CmdArg) (*CreatedServer, error) {
	r := &CreatedServer{}
	args = append(args, NewArg("virtualserver_name", name))
	if _, err := s.ExecCmd(NewCmd("servercreate").WithArgs(args...).WithResponse(r)); err != nil {
		return nil, err
	}

	return r, nil
}

// Start starts the virtual server specified by id.
func (s *ServerMethods) Start(id int) error {
	_, err := s.ExecCmd(NewCmd("serverstart").WithArgs(NewArg("sid", id)))
	return err
}

// Stop stops the virtual server specified by id.
func (s *ServerMethods) Stop(id int) error {
	_, err := s.ExecCmd(NewCmd("serverstop").WithArgs(NewArg("sid", id)))
	return err
}

// Group represents a virtual server group.
type Group struct {
	ID                int `ms:"sgid"`
	Name              string
	Type              int
	IconID            int
	Saved             bool `ms:"savedb"`
	SortID            int
	NameMode          int
	ModifyPower       int `ms:"n_modifyp"`
	MemberAddPower    int `ms:"n_member_addp"`
	MemberRemovePower int `ms:"n_member_addp"`
}

// GroupList returns a list of available groups for the selected server.
func (s *ServerMethods) GroupList() ([]*Group, error) {
	var groups []*Group
	if _, err := s.ExecCmd(NewCmd("servergrouplist").WithResponse(&groups)); err != nil {
		return nil, err
	}

	return groups, nil
}

// Channel represents a TeamSpeak 3 channel in a virtual server.
type Channel struct {
	ID                   int    `ms:"cid"`
	ParentID             int    `ms:"pid"`
	ChannelOrder         int    `ms:"channel_order"`
	ChannelName          string `ms:"channel_name"`
	TotalClients         int    `ms:"total_clients"`
	NeededSubscribePower int    `ms:"channel_needed_subscribe_power"`
}

// ChannelList returns a list of channels for the selected server.
func (s *ServerMethods) ChannelList() ([]*Channel, error) {
	var channels []*Channel
	if _, err := s.ExecCmd(NewCmd("channellist").WithResponse(&channels)); err != nil {
		return nil, err
	}

	return channels, nil
}

// PrivilegeKey represents a server privilege key.
type PrivilegeKey struct {
	Token       string
	Type        int    `ms:"token_type"`
	ID1         int    `ms:"token_id1"`
	ID2         int    `ms:"token_id2"`
	Created     int    `ms:"token_created"`
	Description string `ms:"token_description"`
}

// PrivilegeKeyList returns a list of available privilege keys for the selected server,
// including their type and group IDs.
func (s *ServerMethods) PrivilegeKeyList() ([]*PrivilegeKey, error) {
	var keys []*PrivilegeKey
	if _, err := s.ExecCmd(NewCmd("privilegekeylist").WithResponse(&keys)); err != nil {
		return nil, err
	}

	return keys, nil
}

// PrivilegeKeyAdd creates a new privilege token to the selected server and returns it.
// If tokentype is set to 0, the ID specified with id1 will be a server group ID.
// Otherwise, id1 is used as a channel group ID and you need to provide a valid channel ID using id2.
func (s *ServerMethods) PrivilegeKeyAdd(ttype, id1, id2 int, options ...CmdArg) (string, error) {
	t := struct {
		Token string
	}{}
	options = append(options, NewArg("tokentype", ttype), NewArg("tokenid1", id1), NewArg("tokenid2", id2))
	_, err := s.ExecCmd(NewCmd("privilegekeylist").WithArgs(options...).WithResponse(&t))
	return t.Token, err
}
<commit_msg>Adding extended list method to prevent empty values in struct<commit_after>package ts3

// ServerMethods groups server methods.
type ServerMethods struct {
	*Client
}

// Instance represents basic information for a TeamSpeak 3 instance.
type Instance struct {
	DatabaseVersion             int    `ms:"serverinstance_database_version"`
	FileTransferPort            int    `ms:"serverinstance_filetransfer_port"`
	MaxTotalDownloadBandwidth   uint64 `ms:"serverinstance_max_download_total_bandwidth"`
	MaxTotalUploadBandwidth     uint64 `ms:"serverinstance_max_upload_total_bandwidth"`
	GuestServerQueryGroup       int    `ms:"serverinstance_guest_serverquery_group"`
	ServerQueryFloodCommands    int    `ms:"serverinstance_serverquery_flood_commands"`
	ServerQueryFloodTime        int    `ms:"serverinstance_serverquery_flood_time"`
	ServerQueryBanTime          int    `ms:"serverinstance_serverquery_ban_time"`
	TemplateServerAdminGroup    int    `ms:"serverinstance_template_serveradmin_group"`
	TemplateServerDefaultGroup  int    `ms:"serverinstance_template_serverdefault_group"`
	TemplateChannelAdminGroup   int    `ms:"serverinstance_template_channeladmin_group"`
	TemplateChannelDefaultGroup int    `ms:"serverinstance_template_channeldefault_group"`
	PermissionsVersion          int    `ms:"serverinstance_permissions_version"`
	PendingConnectionsPerIP     int    `ms:"serverinstance_pending_connections_per_ip"`
}

// ServerConnectionInfo represents the connection info for a TeamSpeak 3 instance.
type ServerConnectionInfo struct {
	FileTransferBandwidthSent     uint64  `ms:"connection_filetransfer_bandwidth_sent"`
	FileTransferBandwidthReceived uint64  `ms:"connection_filetransfer_bandwidth_received"`
	FileTransferTotalSent         uint64  `ms:"connection_filetransfer_bytes_sent_total"`
	FileTransferTotalReceived     uint64  `ms:"connection_filetransfer_bytes_received_total"`
	PacketsSentTotal              uint64  `ms:"connection_packets_sent_total"`
	PacketsReceivedTotal          uint64  `ms:"connection_packets_received_total"`
	BytesSentTotal                uint64  `ms:"connection_bytes_sent_total"`
	BytesReceivedTotal            uint64  `ms:"connection_bytes_received_total"`
	BandwidthSentLastSecond       uint64  `ms:"connection_bandwidth_sent_last_second_total"`
	BandwidthReceivedLastSecond   uint64  `ms:"connection_bandwidth_received_last_second_total"`
	BandwidthSentLastMinute       uint64  `ms:"connection_bandwidth_sent_last_minute_total"`
	BandwidthReceivedLastMinute   uint64  `ms:"connection_bandwidth_received_last_minute_total"`
	ConnectedTime                 uint32  `ms:"connection_connected_time"`
	PacketLossTotalAvg            float32 `ms:"connection_packetloss_total"`
	PingTotalAvg                  float32 `ms:"connection_ping"`
}

// Server represents a TeamSpeak 3 virtual server.
type Server struct {
	AntiFloodPointsNeededCommandBlock      int     `ms:"virtualserver_antiflood_points_needed_command_block"`
	AntiFloodPointsNeededIPBlock           int     `ms:"virtualserver_antiflood_points_needed_ip_block"`
	AntiFloodPointsTickReduce              int     `ms:"virtualserver_antiflood_points_tick_reduce"`
	ChannelsOnline                         int     `ms:"virtualserver_channelsonline"`
	ClientsOnline                          int     `ms:"virtualserver_clientsonline"`
	CodecEncryptionMode                    int     `ms:"virtualserver_codec_encryption_mode"`
	ComplainAutoBanCount                   int     `ms:"virtualserver_complain_autoban_count"`
	ComplainAutoBanTime                    int     `ms:"virtualserver_complain_autoban_time"`
	ComplainRemoveTime                     int     `ms:"virtualserver_complain_remove_time"`
	Created                                int     `ms:"virtualserver_created"`
	DefaultChannelAdminGroup               int     `ms:"virtualserver_default_channel_admin_group"`
	DefaultChannelGroup                    int     `ms:"virtualserver_default_channel_group"`
	DefaultServerGroup                     int     `ms:"virtualserver_default_server_group"`
	HostBannerGFXInterval                  int     `ms:"virtualserver_hostbanner_gfx_interval"`
	HostMessageMode                        int     `ms:"virtualserver_hostmessage_mode"`
	ID                                     int     `ms:"virtualserver_id"`
	MachineID                              string  `ms:"virtualserver_machine_id"`
	MaxClients                             int     `ms:"virtualserver_maxclients"`
	MinClientsInChannelBeforeForcedSilence int     `ms:"virtualserver_min_clients_in_channel_before_forced_silence"`
	NeededIdentitySecurityLevel            int     `ms:"virtualserver_needed_identity_security_level"`
	Port                                   int     `ms:"virtualserver_port"`
	QueryClientsOnline                     int     `ms:"virtualserver_queryclientsonline"`
	Uptime                                 int     `ms:"virtualserver_uptime"` // TODO(steve): use time.Duration
	AskForPrivilegeKey                     bool    `ms:"virtualserver_ask_for_privilegekey"`
	AutoStart                              bool    `ms:"virtualserver_autostart"`
	FlagPassword                           bool    `ms:"virtualserver_flag_password"`
	LogChannel                             bool    `ms:"virtualserver_log_channel"`
	LogClient                              bool    `ms:"virtualserver_log_client"`
	LogFileTransfer                        bool    `ms:"virtualserver_log_filetransfer"`
	LogPermissions                         bool    `ms:"virtualserver_log_permissions"`
	LogQuery                               bool    `ms:"virtualserver_log_client"`
	LogServer                              bool    `ms:"virtualserver_log_server"`
	WebListEnabled                         bool    `ms:"virtualserver_web_list_enabled"`
	PrioritySpeakerDimmModificator         float32 `ms:"virtualserver_priority_speaker_dimm_modificator"`
	BandwidthReceivedLastMinuteTotal       int     `ms:"virtualserver_bandwidth_received_last_minute_total"`
	BandwidthReceivedLastSecondTotal       int     `ms:"virtualserver_bandwidth_received_last_second_total"`
	BandwidthSentLastMinuteTotal           int     `ms:"virtualserver_bandwidth_sent_last_minute_total"`
	BandwidthSentLastSecondTotal           int     `ms:"virtualserver_bandwidth_sent_last_second_total"`
	ChannelTempDeleteDelayDefault          int     `ms:"virtualserver_channel_temp_delete_delay_default"`
	HostBannerMode                         int     `ms:"virtualserver_hostbanner_mode"`
	IconID                                 int     `ms:"virtualserver_icon_id"`
	MinAndroidVersion                      int     `ms:"virtualserver_min_android_version"`
	MinClientVersion                       int     `ms:"virtualserver_min_client_version"`
	MiniOSVersion                          int     `ms:"virtualserver_min_ios_version"`
	ReservedSlots                          int     `ms:"virtualserver_reserved_slots"`
	TotalPing                              float32 `ms:"virtualserver_total_ping"`
	MaxDownloadTotalBandwidth              uint64  `ms:"virtualserver_max_download_total_bandwidth"`
	MaxUploadTotalBandwidth                uint64  `ms:"virtualserver_max_upload_total_bandwidth"`
	MonthBytesDownloaded                   int64   `ms:"virtualserver_MonthBytesDownloaded"`
	MonthBytesUploaded                     int64   `ms:"virtualserver_MonthBytesUploaded"`
	TotalBytesDownloaded                   int64   `ms:"virtualserver_TotalBytesDownloaded"`
	TotalBytesUploaded                     int64   `ms:"virtualserver_TotalBytesUploaded"`
	TotalPacketLossControl                 int64   `ms:"virtualserver_total_packet_loss_control"`
	TotalPacketLossKeepalive               int64   `ms:"virtualserver_total_packet_loss_keepalive"`
	TotalPacketLossSpeech                  int64   `ms:"virtualserver_total_packet_loss_speech"`
	TotalPacketLossTotal                   int64   `ms:"virtualserver_total_packet_loss_total"`
	VirtualServerDownloadQuota             int64   `ms:"virtualserver_virtualserver_download_quota"`
	VirtualServerUploadQuota               int64   `ms:"virtualserver_virtualserver_Upload_quota"`
	FileBase                               string  `ms:"virtualserver_filebase"`
	HostBannerGFXURL                       string  `ms:"virtualserver_hostbanner_gfx_url"`
	HostBannerURL                          string  `ms:"virtualserver_hostbanner_url"`
	HostButtonGFXURL                       string  `ms:"virtualserver_hostbutton_gfx_url"`
	HostButtonToolTip                      string  `ms:"virtualserver_hostbutton_tooltip"`
	HostButtonURL                          string  `ms:"virtualserver_hostbutton_url"`
	HostMessage                            string  `ms:"virtualserver_hostmessage"`
	Name                                   string  `ms:"virtualserver_name"`
	NamePhonetic                           string  `ms:"virtualserver_name_phonetic"`
	Password                               string  `ms:"virtualserver_password"`
	Platform                               string  `ms:"virtualserver_platform"`
	Status                                 string  `ms:"virtualserver_status"`
	UniqueIdentifier                       string  `ms:"virtualserver_unique_identifier"`
	Version                                string  `ms:"virtualserver_version"`
	WelcomeMessage                         string  `ms:"virtualserver_welcomemessage"`
}

// List lists virtual servers.
func (s *ServerMethods) List(options ...string) ([]*Server, error) {
	var servers []*Server
	if _, err := s.ExecCmd(NewCmd("serverlist").WithOptions(options...).WithResponse(&servers)); err != nil {
		return nil, err
	}

	return servers, nil
}

// Lists all virtual servers including all information you get when executing serverinfo command on it
func (s *ServerMethods) ExtendedList(options ...string) ([]*Server, error) {
	var servers []*Server
	var output_servers []*Server

	if _, err := s.ExecCmd(NewCmd("serverlist").WithOptions(options...).WithResponse(&servers)); err != nil {
		return nil, err
	}

	for _, server := range servers {
		s.Use(server.ID)
		if _, err := s.ExecCmd(NewCmd("serverinfo").WithResponse(&output_servers)); err != nil {
			return nil, err
		}
	}

	return output_servers, nil
}

// IDGetByPort returns the database id of the virtual server running on UDP port.
func (s *ServerMethods) IDGetByPort(port uint16) (int, error) {
	r := struct {
		ID int `ms:"server_id"`
	}{}
	_, err := s.ExecCmd(NewCmd("serveridgetbyport").WithArgs(NewArg("virtualserver_port", port)).WithResponse(&r))
	return r.ID, err
}

// Info returns detailed configuration information about the selected server.
func (s *ServerMethods) Info() (*Server, error) {
	r := &Server{}
	if _, err := s.ExecCmd(NewCmd("serverinfo").WithResponse(&r)); err != nil {
		return nil, err
	}

	return r, nil
}

// InstanceInfo returns detailed information about the selected instance.
func (s *ServerMethods) InstanceInfo() (*Instance, error) {
	r := &Instance{}
	if _, err := s.ExecCmd(NewCmd("instanceinfo").WithResponse(&r)); err != nil {
		return nil, err
	}

	return r, nil
}

// ServerConnectionInfo returns detailed bandwidth and transfer information about the selected instance.
func (s *ServerMethods) ServerConnectionInfo() (*ServerConnectionInfo, error) {
	r := &ServerConnectionInfo{}
	if _, err := s.ExecCmd(NewCmd("serverrequestconnectioninfo").WithResponse(&r)); err != nil {
		return nil, err
	}

	return r, nil

}

// Edit changes the selected virtual servers configuration using the given args.
func (s *ServerMethods) Edit(args ...CmdArg) error {
	_, err := s.ExecCmd(NewCmd("serveredit").WithArgs(args...))
	return err
}

// Delete deletes the virtual server specified by id.
// Only virtual server in a stopped state can be deleted.
func (s *ServerMethods) Delete(id int) error {
	_, err := s.ExecCmd(NewCmd("serverdelete").WithArgs(NewArg("sid", id)))
	return err
}

// CreatedServer is the details returned by a server create.
type CreatedServer struct {
	ID    int    `ms:"sid"`
	Port  uint16 `ms:"virtualserver_port"`
	Token string
}

// Create creates a new virtual server using the given properties and returns
// its ID, port and initial administrator privilege key.
// If virtualserver_port arg is not specified, the server will use the first unused
// UDP port.
func (s *ServerMethods) Create(name string, args ...CmdArg) (*CreatedServer, error) {
	r := &CreatedServer{}
	args = append(args, NewArg("virtualserver_name", name))
	if _, err := s.ExecCmd(NewCmd("servercreate").WithArgs(args...).WithResponse(r)); err != nil {
		return nil, err
	}

	return r, nil
}

// Start starts the virtual server specified by id.
func (s *ServerMethods) Start(id int) error {
	_, err := s.ExecCmd(NewCmd("serverstart").WithArgs(NewArg("sid", id)))
	return err
}

// Stop stops the virtual server specified by id.
func (s *ServerMethods) Stop(id int) error {
	_, err := s.ExecCmd(NewCmd("serverstop").WithArgs(NewArg("sid", id)))
	return err
}

// Group represents a virtual server group.
type Group struct {
	ID                int `ms:"sgid"`
	Name              string
	Type              int
	IconID            int
	Saved             bool `ms:"savedb"`
	SortID            int
	NameMode          int
	ModifyPower       int `ms:"n_modifyp"`
	MemberAddPower    int `ms:"n_member_addp"`
	MemberRemovePower int `ms:"n_member_addp"`
}

// GroupList returns a list of available groups for the selected server.
func (s *ServerMethods) GroupList() ([]*Group, error) {
	var groups []*Group
	if _, err := s.ExecCmd(NewCmd("servergrouplist").WithResponse(&groups)); err != nil {
		return nil, err
	}

	return groups, nil
}

// Channel represents a TeamSpeak 3 channel in a virtual server.
type Channel struct {
	ID                   int    `ms:"cid"`
	ParentID             int    `ms:"pid"`
	ChannelOrder         int    `ms:"channel_order"`
	ChannelName          string `ms:"channel_name"`
	TotalClients         int    `ms:"total_clients"`
	NeededSubscribePower int    `ms:"channel_needed_subscribe_power"`
}

// ChannelList returns a list of channels for the selected server.
func (s *ServerMethods) ChannelList() ([]*Channel, error) {
	var channels []*Channel
	if _, err := s.ExecCmd(NewCmd("channellist").WithResponse(&channels)); err != nil {
		return nil, err
	}

	return channels, nil
}

// PrivilegeKey represents a server privilege key.
type PrivilegeKey struct {
	Token       string
	Type        int    `ms:"token_type"`
	ID1         int    `ms:"token_id1"`
	ID2         int    `ms:"token_id2"`
	Created     int    `ms:"token_created"`
	Description string `ms:"token_description"`
}

// PrivilegeKeyList returns a list of available privilege keys for the selected server,
// including their type and group IDs.
func (s *ServerMethods) PrivilegeKeyList() ([]*PrivilegeKey, error) {
	var keys []*PrivilegeKey
	if _, err := s.ExecCmd(NewCmd("privilegekeylist").WithResponse(&keys)); err != nil {
		return nil, err
	}

	return keys, nil
}

// PrivilegeKeyAdd creates a new privilege token to the selected server and returns it.
// If tokentype is set to 0, the ID specified with id1 will be a server group ID.
// Otherwise, id1 is used as a channel group ID and you need to provide a valid channel ID using id2.
func (s *ServerMethods) PrivilegeKeyAdd(ttype, id1, id2 int, options ...CmdArg) (string, error) {
	t := struct {
		Token string
	}{}
	options = append(options, NewArg("tokentype", ttype), NewArg("tokenid1", id1), NewArg("tokenid2", id2))
	_, err := s.ExecCmd(NewCmd("privilegekeylist").WithArgs(options...).WithResponse(&t))
	return t.Token, err
}
<|endoftext|>