<commit_before>// Copyright (c) 2019 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package zanzibar

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"time"

	"github.com/opentracing/opentracing-go"
	"github.com/pkg/errors"
	"go.uber.org/zap"
)

// ClientHTTPRequest is the struct for making a single client request using an outbound http client.
type ClientHTTPRequest struct {
	ClientID       string
	MethodName     string
	client         *HTTPClient
	httpReq        *http.Request
	res            *ClientHTTPResponse
	started        bool
	startTime      time.Time
	Logger         *zap.Logger
	ContextLogger  ContextLogger
	rawBody        []byte
	defaultHeaders map[string]string
	ctx            context.Context
	metrics        ContextMetrics
}

// NewClientHTTPRequest allocates a ClientHTTPRequest. The ctx parameter is the context associated with the outbound requests.
func NewClientHTTPRequest(
	ctx context.Context,
	clientID, methodName string,
	client *HTTPClient,
) *ClientHTTPRequest {
	scopeTags := map[string]string{scopeTagClientMethod: methodName, scopeTagClient: clientID}
	ctx = WithScopeTags(ctx, scopeTags)
	req := &ClientHTTPRequest{
		ClientID:       clientID,
		MethodName:     methodName,
		client:         client,
		Logger:         client.loggers[methodName],
		ContextLogger:  NewContextLogger(client.loggers[methodName]),
		defaultHeaders: client.DefaultHeaders,
		ctx:            ctx,
		metrics:        client.contextMetrics,
	}
	req.res = NewClientHTTPResponse(req)
	req.start()
	return req
}

// Start the request, do some metrics book keeping
func (req *ClientHTTPRequest) start() {
	if req.started {
		/* coverage ignore next line */
		req.Logger.Error("Cannot start ClientHTTPRequest twice")
		/* coverage ignore next line */
		return
	}
	req.started = true
	req.startTime = time.Now()
}

// CheckHeaders verifies that the outbound request contains required headers
func (req *ClientHTTPRequest) CheckHeaders(expected []string) error {
	if req.httpReq == nil {
		/* coverage ignore next line */
		panic("must call `req.WriteJSON()` before `req.CheckHeaders()`")
	}

	actualHeaders := req.httpReq.Header

	for _, headerName := range expected {
		// headerName is case insensitive, http.Header Get canonicalize the key
		headerValue := actualHeaders.Get(headerName)
		if headerValue == "" {
			req.Logger.Warn("Got outbound request without mandatory header",
				zap.String("headerName", headerName),
			)

			return errors.New("Missing mandatory header: " + headerName)
		}
	}

	return nil
}

// WriteJSON will send a json http request out.
func (req *ClientHTTPRequest) WriteJSON(
	method, url string,
	headers map[string]string,
	body json.Marshaler,
) error {
	var httpReq *http.Request
	var httpErr error
	if body != nil {
		rawBody, err := body.MarshalJSON()
		if err != nil {
			req.Logger.Error("Could not serialize request json", zap.Error(err))
			return errors.Wrapf(
				err, "Could not serialize %s.%s request json",
				req.ClientID, req.MethodName,
			)
		}
		req.rawBody = rawBody
		httpReq, httpErr = http.NewRequest(method, url, bytes.NewReader(rawBody))
	} else {
		httpReq, httpErr = http.NewRequest(method, url, nil)
	}

	if httpErr != nil {
		req.Logger.Error("Could not create outbound request", zap.Error(httpErr))
		return errors.Wrapf(
			httpErr, "Could not create outbound %s.%s request",
			req.ClientID, req.MethodName,
		)
	}

	// Using `Add` over `Set` intentionally, allowing us to create a list
	// of headerValues for a given key.
	for headerKey, headerValue := range req.defaultHeaders {
		httpReq.Header.Add(headerKey, headerValue)
	}

	for k := range headers {
		httpReq.Header.Add(k, headers[k])
	}

	if body != nil {
		httpReq.Header.Set("Content-Type", "application/json")
	}

	req.httpReq = httpReq
	req.ctx = WithLogFields(req.ctx,
		zap.String(logFieldRequestMethod, method),
		zap.String(logFieldRequestURL, url),
		zap.Time(logFieldRequestStartTime, req.startTime),
	)

	return nil
}

// Do will send the request out.
func (req *ClientHTTPRequest) Do() (*ClientHTTPResponse, error) {
	opName := fmt.Sprintf("%s.%s", req.ClientID, req.MethodName)
	urlTag := opentracing.Tag{Key: "URL", Value: req.httpReq.URL}
	methodTag := opentracing.Tag{Key: "Method", Value: req.httpReq.Method}
	span, ctx := opentracing.StartSpanFromContext(req.ctx, opName, urlTag, methodTag)
	err := req.InjectSpanToHeader(span, opentracing.HTTPHeaders)
	if err != nil {
		/* coverage ignore next line */
		req.Logger.Error("Fail to inject span to headers", zap.Error(err))
		/* coverage ignore next line */
		return nil, err
	}

	logFields := make([]zap.Field, 0, len(req.httpReq.Header))
	for k, v := range req.httpReq.Header {
		logFields = append(logFields, zap.String(fmt.Sprintf("%s-%s", logFieldRequestHeaderPrefix, k), v[0]))
	}
	ctx = WithLogFields(ctx, logFields...)
	req.ctx = ctx

	res, err := req.client.Client.Do(req.httpReq.WithContext(ctx))
	span.Finish()
	if err != nil {
		req.Logger.Error("Could not make outbound request", zap.Error(err))
		return nil, err
	}

	// emit metrics
	req.metrics.IncCounter(req.ctx, clientRequest, 1)

	req.res.setRawHTTPResponse(res)
	return req.res, nil
}

// InjectSpanToHeader will inject span to request header
// This method is current used for unit tests
// TODO: we need to set source and test code as same pkg name which would makes UTs easier
func (req *ClientHTTPRequest) InjectSpanToHeader(span opentracing.Span, format interface{}) error {
	carrier := opentracing.HTTPHeadersCarrier(req.httpReq.Header)
	if err := span.Tracer().Inject(span.Context(), format, carrier); err != nil {
		req.Logger.Error("Failed to inject tracing span.", zap.Error(err))
		return err
	}

	return nil
}
<commit_msg>Removed adding multiple uber source request headers<commit_after>// Copyright (c) 2019 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package zanzibar

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"time"

	"github.com/opentracing/opentracing-go"
	"github.com/pkg/errors"
	"go.uber.org/zap"
)

// ClientHTTPRequest is the struct for making a single client request using an outbound http client.
type ClientHTTPRequest struct {
	ClientID       string
	MethodName     string
	client         *HTTPClient
	httpReq        *http.Request
	res            *ClientHTTPResponse
	started        bool
	startTime      time.Time
	Logger         *zap.Logger
	ContextLogger  ContextLogger
	rawBody        []byte
	defaultHeaders map[string]string
	ctx            context.Context
	metrics        ContextMetrics
}

// NewClientHTTPRequest allocates a ClientHTTPRequest. The ctx parameter is the context associated with the outbound requests.
func NewClientHTTPRequest(
	ctx context.Context,
	clientID, methodName string,
	client *HTTPClient,
) *ClientHTTPRequest {
	scopeTags := map[string]string{scopeTagClientMethod: methodName, scopeTagClient: clientID}
	ctx = WithScopeTags(ctx, scopeTags)
	req := &ClientHTTPRequest{
		ClientID:       clientID,
		MethodName:     methodName,
		client:         client,
		Logger:         client.loggers[methodName],
		ContextLogger:  NewContextLogger(client.loggers[methodName]),
		defaultHeaders: client.DefaultHeaders,
		ctx:            ctx,
		metrics:        client.contextMetrics,
	}
	req.res = NewClientHTTPResponse(req)
	req.start()
	return req
}

// Start the request, do some metrics book keeping
func (req *ClientHTTPRequest) start() {
	if req.started {
		/* coverage ignore next line */
		req.Logger.Error("Cannot start ClientHTTPRequest twice")
		/* coverage ignore next line */
		return
	}
	req.started = true
	req.startTime = time.Now()
}

// CheckHeaders verifies that the outbound request contains required headers
func (req *ClientHTTPRequest) CheckHeaders(expected []string) error {
	if req.httpReq == nil {
		/* coverage ignore next line */
		panic("must call `req.WriteJSON()` before `req.CheckHeaders()`")
	}

	actualHeaders := req.httpReq.Header

	for _, headerName := range expected {
		// headerName is case insensitive, http.Header Get canonicalize the key
		headerValue := actualHeaders.Get(headerName)
		if headerValue == "" {
			req.Logger.Warn("Got outbound request without mandatory header",
				zap.String("headerName", headerName),
			)

			return errors.New("Missing mandatory header: " + headerName)
		}
	}

	return nil
}

// WriteJSON will send a json http request out.
func (req *ClientHTTPRequest) WriteJSON(
	method, url string,
	headers map[string]string,
	body json.Marshaler,
) error {
	var httpReq *http.Request
	var httpErr error
	if body != nil {
		rawBody, err := body.MarshalJSON()
		if err != nil {
			req.Logger.Error("Could not serialize request json", zap.Error(err))
			return errors.Wrapf(
				err, "Could not serialize %s.%s request json",
				req.ClientID, req.MethodName,
			)
		}
		req.rawBody = rawBody
		httpReq, httpErr = http.NewRequest(method, url, bytes.NewReader(rawBody))
	} else {
		httpReq, httpErr = http.NewRequest(method, url, nil)
	}

	if httpErr != nil {
		req.Logger.Error("Could not create outbound request", zap.Error(httpErr))
		return errors.Wrapf(
			httpErr, "Could not create outbound %s.%s request",
			req.ClientID, req.MethodName,
		)
	}

	// Using `Add` over `Set` intentionally, allowing us to create a list
	// of headerValues for a given key.
	for headerKey, headerValue := range req.filteredDefaultHeaders(req.defaultHeaders, headers) {
		httpReq.Header.Add(headerKey, headerValue)
	}

	for k := range headers {
		httpReq.Header.Add(k, headers[k])
	}

	if body != nil {
		httpReq.Header.Set("Content-Type", "application/json")
	}

	req.httpReq = httpReq
	req.ctx = WithLogFields(req.ctx,
		zap.String(logFieldRequestMethod, method),
		zap.String(logFieldRequestURL, url),
		zap.Time(logFieldRequestStartTime, req.startTime),
	)

	return nil
}

// Do will send the request out.
func (req *ClientHTTPRequest) Do() (*ClientHTTPResponse, error) {
	opName := fmt.Sprintf("%s.%s", req.ClientID, req.MethodName)
	urlTag := opentracing.Tag{Key: "URL", Value: req.httpReq.URL}
	methodTag := opentracing.Tag{Key: "Method", Value: req.httpReq.Method}
	span, ctx := opentracing.StartSpanFromContext(req.ctx, opName, urlTag, methodTag)
	err := req.InjectSpanToHeader(span, opentracing.HTTPHeaders)
	if err != nil {
		/* coverage ignore next line */
		req.Logger.Error("Fail to inject span to headers", zap.Error(err))
		/* coverage ignore next line */
		return nil, err
	}

	logFields := make([]zap.Field, 0, len(req.httpReq.Header))
	for k, v := range req.httpReq.Header {
		logFields = append(logFields, zap.String(fmt.Sprintf("%s-%s", logFieldRequestHeaderPrefix, k), v[0]))
	}
	ctx = WithLogFields(ctx, logFields...)
	req.ctx = ctx

	res, err := req.client.Client.Do(req.httpReq.WithContext(ctx))
	span.Finish()
	if err != nil {
		req.Logger.Error("Could not make outbound request", zap.Error(err))
		return nil, err
	}

	// emit metrics
	req.metrics.IncCounter(req.ctx, clientRequest, 1)

	req.res.setRawHTTPResponse(res)
	return req.res, nil
}

// InjectSpanToHeader will inject span to request header
// This method is current used for unit tests
// TODO: we need to set source and test code as same pkg name which would makes UTs easier
func (req *ClientHTTPRequest) InjectSpanToHeader(span opentracing.Span, format interface{}) error {
	carrier := opentracing.HTTPHeadersCarrier(req.httpReq.Header)
	if err := span.Tracer().Inject(span.Context(), format, carrier); err != nil {
		req.Logger.Error("Failed to inject tracing span.", zap.Error(err))
		return err
	}

	return nil
}

func (req *ClientHTTPRequest) filteredDefaultHeaders(defaultHeaders map[string]string, headers map[string]string) map[string]string {
	filteredDefaultHeaders := make(map[string]string)
	// Copy from the original map to the filtered map
	for key, value := range defaultHeaders {
		filteredDefaultHeaders[key] = value
	}

	sourceHeader := "x-uber-source"
	if filteredDefaultHeaders[sourceHeader] != "" && headers[sourceHeader] != "" {
		delete(filteredDefaultHeaders, sourceHeader)
	}
	return filteredDefaultHeaders
}
<|endoftext|>


<commit_before>package sync

import (
  "ghighlighter/models"
  "ghighlighter/readmill/readmillreadings"
  "ghighlighter/readmill/readmillhighlights"
)

func Sync() {
  config := models.Config()

  syncHighlights(config.AccessToken)
  syncReadings(config.UserId, config.AccessToken)
}

func syncHighlights(accessToken string) {
  highlights := models.Highlights()

  tmpItems := make([]models.GhHighlight, len(highlights.Items))
  copy(tmpItems, highlights.Items)

  for _, highlight := range tmpItems {
    readmillHighlight := readmillhighlights.Highlight{highlight.Content,
      highlight.Position, highlight.Timestamp, readmillhighlights.HighlightLocators{}}

    success := readmillhighlights.PostHighlight(readmillHighlight, highlight.ReadingReadmillId, accessToken)

    if success {
      highlights.Delete(highlight)
    }
  }
}

func syncReadings(userId int, accessToken string) {
  readings := models.Readings()
  readmillReadings := readmillreadings.GetReadings(userId, accessToken)

  for _, readmillReading := range readmillReadings {
    title := readmillReading.Book.Title + " - " + readmillReading.Book.Author
    reading := models.GhReading{title, readmillReading.Id, 0}
    readings.Add(reading)
  }
}

<commit_msg>Use 1 as default value for total pages of a reading<commit_after>package sync

import (
  "ghighlighter/models"
  "ghighlighter/readmill/readmillreadings"
  "ghighlighter/readmill/readmillhighlights"
)

func Sync() {
  config := models.Config()

  syncHighlights(config.AccessToken)
  syncReadings(config.UserId, config.AccessToken)
}

func syncHighlights(accessToken string) {
  highlights := models.Highlights()

  tmpItems := make([]models.GhHighlight, len(highlights.Items))
  copy(tmpItems, highlights.Items)

  for _, highlight := range tmpItems {
    readmillHighlight := readmillhighlights.Highlight{highlight.Content,
      highlight.Position, highlight.Timestamp, readmillhighlights.HighlightLocators{}}

    success := readmillhighlights.PostHighlight(readmillHighlight, highlight.ReadingReadmillId, accessToken)

    if success {
      highlights.Delete(highlight)
    }
  }
}

func syncReadings(userId int, accessToken string) {
  readings := models.Readings()
  readmillReadings := readmillreadings.GetReadings(userId, accessToken)

  for _, readmillReading := range readmillReadings {
    title := readmillReading.Book.Title + " - " + readmillReading.Book.Author
    reading := models.GhReading{title, readmillReading.Id, 1}
    readings.Add(reading)
  }
}

<|endoftext|>


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

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"strings"
	"time"

	"github.com/nlopes/slack"

	"bazil.org/fuse"
	"golang.org/x/net/context"
)

type IdNamer interface {
	Id() string
	Name() string
}

type FSConn struct {
	//
	super *Super

	api *slack.Slack
	ws  *slack.SlackWS

	in chan slack.SlackEvent

	info *slack.Info

	users    *DirSet
	channels *DirSet
	groups   *DirSet
}

// shared by offline/offline public New functions
func newFSConn(token, infoPath string) (conn *FSConn, err error) {
	var info slack.Info
	conn = new(FSConn)

	if infoPath != "" {
		buf, err := ioutil.ReadFile(infoPath)
		if err != nil {
			return nil, fmt.Errorf("ReadFile(%s): %s", infoPath, err)
		}
		err = json.Unmarshal(buf, &info)
		if err != nil {
			return nil, fmt.Errorf("Unmarshal: %s", err)
		}
	} else {
		conn.api = slack.New(token)
		conn.ws, err = conn.api.StartRTM("", "https://slack.com")
		if err != nil {
			return nil, fmt.Errorf("StartRTM(): %s\n", err)
		}
		info = conn.api.GetInfo()
	}

	//conn.api.SetDebug(true)

	conn.info = &info
	conn.in = make(chan slack.SlackEvent)
	conn.super = NewSuper()

	root := conn.super.GetRoot()

	err = conn.initUsers(root)
	if err != nil {
		return nil, fmt.Errorf("initUsers: %s", err)
	}
	err = conn.initChannels(root)
	if err != nil {
		return nil, fmt.Errorf("initChannels: %s", err)
	}
	err = conn.initGroups(root)
	if err != nil {
		return nil, fmt.Errorf("initChannels: %s", err)
	}

	go conn.ws.HandleIncomingEvents(conn.in)
	go conn.ws.Keepalive(10 * time.Second)
	go conn.routeIncomingEvents()

	return conn, nil
}

func NewFSConn(token string) (*FSConn, error) {
	return newFSConn(token, "")
}

func NewOfflineFSConn(infoPath string) (*FSConn, error) {
	return newFSConn("", infoPath)
}

func (fs *FSConn) initUsers(parent *DirNode) (err error) {
	fs.users, err = NewDirSet(fs.super.root, "users", fs)
	if err != nil {
		return fmt.Errorf("NewDirSet('users'): %s", err)
	}

	userParent := fs.users.Container()
	for _, u := range fs.info.Users {
		up := new(slack.User)
		*up = u
		ud, err := NewUserDir(userParent, up)
		if err != nil {
			return fmt.Errorf("NewUserDir(%s): %s", up.Id, err)
		}
		err = fs.users.Add(u.Id, u.Name, ud)
		if err != nil {
			return fmt.Errorf("Add(%s): %s", up.Id, err)
		}
	}

	fs.users.Activate()
	return nil
}

func (fs *FSConn) initChannels(parent *DirNode) (err error) {
	fs.channels, err = NewDirSet(fs.super.root, "channels", fs)
	if err != nil {
		return fmt.Errorf("NewDirSet('channels'): %s", err)
	}

	chanParent := fs.users.Container()
	for _, c := range fs.info.Channels {
		cp := new(Channel)
		cp.Channel = c
		cd, err := NewChannelDir(chanParent, cp)
		if err != nil {
			return fmt.Errorf("NewChanDir(%s): %s", cp.Id, err)
		}
		err = fs.channels.Add(c.Id, c.Name, cd)
		if err != nil {
			return fmt.Errorf("Add(%s): %s", cp.Id, err)
		}
	}

	fs.channels.Activate()
	return nil
}

func (fs *FSConn) initGroups(parent *DirNode) (err error) {
	fs.groups, err = NewDirSet(fs.super.root, "groups", fs)
	if err != nil {
		return fmt.Errorf("NewDirSet('groups'): %s", err)
	}

	groupParent := fs.users.Container()
	for _, g := range fs.info.Groups {
		gp := new(Group)
		gp.Group = g
		gd, err := NewGroupDir(groupParent, gp)
		if err != nil {
			return fmt.Errorf("NewChanDir(%s): %s", gp.Id, err)
		}
		err = fs.groups.Add(g.Id, g.Name, gd)
		if err != nil {
			return fmt.Errorf("Add(%s): %s", gp.Id, err)
		}
	}

	fs.groups.Activate()
	return nil
}

func (fs *FSConn) GetUser(id string) (*slack.User, bool) {
	userDir := fs.users.LookupId(id)
	if userDir == nil {
		return nil, false
	}
	u, ok := userDir.priv.(*slack.User)
	return u, ok
}

func (fs *FSConn) routeIncomingEvents() {
	for {
		msg := <-fs.in

		switch ev := msg.Data.(type) {
		case *slack.MessageEvent:
			fmt.Printf("msg\t%s\t%s\t%s\t(%#v)\n", ev.Timestamp, ev.UserId, ev.Text, ev)
		case *slack.PresenceChangeEvent:
			name := "<unknown>"
			if u, ok := fs.GetUser(ev.UserId); ok {
				name = u.Name
			}
			fmt.Printf("presence\t%s\t%s\n", name, ev.Presence)
		case *slack.SlackWSError:
			fmt.Printf("err: %s\n", ev)
		}
	}
}

func (fs *FSConn) Send(txtBytes []byte, id string) error {
	txt := strings.TrimSpace(string(txtBytes))

	out := fs.ws.NewOutgoingMessage(txt, id)
	err := fs.ws.SendMessage(out)
	if err != nil {
		log.Printf("SendMessage: %s", err)
	}
	// TODO(bp) add this message to the session buffer, after we
	// get an ok
	return err
}
<commit_msg>fsconn: small cleanups to logging and a missing comment<commit_after>// Copyright 2015 Bobby Powers. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"strings"
	"time"

	"github.com/nlopes/slack"

	"bazil.org/fuse"
	"golang.org/x/net/context"
)

type IdNamer interface {
	Id() string
	Name() string
}

type FSConn struct {
	super *Super

	api  *slack.Slack
	ws   *slack.SlackWS
	in   chan slack.SlackEvent
	info *slack.Info

	users    *DirSet
	channels *DirSet
	groups   *DirSet
}

// shared by offline/offline public New functions
func newFSConn(token, infoPath string) (conn *FSConn, err error) {
	var info slack.Info
	conn = new(FSConn)

	if infoPath != "" {
		buf, err := ioutil.ReadFile(infoPath)
		if err != nil {
			return nil, fmt.Errorf("ReadFile(%s): %s", infoPath, err)
		}
		err = json.Unmarshal(buf, &info)
		if err != nil {
			return nil, fmt.Errorf("Unmarshal: %s", err)
		}
	} else {
		conn.api = slack.New(token)
		conn.ws, err = conn.api.StartRTM("", "https://slack.com")
		if err != nil {
			return nil, fmt.Errorf("StartRTM(): %s\n", err)
		}
		info = conn.api.GetInfo()
	}

	//conn.api.SetDebug(true)

	conn.info = &info
	conn.in = make(chan slack.SlackEvent)
	conn.super = NewSuper()

	root := conn.super.GetRoot()

	err = conn.initUsers(root)
	if err != nil {
		return nil, fmt.Errorf("initUsers: %s", err)
	}
	err = conn.initChannels(root)
	if err != nil {
		return nil, fmt.Errorf("initChannels: %s", err)
	}
	err = conn.initGroups(root)
	if err != nil {
		return nil, fmt.Errorf("initChannels: %s", err)
	}

	go conn.ws.HandleIncomingEvents(conn.in)
	go conn.ws.Keepalive(10 * time.Second)
	go conn.routeIncomingEvents()

	return conn, nil
}

func NewFSConn(token string) (*FSConn, error) {
	return newFSConn(token, "")
}

func NewOfflineFSConn(infoPath string) (*FSConn, error) {
	return newFSConn("", infoPath)
}

func (fs *FSConn) initUsers(parent *DirNode) (err error) {
	fs.users, err = NewDirSet(fs.super.root, "users", fs)
	if err != nil {
		return fmt.Errorf("NewDirSet('users'): %s", err)
	}

	userParent := fs.users.Container()
	for _, u := range fs.info.Users {
		up := new(slack.User)
		*up = u
		ud, err := NewUserDir(userParent, up)
		if err != nil {
			return fmt.Errorf("NewUserDir(%s): %s", up.Id, err)
		}
		err = fs.users.Add(u.Id, u.Name, ud)
		if err != nil {
			return fmt.Errorf("Add(%s): %s", up.Id, err)
		}
	}

	fs.users.Activate()
	return nil
}

func (fs *FSConn) initChannels(parent *DirNode) (err error) {
	fs.channels, err = NewDirSet(fs.super.root, "channels", fs)
	if err != nil {
		return fmt.Errorf("NewDirSet('channels'): %s", err)
	}

	chanParent := fs.users.Container()
	for _, c := range fs.info.Channels {
		cp := new(Channel)
		cp.Channel = c
		cd, err := NewChannelDir(chanParent, cp)
		if err != nil {
			return fmt.Errorf("NewChanDir(%s): %s", cp.Id, err)
		}
		err = fs.channels.Add(c.Id, c.Name, cd)
		if err != nil {
			return fmt.Errorf("Add(%s): %s", cp.Id, err)
		}
	}

	fs.channels.Activate()
	return nil
}

func (fs *FSConn) initGroups(parent *DirNode) (err error) {
	fs.groups, err = NewDirSet(fs.super.root, "groups", fs)
	if err != nil {
		return fmt.Errorf("NewDirSet('groups'): %s", err)
	}

	groupParent := fs.users.Container()
	for _, g := range fs.info.Groups {
		gp := new(Group)
		gp.Group = g
		gd, err := NewGroupDir(groupParent, gp)
		if err != nil {
			return fmt.Errorf("NewChanDir(%s): %s", gp.Id, err)
		}
		err = fs.groups.Add(g.Id, g.Name, gd)
		if err != nil {
			return fmt.Errorf("Add(%s): %s", gp.Id, err)
		}
	}

	fs.groups.Activate()
	return nil
}

func (fs *FSConn) GetUser(id string) (*slack.User, bool) {
	userDir := fs.users.LookupId(id)
	if userDir == nil {
		return nil, false
	}
	u, ok := userDir.priv.(*slack.User)
	return u, ok
}

func (fs *FSConn) routeIncomingEvents() {
	for {
		msg := <-fs.in

		switch ev := msg.Data.(type) {
		case *slack.MessageEvent:
			fmt.Printf("msg\t%s\t%s\t%s\n", ev.Timestamp, ev.UserId, ev.Text)
		case *slack.PresenceChangeEvent:
			name := "<unknown>"
			if u, ok := fs.GetUser(ev.UserId); ok {
				name = u.Name
			}
			fmt.Printf("presence\t%s\t%s\n", name, ev.Presence)
		case *slack.SlackWSError:
			fmt.Printf("err: %s\n", ev)
		}
	}
}

func (fs *FSConn) Send(txtBytes []byte, id string) error {
	txt := strings.TrimSpace(string(txtBytes))

	out := fs.ws.NewOutgoingMessage(txt, id)
	err := fs.ws.SendMessage(out)
	if err != nil {
		log.Printf("SendMessage: %s", err)
	}
	// TODO(bp) add this message to the session buffer, after we
	// get an ok
	return err
}
<|endoftext|>


<commit_before>package tcpreuse

import (
	"testing"

	ma "github.com/multiformats/go-multiaddr"
)

func TestAll(t *testing.T) {
	var trA Transport
	var trB Transport
	laddr, _ := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/0")
	listenerA, err := trA.Listen(laddr)
	if err != nil {
		t.Fatal(err)
	}
	defer listenerA.Close()
	listenerB, err := trB.Listen(laddr)
	if err != nil {
		t.Fatal(err)
	}
	defer listenerB.Close()

	done := make(chan struct{})
	go func() {
		defer close(done)
		c, err := listenerA.Accept()
		if err != nil {
			t.Fatal(err)
		}
		c.Close()
	}()

	c, err := trB.Dial(listenerA.Multiaddr())
	if err != nil {
		t.Fatal(err)
	}
	<-done
	c.Close()
}
<commit_msg>add another test case<commit_after>package tcpreuse

import (
	"net"
	"testing"

	ma "github.com/multiformats/go-multiaddr"
)

func TestSingle(t *testing.T) {
	var trA Transport
	var trB Transport
	laddr, _ := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/0")
	listenerA, err := trA.Listen(laddr)
	if err != nil {
		t.Fatal(err)
	}
	defer listenerA.Close()
	listenerB, err := trB.Listen(laddr)
	if err != nil {
		t.Fatal(err)
	}
	defer listenerB.Close()

	done := make(chan struct{})
	go func() {
		defer close(done)
		c, err := listenerA.Accept()
		if err != nil {
			t.Fatal(err)
		}
		c.Close()
	}()

	c, err := trB.Dial(listenerA.Multiaddr())
	if err != nil {
		t.Fatal(err)
	}
	<-done
	c.Close()
}

func TestTwoLocal(t *testing.T) {
	var trA Transport
	var trB Transport
	laddr, _ := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/0")
	listenerA, err := trA.Listen(laddr)
	if err != nil {
		t.Fatal(err)
	}
	defer listenerA.Close()

	listenerB1, err := trB.Listen(laddr)
	if err != nil {
		t.Fatal(err)
	}
	defer listenerB1.Close()

	listenerB2, err := trB.Listen(laddr)
	if err != nil {
		t.Fatal(err)
	}
	defer listenerB2.Close()

	done := make(chan struct{})
	go func() {
		defer close(done)
		c, err := listenerA.Accept()
		if err != nil {
			t.Fatal(err)
		}
		c.Close()
	}()

	c, err := trB.Dial(listenerA.Multiaddr())
	if err != nil {
		t.Fatal(err)
	}
	localPort := c.LocalAddr().(*net.TCPAddr).Port
	if localPort != listenerB1.Addr().(*net.TCPAddr).Port &&
		localPort != listenerB2.Addr().(*net.TCPAddr).Port {
		t.Fatal("didn't dial from one of our listener ports")
	}
	<-done
	c.Close()
}
<|endoftext|>


<commit_before>package controllers

import (
	"bytes"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/assert"
	"gopkg.in/DATA-DOG/go-sqlmock.v1"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/eirka/eirka-libs/audit"
	"github.com/eirka/eirka-libs/db"
	e "github.com/eirka/eirka-libs/errors"
	"github.com/eirka/eirka-libs/redis"
	"github.com/eirka/eirka-libs/user"
)

// gin router for tests
var router *gin.Engine

func init() {
	user.Secret = "secret"

	// Set up fake Redis connection
	redis.NewRedisMock()

	gin.SetMode(gin.ReleaseMode)

	router = gin.New()

	router.Use(user.Auth(false))

	router.POST("/tag/add", AddTagController)
}

func performRequest(r http.Handler, method, path string) *httptest.ResponseRecorder {
	req, _ := http.NewRequest(method, path, nil)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)
	return w
}

func performJsonRequest(r http.Handler, method, path string, body []byte) *httptest.ResponseRecorder {
	req, _ := http.NewRequest(method, path, bytes.NewBuffer(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)
	return w
}

func errorMessage(err error) string {
	return fmt.Sprintf(`{"error_message":"%s"}`, err)
}

func successMessage(message string) string {
	return fmt.Sprintf(`{"success_message":"%s"}`, message)
}

func TestAddTagController(t *testing.T) {

	var err error

	mock, err := db.NewTestDb()
	assert.NoError(t, err, "An error was not expected")

	statusrows := sqlmock.NewRows([]string{"count"}).AddRow(1)
	mock.ExpectQuery(`SELECT count\(1\) FROM images`).WillReturnRows(statusrows)

	duperows := sqlmock.NewRows([]string{"count"}).AddRow(0)
	mock.ExpectQuery(`select count\(1\) from tagmap`).WillReturnRows(duperows)

	mock.ExpectExec("INSERT into tagmap").
		WithArgs(1, 1).
		WillReturnResult(sqlmock.NewResult(1, 1))

	mock.ExpectExec(`INSERT INTO audit \(user_id,ib_id,audit_type,audit_ip,audit_time,audit_action,audit_info\)`).
		WithArgs(1, 1, audit.BoardLog, "127.0.0.1", audit.AuditAddTag, "1").
		WillReturnResult(sqlmock.NewResult(1, 1))

	redis.RedisCache.Mock.Command("DEL", "tags:1", "tag:1:1", "image:1")

	request := []byte(`{"ib": 1, "tag": 1, "image": 1}`)

	first := performJsonRequest(router, "POST", "/tag/add", request)

	assert.Equal(t, first.Code, 200, "HTTP request code should match")
	assert.JSONEq(t, first.Body.String(), successMessage(audit.AuditAddTag), "HTTP response should match")

	assert.NoError(t, mock.ExpectationsWereMet(), "An error was not expected")

}

func TestAddTagControllerBadInput(t *testing.T) {

	var reuesttests = []struct {
		name string
		in   []byte
	}{
		{"nofield", []byte(`{}`)},
		{"badfield", []byte(`{"derp": 1}`)},
		{"badmissing", []byte(`{"ib": 0}`)},
		{"badmissing", []byte(`{"ib": 0, "tag": 1}`)},
		{"badmissing", []byte(`{"image": 1}`)},
		{"badib", []byte(`{"ib": 0, "tag": 1, "image": 1}`)},
		{"badib", []byte(`{"ib": dur, "tag": 1, "image": 1}`)},
		{"badtag", []byte(`{"ib": 1, "tag": 0, "image": 1}`)},
		{"badtag", []byte(`{"ib": 1, "tag": dur, "image": 1}`)},
		{"badimage", []byte(`{"ib": 1, "tag": 1, "image": 0}`)},
		{"badimage", []byte(`{"ib": 1, "tag": 1, "image": dur}`)},
		{"badall", []byte(`{"ib": 0, "tag": 0, "image": 0}`)},
	}

	for _, test := range reuesttests {
		first := performJsonRequest(router, "POST", "/tag/add", test.in)
		assert.Equal(t, first.Code, 400, fmt.Sprintf("HTTP request code should match for request %s", test.name))
	}

}

func TestAddTagControllerImageNotFound(t *testing.T) {

	var err error

	mock, err := db.NewTestDb()
	assert.NoError(t, err, "An error was not expected")

	statusrows := sqlmock.NewRows([]string{"count"}).AddRow(0)
	mock.ExpectQuery(`SELECT count\(1\) FROM images`).WillReturnRows(statusrows)

	request := []byte(`{"ib": 1, "tag": 1, "image": 1}`)

	first := performJsonRequest(router, "POST", "/tag/add", request)

	assert.Equal(t, first.Code, 400, "HTTP request code should match")
	assert.JSONEq(t, first.Body.String(), errorMessage(e.ErrNotFound), "HTTP response should match")

	assert.NoError(t, mock.ExpectationsWereMet(), "An error was not expected")
}

func TestAddTagControllerDuplicate(t *testing.T) {

	var err error

	mock, err := db.NewTestDb()
	assert.NoError(t, err, "An error was not expected")

	statusrows := sqlmock.NewRows([]string{"count"}).AddRow(1)
	mock.ExpectQuery(`SELECT count\(1\) FROM images`).WillReturnRows(statusrows)

	duperows := sqlmock.NewRows([]string{"count"}).AddRow(1)
	mock.ExpectQuery(`select count\(1\) from tagmap`).WillReturnRows(duperows)

	request := []byte(`{"ib": 1, "tag": 1, "image": 1}`)

	first := performJsonRequest(router, "POST", "/tag/add", request)

	assert.Equal(t, first.Code, 400, "HTTP request code should match")
	assert.JSONEq(t, first.Body.String(), errorMessage(e.ErrDuplicateTag), "HTTP response should match")

	assert.NoError(t, mock.ExpectationsWereMet(), "An error was not expected")
}
<commit_msg>add controller tests<commit_after>package controllers

import (
	"bytes"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/assert"
	"gopkg.in/DATA-DOG/go-sqlmock.v1"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/eirka/eirka-libs/audit"
	"github.com/eirka/eirka-libs/db"
	e "github.com/eirka/eirka-libs/errors"
	"github.com/eirka/eirka-libs/redis"
	"github.com/eirka/eirka-libs/user"
)

// gin router for tests
var router *gin.Engine

func init() {
	user.Secret = "secret"

	// Set up fake Redis connection
	redis.NewRedisMock()

	gin.SetMode(gin.ReleaseMode)

	router = gin.New()

	router.Use(user.Auth(false))

	router.POST("/tag/add", AddTagController)
}

func performRequest(r http.Handler, method, path string) *httptest.ResponseRecorder {
	req, _ := http.NewRequest(method, path, nil)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)
	return w
}

func performJsonRequest(r http.Handler, method, path string, body []byte) *httptest.ResponseRecorder {
	req, _ := http.NewRequest(method, path, bytes.NewBuffer(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)
	return w
}

func errorMessage(err error) string {
	return fmt.Sprintf(`{"error_message":"%s"}`, err)
}

func successMessage(message string) string {
	return fmt.Sprintf(`{"success_message":"%s"}`, message)
}

func TestAddTagController(t *testing.T) {

	var err error

	mock, err := db.NewTestDb()
	assert.NoError(t, err, "An error was not expected")

	statusrows := sqlmock.NewRows([]string{"count"}).AddRow(1)
	mock.ExpectQuery(`SELECT count\(1\) FROM images`).WillReturnRows(statusrows)

	duperows := sqlmock.NewRows([]string{"count"}).AddRow(0)
	mock.ExpectQuery(`select count\(1\) from tagmap`).WillReturnRows(duperows)

	mock.ExpectExec("INSERT into tagmap").
		WithArgs(1, 1).
		WillReturnResult(sqlmock.NewResult(1, 1))

	mock.ExpectExec(`INSERT INTO audit \(user_id,ib_id,audit_type,audit_ip,audit_time,audit_action,audit_info\)`).
		WithArgs(1, 1, audit.BoardLog, "127.0.0.1", audit.AuditAddTag).
		WillReturnResult(sqlmock.NewResult(1, 1))

	redis.RedisCache.Mock.Command("DEL", "tags:1", "tag:1:1", "image:1")

	request := []byte(`{"ib": 1, "tag": 1, "image": 1}`)

	first := performJsonRequest(router, "POST", "/tag/add", request)

	assert.Equal(t, first.Code, 200, "HTTP request code should match")
	assert.JSONEq(t, first.Body.String(), successMessage(audit.AuditAddTag), "HTTP response should match")

	assert.NoError(t, mock.ExpectationsWereMet(), "An error was not expected")

}

func TestAddTagControllerBadInput(t *testing.T) {

	var reuesttests = []struct {
		name string
		in   []byte
	}{
		{"nofield", []byte(`{}`)},
		{"badfield", []byte(`{"derp": 1}`)},
		{"badmissing", []byte(`{"ib": 0}`)},
		{"badmissing", []byte(`{"ib": 0, "tag": 1}`)},
		{"badmissing", []byte(`{"image": 1}`)},
		{"badib", []byte(`{"ib": 0, "tag": 1, "image": 1}`)},
		{"badib", []byte(`{"ib": dur, "tag": 1, "image": 1}`)},
		{"badtag", []byte(`{"ib": 1, "tag": 0, "image": 1}`)},
		{"badtag", []byte(`{"ib": 1, "tag": dur, "image": 1}`)},
		{"badimage", []byte(`{"ib": 1, "tag": 1, "image": 0}`)},
		{"badimage", []byte(`{"ib": 1, "tag": 1, "image": dur}`)},
		{"badall", []byte(`{"ib": 0, "tag": 0, "image": 0}`)},
	}

	for _, test := range reuesttests {
		first := performJsonRequest(router, "POST", "/tag/add", test.in)
		assert.Equal(t, first.Code, 400, fmt.Sprintf("HTTP request code should match for request %s", test.name))
	}

}

func TestAddTagControllerImageNotFound(t *testing.T) {

	var err error

	mock, err := db.NewTestDb()
	assert.NoError(t, err, "An error was not expected")

	statusrows := sqlmock.NewRows([]string{"count"}).AddRow(0)
	mock.ExpectQuery(`SELECT count\(1\) FROM images`).WillReturnRows(statusrows)

	request := []byte(`{"ib": 1, "tag": 1, "image": 1}`)

	first := performJsonRequest(router, "POST", "/tag/add", request)

	assert.Equal(t, first.Code, 400, "HTTP request code should match")
	assert.JSONEq(t, first.Body.String(), errorMessage(e.ErrNotFound), "HTTP response should match")

	assert.NoError(t, mock.ExpectationsWereMet(), "An error was not expected")
}

func TestAddTagControllerDuplicate(t *testing.T) {

	var err error

	mock, err := db.NewTestDb()
	assert.NoError(t, err, "An error was not expected")

	statusrows := sqlmock.NewRows([]string{"count"}).AddRow(1)
	mock.ExpectQuery(`SELECT count\(1\) FROM images`).WillReturnRows(statusrows)

	duperows := sqlmock.NewRows([]string{"count"}).AddRow(1)
	mock.ExpectQuery(`select count\(1\) from tagmap`).WillReturnRows(duperows)

	request := []byte(`{"ib": 1, "tag": 1, "image": 1}`)

	first := performJsonRequest(router, "POST", "/tag/add", request)

	assert.Equal(t, first.Code, 400, "HTTP request code should match")
	assert.JSONEq(t, first.Body.String(), errorMessage(e.ErrDuplicateTag), "HTTP response should match")

	assert.NoError(t, mock.ExpectationsWereMet(), "An error was not expected")
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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 condition

import (
	"reflect"
	"sync"
	"time"

	"k8s.io/node-problem-detector/pkg/exporters/k8sexporter/problemclient"
	"k8s.io/node-problem-detector/pkg/types"
	problemutil "k8s.io/node-problem-detector/pkg/util"

	"k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/util/clock"

	"github.com/golang/glog"
)

const (
	// updatePeriod is the period at which condition manager checks update.
	updatePeriod = 1 * time.Second
	// resyncPeriod is the period at which condition manager does resync, only updates when needed.
	resyncPeriod = 10 * time.Second
	// heartbeatPeriod is the period at which condition manager does forcibly sync with apiserver.
	heartbeatPeriod = 1 * time.Minute
)

// ConditionManager synchronizes node conditions with the apiserver with problem client.
// It makes sure that:
// 1) Node conditions are updated to apiserver as soon as possible.
// 2) Node problem detector won't flood apiserver.
// 3) No one else could change the node conditions maintained by node problem detector.
// ConditionManager checks every updatePeriod to see whether there is node condition update. If there are any,
// it will synchronize with the apiserver. This addresses 1) and 2).
// ConditionManager synchronizes with apiserver every resyncPeriod no matter there is node condition update or
// not. This addresses 3).
type ConditionManager interface {
	// Start starts the condition manager.
	Start()
	// UpdateCondition updates a specific condition.
	UpdateCondition(types.Condition)
	// GetConditions returns all current conditions.
	GetConditions() []types.Condition
}

type conditionManager struct {
	// Only 2 fields will be accessed by more than one goroutines at the same time:
	// * `updates`: updates will be written by random caller and the sync routine,
	// so it needs to be protected by write lock in both `UpdateCondition` and
	// `needUpdates`.
	// * `conditions`: conditions will only be written in the sync routine, but
	// it will be read by random caller and the sync routine. So it needs to be
	// protected by write lock in `needUpdates` and read lock in `GetConditions`.
	// No lock is needed in `sync`, because it is in the same goroutine with the
	// write operation.
	sync.RWMutex
	clock        clock.Clock
	latestTry    time.Time
	resyncNeeded bool
	client       problemclient.Client
	updates      map[string]types.Condition
	conditions   map[string]types.Condition
}

// NewConditionManager creates a condition manager.
func NewConditionManager(client problemclient.Client, clock clock.Clock) ConditionManager {
	return &conditionManager{
		client:     client,
		clock:      clock,
		updates:    make(map[string]types.Condition),
		conditions: make(map[string]types.Condition),
	}
}

func (c *conditionManager) Start() {
	go c.syncLoop()
}

func (c *conditionManager) UpdateCondition(condition types.Condition) {
	c.Lock()
	defer c.Unlock()
	// New node condition will override the old condition, because we only need the newest
	// condition for each condition type.
	c.updates[condition.Type] = condition
}

func (c *conditionManager) GetConditions() []types.Condition {
	c.RLock()
	defer c.RUnlock()
	var conditions []types.Condition
	for _, condition := range c.conditions {
		conditions = append(conditions, condition)
	}
	return conditions
}

func (c *conditionManager) syncLoop() {
	updateCh := c.clock.Tick(updatePeriod)
	for {
		select {
		case <-updateCh:
			if c.needUpdates() || c.needResync() || c.needHeartbeat() {
				c.sync()
			}
		}
	}
}

// needUpdates checks whether there are recent updates.
func (c *conditionManager) needUpdates() bool {
	c.Lock()
	defer c.Unlock()
	needUpdate := false
	for t, update := range c.updates {
		if !reflect.DeepEqual(c.conditions[t], update) {
			needUpdate = true
			c.conditions[t] = update
		}
		delete(c.updates, t)
	}
	return needUpdate
}

// needResync checks whether a resync is needed.
func (c *conditionManager) needResync() bool {
	// Only update when resync is needed.
	return c.clock.Now().Sub(c.latestTry) >= resyncPeriod && c.resyncNeeded
}

// needHeartbeat checks whether a forcible heartbeat is needed.
func (c *conditionManager) needHeartbeat() bool {
	return c.clock.Now().Sub(c.latestTry) >= heartbeatPeriod
}

// sync synchronizes node conditions with the apiserver.
func (c *conditionManager) sync() {
	c.latestTry = c.clock.Now()
	c.resyncNeeded = false
	conditions := []v1.NodeCondition{}
	for i := range c.conditions {
		conditions = append(conditions, problemutil.ConvertToAPICondition(c.conditions[i]))
	}
	if err := c.client.SetConditions(conditions); err != nil {
		// The conditions will be updated again in future sync
		glog.Errorf("failed to update node conditions: %v", err)
		c.resyncNeeded = true
		return
	}
}
<commit_msg>Handle vendor change in k8s.io/apimachinery/pkg/util/clock<commit_after>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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 condition

import (
	"reflect"
	"sync"
	"time"

	"k8s.io/node-problem-detector/pkg/exporters/k8sexporter/problemclient"
	"k8s.io/node-problem-detector/pkg/types"
	problemutil "k8s.io/node-problem-detector/pkg/util"

	"k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/util/clock"

	"github.com/golang/glog"
)

const (
	// updatePeriod is the period at which condition manager checks update.
	updatePeriod = 1 * time.Second
	// resyncPeriod is the period at which condition manager does resync, only updates when needed.
	resyncPeriod = 10 * time.Second
	// heartbeatPeriod is the period at which condition manager does forcibly sync with apiserver.
	heartbeatPeriod = 1 * time.Minute
)

// ConditionManager synchronizes node conditions with the apiserver with problem client.
// It makes sure that:
// 1) Node conditions are updated to apiserver as soon as possible.
// 2) Node problem detector won't flood apiserver.
// 3) No one else could change the node conditions maintained by node problem detector.
// ConditionManager checks every updatePeriod to see whether there is node condition update. If there are any,
// it will synchronize with the apiserver. This addresses 1) and 2).
// ConditionManager synchronizes with apiserver every resyncPeriod no matter there is node condition update or
// not. This addresses 3).
type ConditionManager interface {
	// Start starts the condition manager.
	Start()
	// UpdateCondition updates a specific condition.
	UpdateCondition(types.Condition)
	// GetConditions returns all current conditions.
	GetConditions() []types.Condition
}

type conditionManager struct {
	// Only 2 fields will be accessed by more than one goroutines at the same time:
	// * `updates`: updates will be written by random caller and the sync routine,
	// so it needs to be protected by write lock in both `UpdateCondition` and
	// `needUpdates`.
	// * `conditions`: conditions will only be written in the sync routine, but
	// it will be read by random caller and the sync routine. So it needs to be
	// protected by write lock in `needUpdates` and read lock in `GetConditions`.
	// No lock is needed in `sync`, because it is in the same goroutine with the
	// write operation.
	sync.RWMutex
	clock        clock.Clock
	latestTry    time.Time
	resyncNeeded bool
	client       problemclient.Client
	updates      map[string]types.Condition
	conditions   map[string]types.Condition
}

// NewConditionManager creates a condition manager.
func NewConditionManager(client problemclient.Client, clock clock.Clock) ConditionManager {
	return &conditionManager{
		client:     client,
		clock:      clock,
		updates:    make(map[string]types.Condition),
		conditions: make(map[string]types.Condition),
	}
}

func (c *conditionManager) Start() {
	go c.syncLoop()
}

func (c *conditionManager) UpdateCondition(condition types.Condition) {
	c.Lock()
	defer c.Unlock()
	// New node condition will override the old condition, because we only need the newest
	// condition for each condition type.
	c.updates[condition.Type] = condition
}

func (c *conditionManager) GetConditions() []types.Condition {
	c.RLock()
	defer c.RUnlock()
	var conditions []types.Condition
	for _, condition := range c.conditions {
		conditions = append(conditions, condition)
	}
	return conditions
}

func (c *conditionManager) syncLoop() {
	ticker := c.clock.NewTicker(updatePeriod)
	defer ticker.Stop()
	for {
		select {
		case <-ticker.C():
			if c.needUpdates() || c.needResync() || c.needHeartbeat() {
				c.sync()
			}
		}
	}
}

// needUpdates checks whether there are recent updates.
func (c *conditionManager) needUpdates() bool {
	c.Lock()
	defer c.Unlock()
	needUpdate := false
	for t, update := range c.updates {
		if !reflect.DeepEqual(c.conditions[t], update) {
			needUpdate = true
			c.conditions[t] = update
		}
		delete(c.updates, t)
	}
	return needUpdate
}

// needResync checks whether a resync is needed.
func (c *conditionManager) needResync() bool {
	// Only update when resync is needed.
	return c.clock.Now().Sub(c.latestTry) >= resyncPeriod && c.resyncNeeded
}

// needHeartbeat checks whether a forcible heartbeat is needed.
func (c *conditionManager) needHeartbeat() bool {
	return c.clock.Now().Sub(c.latestTry) >= heartbeatPeriod
}

// sync synchronizes node conditions with the apiserver.
func (c *conditionManager) sync() {
	c.latestTry = c.clock.Now()
	c.resyncNeeded = false
	conditions := []v1.NodeCondition{}
	for i := range c.conditions {
		conditions = append(conditions, problemutil.ConvertToAPICondition(c.conditions[i]))
	}
	if err := c.client.SetConditions(conditions); err != nil {
		// The conditions will be updated again in future sync
		glog.Errorf("failed to update node conditions: %v", err)
		c.resyncNeeded = true
		return
	}
}
<|endoftext|>


<commit_before>// Copyright 2012 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 main

import (
	"errors"
	"fmt"
	"sync"
)

type Fetcher interface {
	// Fetch returns the body of URL and
	// a slice of URLs found on that page.
	Fetch(url string) (body string, urls []string, err error)
}

// fetched tracks URLs that have been (or are being) fetched.
// The lock must be held while reading from or writing to the map.
// See http://golang.org/ref/spec#Struct_types section on embedded types.
var fetched = struct {
	m map[string]error
	sync.Mutex
}{m: make(map[string]error)}

var loading = errors.New("url load in progress") // sentinel value

// Crawl uses fetcher to recursively crawl
// pages starting with url, to a maximum of depth.
func Crawl(url string, depth int, fetcher Fetcher) {
	if depth <= 0 {
		fmt.Printf("<- Done with %v, depth 0.\n", url)
		return
	}

	fetched.Lock()
	if _, ok := fetched.m[url]; ok {
		fetched.Unlock()
		fmt.Printf("<- Done with %v, already fetched.\n", url)
		return
	}
	// We mark the url to be loading to avoid others reloading it at the same time.
	fetched.m[url] = loading
	fetched.Unlock()

	// We load it concurrently.
	body, urls, err := fetcher.Fetch(url)

	// And update the status in a synced zone.
	fetched.Lock()
	fetched.m[url] = err
	fetched.Unlock()

	if err != nil {
		fmt.Printf("<- Error on %v: %v\n", url, err)
		return
	}
	fmt.Printf("Found: %s %q\n", url, body)
	done := make(chan bool)
	for i, u := range urls {
		fmt.Printf("-> Crawling child %v/%v of %v : %v.\n", i, len(urls), url, u)
		go func(url string) {
			Crawl(url, depth, fetcher)
			done <- true
		}(u)
	}
	for i := range urls {
		fmt.Printf("<- [%v] %v/%v Waiting for child %v.\n", url, i, len(urls))
		<-done
	}
	fmt.Printf("<- Done with %v\n", url)
}

func main() {
	Crawl("http://golang.org/", 4, fetcher)

	fmt.Println("Fetching stats\n--------------")
	for url, err := range fetched.m {
		if err != nil {
			fmt.Printf("%v failed: %v\n", url, err)
		} else {
			fmt.Printf("%v was fetched\n", url)
		}
	}
}

// fakeFetcher is Fetcher that returns canned results.
type fakeFetcher map[string]*fakeResult

type fakeResult struct {
	body string
	urls []string
}

func (f *fakeFetcher) Fetch(url string) (string, []string, error) {
	if res, ok := (*f)[url]; ok {
		return res.body, res.urls, nil
	}
	return "", nil, fmt.Errorf("not found: %s", url)
}

// fetcher is a populated fakeFetcher.
var fetcher = &fakeFetcher{
	"http://golang.org/": &fakeResult{
		"The Go Programming Language",
		[]string{
			"http://golang.org/pkg/",
			"http://golang.org/cmd/",
		},
	},
	"http://golang.org/pkg/": &fakeResult{
		"Packages",
		[]string{
			"http://golang.org/",
			"http://golang.org/cmd/",
			"http://golang.org/pkg/fmt/",
			"http://golang.org/pkg/os/",
		},
	},
	"http://golang.org/pkg/fmt/": &fakeResult{
		"Package fmt",
		[]string{
			"http://golang.org/",
			"http://golang.org/pkg/",
		},
	},
	"http://golang.org/pkg/os/": &fakeResult{
		"Package os",
		[]string{
			"http://golang.org/",
			"http://golang.org/pkg/",
		},
	},
}
<commit_msg>[x/tour] go-tour: Fixing webcrawler solution. Fixes #45<commit_after>// Copyright 2012 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 main

import (
	"errors"
	"fmt"
	"sync"
)

type Fetcher interface {
	// Fetch returns the body of URL and
	// a slice of URLs found on that page.
	Fetch(url string) (body string, urls []string, err error)
}

// fetched tracks URLs that have been (or are being) fetched.
// The lock must be held while reading from or writing to the map.
// See http://golang.org/ref/spec#Struct_types section on embedded types.
var fetched = struct {
	m map[string]error
	sync.Mutex
}{m: make(map[string]error)}

var loading = errors.New("url load in progress") // sentinel value

// Crawl uses fetcher to recursively crawl
// pages starting with url, to a maximum of depth.
func Crawl(url string, depth int, fetcher Fetcher) {
	if depth <= 0 {
		fmt.Printf("<- Done with %v, depth 0.\n", url)
		return
	}

	fetched.Lock()
	if _, ok := fetched.m[url]; ok {
		fetched.Unlock()
		fmt.Printf("<- Done with %v, already fetched.\n", url)
		return
	}
	// We mark the url to be loading to avoid others reloading it at the same time.
	fetched.m[url] = loading
	fetched.Unlock()

	// We load it concurrently.
	body, urls, err := fetcher.Fetch(url)

	// And update the status in a synced zone.
	fetched.Lock()
	fetched.m[url] = err
	fetched.Unlock()

	if err != nil {
		fmt.Printf("<- Error on %v: %v\n", url, err)
		return
	}
	fmt.Printf("Found: %s %q\n", url, body)
	done := make(chan bool)
	for i, u := range urls {
		fmt.Printf("-> Crawling child %v/%v of %v : %v.\n", i, len(urls), url, u)
		go func(url string) {
			Crawl(url, depth-1, fetcher)
			done <- true
		}(u)
	}
	for i := range urls {
		fmt.Printf("<- [%v] %v/%v Waiting for child %v.\n", url, i, len(urls))
		<-done
	}
	fmt.Printf("<- Done with %v\n", url)
}

func main() {
	Crawl("http://golang.org/", 4, fetcher)

	fmt.Println("Fetching stats\n--------------")
	for url, err := range fetched.m {
		if err != nil {
			fmt.Printf("%v failed: %v\n", url, err)
		} else {
			fmt.Printf("%v was fetched\n", url)
		}
	}
}

// fakeFetcher is Fetcher that returns canned results.
type fakeFetcher map[string]*fakeResult

type fakeResult struct {
	body string
	urls []string
}

func (f *fakeFetcher) Fetch(url string) (string, []string, error) {
	if res, ok := (*f)[url]; ok {
		return res.body, res.urls, nil
	}
	return "", nil, fmt.Errorf("not found: %s", url)
}

// fetcher is a populated fakeFetcher.
var fetcher = &fakeFetcher{
	"http://golang.org/": &fakeResult{
		"The Go Programming Language",
		[]string{
			"http://golang.org/pkg/",
			"http://golang.org/cmd/",
		},
	},
	"http://golang.org/pkg/": &fakeResult{
		"Packages",
		[]string{
			"http://golang.org/",
			"http://golang.org/cmd/",
			"http://golang.org/pkg/fmt/",
			"http://golang.org/pkg/os/",
		},
	},
	"http://golang.org/pkg/fmt/": &fakeResult{
		"Package fmt",
		[]string{
			"http://golang.org/",
			"http://golang.org/pkg/",
		},
	},
	"http://golang.org/pkg/os/": &fakeResult{
		"Package os",
		[]string{
			"http://golang.org/",
			"http://golang.org/pkg/",
		},
	},
}
<|endoftext|>


<commit_before>package builder

import (
	"database/sql"
	"fmt"
	"reflect"

	"github.com/dev-cloverlab/carpenter/dialect/mysql"
)

func Build(db *sql.DB, old, new *mysql.Table, withDrop bool) (queries []string, err error) {
	if old == nil && new == nil {
		return queries, fmt.Errorf("err: Both pointer of the specified new and old is nil.")
	}
	if old != nil && new != nil && old.TableName != new.TableName {
		return queries, fmt.Errorf("err: Table name of the specified new and old is a difference")
	}
	if reflect.DeepEqual(old, new) {
		return queries, nil
	}
	if q := willCreate(old, new); len(q) > 0 {
		queries = append(queries, q)
	}
	if withDrop {
		if q := willDrop(old, new); len(q) > 0 {
			queries = append(queries, q)
		}
	}
	if q := willAlterTableCharacterSet(old, new); len(q) > 0 {
		queries = append(queries, q)
	}
	if q := willAlterColumnCharacterSet(old, new); len(q) > 0 {
		queries = append(queries, q...)
	}
	if q := willAlter(old, new); len(q) > 0 {
		queries = append(queries, q)
	}
	return queries, nil
}

func willCreate(old, new *mysql.Table) string {
	if old == nil && new != nil {
		return new.ToCreateSQL()
	}
	return ""
}

func willDrop(old, new *mysql.Table) string {
	if old != nil && new == nil {
		return old.ToDropSQL()
	}
	return ""
}

func willAlterTableCharacterSet(old, new *mysql.Table) string {
	if old == nil || new == nil {
		return ""
	}

	alter := []string{}
	if old.GetCharset() != new.GetCharset() {
		alter = append(alter, new.ToConvertCharsetSQL())
		old.TableCollation = new.TableCollation
	}
	return new.ToAlterSQL(alter, "")
}

func willAlterColumnCharacterSet(old, new *mysql.Table) []string {
	if old == nil || new == nil {
		return []string{}
	}

	newCols := new.Columns.GroupByColumnName()
	oldCols := old.Columns.GroupByColumnName()
	sqls := []string{}
	for _, colName := range new.Columns.GetSortedColumnNames() {
		if _, ok := oldCols[colName]; !ok {
			continue
		}
		newCol := newCols[colName]
		oldCol := oldCols[colName]
		if !newCol.CharacterSetName.Valid || (oldCol.CompareCharacterSet(newCol) && oldCol.CompareCollation(newCol)) {
			continue
		}
		oldCols[colName].CollationName = newCol.CollationName
		sqls = append(sqls, new.ToAlterSQL([]string{newCol.ToModifyCharsetSQL()}, ""))
	}
	return sqls
}

func willAlter(old, new *mysql.Table) string {
	if old == nil || new == nil {
		return ""
	}
	if reflect.DeepEqual(old, new) {
		return ""
	}

	alter := []string{}
	alter = append(alter, willDropIndex(old, new)...)
	alter = append(alter, willDropColumn(old, new)...)
	alter = append(alter, willAddColumn(old, new)...)
	alter = append(alter, willAddIndex(old, new)...)
	alter = append(alter, willModifyColumn(old, new)...)
	return new.ToAlterSQL(alter, willModifyPartition(old, new))
}

func willAddColumn(old, new *mysql.Table) []string {
	cols := mysql.Columns{}
	for _, column := range new.Columns {
		if old.Columns.Contains(column) {
			continue
		}
		cols = append(cols, column)
	}
	return cols.ToAddSQL(new.Columns)
}

func willDropColumn(old, new *mysql.Table) []string {
	cols := mysql.Columns{}
	for _, column := range old.Columns {
		if new.Columns.Contains(column) {
			continue
		}
		cols = append(cols, column)
	}
	return cols.ToDropSQL()
}

func willModifyColumn(old, new *mysql.Table) []string {
	newCols := new.Columns.GroupByColumnName()
	oldCols := old.Columns.GroupByColumnName()
	sqls := []string{}
	for _, colName := range new.Columns.GetSortedColumnNames() {
		if _, ok := oldCols[colName]; !ok {
			continue
		}
		newCol := newCols[colName]
		oldCol := oldCols[colName]
		oldTableSchema := oldCol.TableSchema
		oldColumnKey := oldCol.ColumnKey
		oldPrivileges := oldCol.Privileges
		oldOrdinalPosition := oldCol.OrdinalPosition
		oldCol.TableSchema = newCol.TableSchema
		oldCol.ColumnKey = newCol.ColumnKey
		oldCol.Privileges = newCol.Privileges
		oldCol.OrdinalPosition = newCol.OrdinalPosition
		if !reflect.DeepEqual(oldCol, newCol) {
			sqls = append(sqls, newCol.ToModifySQL())
		}
		oldCol.TableSchema = oldTableSchema
		oldCol.ColumnKey = oldColumnKey
		oldCol.Privileges = oldPrivileges
		oldCol.OrdinalPosition = oldOrdinalPosition
	}
	return sqls
}

func willModifyPartition(old, new *mysql.Table) string {
	if reflect.DeepEqual(old.Partitions, new.Partitions) {
		return ""
	}
	if len(new.Partitions) <= 0 {
		return ""
	}
	return new.Partitions.ToSQL()
}

func willAddIndex(old, new *mysql.Table) []string {
	newIndicesMap := new.Indices.GroupByKeyName()
	oldIndicesMap := old.Indices.GroupByKeyName()
	sqls := []string{}
	for _, keyName := range new.Indices.GetSortedKeys() {
		if _, ok := oldIndicesMap[keyName]; !ok {
			sqls = append(sqls, newIndicesMap[keyName].ToAddSQL()...)
			continue
		}
		newIndices := newIndicesMap[keyName]
		oldIndices := oldIndicesMap[keyName]
		if reflect.DeepEqual(oldIndices, newIndices) {
			continue
		}
		sqls = append(sqls, oldIndices.ToDropSQL()...)
		sqls = append(sqls, newIndices.ToAddSQL()...)
	}
	return sqls
}

func willDropIndex(old, new *mysql.Table) []string {
	newIndicesMap := new.Indices.GroupByKeyName()
	oldIndicesMap := old.Indices.GroupByKeyName()
	sqls := []string{}
	for _, keyName := range old.Indices.GetSortedKeys() {
		if _, ok := newIndicesMap[keyName]; ok {
			continue
		}
		sqls = append(sqls, oldIndicesMap[keyName].ToDropSQL()...)
	}
	return sqls
}
<commit_msg>change willAlter calling function willAlter call willAlterTableCharacterSet and willAlterColumnCharacterSet<commit_after>package builder

import (
	"database/sql"
	"fmt"
	"reflect"

	"github.com/dev-cloverlab/carpenter/dialect/mysql"
)

func Build(db *sql.DB, old, new *mysql.Table, withDrop bool) (queries []string, err error) {
	if old == nil && new == nil {
		return queries, fmt.Errorf("err: Both pointer of the specified new and old is nil.")
	}
	if old != nil && new != nil && old.TableName != new.TableName {
		return queries, fmt.Errorf("err: Table name of the specified new and old is a difference")
	}
	if reflect.DeepEqual(old, new) {
		return queries, nil
	}
	if q := willCreate(old, new); len(q) > 0 {
		queries = append(queries, q)
	}
	if withDrop {
		if q := willDrop(old, new); len(q) > 0 {
			queries = append(queries, q)
		}
	}
	if q := willAlter(old, new); len(q) > 0 {
		queries = append(queries, q)
	}
	return queries, nil
}

func willCreate(old, new *mysql.Table) string {
	if old == nil && new != nil {
		return new.ToCreateSQL()
	}
	return ""
}

func willDrop(old, new *mysql.Table) string {
	if old != nil && new == nil {
		return old.ToDropSQL()
	}
	return ""
}

func willAlterTableCharacterSet(old, new *mysql.Table) []string {
	if old == nil || new == nil {
		return []string{}
	}

	alter := []string{}
	if old.GetCharset() != new.GetCharset() {
		alter = append(alter, new.ToConvertCharsetSQL())
		old.TableCollation = new.TableCollation
	}
	return alter
}

func willAlterColumnCharacterSet(old, new *mysql.Table) []string {
	if old == nil || new == nil {
		return []string{}
	}

	newCols := new.Columns.GroupByColumnName()
	oldCols := old.Columns.GroupByColumnName()
	sqls := []string{}
	for _, colName := range new.Columns.GetSortedColumnNames() {
		if _, ok := oldCols[colName]; !ok {
			continue
		}
		newCol := newCols[colName]
		oldCol := oldCols[colName]
		if !newCol.CharacterSetName.Valid || (oldCol.CompareCharacterSet(newCol) && oldCol.CompareCollation(newCol)) {
			continue
		}
		oldCols[colName].CollationName = newCol.CollationName
		sqls = append(sqls, newCol.ToModifyCharsetSQL())
	}
	return sqls
}

func willAlter(old, new *mysql.Table) string {
	if old == nil || new == nil {
		return ""
	}
	if reflect.DeepEqual(old, new) {
		return ""
	}

	alter := []string{}
	alter = append(alter, willAlterTableCharacterSet(old, new)...)
	alter = append(alter, willAlterColumnCharacterSet(old, new)...)
	alter = append(alter, willDropIndex(old, new)...)
	alter = append(alter, willDropColumn(old, new)...)
	alter = append(alter, willAddColumn(old, new)...)
	alter = append(alter, willAddIndex(old, new)...)
	alter = append(alter, willModifyColumn(old, new)...)
	return new.ToAlterSQL(alter, willModifyPartition(old, new))
}

func willAddColumn(old, new *mysql.Table) []string {
	cols := mysql.Columns{}
	for _, column := range new.Columns {
		if old.Columns.Contains(column) {
			continue
		}
		cols = append(cols, column)
	}
	return cols.ToAddSQL(new.Columns)
}

func willDropColumn(old, new *mysql.Table) []string {
	cols := mysql.Columns{}
	for _, column := range old.Columns {
		if new.Columns.Contains(column) {
			continue
		}
		cols = append(cols, column)
	}
	return cols.ToDropSQL()
}

func willModifyColumn(old, new *mysql.Table) []string {
	newCols := new.Columns.GroupByColumnName()
	oldCols := old.Columns.GroupByColumnName()
	sqls := []string{}
	for _, colName := range new.Columns.GetSortedColumnNames() {
		if _, ok := oldCols[colName]; !ok {
			continue
		}
		newCol := newCols[colName]
		oldCol := oldCols[colName]
		oldTableSchema := oldCol.TableSchema
		oldColumnKey := oldCol.ColumnKey
		oldPrivileges := oldCol.Privileges
		oldOrdinalPosition := oldCol.OrdinalPosition
		oldCol.TableSchema = newCol.TableSchema
		oldCol.ColumnKey = newCol.ColumnKey
		oldCol.Privileges = newCol.Privileges
		oldCol.OrdinalPosition = newCol.OrdinalPosition
		if !reflect.DeepEqual(oldCol, newCol) {
			sqls = append(sqls, newCol.ToModifySQL())
		}
		oldCol.TableSchema = oldTableSchema
		oldCol.ColumnKey = oldColumnKey
		oldCol.Privileges = oldPrivileges
		oldCol.OrdinalPosition = oldOrdinalPosition
	}
	return sqls
}

func willModifyPartition(old, new *mysql.Table) string {
	if reflect.DeepEqual(old.Partitions, new.Partitions) {
		return ""
	}
	if len(new.Partitions) <= 0 {
		return ""
	}
	return new.Partitions.ToSQL()
}

func willAddIndex(old, new *mysql.Table) []string {
	newIndicesMap := new.Indices.GroupByKeyName()
	oldIndicesMap := old.Indices.GroupByKeyName()
	sqls := []string{}
	for _, keyName := range new.Indices.GetSortedKeys() {
		if _, ok := oldIndicesMap[keyName]; !ok {
			sqls = append(sqls, newIndicesMap[keyName].ToAddSQL()...)
			continue
		}
		newIndices := newIndicesMap[keyName]
		oldIndices := oldIndicesMap[keyName]
		if reflect.DeepEqual(oldIndices, newIndices) {
			continue
		}
		sqls = append(sqls, oldIndices.ToDropSQL()...)
		sqls = append(sqls, newIndices.ToAddSQL()...)
	}
	return sqls
}

func willDropIndex(old, new *mysql.Table) []string {
	newIndicesMap := new.Indices.GroupByKeyName()
	oldIndicesMap := old.Indices.GroupByKeyName()
	sqls := []string{}
	for _, keyName := range old.Indices.GetSortedKeys() {
		if _, ok := newIndicesMap[keyName]; ok {
			continue
		}
		sqls = append(sqls, oldIndicesMap[keyName].ToDropSQL()...)
	}
	return sqls
}
<|endoftext|>


<commit_before>// Built-in functions
package builtin

import (
	"fmt"
	"github.com/ncw/gpython/py"
	"github.com/ncw/gpython/vm"
)

const builtin_doc = `Built-in functions, exceptions, and other objects.

Noteworthy: None is the 'nil' object; Ellipsis represents '...' in slices.`

// Initialise the module
func init() {
	methods := []*py.Method{
		py.NewMethod("__build_class__", builtin___build_class__, 0, build_class_doc),
		// py.NewMethod("__import__", builtin___import__, 0, import_doc),
		py.NewMethod("abs", builtin_abs, 0, abs_doc),
		// py.NewMethod("all", builtin_all, 0, all_doc),
		// py.NewMethod("any", builtin_any, 0, any_doc),
		// py.NewMethod("ascii", builtin_ascii, 0, ascii_doc),
		// py.NewMethod("bin", builtin_bin, 0, bin_doc),
		// py.NewMethod("callable", builtin_callable, 0, callable_doc),
		// py.NewMethod("chr", builtin_chr, 0, chr_doc),
		// py.NewMethod("compile", builtin_compile, 0, compile_doc),
		// py.NewMethod("delattr", builtin_delattr, 0, delattr_doc),
		// py.NewMethod("dir", builtin_dir, 0, dir_doc),
		// py.NewMethod("divmod", builtin_divmod, 0, divmod_doc),
		// py.NewMethod("eval", builtin_eval, 0, eval_doc),
		// py.NewMethod("exec", builtin_exec, 0, exec_doc),
		// py.NewMethod("format", builtin_format, 0, format_doc),
		// py.NewMethod("getattr", builtin_getattr, 0, getattr_doc),
		// py.NewMethod("globals", builtin_globals, py.METH_NOARGS, globals_doc),
		// py.NewMethod("hasattr", builtin_hasattr, 0, hasattr_doc),
		// py.NewMethod("hash", builtin_hash, 0, hash_doc),
		// py.NewMethod("hex", builtin_hex, 0, hex_doc),
		// py.NewMethod("id", builtin_id, 0, id_doc),
		// py.NewMethod("input", builtin_input, 0, input_doc),
		// py.NewMethod("isinstance", builtin_isinstance, 0, isinstance_doc),
		// py.NewMethod("issubclass", builtin_issubclass, 0, issubclass_doc),
		// py.NewMethod("iter", builtin_iter, 0, iter_doc),
		// py.NewMethod("len", builtin_len, 0, len_doc),
		// py.NewMethod("locals", builtin_locals, py.METH_NOARGS, locals_doc),
		// py.NewMethod("max", builtin_max, 0, max_doc),
		// py.NewMethod("min", builtin_min, 0, min_doc),
		// py.NewMethod("next", builtin_next, 0, next_doc),
		// py.NewMethod("oct", builtin_oct, 0, oct_doc),
		// py.NewMethod("ord", builtin_ord, 0, ord_doc),
		py.NewMethod("pow", builtin_pow, 0, pow_doc),
		py.NewMethod("print", builtin_print, 0, print_doc),
		// py.NewMethod("repr", builtin_repr, 0, repr_doc),
		py.NewMethod("round", builtin_round, 0, round_doc),
		// py.NewMethod("setattr", builtin_setattr, 0, setattr_doc),
		// py.NewMethod("sorted", builtin_sorted, 0, sorted_doc),
		// py.NewMethod("sum", builtin_sum, 0, sum_doc),
		// py.NewMethod("vars", builtin_vars, 0, vars_doc),
	}
	globals := py.StringDict{
		"None":           py.None,
		"Ellipsis":       py.Ellipsis,
		"NotImplemented": py.NotImplemented,
		"False":          py.False,
		"True":           py.True,
		"bool":           py.BoolType,
		// "memoryview":     py.MemoryViewType,
		// "bytearray":      py.ByteArrayType,
		"bytes": py.BytesType,
		// "classmethod":    py.ClassMethodType,
		"complex": py.ComplexType,
		"dict":    py.StringDictType, // FIXME
		// "enumerate":      py.EnumType,
		// "filter":         py.FilterType,
		"float":     py.FloatType,
		"frozenset": py.FrozenSetType,
		// "property":       py.PropertyType,
		"int":  py.IntType, // FIXME LongType?
		"list": py.ListType,
		// "map":            py.MapType,
		// "object":         py.BaseObjectType,
		// "range":          py.RangeType,
		// "reversed":       py.ReversedType,
		"set": py.SetType,
		// "slice":          py.SliceType,
		// "staticmethod":   py.StaticMethodType,
		"str": py.StringType,
		// "super":          py.SuperType,
		"tuple": py.TupleType,
		"type":  py.TypeType,
		// "zip":            py.ZipType,
	}
	py.NewModule("builtins", builtin_doc, methods, globals)
}

const print_doc = `print(value, ..., sep=' ', end='\\n', file=sys.stdout, flush=False)

Prints the values to a stream, or to sys.stdout by default.
Optional keyword arguments:
file:  a file-like object (stream); defaults to the current sys.stdout.
sep:   string inserted between values, default a space.
end:   string appended after the last value, default a newline.
flush: whether to forcibly flush the stream.`

func builtin_print(self py.Object, args py.Tuple, kwargs py.StringDict) py.Object {
	fmt.Printf("print %v, %v, %v\n", self, args, kwargs)
	return py.None
}

const pow_doc = `pow(x, y[, z]) -> number

With two arguments, equivalent to x**y.  With three arguments,
equivalent to (x**y) % z, but may be more efficient (e.g. for ints).`

func builtin_pow(self py.Object, args py.Tuple) py.Object {
	var v, w, z py.Object
	z = py.None
	py.UnpackTuple(args, "pow", 2, 3, &v, &w, &z)
	return py.Pow(v, w, z)
}

const abs_doc = `"abs(number) -> number

Return the absolute value of the argument.`

func builtin_abs(self, v py.Object) py.Object {
	return py.Abs(v)
}

const round_doc = `round(number[, ndigits]) -> number

Round a number to a given precision in decimal digits (default 0 digits).
This returns an int when called with one argument, otherwise the
same type as the number. ndigits may be negative.`

func builtin_round(self py.Object, args py.Tuple, kwargs py.StringDict) py.Object {
	var number, ndigits py.Object
	ndigits = py.Int(0)
	// var kwlist = []string{"number", "ndigits"}
	// FIXME py.ParseTupleAndKeywords(args, kwargs, "O|O:round", kwlist, &number, &ndigits)
	py.UnpackTuple(args, "round", 1, 2, &number, &ndigits)

	numberRounder, ok := number.(py.I__round__)
	if !ok {
		// FIXME TypeError
		panic(fmt.Sprintf("TypeError: type %s doesn't define __round__ method", number.Type().Name))
	}

	return numberRounder.M__round__(ndigits)
}

const build_class_doc = `__build_class__(func, name, *bases, metaclass=None, **kwds) -> class

Internal helper function used by the class statement.`

func builtin___build_class__(self py.Object, args py.Tuple, kwargs py.StringDict) py.Object {
	fmt.Printf("__build_class__(self=%#v, args=%#v, kwargs=%#v\n", self, args, kwargs)
	var prep, cell, cls py.Object
	var mkw, ns py.StringDict
	var meta, winner *py.Type
	var isclass bool

	if len(args) < 2 {
		// FIXME TypeError
		panic(fmt.Sprintf("TypeError: __build_class__: not enough arguments"))
	}

	// Better be callable
	fn, ok := args[0].(*py.Function)
	if !ok {
		// FIXME TypeError
		panic(fmt.Sprintf("TypeError: __build__class__: func must be a function"))
	}

	name := args[1].(py.String)
	if !ok {
		// FIXME TypeError
		panic(fmt.Sprintf("TypeError: __build_class__: name is not a string"))
	}
	bases := args[2:]

	if kwargs != nil {
		mkw = kwargs.Copy()      // Don't modify kwds passed in!
		meta := mkw["metaclass"] // _PyDict_GetItemId(mkw, &PyId_metaclass)
		if meta != nil {
			delete(mkw, "metaclass")
			// metaclass is explicitly given, check if it's indeed a class
			_, isclass = meta.(*py.Type)
		}
	}
	if meta == nil {
		// if there are no bases, use type:
		if len(bases) == 0 {
			meta = py.TypeType
		} else {
			// else get the type of the first base
			meta = bases[0].Type()
		}
		isclass = true // meta is really a class
	}

	if isclass {
		// meta is really a class, so check for a more derived
		// metaclass, or possible metaclass conflicts:
		winner = meta.CalculateMetaclass(bases)
		if winner != meta {
			meta = winner
		}
	}
	// else: meta is not a class, so we cannot do the metaclass
	// calculation, so we will use the explicitly given object as it is
	prep = meta.Type().Dict["___prepare__"] // FIXME should be using _PyObject_GetAttr
	if prep == nil {
		ns = py.NewStringDict()
	} else {
		ns = py.Call(prep, py.Tuple{name, bases}, mkw).(py.StringDict)
	}
	fmt.Printf("Calling %v with %#v and %#v\n", fn.Name, fn.Globals, ns)
	cell, err := vm.Run(fn.Globals, ns, fn.Code) // FIXME PyFunction_GET_CLOSURE(fn))
	fmt.Printf("result %v %s\n", cell, err)
	if err != nil {
		// FIXME
		panic(err)
	}
	if cell != nil {
		fmt.Printf("Calling %v\n", meta)
		cls = py.Call(meta, py.Tuple{name, bases, ns}, mkw)
		if c, ok := cell.(*py.Cell); ok {
			c.Set(cls)
		}
	}
	fmt.Printf("Globals = %v, Locals = %v\n", fn.Globals, ns)
	return cls
}
<commit_msg>Fix locals for class constructor call<commit_after>// Built-in functions
package builtin

import (
	"fmt"
	"github.com/ncw/gpython/py"
	"github.com/ncw/gpython/vm"
)

const builtin_doc = `Built-in functions, exceptions, and other objects.

Noteworthy: None is the 'nil' object; Ellipsis represents '...' in slices.`

// Initialise the module
func init() {
	methods := []*py.Method{
		py.NewMethod("__build_class__", builtin___build_class__, 0, build_class_doc),
		// py.NewMethod("__import__", builtin___import__, 0, import_doc),
		py.NewMethod("abs", builtin_abs, 0, abs_doc),
		// py.NewMethod("all", builtin_all, 0, all_doc),
		// py.NewMethod("any", builtin_any, 0, any_doc),
		// py.NewMethod("ascii", builtin_ascii, 0, ascii_doc),
		// py.NewMethod("bin", builtin_bin, 0, bin_doc),
		// py.NewMethod("callable", builtin_callable, 0, callable_doc),
		// py.NewMethod("chr", builtin_chr, 0, chr_doc),
		// py.NewMethod("compile", builtin_compile, 0, compile_doc),
		// py.NewMethod("delattr", builtin_delattr, 0, delattr_doc),
		// py.NewMethod("dir", builtin_dir, 0, dir_doc),
		// py.NewMethod("divmod", builtin_divmod, 0, divmod_doc),
		// py.NewMethod("eval", builtin_eval, 0, eval_doc),
		// py.NewMethod("exec", builtin_exec, 0, exec_doc),
		// py.NewMethod("format", builtin_format, 0, format_doc),
		// py.NewMethod("getattr", builtin_getattr, 0, getattr_doc),
		// py.NewMethod("globals", builtin_globals, py.METH_NOARGS, globals_doc),
		// py.NewMethod("hasattr", builtin_hasattr, 0, hasattr_doc),
		// py.NewMethod("hash", builtin_hash, 0, hash_doc),
		// py.NewMethod("hex", builtin_hex, 0, hex_doc),
		// py.NewMethod("id", builtin_id, 0, id_doc),
		// py.NewMethod("input", builtin_input, 0, input_doc),
		// py.NewMethod("isinstance", builtin_isinstance, 0, isinstance_doc),
		// py.NewMethod("issubclass", builtin_issubclass, 0, issubclass_doc),
		// py.NewMethod("iter", builtin_iter, 0, iter_doc),
		// py.NewMethod("len", builtin_len, 0, len_doc),
		// py.NewMethod("locals", builtin_locals, py.METH_NOARGS, locals_doc),
		// py.NewMethod("max", builtin_max, 0, max_doc),
		// py.NewMethod("min", builtin_min, 0, min_doc),
		// py.NewMethod("next", builtin_next, 0, next_doc),
		// py.NewMethod("oct", builtin_oct, 0, oct_doc),
		// py.NewMethod("ord", builtin_ord, 0, ord_doc),
		py.NewMethod("pow", builtin_pow, 0, pow_doc),
		py.NewMethod("print", builtin_print, 0, print_doc),
		// py.NewMethod("repr", builtin_repr, 0, repr_doc),
		py.NewMethod("round", builtin_round, 0, round_doc),
		// py.NewMethod("setattr", builtin_setattr, 0, setattr_doc),
		// py.NewMethod("sorted", builtin_sorted, 0, sorted_doc),
		// py.NewMethod("sum", builtin_sum, 0, sum_doc),
		// py.NewMethod("vars", builtin_vars, 0, vars_doc),
	}
	globals := py.StringDict{
		"None":           py.None,
		"Ellipsis":       py.Ellipsis,
		"NotImplemented": py.NotImplemented,
		"False":          py.False,
		"True":           py.True,
		"bool":           py.BoolType,
		// "memoryview":     py.MemoryViewType,
		// "bytearray":      py.ByteArrayType,
		"bytes": py.BytesType,
		// "classmethod":    py.ClassMethodType,
		"complex": py.ComplexType,
		"dict":    py.StringDictType, // FIXME
		// "enumerate":      py.EnumType,
		// "filter":         py.FilterType,
		"float":     py.FloatType,
		"frozenset": py.FrozenSetType,
		// "property":       py.PropertyType,
		"int":  py.IntType, // FIXME LongType?
		"list": py.ListType,
		// "map":            py.MapType,
		// "object":         py.BaseObjectType,
		// "range":          py.RangeType,
		// "reversed":       py.ReversedType,
		"set": py.SetType,
		// "slice":          py.SliceType,
		// "staticmethod":   py.StaticMethodType,
		"str": py.StringType,
		// "super":          py.SuperType,
		"tuple": py.TupleType,
		"type":  py.TypeType,
		// "zip":            py.ZipType,
	}
	py.NewModule("builtins", builtin_doc, methods, globals)
}

const print_doc = `print(value, ..., sep=' ', end='\\n', file=sys.stdout, flush=False)

Prints the values to a stream, or to sys.stdout by default.
Optional keyword arguments:
file:  a file-like object (stream); defaults to the current sys.stdout.
sep:   string inserted between values, default a space.
end:   string appended after the last value, default a newline.
flush: whether to forcibly flush the stream.`

func builtin_print(self py.Object, args py.Tuple, kwargs py.StringDict) py.Object {
	fmt.Printf("print %v, %v, %v\n", self, args, kwargs)
	return py.None
}

const pow_doc = `pow(x, y[, z]) -> number

With two arguments, equivalent to x**y.  With three arguments,
equivalent to (x**y) % z, but may be more efficient (e.g. for ints).`

func builtin_pow(self py.Object, args py.Tuple) py.Object {
	var v, w, z py.Object
	z = py.None
	py.UnpackTuple(args, "pow", 2, 3, &v, &w, &z)
	return py.Pow(v, w, z)
}

const abs_doc = `"abs(number) -> number

Return the absolute value of the argument.`

func builtin_abs(self, v py.Object) py.Object {
	return py.Abs(v)
}

const round_doc = `round(number[, ndigits]) -> number

Round a number to a given precision in decimal digits (default 0 digits).
This returns an int when called with one argument, otherwise the
same type as the number. ndigits may be negative.`

func builtin_round(self py.Object, args py.Tuple, kwargs py.StringDict) py.Object {
	var number, ndigits py.Object
	ndigits = py.Int(0)
	// var kwlist = []string{"number", "ndigits"}
	// FIXME py.ParseTupleAndKeywords(args, kwargs, "O|O:round", kwlist, &number, &ndigits)
	py.UnpackTuple(args, "round", 1, 2, &number, &ndigits)

	numberRounder, ok := number.(py.I__round__)
	if !ok {
		// FIXME TypeError
		panic(fmt.Sprintf("TypeError: type %s doesn't define __round__ method", number.Type().Name))
	}

	return numberRounder.M__round__(ndigits)
}

const build_class_doc = `__build_class__(func, name, *bases, metaclass=None, **kwds) -> class

Internal helper function used by the class statement.`

func builtin___build_class__(self py.Object, args py.Tuple, kwargs py.StringDict) py.Object {
	fmt.Printf("__build_class__(self=%#v, args=%#v, kwargs=%#v\n", self, args, kwargs)
	var prep, cell, cls py.Object
	var mkw, ns py.StringDict
	var meta, winner *py.Type
	var isclass bool

	if len(args) < 2 {
		// FIXME TypeError
		panic(fmt.Sprintf("TypeError: __build_class__: not enough arguments"))
	}

	// Better be callable
	fn, ok := args[0].(*py.Function)
	if !ok {
		// FIXME TypeError
		panic(fmt.Sprintf("TypeError: __build__class__: func must be a function"))
	}

	name := args[1].(py.String)
	if !ok {
		// FIXME TypeError
		panic(fmt.Sprintf("TypeError: __build_class__: name is not a string"))
	}
	bases := args[2:]

	if kwargs != nil {
		mkw = kwargs.Copy()      // Don't modify kwds passed in!
		meta := mkw["metaclass"] // _PyDict_GetItemId(mkw, &PyId_metaclass)
		if meta != nil {
			delete(mkw, "metaclass")
			// metaclass is explicitly given, check if it's indeed a class
			_, isclass = meta.(*py.Type)
		}
	}
	if meta == nil {
		// if there are no bases, use type:
		if len(bases) == 0 {
			meta = py.TypeType
		} else {
			// else get the type of the first base
			meta = bases[0].Type()
		}
		isclass = true // meta is really a class
	}

	if isclass {
		// meta is really a class, so check for a more derived
		// metaclass, or possible metaclass conflicts:
		winner = meta.CalculateMetaclass(bases)
		if winner != meta {
			meta = winner
		}
	}
	// else: meta is not a class, so we cannot do the metaclass
	// calculation, so we will use the explicitly given object as it is
	prep = meta.Type().Dict["___prepare__"] // FIXME should be using _PyObject_GetAttr
	if prep == nil {
		ns = py.NewStringDict()
	} else {
		ns = py.Call(prep, py.Tuple{name, bases}, mkw).(py.StringDict)
	}
	// fmt.Printf("Calling %v with %p and %p\n", fn.Name, fn.Globals, ns)
	// fmt.Printf("Code = %#v\n", fn.Code)
	locals := fn.LocalsForCall(py.Tuple{ns})
	cell, err := vm.Run(fn.Globals, locals, fn.Code) // FIXME PyFunction_GET_CLOSURE(fn))

	// fmt.Printf("result = %#v err = %s\n", cell, err)
	// fmt.Printf("locals = %#v\n", locals)
	// fmt.Printf("ns = %#v\n", ns)
	if err != nil {
		// FIXME
		panic(err)
	}
	if cell != nil {
		fmt.Printf("Calling %v\n", meta)
		cls = py.Call(meta, py.Tuple{name, bases, ns}, mkw)
		if c, ok := cell.(*py.Cell); ok {
			c.Set(cls)
		}
	}
	fmt.Printf("Globals = %v, Locals = %v\n", fn.Globals, ns)
	return cls
}
<|endoftext|>