<commit_before>// Copyright © 2017 Karl Hepworth <Karl.Hepworth@gmail.com>
//
// 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 cmd

import (
	"fmt"
	"os"

	homedir "github.com/mitchellh/go-homedir"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var (

	// alias is the destination drush alias this site should be using.
	// in many places this will default to the domain name if not specified.
	alias string

	// alias_template is the path to the drush alias template file
	// processed by this application. It can be blank/empty and
	// it will use the template file located parallel to this.cmd
	// this value is configurable through configuration management.
	alias_template string

	// aliases is a comma-separated list of aliases which translates into a
	// []string. each string in the slice represents a target in commands
	// which use multiple aliases. the usage of this variable often will
	// accompany the use of the pattern variable to match aliases against
	// patterns.
	aliases string

	// cfgFile is the path to the config file in use.
	// cfgFile will default to $HOME/golang-drush.yaml
	// Other formats are supported natively by Viper,
	// however in this case yaml is recommended.
	cfgFile string

	// commands is a comma-separated string which contains translates to a
	// []string of drush commands which are executed upon a list of aliases
	// provided with the aliases and pattern variables.
	commands string

	// composer represents the path to the composer file to be used.
	// it also represents a source file, in the event a composer.json file
	// does not exist at the destination path.
	// this flag will also supersede the necessity and the functionality
	// associated with legacy make files.
	composer string

	// db_host is the string which represents the configured database host
	// this host path can be configured at $HOME/golang-drush.yml, and
	// defaults to '127.0.0.1'.
	db_host string

	// db_pass is an unprotected string which represents the configured user
	// password. this user account should have permission to create
	// databases, and this password can be configured at
	// $HOME/golang-drush.yml, and defaults to 'root'.
	db_pass string

	// db_port is an integer which represents the configured database port
	// this port path can be configured at $HOME/golang-drush.yml, and
	// defaults to 3306.
	db_port int

	// db_user is the string which represents the configured user account.
	// this user account should have permission to create databases, and
	// this user can be configured at $HOME/golang-drush.yml, and defaults
	// to 'root'.
	db_user string

	// destination is the destination alias or path for the desired action.
	// it will be determined based upon the command in use.
	destination string

	// domain is the destination domain to be used when setting up a new site
	domain string

	// makes is a comma-separated list of legacy make files to be used.
	// it will be automatically superseded by the use of the composer flag
	// however there is a lot of available deprecated functionality here.
	//
	// it is still appropriate to use this subset of functionality when
	// working with older codebases still accommodated to using make files.
	// these features may or may not be removed or isolated at a later time.
	//
	// Deprecated: use composer instead.
	makes string

	// name is the human-readable name for the target of this application.
	name string

	// pattern is a string which replaces the substring '%v' with another string
	// when dealing with operational work - most commonly aliases.
	pattern string

	// when working with make files, you can tell the system to rewrite
	// a given module branch to change via a unique string inside the make
	// file(s). this represents the destination result of that change, what the
	// string is to be replaced to be in the generated make file.
	//
	// Deprecated: used exclusively by make file functionality.
	// upgrade to use composer instead.
	rewriteDestination string

	// when working with make files, you can tell the system to rewrite
	// a given module branch to change via a unique string inside the make
	// file(s). this represents the source of that change, what string is to be
	// replaced in the generated make file.
	//
	// Deprecated: used exclusively by make file functionality.
	// upgrade to use composer instead.
	rewriteSource string

	// sites_php_template is the path to a template to be used for sites.php
	// for the default multi-site installation which must accompany builds.
	// this is to match server-side consistency for multi-sites or non-default
	// file system naming conventions.
	sites_php_template string

	// source is the source alias or path to a source file to be used.
	// the specific action will be determined based on the command.
	source string

	// syncDatabase is a bool which represents the expressive action to
	// syncronise databases between a source and destination in the sync
	// command.
	syncDatabase bool

	// syncFiles is a bool which represents the expressive action to
	// syncronise public and private file systems between a source
	// and destination in the sync command.
	syncFiles bool

	// timestamp is an int64 which is representational of a date format in the
	// format of YYYYMMDDHHMMSS. An example of this is
	// 19700101000000.
	//
	// if the timestamp is not set, a timestamp will be generated.
	// this value will affect the output file-system paths used by drush
	// aliases and virtual hosts which are created or modified.
	//
	// these formats are used depending on this timestamp, and if composer
	// is being used, or drush make is used:
	//  - drush, timestamp
	//     /path/to/sites/mysite/mysite.timestamp/
	//  - drush, no timestamp
	//     /path/to/sites/mysite/mysite/
	//  - composer, timestamp
	//     /path/to/sites/mysite/mysite.timestamp/docroot
	//  - composer, no timestamp
	//     /path/to/sites/mysite/mysite/docroot
	//
	timestamp int64

	// user_block is a boolean which controls command action in the user command.
	// in this case, the user block action will be invoked.
	user_block bool

	// user_create is a boolean which controls command action in the user command.
	// in this case, the user create action will be invoked.
	user_create bool

	// user_delete is a boolean which controls command action in the user command.
	// in this case, the user delete action will be invoked.
	user_delete bool

	// user_email is a string which represents the drupal user's emails to be affected.
	user_email string

	// user_name is a string which represents the drupal user to be affected.
	user_name string

	// user_password is a string which represents the drupal user's password to be affected.
	user_password string

	// user_role is a string which represents the drupal user's role to be affected.
	user_role string

	// user_unblock is a boolean which controls command action in the user command.
	// in this case, the user unblock action will be invoked.
	user_unblock bool

	// user_verify is a boolean which controls command action in the user command.
	// in this case, the user verification action will be invoked.
	user_verify bool

	// webserver is the name of the software package which handles HTTP
	// and HTTPS requests. this variable simply represents the name of
	// the service associated with web request handling.
	// setting this value is done through configuration management.
	webserver string

	// working-copy identifies if the build should leave the .git file-system
	// in-tact during the build. this would be useful when you are expecting
	// to send a file system to production, or for local development.
	// a working-copy is the local file-system including any development
	// file system data associated with each project/module.
	workingCopy bool

	// virtualhost_path is the path which the web server uses to store
	// all virtual hosts for the server. this is to identify where
	// processed templates should live and be removed from.
	// setting this value is done through configuration management.
	virtualhost_path string

	// path to the template to be used for virtual hosts supported by
	// the websrver variable. This assists to provide the webserver
	// a pre-configured set of defaults for a working site.
	virtualhost_template string
)

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "yoink",
	Short: "A Drupal build system.",
	Long:  ``,
}

// Execute is the main function for the root command.
func Execute() {

	if cfgFile != "" {
		// Use config file from the flag.
		viper.SetConfigFile(cfgFile)
	} else {
		// Find home directory.
		home, err := homedir.Dir()
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}

		// Search config in home directory with name "golang-drush" (without extension).
		viper.AddConfigPath(home)
		viper.SetConfigName("golang-drush")
	}

	viper.AutomaticEnv() // read in environment variables that match

	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Println("Using config file:", viper.ConfigFileUsed())
	}

	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
<commit_msg>Adjust configuration paths<commit_after>// Copyright © 2017 Karl Hepworth <Karl.Hepworth@gmail.com>
//
// 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 cmd

import (
	"fmt"
	"os"

	"strings"

	homedir "github.com/mitchellh/go-homedir"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var (

	// add is a boolean which will indicate to install a composer application.
	add bool

	// alias is the destination drush alias this site should be using.
	// in many places this will default to the domain name if not specified.
	alias string

	// alias_template is the path to the drush alias template file
	// processed by this application. It can be blank/empty and
	// it will use the template file located parallel to this.cmd
	// this value is configurable through configuration management.
	alias_template string

	// aliases is a comma-separated list of aliases which translates into a
	// []string. each string in the slice represents a target in commands
	// which use multiple aliases. the usage of this variable often will
	// accompany the use of the pattern variable to match aliases against
	// patterns.
	aliases string

	// cfgFile is the path to the config file in use.
	// cfgFile will default to $HOME/yoink/config.yml
	// Other formats are supported natively by Viper,
	// however in this case yaml is recommended.
	cfgFile string

	// commands is a comma-separated string which contains translates to a
	// []string of drush commands which are executed upon a list of aliases
	// provided with the aliases and pattern variables.
	commands string

	// composer represents the path to the composer file to be used.
	// it also represents a source file, in the event a composer.json file
	// does not exist at the destination path.
	// this flag will also supersede the necessity and the functionality
	// associated with legacy make files.
	composer string

	// db_host is the string which represents the configured database host
	// this host path can be configured at $HOME/yoink/config.yml, and
	// defaults to '127.0.0.1'.
	db_host string

	// db_pass is an unprotected string which represents the configured user
	// password. this user account should have permission to create
	// databases, and this password can be configured at
	// $HOME/yoink/config.yml, and defaults to 'root'.
	db_pass string

	// db_port is an integer which represents the configured database port
	// this port path can be configured at $HOME/yoink/config.yml, and
	// defaults to 3306.
	db_port int

	// db_user is the string which represents the configured user account.
	// this user account should have permission to create databases, and
	// this user can be configured at $HOME/yoink/config.yml, and defaults
	// to 'root'.
	db_user string

	// destination is the destination alias or path for the desired action.
	// it will be determined based upon the command in use.
	destination string

	// domain is the destination domain to be used when setting up a new site
	domain string

	// makes is a comma-separated list of legacy make files to be used.
	// it will be automatically superseded by the use of the composer flag
	// however there is a lot of available deprecated functionality here.
	//
	// it is still appropriate to use this subset of functionality when
	// working with older codebases still accommodated to using make files.
	// these features may or may not be removed or isolated at a later time.
	//
	// Deprecated: use composer instead.
	makes string

	// name is the human-readable name for the target of this application.
	name string

	// pattern is a string which replaces the substring '%v' with another string
	// when dealing with operational work - most commonly aliases.
	pattern string

	// remove is a boolean which will indicate to remove a composer application.
	remove bool

	// when working with make files, you can tell the system to rewrite
	// a given module branch to change via a unique string inside the make
	// file(s). this represents the destination result of that change, what the
	// string is to be replaced to be in the generated make file.
	//
	// Deprecated: used exclusively by make file functionality.
	// upgrade to use composer instead.
	rewriteDestination string

	// when working with make files, you can tell the system to rewrite
	// a given module branch to change via a unique string inside the make
	// file(s). this represents the source of that change, what string is to be
	// replaced in the generated make file.
	//
	// Deprecated: used exclusively by make file functionality.
	// upgrade to use composer instead.
	rewriteSource string

	// sites_php_template is the path to a template to be used for sites.php
	// for the default multi-site installation which must accompany builds.
	// this is to match server-side consistency for multi-sites or non-default
	// file system naming conventions.
	sites_php_template string

	// source is the source alias or path to a source file to be used.
	// the specific action will be determined based on the command.
	source string

	// syncDatabase is a bool which represents the expressive action to
	// syncronise databases between a source and destination in the sync
	// command.
	syncDatabase bool

	// syncFiles is a bool which represents the expressive action to
	// syncronise public and private file systems between a source
	// and destination in the sync command.
	syncFiles bool

	// timestamp is an int64 which is representational of a date format in the
	// format of YYYYMMDDHHMMSS. An example of this is
	// 19700101000000.
	//
	// if the timestamp is not set, a timestamp will be generated.
	// this value will affect the output file-system paths used by drush
	// aliases and virtual hosts which are created or modified.
	//
	// these formats are used depending on this timestamp, and if composer
	// is being used, or drush make is used:
	//  - drush, timestamp
	//     /path/to/sites/mysite/mysite.timestamp/
	//  - drush, no timestamp
	//     /path/to/sites/mysite/mysite/
	//  - composer, timestamp
	//     /path/to/sites/mysite/mysite.timestamp/docroot
	//  - composer, no timestamp
	//     /path/to/sites/mysite/mysite/docroot
	//
	timestamp int64

	// user_block is a boolean which controls command action in the user command.
	// in this case, the user block action will be invoked.
	user_block bool

	// user_create is a boolean which controls command action in the user command.
	// in this case, the user create action will be invoked.
	user_create bool

	// user_delete is a boolean which controls command action in the user command.
	// in this case, the user delete action will be invoked.
	user_delete bool

	// user_email is a string which represents the drupal user's emails to be affected.
	user_email string

	// user_name is a string which represents the drupal user to be affected.
	user_name string

	// user_password is a string which represents the drupal user's password to be affected.
	user_password string

	// user_role is a string which represents the drupal user's role to be affected.
	user_role string

	// user_unblock is a boolean which controls command action in the user command.
	// in this case, the user unblock action will be invoked.
	user_unblock bool

	// user_verify is a boolean which controls command action in the user command.
	// in this case, the user verification action will be invoked.
	user_verify bool

	// webserver is the name of the software package which handles HTTP
	// and HTTPS requests. this variable simply represents the name of
	// the service associated with web request handling.
	// setting this value is done through configuration management.
	webserver string

	// working-copy identifies if the build should leave the .git file-system
	// in-tact during the build. this would be useful when you are expecting
	// to send a file system to production, or for local development.
	// a working-copy is the local file-system including any development
	// file system data associated with each project/module.
	workingCopy bool

	// virtualhost_path is the path which the web server uses to store
	// all virtual hosts for the server. this is to identify where
	// processed templates should live and be removed from.
	// setting this value is done through configuration management.
	virtualhost_path string

	// path to the template to be used for virtual hosts supported by
	// the websrver variable. This assists to provide the webserver
	// a pre-configured set of defaults for a working site.
	virtualhost_template string
)

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "yoink",
	Short: "A Drupal build system.",
	Long:  ``,
}

// Execute is the main function for the root command.
func Execute() {

	if cfgFile != "" {
		// Use config file from the flag.
		viper.SetConfigFile(cfgFile)
	} else {
		// Find home directory.
		home, err := homedir.Dir()
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}

		r := strings.Join([]string{home, "yoink"}, string(os.PathSeparator))

		// Search config in home directory with name "golang-drush" (without extension).
		viper.AddConfigPath(r)
		viper.SetConfigName("config")
		viper.SetConfigType("yml")
	}

	viper.AutomaticEnv() // read in environment variables that match

	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Println("Using config file:", viper.ConfigFileUsed())
	}

	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package tp

import (
	"encoding/json"
	"strconv"
	"unsafe"

	"github.com/tidwall/gjson"

	"github.com/henrylee2cn/goutil"
	"github.com/henrylee2cn/teleport/utils"
)

// Internal Framework Rerror code.
// NOTE: Recommended custom code is greater than 1000.
//  unknown error code: -1.
//  sender peer error code range: [100,199].
//  message handling error code range: [400,499].
//  receiver peer error code range: [500,599].
const (
	CodeUnknownError        = -1
	CodeConnClosed          = 102
	CodeWriteFailed         = 104
	CodeDialFailed          = 105
	CodeBadMessage          = 400
	CodeUnauthorized        = 401
	CodeNotFound            = 404
	CodeMtypeNotAllowed     = 405
	CodeHandleTimeout       = 408
	CodeInternalServerError = 500
	CodeBadGateway          = 502

	// CodeConflict                      = 409
	// CodeUnsupportedTx                 = 410
	// CodeUnsupportedCodecType          = 415
	// CodeServiceUnavailable            = 503
	// CodeGatewayTimeout                = 504
	// CodeVariantAlsoNegotiates         = 506
	// CodeInsufficientStorage           = 507
	// CodeLoopDetected                  = 508
	// CodeNotExtended                   = 510
	// CodeNetworkAuthenticationRequired = 511
)

// CodeText returns the reply error code text.
// If the type is undefined returns 'Unknown Error'.
func CodeText(rerrCode int32) string {
	switch rerrCode {
	case CodeBadMessage:
		return "Bad Message"
	case CodeUnauthorized:
		return "Unauthorized"
	case CodeDialFailed:
		return "Dial Failed"
	case CodeConnClosed:
		return "Connection Closed"
	case CodeWriteFailed:
		return "Write Failed"
	case CodeNotFound:
		return "Not Found"
	case CodeHandleTimeout:
		return "Handle Timeout"
	case CodeMtypeNotAllowed:
		return "Message Type Not Allowed"
	case CodeInternalServerError:
		return "Internal Server Error"
	case CodeBadGateway:
		return "Bad Gateway"
	case CodeUnknownError:
		fallthrough
	default:
		return "Unknown Error"
	}
}

// Internal Framework Rerror string.
var (
	rerrUnknownError        = NewRerror(CodeUnknownError, CodeText(CodeUnknownError), "")
	rerrDialFailed          = NewRerror(CodeDialFailed, CodeText(CodeDialFailed), "")
	rerrConnClosed          = NewRerror(CodeConnClosed, CodeText(CodeConnClosed), "")
	rerrWriteFailed         = NewRerror(CodeWriteFailed, CodeText(CodeWriteFailed), "")
	rerrBadMessage          = NewRerror(CodeBadMessage, CodeText(CodeBadMessage), "")
	rerrNotFound            = NewRerror(CodeNotFound, CodeText(CodeNotFound), "")
	rerrCodeMtypeNotAllowed = NewRerror(CodeMtypeNotAllowed, CodeText(CodeMtypeNotAllowed), "")
	rerrHandleTimeout       = NewRerror(CodeHandleTimeout, CodeText(CodeHandleTimeout), "")
	rerrInternalServerError = NewRerror(CodeInternalServerError, CodeText(CodeInternalServerError), "")
)

// IsConnRerror determines whether the error is a connection error
func IsConnRerror(rerr *Rerror) bool {
	if rerr == nil {
		return false
	}
	if rerr.Code == CodeDialFailed || rerr.Code == CodeConnClosed {
		return true
	}
	return false
}

type (
	// Rerror error only for reply message
	Rerror struct {
		// Code error code
		Code int32
		// Message the error message displayed to the user (optional)
		Message string
		// Reason the cause of the error for debugging (optional)
		Reason string
	}
)

var (
	_ json.Marshaler   = new(Rerror)
	_ json.Unmarshaler = new(Rerror)

	reA = []byte(`{"code":`)
	reB = []byte(`,"message":`)
	reC = []byte(`,"reason":`)
)

// NewRerror creates a *Rerror.
func NewRerror(code int32, message, reason string) *Rerror {
	return &Rerror{
		Code:    code,
		Message: message,
		Reason:  reason,
	}
}

// NewRerrorFromMeta creates a *Rerror from 'X-Reply-Error' metadata.
// Return nil if there is no 'X-Reply-Error' in metadata.
func NewRerrorFromMeta(meta *utils.Args) *Rerror {
	b := meta.Peek(MetaRerror)
	if len(b) == 0 {
		return nil
	}
	r := new(Rerror)
	r.UnmarshalJSON(b)
	return r
}

// SetToMeta sets self to 'X-Reply-Error' metadata.
func (r *Rerror) SetToMeta(meta *utils.Args) {
	b, _ := r.MarshalJSON()
	if len(b) == 0 {
		return
	}
	meta.Set(MetaRerror, goutil.BytesToString(b))
}

// Copy returns the copy of Rerror
func (r Rerror) Copy() *Rerror {
	return &r
}

// SetMessage sets the error message displayed to the user.
func (r *Rerror) SetMessage(message string) *Rerror {
	r.Message = message
	return r
}

// SetReason sets the cause of the error for debugging.
func (r *Rerror) SetReason(reason string) *Rerror {
	r.Reason = reason
	return r
}

// String prints error info.
func (r *Rerror) String() string {
	if r == nil {
		return "<nil>"
	}
	b, _ := r.MarshalJSON()
	return goutil.BytesToString(b)
}

// MarshalJSON marshals Rerror into JSON, implements json.Marshaler interface.
func (r *Rerror) MarshalJSON() ([]byte, error) {
	if r == nil {
		return []byte{}, nil
	}
	var b = append(reA, strconv.FormatInt(int64(r.Code), 10)...)
	if len(r.Message) > 0 {
		b = append(b, reB...)
		b = append(b, utils.ToJSONStr(goutil.StringToBytes(r.Message), false)...)
	}
	if len(r.Reason) > 0 {
		b = append(b, reC...)
		b = append(b, utils.ToJSONStr(goutil.StringToBytes(r.Reason), false)...)
	}
	b = append(b, '}')
	return b, nil
}

// UnmarshalJSON unmarshals a JSON description of self.
func (r *Rerror) UnmarshalJSON(b []byte) error {
	if r == nil {
		return nil
	}
	s := goutil.BytesToString(b)
	r.Code = int32(gjson.Get(s, "code").Int())
	r.Message = gjson.Get(s, "message").String()
	r.Reason = gjson.Get(s, "reason").String()
	return nil
}

func hasRerror(meta *utils.Args) bool {
	return meta.Has(MetaRerror)
}

func getRerrorBytes(meta *utils.Args) []byte {
	return meta.Peek(MetaRerror)
}

// ToError converts to error
func (r *Rerror) ToError() error {
	if r == nil {
		return nil
	}
	return (*rerror)(unsafe.Pointer(r))
}

// ToRerror converts error to *Rerror
func ToRerror(err error) *Rerror {
	if err == nil {
		return nil
	}
	r, ok := err.(*rerror)
	if ok {
		return r.toRerror()
	}
	rerr := rerrUnknownError.Copy().SetReason(err.Error())
	return rerr
}

type rerror Rerror

func (r *rerror) Error() string {
	b, _ := r.toRerror().MarshalJSON()
	return goutil.BytesToString(b)
}

func (r *rerror) toRerror() *Rerror {
	return (*Rerror)(unsafe.Pointer(r))
}
<commit_msg>feat: Add CodeNoError, improve Rerror.ToError<commit_after>package tp

import (
	"encoding/json"
	"strconv"
	"unsafe"

	"github.com/tidwall/gjson"

	"github.com/henrylee2cn/goutil"
	"github.com/henrylee2cn/teleport/utils"
)

// Internal Framework Rerror code.
// NOTE: Recommended custom code is greater than 1000.
//  unknown error code: -1.
//  sender peer error code range: [100,199].
//  message handling error code range: [400,499].
//  receiver peer error code range: [500,599].
const (
	CodeUnknownError        = -1
	CodeNoError             = 0 // nil error
	CodeConnClosed          = 102
	CodeWriteFailed         = 104
	CodeDialFailed          = 105
	CodeBadMessage          = 400
	CodeUnauthorized        = 401
	CodeNotFound            = 404
	CodeMtypeNotAllowed     = 405
	CodeHandleTimeout       = 408
	CodeInternalServerError = 500
	CodeBadGateway          = 502

	// CodeConflict                      = 409
	// CodeUnsupportedTx                 = 410
	// CodeUnsupportedCodecType          = 415
	// CodeServiceUnavailable            = 503
	// CodeGatewayTimeout                = 504
	// CodeVariantAlsoNegotiates         = 506
	// CodeInsufficientStorage           = 507
	// CodeLoopDetected                  = 508
	// CodeNotExtended                   = 510
	// CodeNetworkAuthenticationRequired = 511
)

// CodeText returns the reply error code text.
// If the type is undefined returns 'Unknown Error'.
func CodeText(rerrCode int32) string {
	switch rerrCode {
	case CodeBadMessage:
		return "Bad Message"
	case CodeUnauthorized:
		return "Unauthorized"
	case CodeDialFailed:
		return "Dial Failed"
	case CodeConnClosed:
		return "Connection Closed"
	case CodeWriteFailed:
		return "Write Failed"
	case CodeNotFound:
		return "Not Found"
	case CodeHandleTimeout:
		return "Handle Timeout"
	case CodeMtypeNotAllowed:
		return "Message Type Not Allowed"
	case CodeInternalServerError:
		return "Internal Server Error"
	case CodeBadGateway:
		return "Bad Gateway"
	case CodeUnknownError:
		fallthrough
	default:
		return "Unknown Error"
	}
}

// Internal Framework Rerror string.
var (
	rerrUnknownError        = NewRerror(CodeUnknownError, CodeText(CodeUnknownError), "")
	rerrDialFailed          = NewRerror(CodeDialFailed, CodeText(CodeDialFailed), "")
	rerrConnClosed          = NewRerror(CodeConnClosed, CodeText(CodeConnClosed), "")
	rerrWriteFailed         = NewRerror(CodeWriteFailed, CodeText(CodeWriteFailed), "")
	rerrBadMessage          = NewRerror(CodeBadMessage, CodeText(CodeBadMessage), "")
	rerrNotFound            = NewRerror(CodeNotFound, CodeText(CodeNotFound), "")
	rerrCodeMtypeNotAllowed = NewRerror(CodeMtypeNotAllowed, CodeText(CodeMtypeNotAllowed), "")
	rerrHandleTimeout       = NewRerror(CodeHandleTimeout, CodeText(CodeHandleTimeout), "")
	rerrInternalServerError = NewRerror(CodeInternalServerError, CodeText(CodeInternalServerError), "")
)

// IsConnRerror determines whether the error is a connection error
func IsConnRerror(rerr *Rerror) bool {
	if rerr == nil {
		return false
	}
	if rerr.Code == CodeDialFailed || rerr.Code == CodeConnClosed {
		return true
	}
	return false
}

type (
	// Rerror error only for reply message
	Rerror struct {
		// Code error code
		Code int32
		// Message the error message displayed to the user (optional)
		Message string
		// Reason the cause of the error for debugging (optional)
		Reason string
	}
)

var (
	_ json.Marshaler   = new(Rerror)
	_ json.Unmarshaler = new(Rerror)

	reA = []byte(`{"code":`)
	reB = []byte(`,"message":`)
	reC = []byte(`,"reason":`)
)

// NewRerror creates a *Rerror.
func NewRerror(code int32, message, reason string) *Rerror {
	return &Rerror{
		Code:    code,
		Message: message,
		Reason:  reason,
	}
}

// NewRerrorFromMeta creates a *Rerror from 'X-Reply-Error' metadata.
// Return nil if there is no 'X-Reply-Error' in metadata.
func NewRerrorFromMeta(meta *utils.Args) *Rerror {
	b := meta.Peek(MetaRerror)
	if len(b) == 0 {
		return nil
	}
	r := new(Rerror)
	r.UnmarshalJSON(b)
	return r
}

// SetToMeta sets self to 'X-Reply-Error' metadata.
func (r *Rerror) SetToMeta(meta *utils.Args) {
	b, _ := r.MarshalJSON()
	if len(b) == 0 {
		return
	}
	meta.Set(MetaRerror, goutil.BytesToString(b))
}

// Copy returns the copy of Rerror
func (r Rerror) Copy() *Rerror {
	return &r
}

// SetMessage sets the error message displayed to the user.
func (r *Rerror) SetMessage(message string) *Rerror {
	r.Message = message
	return r
}

// SetReason sets the cause of the error for debugging.
func (r *Rerror) SetReason(reason string) *Rerror {
	r.Reason = reason
	return r
}

// String prints error info.
func (r *Rerror) String() string {
	if r == nil {
		return "<nil>"
	}
	b, _ := r.MarshalJSON()
	return goutil.BytesToString(b)
}

// MarshalJSON marshals Rerror into JSON, implements json.Marshaler interface.
func (r *Rerror) MarshalJSON() ([]byte, error) {
	if r == nil {
		return []byte{}, nil
	}
	var b = append(reA, strconv.FormatInt(int64(r.Code), 10)...)
	if len(r.Message) > 0 {
		b = append(b, reB...)
		b = append(b, utils.ToJSONStr(goutil.StringToBytes(r.Message), false)...)
	}
	if len(r.Reason) > 0 {
		b = append(b, reC...)
		b = append(b, utils.ToJSONStr(goutil.StringToBytes(r.Reason), false)...)
	}
	b = append(b, '}')
	return b, nil
}

// UnmarshalJSON unmarshals a JSON description of self.
func (r *Rerror) UnmarshalJSON(b []byte) error {
	if r == nil {
		return nil
	}
	s := goutil.BytesToString(b)
	r.Code = int32(gjson.Get(s, "code").Int())
	r.Message = gjson.Get(s, "message").String()
	r.Reason = gjson.Get(s, "reason").String()
	return nil
}

func hasRerror(meta *utils.Args) bool {
	return meta.Has(MetaRerror)
}

func getRerrorBytes(meta *utils.Args) []byte {
	return meta.Peek(MetaRerror)
}

// ToError converts to error
func (r *Rerror) ToError() error {
	if r == nil || r.Code == CodeNoError {
		return nil
	}
	return (*rerror)(unsafe.Pointer(r))
}

// ToRerror converts error to *Rerror
func ToRerror(err error) *Rerror {
	if err == nil {
		return nil
	}
	r, ok := err.(*rerror)
	if ok {
		return r.toRerror()
	}
	rerr := rerrUnknownError.Copy().SetReason(err.Error())
	return rerr
}

type rerror Rerror

func (r *rerror) Error() string {
	b, _ := r.toRerror().MarshalJSON()
	return goutil.BytesToString(b)
}

func (r *rerror) toRerror() *Rerror {
	return (*Rerror)(unsafe.Pointer(r))
}
<|endoftext|>


<commit_before>package quad

import (
	"fmt"

	"github.com/ghthor/engine/coord"
	"github.com/ghthor/engine/rpg2d/entity"
)

// Represents one of the four quad corners
type Corner int

const (
	NW Corner = iota
	NE
	SE
	SW
)

// An interface used to abstract the implementation differences
// of a node and a leaf.
type Quad interface {
	Parent() Quad
	Child(Corner) Quad
	Children() []Quad

	Bounds() coord.Bounds

	Insert(entity.Entity) Quad
	Remove(entity.Entity) Quad

	QueryCell(coord.Cell) []entity.Entity
	QueryBounds(coord.Bounds) []entity.Entity

	Chunk() Chunk
}

func New(bounds coord.Bounds, maxSize int, entities []entity.Entity) (Quad, error) {
	return quadLeaf{
		parent:  nil,
		bounds:  bounds,
		maxSize: maxSize,
	}, nil
}

// A group of entities within a bounding rectangle.
// A chunk is sent to the collision function that is implemented
// by the user of engine.
type Chunk struct {
	Bounds coord.Bounds

	Entities    []entity.Entity
	Moveables   []entity.Movable
	Collidables []entity.Collidable
}

// A collisionhandler takes a chunk of entities
// and does collision checks for the chunk and modifies
// the entities. All entities in the returned chunk will
// be reinserted into the quad tree to update their location.
type CollisionHandler func(Chunk) Chunk

// A node in the quad tree that will contain 4 children,
// one in each corner of the quad nodes bounds.
type quadNode struct {
	parent   Quad
	children [4]Quad

	bounds coord.Bounds
}

func (q quadNode) Parent() Quad        { return q.parent }
func (q quadNode) Child(c Corner) Quad { return q.children[c] }
func (q quadNode) Children() []Quad    { return q.children[0:] }

func (q quadNode) Bounds() coord.Bounds { return q.bounds }

func (q quadNode) Insert(e entity.Entity) Quad {
	for i, quad := range q.children {
		// If the child's bounds contain the entities cell
		if quad.Bounds().Contains(e.Cell()) {
			q.children[i] = quad.Insert(e)
			return q
		}
	}
	panic("entity out of bounds")
}

func (q quadNode) Remove(e entity.Entity) Quad {
	for i, quad := range q.children {
		// If the child's bounds contain the entities cell
		if quad.Bounds().Contains(e.Cell()) {
			q.children[i] = quad.Remove(e)
			break
		}
	}
	return q
}

func (q quadNode) QueryCell(c coord.Cell) []entity.Entity {
	for _, quad := range q.children {
		// If the cell is within the childs bounds
		if quad.Bounds().Expand(1).Contains(c) {
			return quad.QueryCell(c)
		}
	}

	return nil
}

func (q quadNode) QueryBounds(b coord.Bounds) []entity.Entity {
	var matches []entity.Entity
	for _, quad := range q.children {
		if quad.Bounds().Overlaps(b) {
			matches = append(matches, quad.QueryBounds(b)...)
			// We don't return here in case the bounds overlap
			// with some of the other children
		}
	}
	return matches
}

func (q quadNode) Chunk() Chunk {
	var chunk Chunk = Chunk{Bounds: q.bounds}

	for _, quad := range q.children {
		cchunk := quad.Chunk()
		chunk.Entities = append(chunk.Entities, cchunk.Entities...)
		chunk.Moveables = append(chunk.Moveables, cchunk.Moveables...)
		chunk.Collidables = append(chunk.Collidables, cchunk.Collidables...)
	}

	return chunk
}

// A leaf in the quad tree that contains the references
// to entities. A leaf represents one corner in the parents
// bounds.
type quadLeaf struct {
	parent Quad

	bounds coord.Bounds

	entities    []entity.Entity
	moveables   []entity.Movable
	collidables []entity.Collidable

	maxSize int
}

func (q quadLeaf) Parent() Quad        { return q.parent }
func (q quadLeaf) Child(c Corner) Quad { return nil }
func (q quadLeaf) Children() []Quad    { return nil }

func (q quadLeaf) Bounds() coord.Bounds { return q.bounds }

func (q quadLeaf) Insert(e entity.Entity) Quad {
	// If the quad is full it must split
	if len(q.entities) >= q.maxSize {
		return q.divide().Insert(e)
	}

	q.entities = append(q.entities, e)

	// Index Movable Entities
	if me, canMove := e.(entity.Movable); canMove {
		q.moveables = append(q.moveables, me)
	}

	// Index collidable Entities
	if ce, canCollide := e.(entity.Collidable); canCollide {
		q.collidables = append(q.collidables, ce)
	}

	return q
}

func (q quadLeaf) divide() Quad {
	// TODO Remove the need for these panics
	if q.bounds.Width() == 1 {
		panic("unable to divide quad with width of 1")
	}

	if q.bounds.Height() == 1 {
		panic("unable to divide quad with height of 1")
	}

	qn := quadNode{
		parent: q.parent,
		bounds: q.bounds,
	}

	quads, err := q.bounds.Quads()

	// TODO Remove the need for this panic
	if err != nil {
		panic(fmt.Sprintf("error splitting bounds into quads: %e", err))
	}

	//TODO Reuse this leaf forming 3 new leaves + this 1
	for i, _ := range qn.children {
		qn.children[i] = quadLeaf{
			parent: qn,
			bounds: quads[i],

			entities:    make([]entity.Entity, 0, q.maxSize),
			moveables:   make([]entity.Movable, 0, q.maxSize),
			collidables: make([]entity.Collidable, 0, q.maxSize),

			maxSize: q.maxSize,
		}
	}

	for _, e := range q.entities {
		qn.Insert(e)
	}

	return qn
}

func (q quadLeaf) Remove(remove entity.Entity) Quad {
	// Remove Entity
	for i, entity := range q.entities {
		if entity.Id() == remove.Id() {
			q.entities = append(q.entities[:i], q.entities[i+1:]...)
			break
		}
	}

	// Remove Movable Entity
	if _, canMove := remove.(entity.Movable); canMove {
		for i, me := range q.moveables {
			if me.Id() == remove.Id() {
				q.moveables = append(q.moveables[:i], q.moveables[i+1:]...)
				break
			}
		}
	}

	if _, canCollide := remove.(entity.Collidable); canCollide {
		for i, ce := range q.collidables {
			if ce.Id() == remove.Id() {
				q.collidables = append(q.collidables[:i], q.collidables[i+1:]...)
			}
		}
	}

	return q
}

func (q quadLeaf) QueryCell(c coord.Cell) []entity.Entity {
	entities := make([]entity.Entity, 0, 1)
	for _, e := range q.entities {
		if e.Cell() == c {
			entities = append(entities, e)
		}
	}

	if len(entities) == 0 {
		return nil
	}

	return entities
}

func (q quadLeaf) QueryBounds(b coord.Bounds) []entity.Entity {
	entities := make([]entity.Entity, 0, q.maxSize)
	for _, e := range q.entities {
		if b.Contains(e.Cell()) {
			entities = append(entities, e)
		}
	}

	if len(entities) == 0 {
		return nil
	}

	return entities
}

func (q quadLeaf) Chunk() Chunk {
	chunk := Chunk{Bounds: q.bounds}

	chunk.Entities = append(chunk.Entities, q.entities...)
	chunk.Moveables = append(chunk.Moveables, q.moveables...)
	chunk.Collidables = append(chunk.Collidables, q.collidables...)

	return chunk
}
<commit_msg>Retype the collision handler to an  interface type<commit_after>package quad

import (
	"fmt"

	"github.com/ghthor/engine/coord"
	"github.com/ghthor/engine/rpg2d/entity"
)

// Represents one of the four quad corners
type Corner int

const (
	NW Corner = iota
	NE
	SE
	SW
)

// An interface used to abstract the implementation differences
// of a node and a leaf.
type Quad interface {
	Parent() Quad
	Child(Corner) Quad
	Children() []Quad

	Bounds() coord.Bounds

	Insert(entity.Entity) Quad
	Remove(entity.Entity) Quad

	QueryCell(coord.Cell) []entity.Entity
	QueryBounds(coord.Bounds) []entity.Entity

	Chunk() Chunk
}

func New(bounds coord.Bounds, maxSize int, entities []entity.Entity) (Quad, error) {
	return quadLeaf{
		parent:  nil,
		bounds:  bounds,
		maxSize: maxSize,
	}, nil
}

// A group of entities within a bounding rectangle.
// A chunk is sent to the collision function that is implemented
// by the user of engine.
type Chunk struct {
	Bounds coord.Bounds

	Entities    []entity.Entity
	Moveables   []entity.Movable
	Collidables []entity.Collidable
}

// A collisionhandler takes a chunk of entities
// and does collision checks for the chunk and modifies
// the entities. All entities in the returned chunk will
// be reinserted into the quad tree to update their location.
type CollisionHandle interface {
	NarrowPhaseIn(Chunk) Chunk
}

// A node in the quad tree that will contain 4 children,
// one in each corner of the quad nodes bounds.
type quadNode struct {
	parent   Quad
	children [4]Quad

	bounds coord.Bounds
}

func (q quadNode) Parent() Quad        { return q.parent }
func (q quadNode) Child(c Corner) Quad { return q.children[c] }
func (q quadNode) Children() []Quad    { return q.children[0:] }

func (q quadNode) Bounds() coord.Bounds { return q.bounds }

func (q quadNode) Insert(e entity.Entity) Quad {
	for i, quad := range q.children {
		// If the child's bounds contain the entities cell
		if quad.Bounds().Contains(e.Cell()) {
			q.children[i] = quad.Insert(e)
			return q
		}
	}
	panic("entity out of bounds")
}

func (q quadNode) Remove(e entity.Entity) Quad {
	for i, quad := range q.children {
		// If the child's bounds contain the entities cell
		if quad.Bounds().Contains(e.Cell()) {
			q.children[i] = quad.Remove(e)
			break
		}
	}
	return q
}

func (q quadNode) QueryCell(c coord.Cell) []entity.Entity {
	for _, quad := range q.children {
		// If the cell is within the childs bounds
		if quad.Bounds().Expand(1).Contains(c) {
			return quad.QueryCell(c)
		}
	}

	return nil
}

func (q quadNode) QueryBounds(b coord.Bounds) []entity.Entity {
	var matches []entity.Entity
	for _, quad := range q.children {
		if quad.Bounds().Overlaps(b) {
			matches = append(matches, quad.QueryBounds(b)...)
			// We don't return here in case the bounds overlap
			// with some of the other children
		}
	}
	return matches
}

func (q quadNode) Chunk() Chunk {
	var chunk Chunk = Chunk{Bounds: q.bounds}

	for _, quad := range q.children {
		cchunk := quad.Chunk()
		chunk.Entities = append(chunk.Entities, cchunk.Entities...)
		chunk.Moveables = append(chunk.Moveables, cchunk.Moveables...)
		chunk.Collidables = append(chunk.Collidables, cchunk.Collidables...)
	}

	return chunk
}

// A leaf in the quad tree that contains the references
// to entities. A leaf represents one corner in the parents
// bounds.
type quadLeaf struct {
	parent Quad

	bounds coord.Bounds

	entities    []entity.Entity
	moveables   []entity.Movable
	collidables []entity.Collidable

	maxSize int
}

func (q quadLeaf) Parent() Quad        { return q.parent }
func (q quadLeaf) Child(c Corner) Quad { return nil }
func (q quadLeaf) Children() []Quad    { return nil }

func (q quadLeaf) Bounds() coord.Bounds { return q.bounds }

func (q quadLeaf) Insert(e entity.Entity) Quad {
	// If the quad is full it must split
	if len(q.entities) >= q.maxSize {
		return q.divide().Insert(e)
	}

	q.entities = append(q.entities, e)

	// Index Movable Entities
	if me, canMove := e.(entity.Movable); canMove {
		q.moveables = append(q.moveables, me)
	}

	// Index collidable Entities
	if ce, canCollide := e.(entity.Collidable); canCollide {
		q.collidables = append(q.collidables, ce)
	}

	return q
}

func (q quadLeaf) divide() Quad {
	// TODO Remove the need for these panics
	if q.bounds.Width() == 1 {
		panic("unable to divide quad with width of 1")
	}

	if q.bounds.Height() == 1 {
		panic("unable to divide quad with height of 1")
	}

	qn := quadNode{
		parent: q.parent,
		bounds: q.bounds,
	}

	quads, err := q.bounds.Quads()

	// TODO Remove the need for this panic
	if err != nil {
		panic(fmt.Sprintf("error splitting bounds into quads: %e", err))
	}

	//TODO Reuse this leaf forming 3 new leaves + this 1
	for i, _ := range qn.children {
		qn.children[i] = quadLeaf{
			parent: qn,
			bounds: quads[i],

			entities:    make([]entity.Entity, 0, q.maxSize),
			moveables:   make([]entity.Movable, 0, q.maxSize),
			collidables: make([]entity.Collidable, 0, q.maxSize),

			maxSize: q.maxSize,
		}
	}

	for _, e := range q.entities {
		qn.Insert(e)
	}

	return qn
}

func (q quadLeaf) Remove(remove entity.Entity) Quad {
	// Remove Entity
	for i, entity := range q.entities {
		if entity.Id() == remove.Id() {
			q.entities = append(q.entities[:i], q.entities[i+1:]...)
			break
		}
	}

	// Remove Movable Entity
	if _, canMove := remove.(entity.Movable); canMove {
		for i, me := range q.moveables {
			if me.Id() == remove.Id() {
				q.moveables = append(q.moveables[:i], q.moveables[i+1:]...)
				break
			}
		}
	}

	if _, canCollide := remove.(entity.Collidable); canCollide {
		for i, ce := range q.collidables {
			if ce.Id() == remove.Id() {
				q.collidables = append(q.collidables[:i], q.collidables[i+1:]...)
			}
		}
	}

	return q
}

func (q quadLeaf) QueryCell(c coord.Cell) []entity.Entity {
	entities := make([]entity.Entity, 0, 1)
	for _, e := range q.entities {
		if e.Cell() == c {
			entities = append(entities, e)
		}
	}

	if len(entities) == 0 {
		return nil
	}

	return entities
}

func (q quadLeaf) QueryBounds(b coord.Bounds) []entity.Entity {
	entities := make([]entity.Entity, 0, q.maxSize)
	for _, e := range q.entities {
		if b.Contains(e.Cell()) {
			entities = append(entities, e)
		}
	}

	if len(entities) == 0 {
		return nil
	}

	return entities
}

func (q quadLeaf) Chunk() Chunk {
	chunk := Chunk{Bounds: q.bounds}

	chunk.Entities = append(chunk.Entities, q.entities...)
	chunk.Moveables = append(chunk.Moveables, q.moveables...)
	chunk.Collidables = append(chunk.Collidables, q.collidables...)

	return chunk
}
<|endoftext|>


<commit_before>package linq

import (
	"math"
	"reflect"
)

// All determines whether all elements of a collection satisfy a condition.
func (q Query) All(predicate func(interface{}) bool) bool {
	next := q.Iterate()

	for item, ok := next(); ok; item, ok = next() {
		if !predicate(item) {
			return false
		}
	}

	return true
}

// Any determines whether any element of a collection exists.
func (q Query) Any() bool {
	_, ok := q.Iterate()()
	return ok
}

// AnyWith determines whether any element of a collection satisfies a condition.
func (q Query) AnyWith(predicate func(interface{}) bool) bool {
	next := q.Iterate()

	for item, ok := next(); ok; item, ok = next() {
		if predicate(item) {
			return true
		}
	}

	return false
}

// Average computes the average of a collection of numeric values.
func (q Query) Average() (r float64) {
	next := q.Iterate()
	item, ok := next()
	if !ok {
		return math.NaN()
	}

	n := 1
	switch item.(type) {
	case int, int8, int16, int32, int64:
		conv := getIntConverter(item)
		sum := conv(item)

		for item, ok = next(); ok; item, ok = next() {
			sum += conv(item)
			n++
		}

		r = float64(sum)
	case uint, uint8, uint16, uint32, uint64:
		conv := getUIntConverter(item)
		sum := conv(item)

		for item, ok = next(); ok; item, ok = next() {
			sum += conv(item)
			n++
		}

		r = float64(sum)
	default:
		conv := getFloatConverter(item)
		r = conv(item)

		for item, ok = next(); ok; item, ok = next() {
			r += conv(item)
			n++
		}
	}

	return r / float64(n)
}

// Contains determines whether a collection contains a specified element.
func (q Query) Contains(value interface{}) bool {
	next := q.Iterate()

	for item, ok := next(); ok; item, ok = next() {
		if item == value {
			return true
		}
	}

	return false
}

// Count returns the number of elements in a collection.
func (q Query) Count() (r int) {
	next := q.Iterate()

	for _, ok := next(); ok; _, ok = next() {
		r++
	}

	return
}

// CountWith returns a number that represents how many elements
// in the specified collection satisfy a condition.
func (q Query) CountWith(predicate func(interface{}) bool) (r int) {
	next := q.Iterate()

	for item, ok := next(); ok; item, ok = next() {
		if predicate(item) {
			r++
		}
	}

	return
}

// First returns the first element of a collection.
func (q Query) First() interface{} {
	item, _ := q.Iterate()()
	return item
}

// FirstWith returns the first element of a collection that satisfies
// a specified condition.
func (q Query) FirstWith(predicate func(interface{}) bool) interface{} {
	next := q.Iterate()

	for item, ok := next(); ok; item, ok = next() {
		if predicate(item) {
			return item
		}
	}

	return nil
}

// Last returns the last element of a collection.
func (q Query) Last() (r interface{}) {
	next := q.Iterate()

	for item, ok := next(); ok; item, ok = next() {
		r = item
	}

	return
}

// LastWith returns the last element of a collection that satisfies
// a specified condition.
func (q Query) LastWith(predicate func(interface{}) bool) (r interface{}) {
	next := q.Iterate()

	for item, ok := next(); ok; item, ok = next() {
		if predicate(item) {
			r = item
		}
	}

	return
}

// Max returns the maximum value in a collection of values.
func (q Query) Max() (r interface{}) {
	next := q.Iterate()
	item, ok := next()
	if !ok {
		return nil
	}

	compare := getComparer(item)
	r = item

	for item, ok := next(); ok; item, ok = next() {
		if compare(item, r) > 0 {
			r = item
		}
	}

	return
}

// Min returns the minimum value in a collection of values.
func (q Query) Min() (r interface{}) {
	next := q.Iterate()
	item, ok := next()
	if !ok {
		return nil
	}

	compare := getComparer(item)
	r = item

	for item, ok := next(); ok; item, ok = next() {
		if compare(item, r) < 0 {
			r = item
		}
	}

	return
}

// Results iterates over a collection and returnes slice of interfaces
func (q Query) Results() (r []interface{}) {
	next := q.Iterate()

	for item, ok := next(); ok; item, ok = next() {
		r = append(r, item)
	}

	return
}

// SequenceEqual determines whether two collections are equal.
func (q Query) SequenceEqual(q2 Query) bool {
	next := q.Iterate()
	next2 := q2.Iterate()

	for item, ok := next(); ok; item, ok = next() {
		item2, ok2 := next2()
		if !ok2 || item != item2 {
			return false
		}
	}

	_, ok2 := next2()
	return !ok2
}

// Single returns the only element of a collection, and nil
// if there is not exactly one element in the collection.
func (q Query) Single() interface{} {
	next := q.Iterate()
	item, ok := next()
	if !ok {
		return nil
	}

	_, ok = next()
	if ok {
		return nil
	}

	return item
}

// SingleWith returns the only element of a collection that satisfies
// a specified condition, and nil if more than one such element exists.
func (q Query) SingleWith(predicate func(interface{}) bool) (r interface{}) {
	next := q.Iterate()
	found := false

	for item, ok := next(); ok; item, ok = next() {
		if predicate(item) {
			if found {
				return nil
			}

			found = true
			r = item
		}
	}

	return
}

// SumInts computes the sum of a collection of numeric values.
//
// Values can be of any integer type: int, int8, int16, int32, int64.
// The result is int64. Method returns zero if collection contains no elements.
func (q Query) SumInts() (r int64) {
	next := q.Iterate()
	item, ok := next()
	if !ok {
		return 0
	}

	conv := getIntConverter(item)
	r = conv(item)

	for item, ok = next(); ok; item, ok = next() {
		r += conv(item)
	}

	return
}

// SumUInts computes the sum of a collection of numeric values.
//
// Values can be of any unsigned integer type: uint, uint8, uint16, uint32, uint64.
// The result is uint64. Method returns zero if collection contains no elements.
func (q Query) SumUInts() (r uint64) {
	next := q.Iterate()
	item, ok := next()
	if !ok {
		return 0
	}

	conv := getUIntConverter(item)
	r = conv(item)

	for item, ok = next(); ok; item, ok = next() {
		r += conv(item)
	}

	return
}

// SumFloats computes the sum of a collection of numeric values.
//
// Values can be of any float type: float32 or float64. The result is float64.
// Method returns zero if collection contains no elements.
func (q Query) SumFloats() (r float64) {
	next := q.Iterate()
	item, ok := next()
	if !ok {
		return 0
	}

	conv := getFloatConverter(item)
	r = conv(item)

	for item, ok = next(); ok; item, ok = next() {
		r += conv(item)
	}

	return
}

// ToChannel iterates over a collection and outputs each element
// to a channel, then closes it.
func (q Query) ToChannel(result chan<- interface{}) {
	next := q.Iterate()

	for item, ok := next(); ok; item, ok = next() {
		result <- item
	}

	close(result)
}

// ToMap iterates over a collection and populates result map with elements.
// Collection elements have to be of KeyValue type to use this method.
// To populate a map with elements of different type use ToMapBy method.
func (q Query) ToMap(result interface{}) {
	q.ToMapBy(
		result,
		func(i interface{}) interface{} {
			return i.(KeyValue).Key
		},
		func(i interface{}) interface{} {
			return i.(KeyValue).Value
		})
}

// ToMapBy iterates over a collection and populates result map with elements.
// Functions keySelector and valueSelector are executed for each element of the collection
// to generate key and value for the map. Generated key and value types must be assignable
// to the map's key and value types.
func (q Query) ToMapBy(
	result interface{},
	keySelector func(interface{}) interface{},
	valueSelector func(interface{}) interface{},
) {
	res := reflect.ValueOf(result)
	m := reflect.Indirect(res)
	next := q.Iterate()

	for item, ok := next(); ok; item, ok = next() {
		key := reflect.ValueOf(keySelector(item))
		value := reflect.ValueOf(valueSelector(item))

		m.SetMapIndex(key, value)
	}

	res.Elem().Set(m)
}

// ToSlice iterates over a collection and populates result slice with elements.
// Collection elements must be assignable to the slice's element type.
func (q Query) ToSlice(result interface{}) {
	res := reflect.ValueOf(result)
	slice := reflect.Indirect(res)
	next := q.Iterate()

	for item, ok := next(); ok; item, ok = next() {
		slice = reflect.Append(slice, reflect.ValueOf(item))
	}

	res.Elem().Set(slice)
}
<commit_msg>ISSUE-43<commit_after>package linq

import (
	"math"
	"reflect"
)

// All determines whether all elements of a collection satisfy a condition.
func (q Query) All(predicate func(interface{}) bool) bool {
	next := q.Iterate()

	for item, ok := next(); ok; item, ok = next() {
		if !predicate(item) {
			return false
		}
	}

	return true
}

// Any determines whether any element of a collection exists.
func (q Query) Any() bool {
	_, ok := q.Iterate()()
	return ok
}

// AnyWith determines whether any element of a collection satisfies a condition.
func (q Query) AnyWith(predicate func(interface{}) bool) bool {
	next := q.Iterate()

	for item, ok := next(); ok; item, ok = next() {
		if predicate(item) {
			return true
		}
	}

	return false
}

// Average computes the average of a collection of numeric values.
func (q Query) Average() (r float64) {
	next := q.Iterate()
	item, ok := next()
	if !ok {
		return math.NaN()
	}

	n := 1
	switch item.(type) {
	case int, int8, int16, int32, int64:
		conv := getIntConverter(item)
		sum := conv(item)

		for item, ok = next(); ok; item, ok = next() {
			sum += conv(item)
			n++
		}

		r = float64(sum)
	case uint, uint8, uint16, uint32, uint64:
		conv := getUIntConverter(item)
		sum := conv(item)

		for item, ok = next(); ok; item, ok = next() {
			sum += conv(item)
			n++
		}

		r = float64(sum)
	default:
		conv := getFloatConverter(item)
		r = conv(item)

		for item, ok = next(); ok; item, ok = next() {
			r += conv(item)
			n++
		}
	}

	return r / float64(n)
}

// Contains determines whether a collection contains a specified element.
func (q Query) Contains(value interface{}) bool {
	next := q.Iterate()

	for item, ok := next(); ok; item, ok = next() {
		if item == value {
			return true
		}
	}

	return false
}

// Count returns the number of elements in a collection.
func (q Query) Count() (r int) {
	next := q.Iterate()

	for _, ok := next(); ok; _, ok = next() {
		r++
	}

	return
}

// CountWith returns a number that represents how many elements
// in the specified collection satisfy a condition.
func (q Query) CountWith(predicate func(interface{}) bool) (r int) {
	next := q.Iterate()

	for item, ok := next(); ok; item, ok = next() {
		if predicate(item) {
			r++
		}
	}

	return
}

// First returns the first element of a collection.
func (q Query) First() interface{} {
	item, _ := q.Iterate()()
	return item
}

// FirstWith returns the first element of a collection that satisfies
// a specified condition.
func (q Query) FirstWith(predicate func(interface{}) bool) interface{} {
	next := q.Iterate()

	for item, ok := next(); ok; item, ok = next() {
		if predicate(item) {
			return item
		}
	}

	return nil
}

// Last returns the last element of a collection.
func (q Query) Last() (r interface{}) {
	next := q.Iterate()

	for item, ok := next(); ok; item, ok = next() {
		r = item
	}

	return
}

// LastWith returns the last element of a collection that satisfies
// a specified condition.
func (q Query) LastWith(predicate func(interface{}) bool) (r interface{}) {
	next := q.Iterate()

	for item, ok := next(); ok; item, ok = next() {
		if predicate(item) {
			r = item
		}
	}

	return
}

// Max returns the maximum value in a collection of values.
func (q Query) Max() (r interface{}) {
	next := q.Iterate()
	item, ok := next()
	if !ok {
		return nil
	}

	compare := getComparer(item)
	r = item

	for item, ok := next(); ok; item, ok = next() {
		if compare(item, r) > 0 {
			r = item
		}
	}

	return
}

// Min returns the minimum value in a collection of values.
func (q Query) Min() (r interface{}) {
	next := q.Iterate()
	item, ok := next()
	if !ok {
		return nil
	}

	compare := getComparer(item)
	r = item

	for item, ok := next(); ok; item, ok = next() {
		if compare(item, r) < 0 {
			r = item
		}
	}

	return
}

// Results iterates over a collection and returnes slice of interfaces
func (q Query) Results() (r []interface{}) {
	next := q.Iterate()

	for item, ok := next(); ok; item, ok = next() {
		r = append(r, item)
	}

	return
}

// SequenceEqual determines whether two collections are equal.
func (q Query) SequenceEqual(q2 Query) bool {
	next := q.Iterate()
	next2 := q2.Iterate()

	for item, ok := next(); ok; item, ok = next() {
		item2, ok2 := next2()
		if !ok2 || item != item2 {
			return false
		}
	}

	_, ok2 := next2()
	return !ok2
}

// Single returns the only element of a collection, and nil
// if there is not exactly one element in the collection.
func (q Query) Single() interface{} {
	next := q.Iterate()
	item, ok := next()
	if !ok {
		return nil
	}

	_, ok = next()
	if ok {
		return nil
	}

	return item
}

// SingleWith returns the only element of a collection that satisfies
// a specified condition, and nil if more than one such element exists.
func (q Query) SingleWith(predicate func(interface{}) bool) (r interface{}) {
	next := q.Iterate()
	found := false

	for item, ok := next(); ok; item, ok = next() {
		if predicate(item) {
			if found {
				return nil
			}

			found = true
			r = item
		}
	}

	return
}

// SumInts computes the sum of a collection of numeric values.
//
// Values can be of any integer type: int, int8, int16, int32, int64.
// The result is int64. Method returns zero if collection contains no elements.
func (q Query) SumInts() (r int64) {
	next := q.Iterate()
	item, ok := next()
	if !ok {
		return 0
	}

	conv := getIntConverter(item)
	r = conv(item)

	for item, ok = next(); ok; item, ok = next() {
		r += conv(item)
	}

	return
}

// SumUInts computes the sum of a collection of numeric values.
//
// Values can be of any unsigned integer type: uint, uint8, uint16, uint32, uint64.
// The result is uint64. Method returns zero if collection contains no elements.
func (q Query) SumUInts() (r uint64) {
	next := q.Iterate()
	item, ok := next()
	if !ok {
		return 0
	}

	conv := getUIntConverter(item)
	r = conv(item)

	for item, ok = next(); ok; item, ok = next() {
		r += conv(item)
	}

	return
}

// SumFloats computes the sum of a collection of numeric values.
//
// Values can be of any float type: float32 or float64. The result is float64.
// Method returns zero if collection contains no elements.
func (q Query) SumFloats() (r float64) {
	next := q.Iterate()
	item, ok := next()
	if !ok {
		return 0
	}

	conv := getFloatConverter(item)
	r = conv(item)

	for item, ok = next(); ok; item, ok = next() {
		r += conv(item)
	}

	return
}

// ToChannel iterates over a collection and outputs each element
// to a channel, then closes it.
func (q Query) ToChannel(result chan<- interface{}) {
	next := q.Iterate()

	for item, ok := next(); ok; item, ok = next() {
		result <- item
	}

	close(result)
}

// ToMap iterates over a collection and populates result map with elements.
// Collection elements have to be of KeyValue type to use this method.
// To populate a map with elements of different type use ToMapBy method.
// ToMap doesn't empty the result map before populating it.
func (q Query) ToMap(result interface{}) {
	q.ToMapBy(
		result,
		func(i interface{}) interface{} {
			return i.(KeyValue).Key
		},
		func(i interface{}) interface{} {
			return i.(KeyValue).Value
		})
}

// ToMapBy iterates over a collection and populates the result map with elements.
// Functions keySelector and valueSelector are executed for each element of the collection
// to generate key and value for the map. Generated key and value types must be assignable
// to the map's key and value types.
// ToMapBy doesn't empty the result map before populating it.
func (q Query) ToMapBy(
	result interface{},
	keySelector func(interface{}) interface{},
	valueSelector func(interface{}) interface{},
) {
	res := reflect.ValueOf(result)
	m := reflect.Indirect(res)
	next := q.Iterate()

	for item, ok := next(); ok; item, ok = next() {
		key := reflect.ValueOf(keySelector(item))
		value := reflect.ValueOf(valueSelector(item))

		m.SetMapIndex(key, value)
	}

	res.Elem().Set(m)
}

// ToSlice iterates over a collection and populates the result slice with elements.
// Collection elements must be assignable to the slice's element type.
// ToSlice doesn't empty the result slice before populating it.
func (q Query) ToSlice(result interface{}) {
	res := reflect.ValueOf(result)
	slice := reflect.Indirect(res)
	next := q.Iterate()

	for item, ok := next(); ok; item, ok = next() {
		slice = reflect.Append(slice, reflect.ValueOf(item))
	}

	res.Elem().Set(slice)
}
<|endoftext|>


<commit_before>package gocb

import (
	"fmt"
	"net"
	"regexp"
	"strconv"
)

// A single address stored within a connection string
type connSpecAddr struct {
	Host string
	Port uint16
}

// A parsed connection string
type connSpec struct {
	Scheme  string
	Hosts   []connSpecAddr
	Bucket  string
	Options map[string]string
}

// Parses a connection string into a structure more easily consumed by the library.
func parseConnSpec(connStr string) connSpec {
	var out connSpec
	out.Options = map[string]string{}

	partMatcher := regexp.MustCompile(`((.*):\/\/)?([^\/?]*)(\/([^\?]*))?(\?(.*))?`)
	hostMatcher := regexp.MustCompile(`([^;\,\:]+)(:([0-9]*))?(;\,)?`)
	kvMatcher := regexp.MustCompile(`([^=]*)=([^&?]*)[&?]?`)
	parts := partMatcher.FindStringSubmatch(connStr)

	if parts[2] != "" {
		out.Scheme = parts[2]
	}

	if parts[3] != "" {
		hosts := hostMatcher.FindAllStringSubmatch(parts[3], -1)
		for _, hostInfo := range hosts {
			port := 0
			if hostInfo[3] != "" {
				port, _ = strconv.Atoi(hostInfo[3])
			}

			out.Hosts = append(out.Hosts, connSpecAddr{
				Host: hostInfo[1],
				Port: uint16(port),
			})
		}
	}

	if parts[5] != "" {
		out.Bucket = parts[5]
	}

	if parts[7] != "" {
		kvs := kvMatcher.FindAllStringSubmatch(parts[7], -1)
		for _, kvInfo := range kvs {
			out.Options[kvInfo[1]] = kvInfo[2]
		}
	}

	return out
}

func csResolveDnsSrv(spec *connSpec) bool {
	if len(spec.Hosts) == 1 && spec.Hosts[0].Port == 0 && (spec.Scheme == "couchbase" || spec.Scheme == "couchbases") {
		srvHostname := spec.Hosts[0].Host
		_, addrs, err := net.LookupSRV(spec.Scheme, "tcp", srvHostname)
		if err != nil {
			return false
		}

		var hostList []connSpecAddr
		for _, srvRecord := range addrs {
			hostList = append(hostList, connSpecAddr{srvRecord.Target, srvRecord.Port})
		}
		spec.Hosts = hostList

		return true
	} else {
		return false
	}
}

// Guesses a list of memcached hosts based on a connection string specification structure.
func csGetMemdHosts(spec connSpec) []connSpecAddr {
	var out []connSpecAddr
	for _, host := range spec.Hosts {
		memdHost := connSpecAddr{
			Host: host.Host,
			Port: 0,
		}

		fmt.Printf("Host parse: %s:%d", host.Host, host.Port)

		if host.Port == 0 {
			if spec.Scheme != "couchbases" {
				memdHost.Port = 11210
			} else {
				memdHost.Port = 11207
			}
		} else if host.Port == 8091 {
			memdHost.Port = 11210
		} else if host.Port == 18091 {
			memdHost.Port = 11207
		}

		if memdHost.Port != 0 {
			out = append(out, memdHost)
		}
	}
	return out
}
<commit_msg>GOCBC-46: Properly handle username/password's specified in connection string.<commit_after>package gocb

import (
	"fmt"
	"net"
	"regexp"
	"strconv"
)

// A single address stored within a connection string
type connSpecAddr struct {
	Host string
	Port uint16
}

// A parsed connection string
type connSpec struct {
	Scheme  string
	Hosts   []connSpecAddr
	Bucket  string
	Options map[string]string
}

// Parses a connection string into a structure more easily consumed by the library.
func parseConnSpec(connStr string) connSpec {
	var out connSpec
	out.Options = map[string]string{}

	partMatcher := regexp.MustCompile(`((.*):\/\/)?(([^\/?:]*)(:([^\/?:@]*))?@)?([^\/?]*)(\/([^\?]*))?(\?(.*))?`)
	hostMatcher := regexp.MustCompile(`([^;\,\:]+)(:([0-9]*))?(;\,)?`)
	kvMatcher := regexp.MustCompile(`([^=]*)=([^&?]*)[&?]?`)
	parts := partMatcher.FindStringSubmatch(connStr)

	if parts[2] != "" {
		out.Scheme = parts[2]
	}

	if parts[7] != "" {
		hosts := hostMatcher.FindAllStringSubmatch(parts[7], -1)
		for _, hostInfo := range hosts {
			port := 0
			if hostInfo[3] != "" {
				port, _ = strconv.Atoi(hostInfo[3])
			}

			out.Hosts = append(out.Hosts, connSpecAddr{
				Host: hostInfo[1],
				Port: uint16(port),
			})
		}
	}

	if parts[9] != "" {
		out.Bucket = parts[9]
	}

	if parts[11] != "" {
		kvs := kvMatcher.FindAllStringSubmatch(parts[11], -1)
		for _, kvInfo := range kvs {
			out.Options[kvInfo[1]] = kvInfo[2]
		}
	}

	return out
}

func csResolveDnsSrv(spec *connSpec) bool {
	if len(spec.Hosts) == 1 && spec.Hosts[0].Port == 0 && (spec.Scheme == "couchbase" || spec.Scheme == "couchbases") {
		srvHostname := spec.Hosts[0].Host
		_, addrs, err := net.LookupSRV(spec.Scheme, "tcp", srvHostname)
		if err != nil {
			return false
		}

		var hostList []connSpecAddr
		for _, srvRecord := range addrs {
			hostList = append(hostList, connSpecAddr{srvRecord.Target, srvRecord.Port})
		}
		spec.Hosts = hostList

		return true
	} else {
		return false
	}
}

// Guesses a list of memcached hosts based on a connection string specification structure.
func csGetMemdHosts(spec connSpec) []connSpecAddr {
	var out []connSpecAddr
	for _, host := range spec.Hosts {
		memdHost := connSpecAddr{
			Host: host.Host,
			Port: 0,
		}

		fmt.Printf("Host parse: %s:%d", host.Host, host.Port)

		if host.Port == 0 {
			if spec.Scheme != "couchbases" {
				memdHost.Port = 11210
			} else {
				memdHost.Port = 11207
			}
		} else if host.Port == 8091 {
			memdHost.Port = 11210
		} else if host.Port == 18091 {
			memdHost.Port = 11207
		}

		if memdHost.Port != 0 {
			out = append(out, memdHost)
		}
	}
	return out
}
<|endoftext|>


<commit_before>package run

import (
	"errors"
	"flag"
	"fmt"
	"os"
	"os/signal"
	"syscall"
	"time"

	"qa/cmd"
	"qa/runner"
	"qa/runner/ruby"
	"qa/runner/server"
	"qa/tapjio"
)

type Env struct {
	Seed          int
	SuiteLabel    string
	SuiteCoderef  string
	WorkerEnvs    []map[string]string
	RunnerConfigs []runner.Config
	Visitor       tapjio.Visitor
	Server        *server.Server
}

type contextStarter func(
	srv *server.Server,
	workerEnvs []map[string]string,
	runnerConfig runner.Config) (runner.Context, error)

func rubyContextStarter(runnerAssetName string) contextStarter {
	return func(
		srv *server.Server,
		workerEnvs []map[string]string,
		runnerConfig runner.Config) (runner.Context, error) {

		config := &ruby.ContextConfig{
			RunnerConfig:    runnerConfig,
			Rubylib:         []string{"spec", "lib", "test"},
			RunnerAssetName: runnerAssetName,
		}

		ctx, err := ruby.StartContext(srv, workerEnvs, config)
		if err != nil {
			return nil, err
		}

		return ctx, nil
	}
}

var starters = map[string]contextStarter{
	"rspec":     rubyContextStarter("ruby/rspec.rb"),
	"minitest":  rubyContextStarter("ruby/minitest.rb"),
	"test-unit": rubyContextStarter("ruby/test-unit.rb"),
}

func Run(env *Env) (tapjio.FinalEvent, error) {
	var final tapjio.FinalEvent
	startTime := time.Now().UTC()
	visitor := env.Visitor

	var testRunners []runner.TestRunner
	count := 0
	for _, runnerConfig := range env.RunnerConfigs {
		starter, ok := starters[runnerConfig.Name]
		if !ok {
			return final, errors.New("Could not find starter: " + runnerConfig.Name)
		}

		ctx, err := starter(env.Server, env.WorkerEnvs, runnerConfig)
		defer ctx.Close()
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error! %v\n", err)
			return final, err
		}

		traceEvents, runners, err := ctx.EnumerateRunners()
		if err != nil {
			return final, err
		}

		for _, runner := range runners {
			count += runner.TestCount()
		}

		testRunners = append(testRunners, runners...)

		for _, traceEvent := range traceEvents {
			err := visitor.TraceEvent(traceEvent)
			if err != nil {
				return final, err
			}
		}
	}

	suiteEvent := tapjio.NewSuiteEvent(startTime, count, env.Seed)
	suiteEvent.Label = env.SuiteLabel
	suiteEvent.Coderef = env.SuiteCoderef
	err := visitor.SuiteStarted(*suiteEvent)
	if err != nil {
		return final, err
	}

	final = *tapjio.NewFinalEvent(suiteEvent)
	err = runner.RunAll(visitor, env.WorkerEnvs, final.Counts, testRunners)

	final.Time = time.Now().UTC().Sub(startTime).Seconds()

	finalErr := visitor.SuiteFinished(final)
	if err == nil {
		err = finalErr
	}

	return final, err
}

func Main(env *cmd.Env, args []string) error {
	flags := flag.NewFlagSet("run", flag.ContinueOnError)

	f := DefineFlags(flags)
	err := flags.Parse(args)
	if err != nil {
		return err
	}

	runEnv, err := f.NewEnv(env, flags.Args())
	if err != nil {
		return err
	}

	srv := runEnv.Server
	defer srv.Close()
	go srv.Run()

	// Handle common process-killing signals so we can gracefully shut down:
	sigc := make(chan os.Signal, 1)
	signal.Notify(sigc, os.Interrupt, os.Kill, syscall.SIGTERM)
	go func(c chan os.Signal) {
		// Wait for signal
		sig, ok := <-c
		if ok {
			fmt.Fprintln(env.Stderr, "Got signal:", sig)
			srv.Close()
		}
	}(sigc)
	defer signal.Stop(sigc)
	defer close(sigc)

	var final tapjio.FinalEvent
	final, err = Run(runEnv)
	if err != nil {
		return err
	}

	if !final.Passed() {
		return errors.New("Test(s) failed.")
	}

	return nil
}
<commit_msg>Only close test context if it started w/o error<commit_after>package run

import (
	"errors"
	"flag"
	"fmt"
	"os"
	"os/signal"
	"syscall"
	"time"

	"qa/cmd"
	"qa/runner"
	"qa/runner/ruby"
	"qa/runner/server"
	"qa/tapjio"
)

type Env struct {
	Seed          int
	SuiteLabel    string
	SuiteCoderef  string
	WorkerEnvs    []map[string]string
	RunnerConfigs []runner.Config
	Visitor       tapjio.Visitor
	Server        *server.Server
}

type contextStarter func(
	srv *server.Server,
	workerEnvs []map[string]string,
	runnerConfig runner.Config) (runner.Context, error)

func rubyContextStarter(runnerAssetName string) contextStarter {
	return func(
		srv *server.Server,
		workerEnvs []map[string]string,
		runnerConfig runner.Config) (runner.Context, error) {

		config := &ruby.ContextConfig{
			RunnerConfig:    runnerConfig,
			Rubylib:         []string{"spec", "lib", "test"},
			RunnerAssetName: runnerAssetName,
		}

		ctx, err := ruby.StartContext(srv, workerEnvs, config)
		if err != nil {
			return nil, err
		}

		return ctx, nil
	}
}

var starters = map[string]contextStarter{
	"rspec":     rubyContextStarter("ruby/rspec.rb"),
	"minitest":  rubyContextStarter("ruby/minitest.rb"),
	"test-unit": rubyContextStarter("ruby/test-unit.rb"),
}

func Run(env *Env) (tapjio.FinalEvent, error) {
	var final tapjio.FinalEvent
	startTime := time.Now().UTC()
	visitor := env.Visitor

	var testRunners []runner.TestRunner
	count := 0
	for _, runnerConfig := range env.RunnerConfigs {
		starter, ok := starters[runnerConfig.Name]
		if !ok {
			return final, errors.New("Could not find starter: " + runnerConfig.Name)
		}

		ctx, err := starter(env.Server, env.WorkerEnvs, runnerConfig)
		if err != nil {
			return final, err
		}
		defer ctx.Close()

		traceEvents, runners, err := ctx.EnumerateRunners()
		if err != nil {
			return final, err
		}

		for _, runner := range runners {
			count += runner.TestCount()
		}

		testRunners = append(testRunners, runners...)

		for _, traceEvent := range traceEvents {
			err := visitor.TraceEvent(traceEvent)
			if err != nil {
				return final, err
			}
		}
	}

	suiteEvent := tapjio.NewSuiteEvent(startTime, count, env.Seed)
	suiteEvent.Label = env.SuiteLabel
	suiteEvent.Coderef = env.SuiteCoderef
	err := visitor.SuiteStarted(*suiteEvent)
	if err != nil {
		return final, err
	}

	final = *tapjio.NewFinalEvent(suiteEvent)
	err = runner.RunAll(visitor, env.WorkerEnvs, final.Counts, testRunners)

	final.Time = time.Now().UTC().Sub(startTime).Seconds()

	finalErr := visitor.SuiteFinished(final)
	if err == nil {
		err = finalErr
	}

	return final, err
}

func Main(env *cmd.Env, args []string) error {
	flags := flag.NewFlagSet("run", flag.ContinueOnError)

	f := DefineFlags(flags)
	err := flags.Parse(args)
	if err != nil {
		return err
	}

	runEnv, err := f.NewEnv(env, flags.Args())
	if err != nil {
		return err
	}

	srv := runEnv.Server
	defer srv.Close()
	go srv.Run()

	// Handle common process-killing signals so we can gracefully shut down:
	sigc := make(chan os.Signal, 1)
	signal.Notify(sigc, os.Interrupt, os.Kill, syscall.SIGTERM)
	go func(c chan os.Signal) {
		// Wait for signal
		sig, ok := <-c
		if ok {
			fmt.Fprintln(env.Stderr, "Got signal:", sig)
			srv.Close()
		}
	}(sigc)
	defer signal.Stop(sigc)
	defer close(sigc)

	var final tapjio.FinalEvent
	final, err = Run(runEnv)
	if err != nil {
		return err
	}

	if !final.Passed() {
		return errors.New("Test(s) failed.")
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2015 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.

package x11driver

// TODO: implement a back buffer.

import (
	"image"
	"image/color"
	"image/draw"
	"sync"

	"github.com/BurntSushi/xgb"
	"github.com/BurntSushi/xgb/render"
	"github.com/BurntSushi/xgb/xproto"

	"github.com/oakmound/oak/v3/shiny/driver/internal/drawer"
	"github.com/oakmound/oak/v3/shiny/driver/internal/event"
	"github.com/oakmound/oak/v3/shiny/driver/internal/lifecycler"
	"github.com/oakmound/oak/v3/shiny/driver/internal/x11"
	"github.com/oakmound/oak/v3/shiny/driver/internal/x11key"
	"github.com/oakmound/oak/v3/shiny/screen"
	"golang.org/x/image/math/f64"
	"golang.org/x/mobile/event/key"
	"golang.org/x/mobile/event/mouse"
	"golang.org/x/mobile/event/paint"
	"golang.org/x/mobile/event/size"
	"golang.org/x/mobile/geom"
)

type windowImpl struct {
	s *screenImpl

	xw xproto.Window
	xg xproto.Gcontext
	xp render.Picture

	event.Deque
	xevents chan xgb.Event

	// This next group of variables are mutable, but are only modified in the
	// screenImpl.run goroutine.
	width, height uint32

	lifecycler lifecycler.State

	mu sync.Mutex

	x, y     uint32
	released bool
}

func (w *windowImpl) Release() {
	w.mu.Lock()
	released := w.released
	w.released = true
	w.mu.Unlock()

	// TODO: call w.lifecycler.SetDead and w.lifecycler.SendEvent, a la
	// handling atomWMDeleteWindow?

	if released {
		return
	}
	render.FreePicture(w.s.xc, w.xp)
	xproto.FreeGC(w.s.xc, w.xg)
	xproto.DestroyWindow(w.s.xc, w.xw)
}

func (w *windowImpl) Upload(dp image.Point, src screen.Image, sr image.Rectangle) {
	src.(*bufferImpl).upload(xproto.Drawable(w.xw), w.xg, w.s.xsi.RootDepth, dp, sr)
}

func (w *windowImpl) Fill(dr image.Rectangle, src color.Color, op draw.Op) {
	fill(w.s.xc, w.xp, dr, src, op)
}

func (w *windowImpl) DrawUniform(src2dst f64.Aff3, src color.Color, sr image.Rectangle, op draw.Op) {
	w.s.drawUniform(w.xp, &src2dst, src, sr, op)
}

func (w *windowImpl) Draw(src2dst f64.Aff3, src screen.Texture, sr image.Rectangle, op draw.Op) {
	src.(*textureImpl).draw(w.xp, &src2dst, sr, op)
}

func (w *windowImpl) Copy(dp image.Point, src screen.Texture, sr image.Rectangle, op draw.Op) {
	drawer.Copy(w, dp, src, sr, op)
}

func (w *windowImpl) Scale(dr image.Rectangle, src screen.Texture, sr image.Rectangle, op draw.Op) {
	drawer.Scale(w, dr, src, sr, op)
}

func (w *windowImpl) Publish() screen.PublishResult {
	// TODO: implement a back buffer, and copy or flip that here to the front
	// buffer.

	// This sync isn't needed to flush the outgoing X11 requests. Instead, it
	// acts as a form of flow control. Outgoing requests can be quite small on
	// the wire, e.g. draw this texture ID (an integer) to this rectangle (four
	// more integers), but much more expensive on the server (blending a
	// million source and destination pixels). Without this sync, the Go X11
	// client could easily end up sending work at a faster rate than the X11
	// server can serve.
	w.s.xc.Sync()

	return screen.PublishResult{}
}

func (w *windowImpl) SetFullScreen(fullscreen bool) error {
	return x11.SetFullScreen(w.s.XUtil, w.xw, fullscreen)
}

func (w *windowImpl) SetBorderless(borderless bool) error {
	return x11.SetBorderless(w.s.XUtil, w.xw, borderless)
}

func (w *windowImpl) handleConfigureNotify(ev xproto.ConfigureNotifyEvent) {
	// TODO: does the order of these lifecycle and size events matter? Should
	// they really be a single, atomic event?
	w.lifecycler.SetVisible((int(ev.X)+int(ev.Width)) > 0 && (int(ev.Y)+int(ev.Height)) > 0)
	w.lifecycler.SendEvent(w, nil)

	newWidth, newHeight := uint32(ev.Width), uint32(ev.Height)
	if w.width == newWidth && w.height == newHeight {
		return
	}
	w.width, w.height = newWidth, newHeight
	w.Send(size.Event{
		WidthPx:     int(newWidth),
		HeightPx:    int(newHeight),
		WidthPt:     geom.Pt(newWidth),
		HeightPt:    geom.Pt(newHeight),
		PixelsPerPt: w.s.pixelsPerPt,
	})
}

func (w *windowImpl) handleExpose() {
	w.Send(paint.Event{})
}

func (w *windowImpl) handleKey(detail xproto.Keycode, state uint16, dir key.Direction) {
	r, c := w.s.keysyms.Lookup(uint8(detail), state, w.s.numLockMod)
	w.Send(key.Event{
		Rune:      r,
		Code:      c,
		Modifiers: x11key.KeyModifiers(state),
		Direction: dir,
	})
}

func (w *windowImpl) handleMouse(x, y int16, b xproto.Button, state uint16, dir mouse.Direction) {
	// TODO: should a mouse.Event have a separate MouseModifiers field, for
	// which buttons are pressed during a mouse move?
	btn := mouse.Button(b)
	switch btn {
	case 4:
		btn = mouse.ButtonWheelUp
	case 5:
		btn = mouse.ButtonWheelDown
	case 6:
		btn = mouse.ButtonWheelLeft
	case 7:
		btn = mouse.ButtonWheelRight
	}
	if btn.IsWheel() {
		if dir != mouse.DirPress {
			return
		}
		dir = mouse.DirStep
	}
	w.Send(mouse.Event{
		X:         float32(x),
		Y:         float32(y),
		Button:    btn,
		Modifiers: x11key.KeyModifiers(state),
		Direction: dir,
	})
}

func (w *windowImpl) MoveWindow(x, y, width, height int32) error {
	newX, newY, newW, newH := x11.MoveWindow(w.s.xc, w.xw, x, y, width, height)
	w.x = uint32(newX)
	w.y = uint32(newY)
	w.width = uint32(newW)
	w.height = uint32(newH)
	w.Send(size.Event{
		WidthPx:     int(newW),
		HeightPx:    int(newH),
		WidthPt:     geom.Pt(newW),
		HeightPt:    geom.Pt(newH),
		PixelsPerPt: w.s.pixelsPerPt,
	})
	return nil
}
<commit_msg>shiny/driver/x11driver: add SetTitle<commit_after>// Copyright 2015 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.

package x11driver

// TODO: implement a back buffer.

import (
	"image"
	"image/color"
	"image/draw"
	"sync"

	"github.com/BurntSushi/xgb"
	"github.com/BurntSushi/xgb/render"
	"github.com/BurntSushi/xgb/xproto"

	"github.com/oakmound/oak/v3/shiny/driver/internal/drawer"
	"github.com/oakmound/oak/v3/shiny/driver/internal/event"
	"github.com/oakmound/oak/v3/shiny/driver/internal/lifecycler"
	"github.com/oakmound/oak/v3/shiny/driver/internal/x11"
	"github.com/oakmound/oak/v3/shiny/driver/internal/x11key"
	"github.com/oakmound/oak/v3/shiny/screen"
	"golang.org/x/image/math/f64"
	"golang.org/x/mobile/event/key"
	"golang.org/x/mobile/event/mouse"
	"golang.org/x/mobile/event/paint"
	"golang.org/x/mobile/event/size"
	"golang.org/x/mobile/geom"
)

type windowImpl struct {
	s *screenImpl

	xw xproto.Window
	xg xproto.Gcontext
	xp render.Picture

	event.Deque
	xevents chan xgb.Event

	// This next group of variables are mutable, but are only modified in the
	// screenImpl.run goroutine.
	width, height uint32

	lifecycler lifecycler.State

	mu sync.Mutex

	x, y     uint32
	released bool
}

func (w *windowImpl) Release() {
	w.mu.Lock()
	released := w.released
	w.released = true
	w.mu.Unlock()

	// TODO: call w.lifecycler.SetDead and w.lifecycler.SendEvent, a la
	// handling atomWMDeleteWindow?

	if released {
		return
	}
	render.FreePicture(w.s.xc, w.xp)
	xproto.FreeGC(w.s.xc, w.xg)
	xproto.DestroyWindow(w.s.xc, w.xw)
}

func (w *windowImpl) Upload(dp image.Point, src screen.Image, sr image.Rectangle) {
	src.(*bufferImpl).upload(xproto.Drawable(w.xw), w.xg, w.s.xsi.RootDepth, dp, sr)
}

func (w *windowImpl) Fill(dr image.Rectangle, src color.Color, op draw.Op) {
	fill(w.s.xc, w.xp, dr, src, op)
}

func (w *windowImpl) DrawUniform(src2dst f64.Aff3, src color.Color, sr image.Rectangle, op draw.Op) {
	w.s.drawUniform(w.xp, &src2dst, src, sr, op)
}

func (w *windowImpl) Draw(src2dst f64.Aff3, src screen.Texture, sr image.Rectangle, op draw.Op) {
	src.(*textureImpl).draw(w.xp, &src2dst, sr, op)
}

func (w *windowImpl) Copy(dp image.Point, src screen.Texture, sr image.Rectangle, op draw.Op) {
	drawer.Copy(w, dp, src, sr, op)
}

func (w *windowImpl) Scale(dr image.Rectangle, src screen.Texture, sr image.Rectangle, op draw.Op) {
	drawer.Scale(w, dr, src, sr, op)
}

func (w *windowImpl) Publish() screen.PublishResult {
	// TODO: implement a back buffer, and copy or flip that here to the front
	// buffer.

	// This sync isn't needed to flush the outgoing X11 requests. Instead, it
	// acts as a form of flow control. Outgoing requests can be quite small on
	// the wire, e.g. draw this texture ID (an integer) to this rectangle (four
	// more integers), but much more expensive on the server (blending a
	// million source and destination pixels). Without this sync, the Go X11
	// client could easily end up sending work at a faster rate than the X11
	// server can serve.
	w.s.xc.Sync()

	return screen.PublishResult{}
}

func (w *windowImpl) SetFullScreen(fullscreen bool) error {
	return x11.SetFullScreen(w.s.XUtil, w.xw, fullscreen)
}

func (w *windowImpl) SetBorderless(borderless bool) error {
	return x11.SetBorderless(w.s.XUtil, w.xw, borderless)
}

func (w *windowImpl) handleConfigureNotify(ev xproto.ConfigureNotifyEvent) {
	// TODO: does the order of these lifecycle and size events matter? Should
	// they really be a single, atomic event?
	w.lifecycler.SetVisible((int(ev.X)+int(ev.Width)) > 0 && (int(ev.Y)+int(ev.Height)) > 0)
	w.lifecycler.SendEvent(w, nil)

	newWidth, newHeight := uint32(ev.Width), uint32(ev.Height)
	if w.width == newWidth && w.height == newHeight {
		return
	}
	w.width, w.height = newWidth, newHeight
	w.Send(size.Event{
		WidthPx:     int(newWidth),
		HeightPx:    int(newHeight),
		WidthPt:     geom.Pt(newWidth),
		HeightPt:    geom.Pt(newHeight),
		PixelsPerPt: w.s.pixelsPerPt,
	})
}

func (w *windowImpl) handleExpose() {
	w.Send(paint.Event{})
}

func (w *windowImpl) handleKey(detail xproto.Keycode, state uint16, dir key.Direction) {
	r, c := w.s.keysyms.Lookup(uint8(detail), state, w.s.numLockMod)
	w.Send(key.Event{
		Rune:      r,
		Code:      c,
		Modifiers: x11key.KeyModifiers(state),
		Direction: dir,
	})
}

func (w *windowImpl) handleMouse(x, y int16, b xproto.Button, state uint16, dir mouse.Direction) {
	// TODO: should a mouse.Event have a separate MouseModifiers field, for
	// which buttons are pressed during a mouse move?
	btn := mouse.Button(b)
	switch btn {
	case 4:
		btn = mouse.ButtonWheelUp
	case 5:
		btn = mouse.ButtonWheelDown
	case 6:
		btn = mouse.ButtonWheelLeft
	case 7:
		btn = mouse.ButtonWheelRight
	}
	if btn.IsWheel() {
		if dir != mouse.DirPress {
			return
		}
		dir = mouse.DirStep
	}
	w.Send(mouse.Event{
		X:         float32(x),
		Y:         float32(y),
		Button:    btn,
		Modifiers: x11key.KeyModifiers(state),
		Direction: dir,
	})
}

func (w *windowImpl) MoveWindow(x, y, width, height int32) error {
	newX, newY, newW, newH := x11.MoveWindow(w.s.xc, w.xw, x, y, width, height)
	w.x = uint32(newX)
	w.y = uint32(newY)
	w.width = uint32(newW)
	w.height = uint32(newH)
	w.Send(size.Event{
		WidthPx:     int(newW),
		HeightPx:    int(newH),
		WidthPt:     geom.Pt(newW),
		HeightPt:    geom.Pt(newH),
		PixelsPerPt: w.s.pixelsPerPt,
	})
	return nil
}

func (w *Window) SetTitle(title string) error {
	xproto.ChangeProperty(w.s.xc, xproto.PropModeReplace, w.xw,
		w.s.atoms["_NET_WM_NAME"], w.s.atoms["UTF8_STRING"],
		8, uint32(len(title)), []byte(title))
	return nil
}
<|endoftext|>