<commit_before>//
// Copyright 2017, Sander van Harmelen
//
// 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 gitlab

import (
	"fmt"
)

// ProjectMembersService handles communication with the project members
// related methods of the GitLab API.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/members.html
type ProjectMembersService struct {
	client *Client
}

// ListProjectMembersOptions represents the available ListProjectMembers() and
// ListAllProjectMembers() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project
type ListProjectMembersOptions struct {
	ListOptions
	Query *string `url:"query,omitempty" json:"query,omitempty"`
}

// ListProjectMembers gets a list of a project's team members viewable by the
// authenticated user. Returns only direct members and not inherited members
// through ancestors groups.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project
func (s *ProjectMembersService) ListProjectMembers(pid interface{}, opt *ListProjectMembersOptions, options ...RequestOptionFunc) ([]*ProjectMember, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/members", pathEscape(project))

	req, err := s.client.NewRequest("GET", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	var pm []*ProjectMember
	resp, err := s.client.Do(req, &pm)
	if err != nil {
		return nil, resp, err
	}

	return pm, resp, err
}

// ListAllProjectMembers gets a list of a project's team members viewable by the
// authenticated user. Returns a list including inherited members through
// ancestor groups.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project-including-inherited-members
func (s *ProjectMembersService) ListAllProjectMembers(pid interface{}, opt *ListProjectMembersOptions, options ...RequestOptionFunc) ([]*ProjectMember, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/members/all", pathEscape(project))

	req, err := s.client.NewRequest("GET", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	var pm []*ProjectMember
	resp, err := s.client.Do(req, &pm)
	if err != nil {
		return nil, resp, err
	}

	return pm, resp, err
}

// GetProjectMember gets a project team member.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/members.html#get-a-member-of-a-group-or-project
func (s *ProjectMembersService) GetProjectMember(pid interface{}, user int, options ...RequestOptionFunc) (*ProjectMember, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/members/%d", pathEscape(project), user)

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	pm := new(ProjectMember)
	resp, err := s.client.Do(req, pm)
	if err != nil {
		return nil, resp, err
	}

	return pm, resp, err
}

// GetInheritedProjectMember gets a project team member, including inherited
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/members.html#get-a-member-of-a-group-or-project-including-inherited-members
func (s *ProjectMembersService) GetInheritedProjectMember(pid interface{}, user int, options ...RequestOptionFunc) (*ProjectMember, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/members/all/%d", pathEscape(project), user)

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	pm := new(ProjectMember)
	resp, err := s.client.Do(req, pm)
	if err != nil {
		return nil, resp, err
	}

	return pm, resp, err
}

// AddProjectMemberOptions represents the available AddProjectMember() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/members.html#add-a-member-to-a-group-or-project
type AddProjectMemberOptions struct {
	UserID      *string           `url:"user_id,omitempty" json:"user_id,omitempty"`
	AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"`
	ExpiresAt   *string           `url:"expires_at,omitempty" json:"expires_at"`
}

// AddProjectMember adds a user to a project team. This is an idempotent
// method and can be called multiple times with the same parameters. Adding
// team membership to a user that is already a member does not affect the
// existing membership.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/members.html#add-a-member-to-a-group-or-project
func (s *ProjectMembersService) AddProjectMember(pid interface{}, opt *AddProjectMemberOptions, options ...RequestOptionFunc) (*ProjectMember, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/members", pathEscape(project))

	req, err := s.client.NewRequest("POST", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	pm := new(ProjectMember)
	resp, err := s.client.Do(req, pm)
	if err != nil {
		return nil, resp, err
	}

	return pm, resp, err
}

// EditProjectMemberOptions represents the available EditProjectMember() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/members.html#edit-a-member-of-a-group-or-project
type EditProjectMemberOptions struct {
	AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"`
	ExpiresAt   *string           `url:"expires_at,omitempty" json:"expires_at"`
}

// EditProjectMember updates a project team member to a specified access level..
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/members.html#edit-a-member-of-a-group-or-project
func (s *ProjectMembersService) EditProjectMember(pid interface{}, user int, opt *EditProjectMemberOptions, options ...RequestOptionFunc) (*ProjectMember, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/members/%d", pathEscape(project), user)

	req, err := s.client.NewRequest("PUT", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	pm := new(ProjectMember)
	resp, err := s.client.Do(req, pm)
	if err != nil {
		return nil, resp, err
	}

	return pm, resp, err
}

// DeleteProjectMember removes a user from a project team.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/members.html#remove-a-member-from-a-group-or-project
func (s *ProjectMembersService) DeleteProjectMember(pid interface{}, user int, options ...RequestOptionFunc) (*Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("projects/%s/members/%d", pathEscape(project), user)

	req, err := s.client.NewRequest("DELETE", u, nil, options)
	if err != nil {
		return nil, err
	}

	return s.client.Do(req, nil)
}
<commit_msg>Update project_members.go<commit_after>//
// Copyright 2017, Sander van Harmelen
//
// 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 gitlab

import (
	"fmt"
)

// ProjectMembersService handles communication with the project members
// related methods of the GitLab API.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/members.html
type ProjectMembersService struct {
	client *Client
}

// ListProjectMembersOptions represents the available ListProjectMembers() and
// ListAllProjectMembers() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project
type ListProjectMembersOptions struct {
	ListOptions
	Query *string `url:"query,omitempty" json:"query,omitempty"`
}

// ListProjectMembers gets a list of a project's team members viewable by the
// authenticated user. Returns only direct members and not inherited members
// through ancestors groups.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project
func (s *ProjectMembersService) ListProjectMembers(pid interface{}, opt *ListProjectMembersOptions, options ...RequestOptionFunc) ([]*ProjectMember, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/members", pathEscape(project))

	req, err := s.client.NewRequest("GET", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	var pm []*ProjectMember
	resp, err := s.client.Do(req, &pm)
	if err != nil {
		return nil, resp, err
	}

	return pm, resp, err
}

// ListAllProjectMembers gets a list of a project's team members viewable by the
// authenticated user. Returns a list including inherited members through
// ancestor groups.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project-including-inherited-members
func (s *ProjectMembersService) ListAllProjectMembers(pid interface{}, opt *ListProjectMembersOptions, options ...RequestOptionFunc) ([]*ProjectMember, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/members/all", pathEscape(project))

	req, err := s.client.NewRequest("GET", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	var pm []*ProjectMember
	resp, err := s.client.Do(req, &pm)
	if err != nil {
		return nil, resp, err
	}

	return pm, resp, err
}

// GetProjectMember gets a project team member.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/members.html#get-a-member-of-a-group-or-project
func (s *ProjectMembersService) GetProjectMember(pid interface{}, user int, options ...RequestOptionFunc) (*ProjectMember, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/members/%d", pathEscape(project), user)

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	pm := new(ProjectMember)
	resp, err := s.client.Do(req, pm)
	if err != nil {
		return nil, resp, err
	}

	return pm, resp, err
}

// GetInheritedProjectMember gets a project team member, including inherited
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/members.html#get-a-member-of-a-group-or-project-including-inherited-members
func (s *ProjectMembersService) GetInheritedProjectMember(pid interface{}, user int, options ...RequestOptionFunc) (*ProjectMember, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/members/all/%d", pathEscape(project), user)

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	pm := new(ProjectMember)
	resp, err := s.client.Do(req, pm)
	if err != nil {
		return nil, resp, err
	}

	return pm, resp, err
}

// AddProjectMemberOptions represents the available AddProjectMember() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/members.html#add-a-member-to-a-group-or-project
type AddProjectMemberOptions struct {
	UserID      interface{}       `url:"user_id,omitempty" json:"user_id,omitempty"`
	AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"`
	ExpiresAt   *string           `url:"expires_at,omitempty" json:"expires_at"`
}

// AddProjectMember adds a user to a project team. This is an idempotent
// method and can be called multiple times with the same parameters. Adding
// team membership to a user that is already a member does not affect the
// existing membership.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/members.html#add-a-member-to-a-group-or-project
func (s *ProjectMembersService) AddProjectMember(pid interface{}, opt *AddProjectMemberOptions, options ...RequestOptionFunc) (*ProjectMember, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/members", pathEscape(project))

	req, err := s.client.NewRequest("POST", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	pm := new(ProjectMember)
	resp, err := s.client.Do(req, pm)
	if err != nil {
		return nil, resp, err
	}

	return pm, resp, err
}

// EditProjectMemberOptions represents the available EditProjectMember() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/members.html#edit-a-member-of-a-group-or-project
type EditProjectMemberOptions struct {
	AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"`
	ExpiresAt   *string           `url:"expires_at,omitempty" json:"expires_at"`
}

// EditProjectMember updates a project team member to a specified access level..
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/members.html#edit-a-member-of-a-group-or-project
func (s *ProjectMembersService) EditProjectMember(pid interface{}, user int, opt *EditProjectMemberOptions, options ...RequestOptionFunc) (*ProjectMember, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/members/%d", pathEscape(project), user)

	req, err := s.client.NewRequest("PUT", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	pm := new(ProjectMember)
	resp, err := s.client.Do(req, pm)
	if err != nil {
		return nil, resp, err
	}

	return pm, resp, err
}

// DeleteProjectMember removes a user from a project team.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/members.html#remove-a-member-from-a-group-or-project
func (s *ProjectMembersService) DeleteProjectMember(pid interface{}, user int, options ...RequestOptionFunc) (*Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("projects/%s/members/%d", pathEscape(project), user)

	req, err := s.client.NewRequest("DELETE", u, nil, options)
	if err != nil {
		return nil, err
	}

	return s.client.Do(req, nil)
}
<|endoftext|>


<commit_before>// Package errors provides simple error handling primitives.
//
// The traditional error handling idiom in Go is roughly akin to
//
//     if err != nil {
//             return err
//     }
//
// which applied recursively up the call stack results in error reports
// without context or debugging information. The errors package allows
// programmers to add context to the failure path in their code in a way
// that does not destroy the original value of the error.
//
// Adding context to an error
//
// The errors.Wrap function returns a new error that adds context to the
// original error by recording a stack trace at the point Wrap is called,
// and the supplied message. For example
//
//     _, err := ioutil.ReadAll(r)
//     if err != nil {
//             return errors.Wrap(err, "read failed")
//     }
//
// If additional control is required the errors.WithStack and errors.WithMessage
// functions destructure errors.Wrap into its component operations of annotating
// an error with a stack trace and an a message, respectively.
//
// Retrieving the cause of an error
//
// Using errors.Wrap constructs a stack of errors, adding context to the
// preceding error. Depending on the nature of the error it may be necessary
// to reverse the operation of errors.Wrap to retrieve the original error
// for inspection. Any error value which implements this interface
//
//     type causer interface {
//             Cause() error
//     }
//
// can be inspected by errors.Cause. errors.Cause will recursively retrieve
// the topmost error which does not implement causer, which is assumed to be
// the original cause. For example:
//
//     switch err := errors.Cause(err).(type) {
//     case *MyError:
//             // handle specifically
//     default:
//             // unknown error
//     }
//
// causer interface is not exported by this package, but is considered a part
// of stable public API.
//
// Formatted printing of errors
//
// All error values returned from this package implement fmt.Formatter and can
// be formatted by the fmt package. The following verbs are supported
//
//     %s    print the error. If the error has a Cause it will be
//           printed recursively
//     %v    see %s
//     %+v   extended format. Each Frame of the error's StackTrace will
//           be printed in detail.
//
// Retrieving the stack trace of an error or wrapper
//
// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
// invoked. This information can be retrieved with the following interface.
//
//     type stackTracer interface {
//             StackTrace() errors.StackTrace
//     }
//
// Where errors.StackTrace is defined as
//
//     type StackTrace []Frame
//
// The Frame type represents a call site in the stack trace. Frame supports
// the fmt.Formatter interface that can be used for printing information about
// the stack trace of this error. For example:
//
//     if err, ok := err.(stackTracer); ok {
//             for _, f := range err.StackTrace() {
//                     fmt.Printf("%+s:%d", f)
//             }
//     }
//
// stackTracer interface is not exported by this package, but is considered a part
// of stable public API.
//
// See the documentation for Frame.Format for more details.
package errors

import (
	"fmt"
	"io"
)

// New returns an error with the supplied message.
// New also records the stack trace at the point it was called.
func New(message string) error {
	return &fundamental{
		msg:   message,
		stack: callers(),
	}
}

// Errorf formats according to a format specifier and returns the string
// as a value that satisfies error.
// Errorf also records the stack trace at the point it was called.
func Errorf(format string, args ...interface{}) error {
	return &fundamental{
		msg:   fmt.Sprintf(format, args...),
		stack: callers(),
	}
}

// fundamental is an error that has a message and a stack, but no caller.
type fundamental struct {
	msg string
	*stack
}

func (f *fundamental) Error() string { return f.msg }

func (f *fundamental) Format(s fmt.State, verb rune) {
	switch verb {
	case 'v':
		if s.Flag('+') {
			io.WriteString(s, f.msg)
			f.stack.Format(s, verb)
			return
		}
		fallthrough
	case 's':
		io.WriteString(s, f.msg)
	case 'q':
		fmt.Fprintf(s, "%q", f.msg)
	}
}

// WithStack annotates err with a stack trace at the point WithStack was called.
// If err is nil, WithStack returns nil.
func WithStack(err error) error {
	if err == nil {
		return nil
	}
	return &withStack{
		err,
		callers(),
	}
}

type withStack struct {
	error
	*stack
}

func (w *withStack) Cause() error { return w.error }

func (w *withStack) Format(s fmt.State, verb rune) {
	switch verb {
	case 'v':
		if s.Flag('+') {
			fmt.Fprintf(s, "%+v", w.Cause())
			w.stack.Format(s, verb)
			return
		}
		fallthrough
	case 's':
		io.WriteString(s, w.Error())
	case 'q':
		fmt.Fprintf(s, "%q", w.Error())
	}
}

// Wrap returns an error annotating err with a stack trace
// at the point Wrap is called, and the supplied message.
// If err is nil, Wrap returns nil.
func Wrap(err error, message string) error {
	if err == nil {
		return nil
	}
	err = &withMessage{
		cause: err,
		msg:   message,
	}
	return &withStack{
		err,
		callers(),
	}
}

// Wrapf returns an error annotating err with a stack trace
// at the point Wrapf is call, and the format specifier.
// If err is nil, Wrapf returns nil.
func Wrapf(err error, format string, args ...interface{}) error {
	if err == nil {
		return nil
	}
	err = &withMessage{
		cause: err,
		msg:   fmt.Sprintf(format, args...),
	}
	return &withStack{
		err,
		callers(),
	}
}

// WithMessage annotates err with a new message.
// If err is nil, WithMessage returns nil.
func WithMessage(err error, message string) error {
	if err == nil {
		return nil
	}
	return &withMessage{
		cause: err,
		msg:   message,
	}
}

type withMessage struct {
	cause error
	msg   string
}

func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() }
func (w *withMessage) Cause() error  { return w.cause }

func (w *withMessage) Format(s fmt.State, verb rune) {
	switch verb {
	case 'v':
		if s.Flag('+') {
			fmt.Fprintf(s, "%+v\n", w.Cause())
			io.WriteString(s, w.msg)
			return
		}
		fallthrough
	case 's', 'q':
		io.WriteString(s, w.Error())
	}
}

// Cause returns the underlying cause of the error, if possible.
// An error value has a cause if it implements the following
// interface:
//
//     type causer interface {
//            Cause() error
//     }
//
// If the error does not implement Cause, the original error will
// be returned. If the error is nil, nil will be returned without further
// investigation.
func Cause(err error) error {
	type causer interface {
		Cause() error
	}

	for err != nil {
		cause, ok := err.(causer)
		if !ok {
			break
		}
		err = cause.Cause()
	}
	return err
}
<commit_msg>fixed spelling (#156)<commit_after>// Package errors provides simple error handling primitives.
//
// The traditional error handling idiom in Go is roughly akin to
//
//     if err != nil {
//             return err
//     }
//
// which applied recursively up the call stack results in error reports
// without context or debugging information. The errors package allows
// programmers to add context to the failure path in their code in a way
// that does not destroy the original value of the error.
//
// Adding context to an error
//
// The errors.Wrap function returns a new error that adds context to the
// original error by recording a stack trace at the point Wrap is called,
// and the supplied message. For example
//
//     _, err := ioutil.ReadAll(r)
//     if err != nil {
//             return errors.Wrap(err, "read failed")
//     }
//
// If additional control is required the errors.WithStack and errors.WithMessage
// functions destructure errors.Wrap into its component operations of annotating
// an error with a stack trace and an a message, respectively.
//
// Retrieving the cause of an error
//
// Using errors.Wrap constructs a stack of errors, adding context to the
// preceding error. Depending on the nature of the error it may be necessary
// to reverse the operation of errors.Wrap to retrieve the original error
// for inspection. Any error value which implements this interface
//
//     type causer interface {
//             Cause() error
//     }
//
// can be inspected by errors.Cause. errors.Cause will recursively retrieve
// the topmost error which does not implement causer, which is assumed to be
// the original cause. For example:
//
//     switch err := errors.Cause(err).(type) {
//     case *MyError:
//             // handle specifically
//     default:
//             // unknown error
//     }
//
// causer interface is not exported by this package, but is considered a part
// of stable public API.
//
// Formatted printing of errors
//
// All error values returned from this package implement fmt.Formatter and can
// be formatted by the fmt package. The following verbs are supported
//
//     %s    print the error. If the error has a Cause it will be
//           printed recursively
//     %v    see %s
//     %+v   extended format. Each Frame of the error's StackTrace will
//           be printed in detail.
//
// Retrieving the stack trace of an error or wrapper
//
// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
// invoked. This information can be retrieved with the following interface.
//
//     type stackTracer interface {
//             StackTrace() errors.StackTrace
//     }
//
// Where errors.StackTrace is defined as
//
//     type StackTrace []Frame
//
// The Frame type represents a call site in the stack trace. Frame supports
// the fmt.Formatter interface that can be used for printing information about
// the stack trace of this error. For example:
//
//     if err, ok := err.(stackTracer); ok {
//             for _, f := range err.StackTrace() {
//                     fmt.Printf("%+s:%d", f)
//             }
//     }
//
// stackTracer interface is not exported by this package, but is considered a part
// of stable public API.
//
// See the documentation for Frame.Format for more details.
package errors

import (
	"fmt"
	"io"
)

// New returns an error with the supplied message.
// New also records the stack trace at the point it was called.
func New(message string) error {
	return &fundamental{
		msg:   message,
		stack: callers(),
	}
}

// Errorf formats according to a format specifier and returns the string
// as a value that satisfies error.
// Errorf also records the stack trace at the point it was called.
func Errorf(format string, args ...interface{}) error {
	return &fundamental{
		msg:   fmt.Sprintf(format, args...),
		stack: callers(),
	}
}

// fundamental is an error that has a message and a stack, but no caller.
type fundamental struct {
	msg string
	*stack
}

func (f *fundamental) Error() string { return f.msg }

func (f *fundamental) Format(s fmt.State, verb rune) {
	switch verb {
	case 'v':
		if s.Flag('+') {
			io.WriteString(s, f.msg)
			f.stack.Format(s, verb)
			return
		}
		fallthrough
	case 's':
		io.WriteString(s, f.msg)
	case 'q':
		fmt.Fprintf(s, "%q", f.msg)
	}
}

// WithStack annotates err with a stack trace at the point WithStack was called.
// If err is nil, WithStack returns nil.
func WithStack(err error) error {
	if err == nil {
		return nil
	}
	return &withStack{
		err,
		callers(),
	}
}

type withStack struct {
	error
	*stack
}

func (w *withStack) Cause() error { return w.error }

func (w *withStack) Format(s fmt.State, verb rune) {
	switch verb {
	case 'v':
		if s.Flag('+') {
			fmt.Fprintf(s, "%+v", w.Cause())
			w.stack.Format(s, verb)
			return
		}
		fallthrough
	case 's':
		io.WriteString(s, w.Error())
	case 'q':
		fmt.Fprintf(s, "%q", w.Error())
	}
}

// Wrap returns an error annotating err with a stack trace
// at the point Wrap is called, and the supplied message.
// If err is nil, Wrap returns nil.
func Wrap(err error, message string) error {
	if err == nil {
		return nil
	}
	err = &withMessage{
		cause: err,
		msg:   message,
	}
	return &withStack{
		err,
		callers(),
	}
}

// Wrapf returns an error annotating err with a stack trace
// at the point Wrapf is called, and the format specifier.
// If err is nil, Wrapf returns nil.
func Wrapf(err error, format string, args ...interface{}) error {
	if err == nil {
		return nil
	}
	err = &withMessage{
		cause: err,
		msg:   fmt.Sprintf(format, args...),
	}
	return &withStack{
		err,
		callers(),
	}
}

// WithMessage annotates err with a new message.
// If err is nil, WithMessage returns nil.
func WithMessage(err error, message string) error {
	if err == nil {
		return nil
	}
	return &withMessage{
		cause: err,
		msg:   message,
	}
}

type withMessage struct {
	cause error
	msg   string
}

func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() }
func (w *withMessage) Cause() error  { return w.cause }

func (w *withMessage) Format(s fmt.State, verb rune) {
	switch verb {
	case 'v':
		if s.Flag('+') {
			fmt.Fprintf(s, "%+v\n", w.Cause())
			io.WriteString(s, w.msg)
			return
		}
		fallthrough
	case 's', 'q':
		io.WriteString(s, w.Error())
	}
}

// Cause returns the underlying cause of the error, if possible.
// An error value has a cause if it implements the following
// interface:
//
//     type causer interface {
//            Cause() error
//     }
//
// If the error does not implement Cause, the original error will
// be returned. If the error is nil, nil will be returned without further
// investigation.
func Cause(err error) error {
	type causer interface {
		Cause() error
	}

	for err != nil {
		cause, ok := err.(causer)
		if !ok {
			break
		}
		err = cause.Cause()
	}
	return err
}
<|endoftext|>


<commit_before>// +build all slack

package providers

import (
	"bytes"
	"encoding/json"
	"fmt"
	"html"
	"html/template"
	"log"
	"net/http"
	"strings"
	"time"

	"golang.org/x/net/websocket"

	"cirello.io/gochatbot/messages"
)

const (
	slackEnvVarName = "GOCHATBOT_SLACK_TOKEN"
	urlSlackAPI     = "https://slack.com/api/"
)

func init() {
	availableProviders = append(availableProviders, func(getenv func(string) string) (Provider, bool) {
		token := getenv(slackEnvVarName)
		if token == "" {
			log.Println("providers: skipping Slack. if you want Slack enabled, please set a valid value for the environment variables", slackEnvVarName)
			return nil, false
		}
		return Slack(token), true
	})
}

type providerSlack struct {
	token  string
	wsURL  string
	wsConn *websocket.Conn
	selfID string

	in  chan messages.Message
	out chan messages.Message
	err error
}

// Slack is the message provider meant to be used in development of rule sets.
func Slack(token string) *providerSlack {
	slack := &providerSlack{
		token: token,
		in:    make(chan messages.Message),
		out:   make(chan messages.Message),
	}
	slack.handshake()
	slack.dial()
	if slack.err == nil {
		go slack.intakeLoop()
		go slack.dispatchLoop()
	}
	go slack.reconnect()
	return slack
}

func (p *providerSlack) IncomingChannel() chan messages.Message {
	return p.in
}

func (p *providerSlack) OutgoingChannel() chan messages.Message {
	return p.out
}

func (p *providerSlack) Error() error {
	return p.err
}

func (p *providerSlack) handshake() {
	log.Println("slack: connecting to HTTP API handshake interface")
	resp, err := http.Get(fmt.Sprint(urlSlackAPI, "rtm.start?no_unreads&simple_latest&token=", p.token))
	if err != nil {
		p.err = err
		return
	}
	defer resp.Body.Close()
	var data struct {
		OK   interface{} `json:"ok"`
		URL  string      `json:"url"`
		Self struct {
			ID string `json:"id"`
		} `json:"self"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
		p.err = err
		return
	}

	switch v := data.OK.(type) {
	case bool:
		if !v {
			p.err = err
			return

		}
	default:
		p.err = err
		return
	}
	p.wsURL = data.URL
	p.selfID = data.Self.ID
}

func (p *providerSlack) dial() {
	log.Println("slack: dialing to HTTP WS rtm interface")
	if p.wsURL == "" {
		p.err = fmt.Errorf("could not connnect to Slack HTTP WS rtm. please, check your connection and your token (%s). error: %v", slackEnvVarName, p.err)
		return
	}
	ws, err := websocket.Dial(p.wsURL, "", urlSlackAPI)
	if err != nil {
		p.err = err
		return
	}
	p.wsConn = ws
}

func (p *providerSlack) intakeLoop() {
	log.Println("slack: started message intake loop")
	for {
		var data struct {
			Type    string `json:"type"`
			Channel string `json:"channel"`
			UserID  string `json:"user"`
			Text    string `json:"text"`
		}
		if err := json.NewDecoder(p.wsConn).Decode(&data); err != nil {
			continue
		}
		if data.Type != "message" {
			continue
		}

		msg := messages.Message{
			Room:       data.Channel,
			FromUserID: data.UserID,
			Message:    data.Text,
			Direct:     strings.HasPrefix(data.Channel, "D"),
		}
		p.in <- msg
	}
}

func (p *providerSlack) dispatchLoop() {
	log.Println("slack: started message dispatch loop")
	for msg := range p.out {
		// TODO(ccf): find a way in that text/template does not escape username DMs.
		var finalMsg bytes.Buffer
		template.Must(template.New("tmpl").Parse(msg.Message)).Execute(&finalMsg, struct{ User string }{"<@" + msg.ToUserID + ">"})

		data := struct {
			Type    string `json:"type"`
			User    string `json:"user"`
			Channel string `json:"channel"`
			Text    string `json:"text"`
		}{"message", p.selfID, msg.Room, html.UnescapeString(finalMsg.String())}

		// TODO(ccf): look for an idiomatic way of doing limited writers
		b, err := json.Marshal(data)
		if err != nil {
			continue
		}

		wsMsg := string(b)
		if len(wsMsg) > 16*1024 {
			continue
		}
		fmt.Fprint(p.wsConn, wsMsg)
		time.Sleep(1 * time.Second) // https://api.slack.com/docs/rate-limits
	}
}

func (p *providerSlack) reconnect() {
	for {
		time.Sleep(1 * time.Second)
		if p.wsConn == nil {
			log.Println("slack: cannot reconnect")
			break
		}
		_, err := p.wsConn.Write([]byte(`{"type":"hello"}`))
		if err != nil {
			log.Println("slack: reconnecting")
			p.handshake()
			p.dial()
		}
	}
}
<commit_msg>slack provider: protection against bad plugins<commit_after>// +build all slack

package providers

import (
	"bytes"
	"encoding/json"
	"fmt"
	"html"
	"html/template"
	"log"
	"net/http"
	"strings"
	"time"

	"golang.org/x/net/websocket"

	"cirello.io/gochatbot/messages"
)

const (
	slackEnvVarName = "GOCHATBOT_SLACK_TOKEN"
	urlSlackAPI     = "https://slack.com/api/"
)

func init() {
	availableProviders = append(availableProviders, func(getenv func(string) string) (Provider, bool) {
		token := getenv(slackEnvVarName)
		if token == "" {
			log.Println("providers: skipping Slack. if you want Slack enabled, please set a valid value for the environment variables", slackEnvVarName)
			return nil, false
		}
		return Slack(token), true
	})
}

type providerSlack struct {
	token  string
	wsURL  string
	wsConn *websocket.Conn
	selfID string

	in  chan messages.Message
	out chan messages.Message
	err error
}

// Slack is the message provider meant to be used in development of rule sets.
func Slack(token string) *providerSlack {
	slack := &providerSlack{
		token: token,
		in:    make(chan messages.Message),
		out:   make(chan messages.Message),
	}
	slack.handshake()
	slack.dial()
	if slack.err == nil {
		go slack.intakeLoop()
		go slack.dispatchLoop()
	}
	go slack.reconnect()
	return slack
}

func (p *providerSlack) IncomingChannel() chan messages.Message {
	return p.in
}

func (p *providerSlack) OutgoingChannel() chan messages.Message {
	return p.out
}

func (p *providerSlack) Error() error {
	return p.err
}

func (p *providerSlack) handshake() {
	log.Println("slack: connecting to HTTP API handshake interface")
	resp, err := http.Get(fmt.Sprint(urlSlackAPI, "rtm.start?no_unreads&simple_latest&token=", p.token))
	if err != nil {
		p.err = err
		return
	}
	defer resp.Body.Close()
	var data struct {
		OK   interface{} `json:"ok"`
		URL  string      `json:"url"`
		Self struct {
			ID string `json:"id"`
		} `json:"self"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
		p.err = err
		return
	}

	switch v := data.OK.(type) {
	case bool:
		if !v {
			p.err = err
			return

		}
	default:
		p.err = err
		return
	}
	p.wsURL = data.URL
	p.selfID = data.Self.ID
}

func (p *providerSlack) dial() {
	log.Println("slack: dialing to HTTP WS rtm interface")
	if p.wsURL == "" {
		p.err = fmt.Errorf("could not connnect to Slack HTTP WS rtm. please, check your connection and your token (%s). error: %v", slackEnvVarName, p.err)
		return
	}
	ws, err := websocket.Dial(p.wsURL, "", urlSlackAPI)
	if err != nil {
		p.err = err
		return
	}
	p.wsConn = ws
}

func (p *providerSlack) intakeLoop() {
	log.Println("slack: started message intake loop")
	for {
		var data struct {
			Type    string `json:"type"`
			Channel string `json:"channel"`
			UserID  string `json:"user"`
			Text    string `json:"text"`
		}
		if err := json.NewDecoder(p.wsConn).Decode(&data); err != nil {
			continue
		}
		if data.Type != "message" {
			continue
		}

		msg := messages.Message{
			Room:       data.Channel,
			FromUserID: data.UserID,
			Message:    data.Text,
			Direct:     strings.HasPrefix(data.Channel, "D"),
		}
		p.in <- msg
	}
}

func (p *providerSlack) dispatchLoop() {
	log.Println("slack: started message dispatch loop")
	for msg := range p.out {
		// TODO(ccf): find a way in that text/template does not escape username DMs.
		var finalMsg bytes.Buffer
		template.Must(template.New("tmpl").Parse(msg.Message)).Execute(&finalMsg, struct{ User string }{"<@" + msg.ToUserID + ">"})

		if strings.TrimSpace(finalMsg.String()) == "" {
			fmt.Print(".")
			continue
		}

		data := struct {
			Type    string `json:"type"`
			User    string `json:"user"`
			Channel string `json:"channel"`
			Text    string `json:"text"`
		}{"message", p.selfID, msg.Room, html.UnescapeString(finalMsg.String())}

		// TODO(ccf): look for an idiomatic way of doing limited writers
		b, err := json.Marshal(data)
		if err != nil {
			continue
		}

		wsMsg := string(b)
		if len(wsMsg) > 16*1024 {
			continue
		}
		fmt.Fprint(p.wsConn, wsMsg)
		time.Sleep(1 * time.Second) // https://api.slack.com/docs/rate-limits
	}
}

func (p *providerSlack) reconnect() {
	for {
		time.Sleep(1 * time.Second)
		if p.wsConn == nil {
			log.Println("slack: cannot reconnect")
			break
		}
		_, err := p.wsConn.Write([]byte(`{"type":"hello"}`))
		if err != nil {
			log.Println("slack: reconnecting")
			p.handshake()
			p.dial()
		}
	}
}
<|endoftext|>


<commit_before>package base

import (
	"errors"
	"net/http"
	"sync"
	"time"

	"github.com/couchbaselabs/sg-replicate"
)

const (
	DefaultContinuousRetryTimeMs = 500
)

type Replicator struct {
	replications map[string]sgreplicate.SGReplication
	lock         sync.RWMutex
}

type ActiveTask struct {
	TaskType         string      `json:"type"`
	ReplicationID    string      `json:"replication_id"`
	Continuous       bool        `json:"continuous"`
	Source           string      `json:"source"`
	Target           string      `json:"target"`
	DocsRead         uint32      `json:"docs_read"`
	DocsWritten      uint32      `json:"docs_written"`
	DocWriteFailures uint32      `json:"doc_write_failures"`
	StartLastSeq     uint32      `json:"start_last_seq"`
	EndLastSeq       interface{} `json:"end_last_seq"`
}

func NewReplicator() *Replicator {
	return &Replicator{
		replications: make(map[string]sgreplicate.SGReplication),
	}
}

func (r *Replicator) Replicate(params sgreplicate.ReplicationParameters, isCancel bool) (task *ActiveTask, err error) {

	replicationId, found := r.getReplicationForParams(params)

	if isCancel {
		// If replicationId isn't defined in the cancel request, attempt to look up the replication based on source, target
		if replicationId == "" {
			if !found {
				return nil, HTTPErrorf(http.StatusNotFound, "No replication found matching specified parameters")
			}
		}
		return nil, r.stopReplication(replicationId)
	} else {
		if found {
			return nil, HTTPErrorf(http.StatusConflict, "Replication already active for specified parameters")
		}
		replication, err := r.startReplication(params)
		return populateActiveTaskFromReplication(replication), err
	}
}

func (r *Replicator) ActiveTasks() (tasks []ActiveTask) {
	r.lock.RLock()
	defer r.lock.RUnlock()

	tasks = make([]ActiveTask, 0)
	for _, replication := range r.replications {
		task := populateActiveTaskFromReplication(replication)
		tasks = append(tasks, *task)
	}
	return tasks

}

func (r *Replicator) addReplication(rep sgreplicate.SGReplication) {
	r.lock.Lock()
	defer r.lock.Unlock()
	r.replications[rep.GetParameters().ReplicationId] = rep
}

func (r *Replicator) getReplication(repId string) sgreplicate.SGReplication {
	r.lock.RLock()
	defer r.lock.RUnlock()
	if rep, ok := r.replications[repId]; ok {
		return rep
	} else {
		return nil
	}
}

func (r *Replicator) getReplicationForParams(queryParams sgreplicate.ReplicationParameters) (replicationId string, found bool) {
	r.lock.RLock()
	defer r.lock.RUnlock()

	// Iterate over the known replications looking for a match
	for _, replication := range r.replications {
		repParams := replication.GetParameters()

		if queryParams.ReplicationId != "" && queryParams.ReplicationId == repParams.ReplicationId {
			return repParams.ReplicationId, true
		}

		if repParams.Equals(queryParams) {
			return repParams.ReplicationId, true
		}
	}
	return "", false
}

func (r *Replicator) removeReplication(repId string) {
	r.lock.Lock()
	defer r.lock.Unlock()
	delete(r.replications, repId)
}

// Starts a replication based on the provided replication config.
func (r *Replicator) startReplication(parameters sgreplicate.ReplicationParameters) (sgreplicate.SGReplication, error) {

	LogTo("Replicate", "Starting replication with parameters %+v", parameters)

	// Generate ID for the new replication, and add to the map of active replications
	if parameters.ReplicationId == "" {
		parameters.ReplicationId = CreateUUID()
	}

	switch parameters.Lifecycle {
	case sgreplicate.ONE_SHOT:
		return r.startOneShotReplication(parameters)
	case sgreplicate.CONTINUOUS:
		return r.startContinuousReplication(parameters)
	default:
		return nil, errors.New("Unknown replication lifecycle")
	}
}

func (r *Replicator) stopReplication(repId string) error {
	replication := r.getReplication(repId)
	if replication == nil {
		return HTTPErrorf(http.StatusNotFound, "No replication found matching specified replication ID")
	}
	err := replication.Stop()
	if err != nil {
		return err
	}
	r.removeReplication(repId)
	return nil
}

func (r *Replicator) startOneShotReplication(parameters sgreplicate.ReplicationParameters) (sgreplicate.SGReplication, error) {

	replication := sgreplicate.StartOneShotReplication(parameters)
	r.addReplication(replication)

	if parameters.Async {
		go r.runOneShotReplication(replication)
		return replication, nil
	} else {
		err := r.runOneShotReplication(replication)
		return replication, err

	}
}

// Calls WaitUntilDone to work the notification channel for the one-shot replication.  Used for both synchronous and async one-shot replications.
func (r *Replicator) runOneShotReplication(replication *sgreplicate.Replication) error {
	defer r.removeReplication(replication.GetParameters().ReplicationId)
	_, err := replication.WaitUntilDone()
	return err
}

func (r *Replicator) startContinuousReplication(parameters sgreplicate.ReplicationParameters) (sgreplicate.SGReplication, error) {

	notificationChan := make(chan sgreplicate.ContinuousReplicationNotification)

	factory := func(parameters sgreplicate.ReplicationParameters, notificationChan chan sgreplicate.ReplicationNotification) sgreplicate.Runnable {
		parameters.Lifecycle = sgreplicate.ONE_SHOT
		return sgreplicate.NewReplication(parameters, notificationChan)
	}

	retryTime := time.Millisecond * time.Duration(DefaultContinuousRetryTimeMs)
	replication := sgreplicate.NewContinuousReplication(parameters, factory, notificationChan, retryTime)
	r.addReplication(replication)
	LogTo("Replicate", "Started continuous replication: %v", replication)

	// Start goroutine to monitor notification channel, to remove the replication if it's terminated internally by sg-replicate
	go func(rep sgreplicate.SGReplication, notificationChan chan sgreplicate.ContinuousReplicationNotification) {
		defer r.removeReplication(rep.GetParameters().ReplicationId)
		for {
			select {
			case notification, ok := <-notificationChan:
				if !ok {
					LogTo("Replicate", "Replication %s was terminated.", rep.GetParameters().ReplicationId)
					return
				}
				LogTo("Replicate+", "Got notification %v", notification)
			}
		}
	}(replication, notificationChan)

	return replication, nil
}

func populateActiveTaskFromReplication (replication sgreplicate.SGReplication) (task *ActiveTask) {
	params := replication.GetParameters()
	stats := replication.GetStats()
	task = &ActiveTask{
		TaskType:         "replication",
		ReplicationID:    params.ReplicationId,
		Source:           params.GetSourceDbUrl(),
		Target:           params.GetTargetDbUrl(),
		Continuous:       params.Lifecycle == sgreplicate.CONTINUOUS,
		DocsRead:         stats.DocsRead,
		DocsWritten:      stats.DocsWritten,
		DocWriteFailures: stats.DocWriteFailures,
		StartLastSeq:     stats.StartLastSeq,
		EndLastSeq:       stats.EndLastSeq,
	}

	return
}<commit_msg>Stripped redundant `if replicationId == "" {` test, also return final task state on cancellation, previously response to cancel was null.<commit_after>package base

import (
	"errors"
	"net/http"
	"sync"
	"time"

	"github.com/couchbaselabs/sg-replicate"
)

const (
	DefaultContinuousRetryTimeMs = 500
)

type Replicator struct {
	replications map[string]sgreplicate.SGReplication
	lock         sync.RWMutex
}

type ActiveTask struct {
	TaskType         string      `json:"type"`
	ReplicationID    string      `json:"replication_id"`
	Continuous       bool        `json:"continuous"`
	Source           string      `json:"source"`
	Target           string      `json:"target"`
	DocsRead         uint32      `json:"docs_read"`
	DocsWritten      uint32      `json:"docs_written"`
	DocWriteFailures uint32      `json:"doc_write_failures"`
	StartLastSeq     uint32      `json:"start_last_seq"`
	EndLastSeq       interface{} `json:"end_last_seq"`
}

func NewReplicator() *Replicator {
	return &Replicator{
		replications: make(map[string]sgreplicate.SGReplication),
	}
}

func (r *Replicator) Replicate(params sgreplicate.ReplicationParameters, isCancel bool) (task *ActiveTask, err error) {

	replicationId, found := r.getReplicationForParams(params)

	if isCancel {
		if !found {
			return nil, HTTPErrorf(http.StatusNotFound, "No replication found matching specified parameters")
		}
		return r.stopReplication(replicationId)
	} else {
		if found {
			return nil, HTTPErrorf(http.StatusConflict, "Replication already active for specified parameters")
		}
		replication, err := r.startReplication(params)
		return populateActiveTaskFromReplication(replication), err
	}
}

func (r *Replicator) ActiveTasks() (tasks []ActiveTask) {
	r.lock.RLock()
	defer r.lock.RUnlock()

	tasks = make([]ActiveTask, 0)
	for _, replication := range r.replications {
		task := populateActiveTaskFromReplication(replication)
		tasks = append(tasks, *task)
	}
	return tasks

}

func (r *Replicator) addReplication(rep sgreplicate.SGReplication) {
	r.lock.Lock()
	defer r.lock.Unlock()
	r.replications[rep.GetParameters().ReplicationId] = rep
}

func (r *Replicator) getReplication(repId string) sgreplicate.SGReplication {
	r.lock.RLock()
	defer r.lock.RUnlock()
	if rep, ok := r.replications[repId]; ok {
		return rep
	} else {
		return nil
	}
}

func (r *Replicator) getReplicationForParams(queryParams sgreplicate.ReplicationParameters) (replicationId string, found bool) {
	r.lock.RLock()
	defer r.lock.RUnlock()

	// Iterate over the known replications looking for a match
	for _, replication := range r.replications {
		repParams := replication.GetParameters()

		if queryParams.ReplicationId != "" && queryParams.ReplicationId == repParams.ReplicationId {
			return repParams.ReplicationId, true
		}

		if repParams.Equals(queryParams) {
			return repParams.ReplicationId, true
		}
	}
	return "", false
}

func (r *Replicator) removeReplication(repId string) {
	r.lock.Lock()
	defer r.lock.Unlock()
	delete(r.replications, repId)
}

// Starts a replication based on the provided replication config.
func (r *Replicator) startReplication(parameters sgreplicate.ReplicationParameters) (sgreplicate.SGReplication, error) {

	LogTo("Replicate", "Starting replication with parameters %+v", parameters)

	// Generate ID for the new replication, and add to the map of active replications
	if parameters.ReplicationId == "" {
		parameters.ReplicationId = CreateUUID()
	}

	switch parameters.Lifecycle {
	case sgreplicate.ONE_SHOT:
		return r.startOneShotReplication(parameters)
	case sgreplicate.CONTINUOUS:
		return r.startContinuousReplication(parameters)
	default:
		return nil, errors.New("Unknown replication lifecycle")
	}
}

func (r *Replicator) stopReplication(repId string) (task *ActiveTask, err error) {
	replication := r.getReplication(repId)
	if replication == nil {
		return nil, HTTPErrorf(http.StatusNotFound, "No replication found matching specified replication ID")
	}
	err = replication.Stop()
	if err != nil {
		return nil, err
	}

	taskState := populateActiveTaskFromReplication(replication)

	r.removeReplication(repId)
	return taskState, nil
}

func (r *Replicator) startOneShotReplication(parameters sgreplicate.ReplicationParameters) (sgreplicate.SGReplication, error) {

	replication := sgreplicate.StartOneShotReplication(parameters)
	r.addReplication(replication)

	if parameters.Async {
		go r.runOneShotReplication(replication)
		return replication, nil
	} else {
		err := r.runOneShotReplication(replication)
		return replication, err

	}
}

// Calls WaitUntilDone to work the notification channel for the one-shot replication.  Used for both synchronous and async one-shot replications.
func (r *Replicator) runOneShotReplication(replication *sgreplicate.Replication) error {
	defer r.removeReplication(replication.GetParameters().ReplicationId)
	_, err := replication.WaitUntilDone()
	return err
}

func (r *Replicator) startContinuousReplication(parameters sgreplicate.ReplicationParameters) (sgreplicate.SGReplication, error) {

	notificationChan := make(chan sgreplicate.ContinuousReplicationNotification)

	factory := func(parameters sgreplicate.ReplicationParameters, notificationChan chan sgreplicate.ReplicationNotification) sgreplicate.Runnable {
		parameters.Lifecycle = sgreplicate.ONE_SHOT
		return sgreplicate.NewReplication(parameters, notificationChan)
	}

	retryTime := time.Millisecond * time.Duration(DefaultContinuousRetryTimeMs)
	replication := sgreplicate.NewContinuousReplication(parameters, factory, notificationChan, retryTime)
	r.addReplication(replication)
	LogTo("Replicate", "Started continuous replication: %v", replication)

	// Start goroutine to monitor notification channel, to remove the replication if it's terminated internally by sg-replicate
	go func(rep sgreplicate.SGReplication, notificationChan chan sgreplicate.ContinuousReplicationNotification) {
		defer r.removeReplication(rep.GetParameters().ReplicationId)
		for {
			select {
			case notification, ok := <-notificationChan:
				if !ok {
					LogTo("Replicate", "Replication %s was terminated.", rep.GetParameters().ReplicationId)
					return
				}
				LogTo("Replicate+", "Got notification %v", notification)
			}
		}
	}(replication, notificationChan)

	return replication, nil
}

func populateActiveTaskFromReplication(replication sgreplicate.SGReplication) (task *ActiveTask) {
	params := replication.GetParameters()
	stats := replication.GetStats()
	task = &ActiveTask{
		TaskType:         "replication",
		ReplicationID:    params.ReplicationId,
		Source:           params.GetSourceDbUrl(),
		Target:           params.GetTargetDbUrl(),
		Continuous:       params.Lifecycle == sgreplicate.CONTINUOUS,
		DocsRead:         stats.DocsRead,
		DocsWritten:      stats.DocsWritten,
		DocWriteFailures: stats.DocWriteFailures,
		StartLastSeq:     stats.StartLastSeq,
		EndLastSeq:       stats.EndLastSeq,
	}

	return
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"errors"
	"flag"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

var (
	Translations map[string]string
	Exclusions   []string
	Replacements int
)

func BuildTranslationsAndExclusions() {
	Translations = make(map[string]string)
	Translations["BITCOIN"] = "LITECOIN"
	Translations["Bitcoin"] = "Litecoin"
	Translations["bitcoin"] = "litecoin"
	Translations["Bitcion"] = "Litecion"
	Translations["BTC"] = "LTC"
	Translations["btc"] = "ltc"
	Translations["بيتكوين"] = "Litecoin"
	Translations["Біткойн"] = "Litecoin"
	Translations["біткойн"] = "litecoin"
	Translations["биткойн"] = "Litecoin"
	Translations["Биткойн"] = "Litecoin"
	Translations["Bitconi"] = "Liteconi"
	Translations["Bitcoini"] = "Litecoini"
	Translations["הביטקוין"] = "לייטקוין"
	Translations["ביטקוין"] = "ללייטקוין"
	Translations["비트코인"] = "라이트코인" // KR: bitcoins -> litecoins
	Translations["بیت‌کوین"] = "Litecoin"
	Translations["بیت کوین"] = "litecoin"
	Translations["बिटकोइन"] = "Litecoin"
	Translations["比特币"] = "莱特币"
	Translations["Bitmon"] = "Litecoin"
	Translations["Bitmono"] = "Litecoin"
	Translations["bitmona"] = "litecoin"
	Translations["비트코인을"] = "라이트코인을" // KR: Bitcoin -> Litecoin
	Translations["비트코인들을"] = "라이트코인들을" // KR: BITCOINS -> LITECOINS
	Translations["БИТКОЙНЫ"] = "ЛАЙТКОИНЫ" // RU: BITCOINS -> LITECOINS
	Translations["ЛАЙТКОИНЫ"] = "лайткоин" // RU: Bitcoin -> Litecoin
	Exclusions = append(Exclusions, []string{"The Bitcoin Core Developers", "BitcoinGUI", "bitcoin-core", ".cpp"}...)
}

func ContainsTranslationString(input []byte) bool {
	inputStr := string(input)
	for x, _ := range Translations {
		if strings.Contains(inputStr, x) {
			return true
		}
	}
	return false
}

func ContainsExclusionString(input []byte) bool {
	inputStr := string(input)
	for _, x := range Exclusions {
		if strings.Contains(inputStr, x) {
			return true
		}
	}
	return false
}

func ProcessAndModifyLine(input []byte) []byte {
	if ContainsExclusionString(input) {
		return input
	}

	if !ContainsTranslationString(input) {
		return input
	}

	output := []byte{}
	for x, y := range Translations {
		if strings.Contains(string(input), x) {
			Replacements++
			output = bytes.Replace(input, []byte(x), []byte(y), -1)
		}
	}
	return output
}

func ProcessFile(file string) error {
	f, err := os.Open(file)
	if err != nil {
		return err
	}

	log.Printf("Processing %s..", file)
	r := bufio.NewReaderSize(f, 4*1024)
	var outputFile []byte
	line, prefix, err := r.ReadLine()

	for err == nil && !prefix {
		result := ProcessAndModifyLine(line)
		outputFile = append(outputFile, result...)
		outputFile = append(outputFile, []byte(GetOSNewLine())...)
		line, prefix, err = r.ReadLine()
	}

	if prefix {
		return errors.New("Buffer size is too small.")
	}

	if err != io.EOF {
		return err
	}

	if !strings.Contains(file, "bitcoin_de.ts") { // uglyyyy
		outputFile = outputFile[:len(outputFile)-len(GetOSNewLine())]
		err = ioutil.WriteFile(file, outputFile, 0644)
	}
	if err != nil {
		return err
	}

	return nil
}

func GetOSNewLine() string {
	switch runtime.GOOS {
	case "Windows":
		return "\r\n"
	case "darwin":
		return "\r"
	default:
		return "\n"
	}
}

func GetOSPathSlash() string {
	if runtime.GOOS == "windows" {
		return "\\"
	}
	return "/"
}

func main() {
	var srcDir string
	flag.StringVar(&srcDir, "srcdir", "", "The source dir of the locale files.")
	flag.Parse()

	if srcDir == "" {
		log.Fatal("A source directory of the locale files must be specified.")
	}

	files, err := ioutil.ReadDir(srcDir)
	if err != nil {
		log.Fatal(err)
	}

	BuildTranslationsAndExclusions()

	for _, file := range files {
		if filepath.Ext(file.Name()) == ".qm" {
			continue
		}

		filePath := srcDir + GetOSPathSlash() + file.Name()
		err := ProcessFile(filePath)
		if err != nil {
			log.Printf("\nError processing file %s. Error: %s", filePath, err)
			continue
		}
		log.Println("OK")
	}

	log.Printf("Done! Replaced %d occurences.\n", Replacements)
}
<commit_msg>Update translations<commit_after>package main

import (
	"bufio"
	"bytes"
	"errors"
	"flag"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

var (
	Translations map[string]string
	Exclusions   []string
	Replacements int
)

func BuildTranslationsAndExclusions() {
	Translations = make(map[string]string)
	Translations["BITCOIN"] = "LITECOIN"
	Translations["Bitcoin"] = "Litecoin"
	Translations["bitcoin"] = "litecoin"
	Translations["Bitcion"] = "Litecion"
	Translations["BTC"] = "LTC"
	Translations["btc"] = "ltc"
	Translations["بيتكوين"] = "Litecoin"
	Translations["Біткойн"] = "Litecoin"
	Translations["біткойн"] = "litecoin"
	Translations["биткойн"] = "Litecoin"
	Translations["Биткойн"] = "Litecoin"
	Translations["Bitconi"] = "Liteconi"
	Translations["Bitcoini"] = "Litecoini"
	Translations["הביטקוין"] = "לייטקוין"
	Translations["ביטקוין"] = "ללייטקוין"
	Translations["비트코인"] = "라이트코인" // KR: bitcoins -> litecoins
	Translations["بیت‌کوین"] = "Litecoin"
	Translations["بیت کوین"] = "litecoin"
	Translations["बिटकोइन"] = "Litecoin"
	Translations["比特币"] = "莱特币"
	Translations["Bitmon"] = "Litecoin"
	Translations["Bitmono"] = "Litecoin"
	Translations["bitmona"] = "litecoin"
	Translations["비트코인을"] = "라이트코인을" // KR: Bitcoin -> Litecoin
	Translations["비트코인들을"] = "라이트코인들을" // KR: BITCOINS -> LITECOINS
	Translations["БИТКОЙНЫ"] = "ЛАЙТКОИНЫ" // RU: BITCOINS -> LITECOINS
	Translations["биткоин"] = "лайткоин" // RU: Bitcoin -> Litecoin
	Exclusions = append(Exclusions, []string{"The Bitcoin Core Developers", "BitcoinGUI", "bitcoin-core", ".cpp"}...)
}

func ContainsTranslationString(input []byte) bool {
	inputStr := string(input)
	for x, _ := range Translations {
		if strings.Contains(inputStr, x) {
			return true
		}
	}
	return false
}

func ContainsExclusionString(input []byte) bool {
	inputStr := string(input)
	for _, x := range Exclusions {
		if strings.Contains(inputStr, x) {
			return true
		}
	}
	return false
}

func ProcessAndModifyLine(input []byte) []byte {
	if ContainsExclusionString(input) {
		return input
	}

	if !ContainsTranslationString(input) {
		return input
	}

	output := []byte{}
	for x, y := range Translations {
		if strings.Contains(string(input), x) {
			Replacements++
			output = bytes.Replace(input, []byte(x), []byte(y), -1)
		}
	}
	return output
}

func ProcessFile(file string) error {
	f, err := os.Open(file)
	if err != nil {
		return err
	}

	log.Printf("Processing %s..", file)
	r := bufio.NewReaderSize(f, 4*1024)
	var outputFile []byte
	line, prefix, err := r.ReadLine()

	for err == nil && !prefix {
		result := ProcessAndModifyLine(line)
		outputFile = append(outputFile, result...)
		outputFile = append(outputFile, []byte(GetOSNewLine())...)
		line, prefix, err = r.ReadLine()
	}

	if prefix {
		return errors.New("Buffer size is too small.")
	}

	if err != io.EOF {
		return err
	}

	if !strings.Contains(file, "bitcoin_de.ts") { // uglyyyy
		outputFile = outputFile[:len(outputFile)-len(GetOSNewLine())]
		err = ioutil.WriteFile(file, outputFile, 0644)
	}
	if err != nil {
		return err
	}

	return nil
}

func GetOSNewLine() string {
	switch runtime.GOOS {
	case "Windows":
		return "\r\n"
	case "darwin":
		return "\r"
	default:
		return "\n"
	}
}

func GetOSPathSlash() string {
	if runtime.GOOS == "windows" {
		return "\\"
	}
	return "/"
}

func main() {
	var srcDir string
	flag.StringVar(&srcDir, "srcdir", "", "The source dir of the locale files.")
	flag.Parse()

	if srcDir == "" {
		log.Fatal("A source directory of the locale files must be specified.")
	}

	files, err := ioutil.ReadDir(srcDir)
	if err != nil {
		log.Fatal(err)
	}

	BuildTranslationsAndExclusions()

	for _, file := range files {
		if filepath.Ext(file.Name()) == ".qm" {
			continue
		}

		filePath := srcDir + GetOSPathSlash() + file.Name()
		err := ProcessFile(filePath)
		if err != nil {
			log.Printf("\nError processing file %s. Error: %s", filePath, err)
			continue
		}
		log.Println("OK")
	}

	log.Printf("Done! Replaced %d occurences.\n", Replacements)
}
<|endoftext|>


<commit_before><commit_msg>after code review<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2015, Emir Pasic. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package btree implements a B tree.
//
// Structure is not thread safe.
//
// References: https://en.wikipedia.org/wiki/B-tree
package btree

import (
	"bytes"
	"fmt"
	"github.com/emirpasic/gods/trees"
	"github.com/emirpasic/gods/utils"
	"strings"
)

func assertTreeImplementation() {
	var _ trees.Tree = (*Tree)(nil)
}

// Tree holds elements of the B-tree
type Tree struct {
	Root       *Node            // Root node
	Comparator utils.Comparator // Key comparator
	size       int              // Total number of keys in the tree
	m          int              // order (maximum number of children)
}

// Node is a single element within the tree
type Node struct {
	Parent   *Node
	Entries  []*Entry // Contained keys in node
	Children []*Node  // Children nodes
}

// Entry represents the key-value pair contained within nodes
type Entry struct {
	Key   interface{}
	Value interface{}
}

// NewWith instantiates a B-tree with the order (maximum number of children) and a custom key comparator.
func NewWith(order int, comparator utils.Comparator) *Tree {
	if order < 2 {
		panic("Invalid order, should be at least 2")
	}
	return &Tree{m: order, Comparator: comparator}
}

// NewWithIntComparator instantiates a B-tree with the order (maximum number of children) and the IntComparator, i.e. keys are of type int.
func NewWithIntComparator(order int) *Tree {
	return NewWith(order, utils.IntComparator)
}

// NewWithStringComparator instantiates a B-tree with the order (maximum number of children) and the StringComparator, i.e. keys are of type string.
func NewWithStringComparator(order int) *Tree {
	return NewWith(order, utils.StringComparator)
}

// Put inserts key-value pair node into the tree.
// If key already exists, then its value is updated with the new value.
// Key should adhere to the comparator's type assertion, otherwise method panics.
func (tree *Tree) Put(key interface{}, value interface{}) {
	entry := &Entry{Key: key, Value: value}

	if tree.Root == nil {
		tree.Root = &Node{Entries: []*Entry{entry}, Children: []*Node{}}
		tree.size++
		return
	}

	if tree.insert(tree.Root, entry) {
		tree.size++
	}
}

// Get searches the node in the tree by key and returns its value or nil if key is not found in tree.
// Second return parameter is true if key was found, otherwise false.
// Key should adhere to the comparator's type assertion, otherwise method panics.
func (tree *Tree) Get(key interface{}) (value interface{}, found bool) {
	if tree.Empty() {
		return nil, false
	}
	node := tree.Root
	for {
		index, found := tree.search(node, key)
		if found {
			return node.Entries[index].Value, true
		}
		if tree.isLeaf(node) {
			return nil, false
		}
		node = node.Children[index]
	}
}

// Remove remove the node from the tree by key.
// Key should adhere to the comparator's type assertion, otherwise method panics.
func (tree *Tree) Remove(key interface{}) {
	// TODO
}

// Empty returns true if tree does not contain any nodes
func (tree *Tree) Empty() bool {
	return tree.size == 0
}

// Size returns number of nodes in the tree.
func (tree *Tree) Size() int {
	return tree.size
}

// Keys returns all keys in-order
func (tree *Tree) Keys() []interface{} {
	return nil // TODO
}

// Values returns all values in-order based on the key.
func (tree *Tree) Values() []interface{} {
	return nil // TODO
}

// Clear removes all nodes from the tree.
func (tree *Tree) Clear() {
	tree.Root = nil
	tree.size = 0
}

// Height returns the height of the tree.
func (tree *Tree) Height() int {
	return tree.Root.height()
}

// String returns a string representation of container (for debugging purposes)
func (tree *Tree) String() string {
	var buffer bytes.Buffer
	buffer.WriteString("BTree\n")
	if !tree.Empty() {
		tree.output(&buffer, tree.Root, 0, true)
	}
	return buffer.String()
}

func (entry *Entry) String() string {
	return fmt.Sprintf("%v", entry.Key)
}

func (tree *Tree) output(buffer *bytes.Buffer, node *Node, level int, isTail bool) {
	for e := 0; e < len(node.Entries)+1; e++ {
		if e < len(node.Children) {
			tree.output(buffer, node.Children[e], level+1, true)
		}
		if e < len(node.Entries) {
			buffer.WriteString(strings.Repeat("   ", level))
			buffer.WriteString(fmt.Sprintf("%v", node.Entries[e].Key) + "\n")
		}
	}
}

func (node *Node) height() int {
	height := 0
	for ; node != nil; node = node.Children[0] {
		height++
		if len(node.Children) == 0 {
			break
		}
	}
	return height
}

func (tree *Tree) isLeaf(node *Node) bool {
	return len(node.Children) == 0
}

func (tree *Tree) isFull(node *Node) bool {
	return len(node.Entries) == tree.maxEntries()
}

func (tree *Tree) shouldSplit(node *Node) bool {
	return len(node.Entries) > tree.maxEntries()
}

func (tree *Tree) maxChildren() int {
	return tree.m
}

func (tree *Tree) maxEntries() int {
	return tree.m - 1
}

func (tree *Tree) middle() int {
	return (tree.m - 1) / 2 // "-1" to favor right nodes to have more keys when splitting
}

func (tree *Tree) search(node *Node, key interface{}) (index int, found bool) {
	low, high := 0, len(node.Entries)-1
	var mid int
	for low <= high {
		mid = (high + low) / 2
		compare := tree.Comparator(key, node.Entries[mid].Key)
		switch {
		case compare > 0:
			low = mid + 1
		case compare < 0:
			high = mid - 1
		case compare == 0:
			return mid, true
		}
	}
	return low, false
}

func (tree *Tree) insert(node *Node, entry *Entry) (inserted bool) {
	if tree.isLeaf(node) {
		return tree.insertIntoLeaf(node, entry)
	}
	return tree.insertIntoInternal(node, entry)
}

func (tree *Tree) insertIntoLeaf(node *Node, entry *Entry) (inserted bool) {
	insertPosition, found := tree.search(node, entry.Key)
	if found {
		node.Entries[insertPosition] = entry
		return false
	}
	// Insert entry's key in the middle of the node
	node.Entries = append(node.Entries, nil)
	copy(node.Entries[insertPosition+1:], node.Entries[insertPosition:])
	node.Entries[insertPosition] = entry
	tree.split(node)
	return true
}

func (tree *Tree) insertIntoInternal(node *Node, entry *Entry) (inserted bool) {
	insertPosition, found := tree.search(node, entry.Key)
	if found {
		node.Entries[insertPosition] = entry
		return false
	}
	return tree.insert(node.Children[insertPosition], entry)
}

func (tree *Tree) split(node *Node) {
	if !tree.shouldSplit(node) {
		return
	}

	if node == tree.Root {
		tree.splitRoot()
		return
	}

	tree.splitNonRoot(node)
}

func (tree *Tree) splitNonRoot(node *Node) {
	middle := tree.middle()
	parent := node.Parent
	if node.Parent == nil {
		panic("test") //TODO
	}

	left := &Node{Entries: append([]*Entry(nil), node.Entries[:middle]...), Parent: parent}
	right := &Node{Entries: append([]*Entry(nil), node.Entries[middle+1:]...), Parent: parent}

	// Move children from the node to be split into left and right nodes
	if !tree.isLeaf(node) {
		left.Children = node.Children[:middle+1]
		right.Children = node.Children[middle+1:]
	}

	insertPosition, _ := tree.search(parent, node.Entries[middle].Key)

	// Insert middle key into parent
	parent.Entries = append(parent.Entries, nil)
	copy(parent.Entries[insertPosition+1:], parent.Entries[insertPosition:])
	parent.Entries[insertPosition] = node.Entries[middle]

	// Set child left of inserted key in parent to the created left node
	parent.Children[insertPosition] = left

	// Set child right of inserted key in parent to the created right node
	parent.Children = append(parent.Children, nil)
	copy(parent.Children[insertPosition+2:], parent.Children[insertPosition+1:])
	parent.Children[insertPosition+1] = right

	tree.split(parent)
}

func (tree *Tree) splitRoot() {
	middle := tree.middle()

	left := &Node{Entries: append([]*Entry(nil), tree.Root.Entries[:middle]...)}
	right := &Node{Entries: append([]*Entry(nil), tree.Root.Entries[middle+1:]...)}

	// Move children from the node to be split into left and right nodes
	if !tree.isLeaf(tree.Root) {
		left.Children = tree.Root.Children[:middle+1]
		right.Children = tree.Root.Children[middle+1:]
	}

	// Root is a node with one entry and two children (left and right)
	newRoot := &Node{
		Entries:  []*Entry{tree.Root.Entries[middle]},
		Children: []*Node{left, right},
	}

	left.Parent = newRoot
	right.Parent = newRoot
	tree.Root = newRoot
}
<commit_msg>- btree put fixes<commit_after>// Copyright (c) 2015, Emir Pasic. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package btree implements a B tree.
//
// Structure is not thread safe.
//
// References: https://en.wikipedia.org/wiki/B-tree
package btree

import (
	"bytes"
	"fmt"
	"github.com/emirpasic/gods/trees"
	"github.com/emirpasic/gods/utils"
	"strings"
)

func assertTreeImplementation() {
	var _ trees.Tree = (*Tree)(nil)
}

// Tree holds elements of the B-tree
type Tree struct {
	Root       *Node            // Root node
	Comparator utils.Comparator // Key comparator
	size       int              // Total number of keys in the tree
	m          int              // order (maximum number of children)
}

// Node is a single element within the tree
type Node struct {
	Parent   *Node
	Entries  []*Entry // Contained keys in node
	Children []*Node  // Children nodes
}

// Entry represents the key-value pair contained within nodes
type Entry struct {
	Key   interface{}
	Value interface{}
}

// NewWith instantiates a B-tree with the order (maximum number of children) and a custom key comparator.
func NewWith(order int, comparator utils.Comparator) *Tree {
	if order < 2 {
		panic("Invalid order, should be at least 2")
	}
	return &Tree{m: order, Comparator: comparator}
}

// NewWithIntComparator instantiates a B-tree with the order (maximum number of children) and the IntComparator, i.e. keys are of type int.
func NewWithIntComparator(order int) *Tree {
	return NewWith(order, utils.IntComparator)
}

// NewWithStringComparator instantiates a B-tree with the order (maximum number of children) and the StringComparator, i.e. keys are of type string.
func NewWithStringComparator(order int) *Tree {
	return NewWith(order, utils.StringComparator)
}

// Put inserts key-value pair node into the tree.
// If key already exists, then its value is updated with the new value.
// Key should adhere to the comparator's type assertion, otherwise method panics.
func (tree *Tree) Put(key interface{}, value interface{}) {
	entry := &Entry{Key: key, Value: value}

	if tree.Root == nil {
		tree.Root = &Node{Entries: []*Entry{entry}, Children: []*Node{}}
		tree.size++
		return
	}

	if tree.insert(tree.Root, entry) {
		tree.size++
	}
}

// Get searches the node in the tree by key and returns its value or nil if key is not found in tree.
// Second return parameter is true if key was found, otherwise false.
// Key should adhere to the comparator's type assertion, otherwise method panics.
func (tree *Tree) Get(key interface{}) (value interface{}, found bool) {
	if tree.Empty() {
		return nil, false
	}
	node := tree.Root
	for {
		index, found := tree.search(node, key)
		if found {
			return node.Entries[index].Value, true
		}
		if tree.isLeaf(node) {
			return nil, false
		}
		node = node.Children[index]
	}
}

// Remove remove the node from the tree by key.
// Key should adhere to the comparator's type assertion, otherwise method panics.
func (tree *Tree) Remove(key interface{}) {
	// TODO
}

// Empty returns true if tree does not contain any nodes
func (tree *Tree) Empty() bool {
	return tree.size == 0
}

// Size returns number of nodes in the tree.
func (tree *Tree) Size() int {
	return tree.size
}

// Keys returns all keys in-order
func (tree *Tree) Keys() []interface{} {
	return nil // TODO
}

// Values returns all values in-order based on the key.
func (tree *Tree) Values() []interface{} {
	return nil // TODO
}

// Clear removes all nodes from the tree.
func (tree *Tree) Clear() {
	tree.Root = nil
	tree.size = 0
}

// Height returns the height of the tree.
func (tree *Tree) Height() int {
	return tree.Root.height()
}

// String returns a string representation of container (for debugging purposes)
func (tree *Tree) String() string {
	var buffer bytes.Buffer
	buffer.WriteString("BTree\n")
	if !tree.Empty() {
		tree.output(&buffer, tree.Root, 0, true)
	}
	return buffer.String()
}

func (entry *Entry) String() string {
	return fmt.Sprintf("%v", entry.Key)
}

func (tree *Tree) output(buffer *bytes.Buffer, node *Node, level int, isTail bool) {
	for e := 0; e < len(node.Entries)+1; e++ {
		if e < len(node.Children) {
			tree.output(buffer, node.Children[e], level+1, true)
		}
		if e < len(node.Entries) {
			buffer.WriteString(strings.Repeat("   ", level))
			buffer.WriteString(fmt.Sprintf("%v", node.Entries[e].Key) + "\n")
		}
	}
}

func (node *Node) height() int {
	height := 0
	for ; node != nil; node = node.Children[0] {
		height++
		if len(node.Children) == 0 {
			break
		}
	}
	return height
}

func (tree *Tree) isLeaf(node *Node) bool {
	return len(node.Children) == 0
}

func (tree *Tree) isFull(node *Node) bool {
	return len(node.Entries) == tree.maxEntries()
}

func (tree *Tree) shouldSplit(node *Node) bool {
	return len(node.Entries) > tree.maxEntries()
}

func (tree *Tree) maxChildren() int {
	return tree.m
}

func (tree *Tree) maxEntries() int {
	return tree.m - 1
}

func (tree *Tree) middle() int {
	return (tree.m - 1) / 2 // "-1" to favor right nodes to have more keys when splitting
}

func (tree *Tree) search(node *Node, key interface{}) (index int, found bool) {
	low, high := 0, len(node.Entries)-1
	var mid int
	for low <= high {
		mid = (high + low) / 2
		compare := tree.Comparator(key, node.Entries[mid].Key)
		switch {
		case compare > 0:
			low = mid + 1
		case compare < 0:
			high = mid - 1
		case compare == 0:
			return mid, true
		}
	}
	return low, false
}

func (tree *Tree) insert(node *Node, entry *Entry) (inserted bool) {
	if tree.isLeaf(node) {
		return tree.insertIntoLeaf(node, entry)
	}
	return tree.insertIntoInternal(node, entry)
}

func (tree *Tree) insertIntoLeaf(node *Node, entry *Entry) (inserted bool) {
	insertPosition, found := tree.search(node, entry.Key)
	if found {
		node.Entries[insertPosition] = entry
		return false
	}
	// Insert entry's key in the middle of the node
	node.Entries = append(node.Entries, nil)
	copy(node.Entries[insertPosition+1:], node.Entries[insertPosition:])
	node.Entries[insertPosition] = entry
	tree.split(node)
	return true
}

func (tree *Tree) insertIntoInternal(node *Node, entry *Entry) (inserted bool) {
	insertPosition, found := tree.search(node, entry.Key)
	if found {
		node.Entries[insertPosition] = entry
		return false
	}
	return tree.insert(node.Children[insertPosition], entry)
}

func (tree *Tree) split(node *Node) {
	if !tree.shouldSplit(node) {
		return
	}

	if node == tree.Root {
		tree.splitRoot()
		return
	}

	tree.splitNonRoot(node)
}

func (tree *Tree) splitNonRoot(node *Node) {
	middle := tree.middle()
	parent := node.Parent

	left := &Node{Entries: append([]*Entry(nil), node.Entries[:middle]...), Parent: parent}
	right := &Node{Entries: append([]*Entry(nil), node.Entries[middle+1:]...), Parent: parent}

	// Move children from the node to be split into left and right nodes
	if !tree.isLeaf(node) {
		left.Children = node.Children[:middle+1]
		right.Children = node.Children[middle+1:]
		setParent(left.Children, left)
		setParent(right.Children, right)
	}

	insertPosition, _ := tree.search(parent, node.Entries[middle].Key)

	// Insert middle key into parent
	parent.Entries = append(parent.Entries, nil)
	copy(parent.Entries[insertPosition+1:], parent.Entries[insertPosition:])
	parent.Entries[insertPosition] = node.Entries[middle]

	// Set child left of inserted key in parent to the created left node
	parent.Children[insertPosition] = left

	// Set child right of inserted key in parent to the created right node
	parent.Children = append(parent.Children, nil)
	copy(parent.Children[insertPosition+2:], parent.Children[insertPosition+1:])
	parent.Children[insertPosition+1] = right

	tree.split(parent)
}

func (tree *Tree) splitRoot() {
	middle := tree.middle()

	left := &Node{Entries: append([]*Entry(nil), tree.Root.Entries[:middle]...)}
	right := &Node{Entries: append([]*Entry(nil), tree.Root.Entries[middle+1:]...)}

	// Move children from the node to be split into left and right nodes
	if !tree.isLeaf(tree.Root) {
		left.Children = tree.Root.Children[:middle+1]
		right.Children = tree.Root.Children[middle+1:]
		setParent(left.Children, left)
		setParent(right.Children, right)
	}

	// Root is a node with one entry and two children (left and right)
	newRoot := &Node{
		Entries:  []*Entry{tree.Root.Entries[middle]},
		Children: []*Node{left, right},
	}

	left.Parent = newRoot
	right.Parent = newRoot
	tree.Root = newRoot
}

func setParent(nodes []*Node, parent *Node) {
	for _, node := range nodes {
		node.Parent = parent
	}
}
<|endoftext|>


<commit_before>package sqlite

import "database/sql"
import "../sqlconstants/"
import _ "github.com/mattn/go-sqlite3"
import "fmt"
import "errors"

type connection struct {
	db     *sql.DB
	dbName string
}

func initDatabase() error {

}

func NewConnection(fileName string) (*connection, error) {

	if fileName == "" {

		fileName = file
	}

	db, err := sql.Open(sqlcontants.DB_TYPE_SQLITE3, sqlconstants.SQLITE3_CONNECTION_STRING)

	if err != nil {
		fmt.Println(err)
		return nil, err
	}

	return &connection{db, fileName}, nil

}

func (Conn *connection) Close() error {
	return Conn.Close()
}

func (Conn *connection) CheckTableExists(tableName string) (bool, error) {
	rows, err := Conn.db.Query(check_if_table_exists, "table", tableName)

	defer rows.Close()

	if err != nil {
		fmt.Println(err)
		return false, err
	}

	return rows.Next(), nil

}

func (Conn *connection) CreateTable(createStatement string, tableName string) error {
	if createStatement == "" {
		return errors.New("Create Statement cannot be empty")

	}

	rowsExist, err := Conn.CheckTableExists(tableName)

	if err != nil {
		return err
	}

	if !rowsExist {

		_, err = Conn.db.Exec(createStatement)
		if err != nil {
			return err
		}

		rowsExist, err = Conn.CheckTableExists(tableName)

		if err != nil {
			return err
		}

		if rowsExist != true {
			return errors.New("Error => Could not create table " + tableName)
		}
	}

	return nil
}

func (Conn *connection) Insert(insertStatement string, data ...interface{}) error {

	if insertStatement == "" {
		return errors.New("Insert Statement cannot be blank")

	}

	if len(data) == 0 {
		return errors.New("data cannot be empty")

	}

	tx, err := Conn.db.Begin()
	if err != nil {
		fmt.Println(err)
		return err
	}

	stmt, err := tx.Prepare(insertStatement)

	if err != nil {
		fmt.Println("Could not prepare statment = >", err)
		return err
	}

	_, err = stmt.Exec(data)

	err = tx.Commit()

	if err != nil {
		return err
	}

	defer stmt.Close()

	return nil
}
<commit_msg>Got current functions in there to work, next stop is to get the select to work<commit_after>package sqlite

import "database/sql"
import "../sqlconstants"
import _ "github.com/mattn/go-sqlite3"
import "fmt"
import "errors"

type connection struct {
	db *sql.DB
}

func NewConnection() (*connection, error) {

	db, err := sql.Open(sqlconstants.CurrentVendor(), sqlconstants.SQLITE3_CONNECTION_STRING)

	if err != nil {
		return nil, err
	}

	return &connection{db}, nil

}

func (Conn *connection) Close() error {
	return Conn.db.Close()
}

func (Conn *connection) CheckTableExists(tableName string) (bool, error) {
	rows, err := Conn.db.Query(sqlconstants.SQLITE3_CHECK_IF_TABLE_EXISTS, "table", tableName)

	defer rows.Close()

	if err != nil {
		fmt.Println(err)
		return false, err
	}

	return rows.Next(), nil

}

/*
func getColumNamesFromSelectQuery(query string) ([]sqlData, error) {

}*/
/*
func (Conn *connection) Select(query string) ([]sqlData, error) {
	rows, err := Conn.db.Query(query, data)

	defer rows.Close()

	if err != nil {
		fmt.Println(err)
		return nil, err
	}

	//cols, err := rows.Columns()
	_, err = rows.Columns()

	if err != nil {
		return nil, err
	}

	return nil, nil

}*/

func (Conn *connection) InitTable(createStatement string, tableName string) error {
	if createStatement == "" {
		return errors.New("Create Statement cannot be empty")

	}

	rowsExist, err := Conn.CheckTableExists(tableName)

	if err != nil {
		return err
	}

	if !rowsExist {

		_, err = Conn.db.Exec(createStatement)
		if err != nil {
			return err
		}

		rowsExist, err = Conn.CheckTableExists(tableName)

		if err != nil {
			return err
		}

		if rowsExist != true {
			return errors.New("Error => Could not create table " + tableName)
		}
	}

	return nil
}

func (Conn *connection) Insert(insertStatement string, data ...interface{}) error {

	if insertStatement == "" {
		return errors.New("Insert Statement cannot be blank")

	}

	if len(data) == 0 {
		return errors.New("data cannot be empty")

	}

	tx, err := Conn.db.Begin()
	if err != nil {
		fmt.Println(err)
		return err
	}

	stmt, err := tx.Prepare(insertStatement)

	if err != nil {
		fmt.Println("Could not prepare statment = >", err)
		return err
	}

	_, err = stmt.Exec(data)

	err = tx.Commit()

	defer stmt.Close()

	return err

}
<|endoftext|>


<commit_before>package tutum

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"reflect"
	"testing"
)

func Test_ListRegions(t *testing.T) {
	User = "test"
	ApiKey = "test"

	fake_response, err := MockupResponse("listregions.json")
	if err != nil {
		t.Fatal(err)
	}
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(200)
		w.Header().Set("Content-Type", "application/json")
		fmt.Fprintln(w, fake_response)
	}))

	defer server.Close()
	url := server.URL + "/api/v1/region/"

	res, err := http.Get(url)
	if err != nil {
		t.Fatal(err)
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		t.Fatal(err)
	}

	var response RegionListResponse
	err = json.Unmarshal(body, &response)
	if err != nil {
		t.Fatal(err)
	}

	BaseUrl = server.URL + "/api/v1/"

	test_response, err := ListRegions()
	if err != nil {
		t.Fatal(err)
	}

	if reflect.DeepEqual(test_response, response) != true {
		t.Fatal("Invalid output")
	}
}

func Test_GetRegion(t *testing.T) {
	User = "test"
	ApiKey = "test"

	fake_response, err := MockupResponse("region.json")
	if err != nil {
		t.Fatal(err)
	}

	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(200)
		w.Header().Set("Content-Type", "application/json")
		fmt.Fprintln(w, fake_response)
	}))

	defer server.Close()
	url := server.URL + "/api/v1/region/" + fake_provider + "/" + fake_location_name + "/"

	res, err := http.Get(url)
	if err != nil {
		t.Fatal(err)
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		t.Fatal(err)
	}

	var response Region
	err = json.Unmarshal(body, &response)
	if err != nil {
		t.Fatal(err)
	}

	BaseUrl = server.URL + "/api/v1/"
	test_response, err := GetRegion(fake_provider, fake_location_name)
	if err != nil {
		t.Fatal(err)
	}
	if reflect.DeepEqual(test_response, response) != true {
		t.Fatal("Invalid output")
	}
}
<commit_msg>fix region test<commit_after>package tutum

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"reflect"
	"testing"
)

func Test_ListRegions(t *testing.T) {
	User = "test"
	ApiKey = "test"

	fake_response, err := MockupResponse("listregions.json")
	if err != nil {
		t.Fatal(err)
	}
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(200)
		w.Header().Set("Content-Type", "application/json")
		fmt.Fprintln(w, fake_response)
	}))

	defer server.Close()
	url := server.URL + "/api/v1/region/"

	res, err := http.Get(url)
	if err != nil {
		t.Fatal(err)
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		t.Fatal(err)
	}

	var response RegionListResponse
	err = json.Unmarshal(body, &response)
	if err != nil {
		t.Fatal(err)
	}

	BaseUrl = server.URL + "/api/v1/"

	test_response, err := ListRegions()
	if err != nil {
		t.Fatal(err)
	}

	if reflect.DeepEqual(test_response, response) != true {
		t.Fatal("Invalid output")
	}
}

func Test_GetRegion(t *testing.T) {
	User = "test"
	ApiKey = "test"

	fake_response, err := MockupResponse("region.json")
	if err != nil {
		t.Fatal(err)
	}

	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(200)
		w.Header().Set("Content-Type", "application/json")
		fmt.Fprintln(w, fake_response)
	}))

	defer server.Close()
	url := server.URL + "/api/v1/region/" + fake_provider + "/" + fake_location_name + "/"

	res, err := http.Get(url)
	if err != nil {
		t.Fatal(err)
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		t.Fatal(err)
	}

	var response Region
	err = json.Unmarshal(body, &response)
	if err != nil {
		t.Fatal(err)
	}

	BaseUrl = server.URL + "/api/v1/"
	test_response, err := GetRegion(fake_provider + "/" + fake_name)
	if err != nil {
		t.Fatal(err)
	}
	if reflect.DeepEqual(test_response, response) != true {
		t.Fatal("Invalid output")
	}
}
<|endoftext|>