<commit_before>package main

import (
	"fmt"
	"net/http"
	"net/http/httputil"
	"net/url"
	"path"
	"strings"

	"github.com/boltdb/bolt"
)

type Request struct {
	Service string
	Method  string
	Path    string
	Data    string

	Settings  Settings
	NoQueries bool
	NoHeaders bool

	Alias string

	URL url.URL

	verbose int
}

func (r *Request) Perform() (*http.Response, error) {
	if err := db.Update(request.LoadSettings); err != nil {
		return nil, err
	}

	req, err := r.Prepare()
	if err != nil {
		return nil, err
	}

	switch r.verbose {
	case 1:
		fmt.Println(request.URL.String())
	case 2, 3:
		// at level 3 display the raw request
		extra := false
		if r.verbose >= 3 {
			extra = true
		}

		dump, err := httputil.DumpRequestOut(req, extra)
		if err != nil {
			// this is only the verbose logging, so carry on in case of error
			fmt.Println(err)
			break
		}
		fmt.Println(string(dump))
	}

	client := &http.Client{}
	return client.Do(req)
}

// Prepare the http request.  This will substitute all the parameters,
// addd all the headers and query parameters
func (r *Request) Prepare() (*http.Request, error) {
	// prepare the url
	r.URL = r.Settings.URL()
	params := paramReplacer(r.Settings.Parameters)

	r.URL.Path = path.Join(r.Settings.BasePath.String, params.Replace(r.Path))
	r.Data = params.Replace(r.Data)

	if !r.NoQueries {
		q := r.URL.Query()
		for key, value := range r.Settings.Queries {
			q.Set(params.Replace(key), params.Replace(value))
		}
		r.URL.RawQuery = q.Encode()
	}

	// prepare the request
	req, err := http.NewRequest(
		strings.ToUpper(r.Method),
		r.URL.String(),
		strings.NewReader(r.Data),
	)
	if err != nil {
		return nil, err
	}

	if r.Settings.Username.Valid && r.Settings.Password.Valid {
		req.SetBasicAuth(r.Settings.Username.String, r.Settings.Password.String)
	}

	if !r.NoHeaders {
		for key, value := range r.Settings.Headers {
			req.Header.Set(params.Replace(key), params.Replace(value))
		}
	}

	return req, nil
}

// MakeServiceBucket creates the bucket for the service
func (r *Request) MakeServiceBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
	if r.Service == "" {
		info := tx.Bucket([]byte("info"))
		current := info.Get([]byte("current"))
		r.Service = string(current)
	}

	sb, err := tx.CreateBucketIfNotExists([]byte("services"))
	if err != nil {
		return nil, err
	}

	b, err := sb.CreateBucketIfNotExists([]byte(r.Service))
	if err != nil {
		return nil, err
	}

	return b, nil
}

// ServiceBucket retrieves the bucket for the current requests service
func (r *Request) ServiceBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
	if r.Service == "" {
		info := tx.Bucket([]byte("info"))
		if info == nil {
			return nil, ErrNoInfoBucket
		}
		current := info.Get([]byte("current"))
		r.Service = string(current)
	}

	if r.Service == "" {
		return nil, ErrNoServiceSet
	}

	sb := tx.Bucket([]byte("services"))
	if sb == nil {
		return nil, ErrNoServicesBucket
	}

	b := sb.Bucket([]byte(r.Service))
	if b == nil {
		return nil, ErrNoService{Name: r.Service}
	}

	return b, nil
}

// MakePathBucket creates the bucket for the path
func (r Request) MakePathBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
	s, err := r.ServiceBucket(tx)
	if err != nil {
		return nil, err
	}

	pb, err := s.CreateBucketIfNotExists([]byte("paths"))
	if err != nil {
		return nil, err
	}

	b, err := pb.CreateBucketIfNotExists([]byte(r.Path))
	if err != nil {
		return nil, err
	}

	return b, nil
}

// PathBucket returns the bucket for the request path, creates if needed
func (r Request) PathBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
	s, err := r.ServiceBucket(tx)
	if err != nil {
		return nil, err
	}

	pb := s.Bucket([]byte("paths"))
	if pb == nil {
		return nil, ErrNoPaths
	}

	b := pb.Bucket([]byte(r.Path))
	if b == nil {
		return nil, ErrInvalidPath{Path: r.Path}
	}

	return b, nil
}

// MakeMethodBucket returns the bucket for the request method, creates if needed
func (r Request) MakeMethodBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
	s, err := r.PathBucket(tx)
	if err != nil {
		return nil, err
	}

	b, err := s.CreateBucketIfNotExists([]byte(r.Method))
	if err != nil {
		return nil, err
	}

	return b, nil
}

// LoadSettings from the database
func (r *Request) LoadSettings(tx *bolt.Tx) error {
	sb, pb, mb, err := request.Match(tx)
	if err != nil {
		return err
	}

	// Start with blank settings
	r.Settings = NewSettings()

	// load service settings
	if sb != nil {
		r.Settings = LoadSettings(sb)
	}

	// load path settings
	if pb != nil {
		r.Settings.Merge(LoadSettings(pb))
	}

	// load method settings
	if mb != nil {
		r.Settings.Merge(LoadSettings(mb))
	}

	// load provided cli flags settings
	r.Settings.Merge(settings)

	return nil
}

// Match returns the relavant db buckets for all request settings, it will first check
// for a matching alias, then check generic paths, if there is a matching alias, it
// will be returned in the path bucket.
func (r Request) Match(tx *bolt.Tx) (service, path, method *bolt.Bucket, err error) {
	service, err = r.ServiceBucket(tx)
	if err != nil {
		return nil, nil, nil, err
	}

	// match aliases first, if an alias matches then ignore path or method matches
	ab := service.Bucket([]byte("aliases"))
	if ab != nil {
		c := ab.Cursor()
		for key, _ := c.First(); key != nil; key, _ = c.Next() {
			if string(key) == r.Alias {
				path = ab.Bucket(key)
				return service, path, nil, nil
			}
		}
	}

	// match path
	pb := service.Bucket([]byte("paths"))
	if pb == nil {
		return service, nil, nil, nil
	}

	// Match the path, this will eventually be expanded to better match
	// the path.  So specific paths will be matched before generic ones
	// at the moment it requires an exact match
	c := pb.Cursor()
	for key, _ := c.First(); key != nil; key, _ = c.Next() {
		if string(key) == r.Path {
			path = pb.Bucket(key)
			break
		}
	}

	if path == nil {
		return service, path, nil, nil
	}

	method = path.Bucket([]byte(r.Method))

	return service, path, method, nil
}
<commit_msg>Fix empty parameters being sent<commit_after>package main

import (
	"fmt"
	"net/http"
	"net/http/httputil"
	"net/url"
	"path"
	"strings"

	"github.com/boltdb/bolt"
)

type Request struct {
	Service string
	Method  string
	Path    string
	Data    string

	Settings  Settings
	NoQueries bool
	NoHeaders bool

	Alias string

	URL url.URL

	verbose int
}

func (r *Request) Perform() (*http.Response, error) {
	if err := db.Update(request.LoadSettings); err != nil {
		return nil, err
	}

	req, err := r.Prepare()
	if err != nil {
		return nil, err
	}

	switch r.verbose {
	case 1:
		fmt.Println(request.URL.String())
	case 2, 3:
		// at level 3 display the raw request
		extra := false
		if r.verbose >= 3 {
			extra = true
		}

		dump, err := httputil.DumpRequestOut(req, extra)
		if err != nil {
			// this is only the verbose logging, so carry on in case of error
			fmt.Println(err)
			break
		}
		fmt.Println(string(dump))
	}

	client := &http.Client{}
	return client.Do(req)
}

// Prepare the http request.  This will substitute all the parameters,
// addd all the headers and query parameters
func (r *Request) Prepare() (*http.Request, error) {
	// prepare the url
	r.URL = r.Settings.URL()
	params := paramReplacer(r.Settings.Parameters)

	r.URL.Path = path.Join(r.Settings.BasePath.String, params.Replace(r.Path))
	r.Data = params.Replace(r.Data)

	if !r.NoQueries {
		q := r.URL.Query()
		for key, value := range r.Settings.Queries {
			v := params.Replace(value)
			if v[0] != ':' {
				q.Set(key, v)
			}
		}
		r.URL.RawQuery = q.Encode()
	}

	// prepare the request
	req, err := http.NewRequest(
		strings.ToUpper(r.Method),
		r.URL.String(),
		strings.NewReader(r.Data),
	)
	if err != nil {
		return nil, err
	}

	if r.Settings.Username.Valid && r.Settings.Password.Valid {
		req.SetBasicAuth(r.Settings.Username.String, r.Settings.Password.String)
	}

	if !r.NoHeaders {
		for key, value := range r.Settings.Headers {
			v := params.Replace(value)
			if v[0] != ':' {
				req.Header.Set(key, v)
			}
		}
	}

	return req, nil
}

// MakeServiceBucket creates the bucket for the service
func (r *Request) MakeServiceBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
	if r.Service == "" {
		info := tx.Bucket([]byte("info"))
		current := info.Get([]byte("current"))
		r.Service = string(current)
	}

	sb, err := tx.CreateBucketIfNotExists([]byte("services"))
	if err != nil {
		return nil, err
	}

	b, err := sb.CreateBucketIfNotExists([]byte(r.Service))
	if err != nil {
		return nil, err
	}

	return b, nil
}

// ServiceBucket retrieves the bucket for the current requests service
func (r *Request) ServiceBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
	if r.Service == "" {
		info := tx.Bucket([]byte("info"))
		if info == nil {
			return nil, ErrNoInfoBucket
		}
		current := info.Get([]byte("current"))
		r.Service = string(current)
	}

	if r.Service == "" {
		return nil, ErrNoServiceSet
	}

	sb := tx.Bucket([]byte("services"))
	if sb == nil {
		return nil, ErrNoServicesBucket
	}

	b := sb.Bucket([]byte(r.Service))
	if b == nil {
		return nil, ErrNoService{Name: r.Service}
	}

	return b, nil
}

// MakePathBucket creates the bucket for the path
func (r Request) MakePathBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
	s, err := r.ServiceBucket(tx)
	if err != nil {
		return nil, err
	}

	pb, err := s.CreateBucketIfNotExists([]byte("paths"))
	if err != nil {
		return nil, err
	}

	b, err := pb.CreateBucketIfNotExists([]byte(r.Path))
	if err != nil {
		return nil, err
	}

	return b, nil
}

// PathBucket returns the bucket for the request path, creates if needed
func (r Request) PathBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
	s, err := r.ServiceBucket(tx)
	if err != nil {
		return nil, err
	}

	pb := s.Bucket([]byte("paths"))
	if pb == nil {
		return nil, ErrNoPaths
	}

	b := pb.Bucket([]byte(r.Path))
	if b == nil {
		return nil, ErrInvalidPath{Path: r.Path}
	}

	return b, nil
}

// MakeMethodBucket returns the bucket for the request method, creates if needed
func (r Request) MakeMethodBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
	s, err := r.PathBucket(tx)
	if err != nil {
		return nil, err
	}

	b, err := s.CreateBucketIfNotExists([]byte(r.Method))
	if err != nil {
		return nil, err
	}

	return b, nil
}

// LoadSettings from the database
func (r *Request) LoadSettings(tx *bolt.Tx) error {
	sb, pb, mb, err := request.Match(tx)
	if err != nil {
		return err
	}

	// Start with blank settings
	r.Settings = NewSettings()

	// load service settings
	if sb != nil {
		r.Settings = LoadSettings(sb)
	}

	// load path settings
	if pb != nil {
		r.Settings.Merge(LoadSettings(pb))
	}

	// load method settings
	if mb != nil {
		r.Settings.Merge(LoadSettings(mb))
	}

	// load provided cli flags settings
	r.Settings.Merge(settings)

	return nil
}

// Match returns the relavant db buckets for all request settings, it will first check
// for a matching alias, then check generic paths, if there is a matching alias, it
// will be returned in the path bucket.
func (r Request) Match(tx *bolt.Tx) (service, path, method *bolt.Bucket, err error) {
	service, err = r.ServiceBucket(tx)
	if err != nil {
		return nil, nil, nil, err
	}

	// match aliases first, if an alias matches then ignore path or method matches
	ab := service.Bucket([]byte("aliases"))
	if ab != nil {
		c := ab.Cursor()
		for key, _ := c.First(); key != nil; key, _ = c.Next() {
			if string(key) == r.Alias {
				path = ab.Bucket(key)
				return service, path, nil, nil
			}
		}
	}

	// match path
	pb := service.Bucket([]byte("paths"))
	if pb == nil {
		return service, nil, nil, nil
	}

	// Match the path, this will eventually be expanded to better match
	// the path.  So specific paths will be matched before generic ones
	// at the moment it requires an exact match
	c := pb.Cursor()
	for key, _ := c.First(); key != nil; key, _ = c.Next() {
		if string(key) == r.Path {
			path = pb.Bucket(key)
			break
		}
	}

	if path == nil {
		return service, path, nil, nil
	}

	method = path.Bucket([]byte(r.Method))

	return service, path, method, nil
}
<|endoftext|>


<commit_before>package client

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"strings"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/versions"
	"github.com/pkg/errors"
	"golang.org/x/net/context"
	"golang.org/x/net/context/ctxhttp"
)

// serverResponse is a wrapper for http API responses.
type serverResponse struct {
	body       io.ReadCloser
	header     http.Header
	statusCode int
}

// head sends an http request to the docker API using the method HEAD.
func (cli *Client) head(ctx context.Context, path string, query url.Values, headers map[string][]string) (serverResponse, error) {
	return cli.sendRequest(ctx, "HEAD", path, query, nil, headers)
}

// getWithContext sends an http request to the docker API using the method GET with a specific go context.
func (cli *Client) get(ctx context.Context, path string, query url.Values, headers map[string][]string) (serverResponse, error) {
	return cli.sendRequest(ctx, "GET", path, query, nil, headers)
}

// postWithContext sends an http request to the docker API using the method POST with a specific go context.
func (cli *Client) post(ctx context.Context, path string, query url.Values, obj interface{}, headers map[string][]string) (serverResponse, error) {
	return cli.sendRequest(ctx, "POST", path, query, obj, headers)
}

func (cli *Client) postRaw(ctx context.Context, path string, query url.Values, body io.Reader, headers map[string][]string) (serverResponse, error) {
	return cli.sendClientRequest(ctx, "POST", path, query, body, headers)
}

// put sends an http request to the docker API using the method PUT.
func (cli *Client) put(ctx context.Context, path string, query url.Values, obj interface{}, headers map[string][]string) (serverResponse, error) {
	return cli.sendRequest(ctx, "PUT", path, query, obj, headers)
}

// put sends an http request to the docker API using the method PUT.
func (cli *Client) putRaw(ctx context.Context, path string, query url.Values, body io.Reader, headers map[string][]string) (serverResponse, error) {
	return cli.sendClientRequest(ctx, "PUT", path, query, body, headers)
}

// delete sends an http request to the docker API using the method DELETE.
func (cli *Client) delete(ctx context.Context, path string, query url.Values, headers map[string][]string) (serverResponse, error) {
	return cli.sendRequest(ctx, "DELETE", path, query, nil, headers)
}

func (cli *Client) sendRequest(ctx context.Context, method, path string, query url.Values, obj interface{}, headers map[string][]string) (serverResponse, error) {
	var body io.Reader

	if obj != nil {
		var err error
		body, err = encodeData(obj)
		if err != nil {
			return serverResponse{}, err
		}
		if headers == nil {
			headers = make(map[string][]string)
		}
		headers["Content-Type"] = []string{"application/json"}
	}

	return cli.sendClientRequest(ctx, method, path, query, body, headers)
}

func (cli *Client) sendClientRequest(ctx context.Context, method, path string, query url.Values, body io.Reader, headers map[string][]string) (serverResponse, error) {
	serverResp := serverResponse{
		body:       nil,
		statusCode: -1,
	}

	expectedPayload := (method == "POST" || method == "PUT")
	if expectedPayload && body == nil {
		body = bytes.NewReader([]byte{})
	}

	req, err := cli.newRequest(method, path, query, body, headers)
	if err != nil {
		return serverResp, err
	}

	if cli.proto == "unix" || cli.proto == "npipe" {
		// For local communications, it doesn't matter what the host is. We just
		// need a valid and meaningful host name. (See #189)
		req.Host = "docker"
	}

	scheme, err := resolveScheme(cli.client.Transport)
	if err != nil {
		return serverResp, err
	}

	req.URL.Host = cli.addr
	req.URL.Scheme = scheme

	if expectedPayload && req.Header.Get("Content-Type") == "" {
		req.Header.Set("Content-Type", "text/plain")
	}

	resp, err := ctxhttp.Do(ctx, cli.client, req)
	if err != nil {

		if scheme == "https" && strings.Contains(err.Error(), "malformed HTTP response") {
			return serverResp, fmt.Errorf("%v.\n* Are you trying to connect to a TLS-enabled daemon without TLS?", err)
		}

		if scheme == "https" && strings.Contains(err.Error(), "bad certificate") {
			return serverResp, fmt.Errorf("The server probably has client authentication (--tlsverify) enabled. Please check your TLS client certification settings: %v", err)
		}

		// Don't decorate context sentinel errors; users may be comparing to
		// them directly.
		switch err {
		case context.Canceled, context.DeadlineExceeded:
			return serverResp, err
		}

		if err, ok := err.(net.Error); ok {
			if err.Timeout() {
				return serverResp, ErrorConnectionFailed(cli.host)
			}
			if !err.Temporary() {
				if strings.Contains(err.Error(), "connection refused") || strings.Contains(err.Error(), "dial unix") {
					return serverResp, ErrorConnectionFailed(cli.host)
				}
			}
		}

		return serverResp, errors.Wrap(err, "error during connect")
	}

	if resp != nil {
		serverResp.statusCode = resp.StatusCode
	}

	if serverResp.statusCode < 200 || serverResp.statusCode >= 400 {
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return serverResp, err
		}
		if len(body) == 0 {
			return serverResp, fmt.Errorf("Error: request returned %s for API route and version %s, check if the server supports the requested API version", http.StatusText(serverResp.statusCode), req.URL)
		}

		var errorMessage string
		if (cli.version == "" || versions.GreaterThan(cli.version, "1.23")) &&
			resp.Header.Get("Content-Type") == "application/json" {
			var errorResponse types.ErrorResponse
			if err := json.Unmarshal(body, &errorResponse); err != nil {
				return serverResp, fmt.Errorf("Error reading JSON: %v", err)
			}
			errorMessage = errorResponse.Message
		} else {
			errorMessage = string(body)
		}

		return serverResp, fmt.Errorf("Error response from daemon: %s", strings.TrimSpace(errorMessage))
	}

	serverResp.body = resp.Body
	serverResp.header = resp.Header
	return serverResp, nil
}

func (cli *Client) newRequest(method, path string, query url.Values, body io.Reader, headers map[string][]string) (*http.Request, error) {
	apiPath := cli.getAPIPath(path, query)
	req, err := http.NewRequest(method, apiPath, body)
	if err != nil {
		return nil, err
	}

	// Add CLI Config's HTTP Headers BEFORE we set the Docker headers
	// then the user can't change OUR headers
	for k, v := range cli.customHTTPHeaders {
		req.Header.Set(k, v)
	}

	if headers != nil {
		for k, v := range headers {
			req.Header[k] = v
		}
	}

	return req, nil
}

func encodeData(data interface{}) (*bytes.Buffer, error) {
	params := bytes.NewBuffer(nil)
	if data != nil {
		if err := json.NewEncoder(params).Encode(data); err != nil {
			return nil, err
		}
	}
	return params, nil
}

func ensureReaderClosed(response serverResponse) {
	if body := response.body; body != nil {
		// Drain up to 512 bytes and close the body to let the Transport reuse the connection
		io.CopyN(ioutil.Discard, body, 512)
		response.body.Close()
	}
}
<commit_msg>Updated the client/request.go sendClientRequest method to return a PermissionDenied error if the connection failed due to permissions.<commit_after>package client

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"strings"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/versions"
	"github.com/pkg/errors"
	"golang.org/x/net/context"
	"golang.org/x/net/context/ctxhttp"
)

// serverResponse is a wrapper for http API responses.
type serverResponse struct {
	body       io.ReadCloser
	header     http.Header
	statusCode int
}

// head sends an http request to the docker API using the method HEAD.
func (cli *Client) head(ctx context.Context, path string, query url.Values, headers map[string][]string) (serverResponse, error) {
	return cli.sendRequest(ctx, "HEAD", path, query, nil, headers)
}

// getWithContext sends an http request to the docker API using the method GET with a specific go context.
func (cli *Client) get(ctx context.Context, path string, query url.Values, headers map[string][]string) (serverResponse, error) {
	return cli.sendRequest(ctx, "GET", path, query, nil, headers)
}

// postWithContext sends an http request to the docker API using the method POST with a specific go context.
func (cli *Client) post(ctx context.Context, path string, query url.Values, obj interface{}, headers map[string][]string) (serverResponse, error) {
	return cli.sendRequest(ctx, "POST", path, query, obj, headers)
}

func (cli *Client) postRaw(ctx context.Context, path string, query url.Values, body io.Reader, headers map[string][]string) (serverResponse, error) {
	return cli.sendClientRequest(ctx, "POST", path, query, body, headers)
}

// put sends an http request to the docker API using the method PUT.
func (cli *Client) put(ctx context.Context, path string, query url.Values, obj interface{}, headers map[string][]string) (serverResponse, error) {
	return cli.sendRequest(ctx, "PUT", path, query, obj, headers)
}

// put sends an http request to the docker API using the method PUT.
func (cli *Client) putRaw(ctx context.Context, path string, query url.Values, body io.Reader, headers map[string][]string) (serverResponse, error) {
	return cli.sendClientRequest(ctx, "PUT", path, query, body, headers)
}

// delete sends an http request to the docker API using the method DELETE.
func (cli *Client) delete(ctx context.Context, path string, query url.Values, headers map[string][]string) (serverResponse, error) {
	return cli.sendRequest(ctx, "DELETE", path, query, nil, headers)
}

func (cli *Client) sendRequest(ctx context.Context, method, path string, query url.Values, obj interface{}, headers map[string][]string) (serverResponse, error) {
	var body io.Reader

	if obj != nil {
		var err error
		body, err = encodeData(obj)
		if err != nil {
			return serverResponse{}, err
		}
		if headers == nil {
			headers = make(map[string][]string)
		}
		headers["Content-Type"] = []string{"application/json"}
	}

	return cli.sendClientRequest(ctx, method, path, query, body, headers)
}

func (cli *Client) sendClientRequest(ctx context.Context, method, path string, query url.Values, body io.Reader, headers map[string][]string) (serverResponse, error) {
	serverResp := serverResponse{
		body:       nil,
		statusCode: -1,
	}

	expectedPayload := (method == "POST" || method == "PUT")
	if expectedPayload && body == nil {
		body = bytes.NewReader([]byte{})
	}

	req, err := cli.newRequest(method, path, query, body, headers)
	if err != nil {
		return serverResp, err
	}

	if cli.proto == "unix" || cli.proto == "npipe" {
		// For local communications, it doesn't matter what the host is. We just
		// need a valid and meaningful host name. (See #189)
		req.Host = "docker"
	}

	scheme, err := resolveScheme(cli.client.Transport)
	if err != nil {
		return serverResp, err
	}

	req.URL.Host = cli.addr
	req.URL.Scheme = scheme

	if expectedPayload && req.Header.Get("Content-Type") == "" {
		req.Header.Set("Content-Type", "text/plain")
	}

	resp, err := ctxhttp.Do(ctx, cli.client, req)
	if err != nil {

		if scheme == "https" && strings.Contains(err.Error(), "malformed HTTP response") {
			return serverResp, fmt.Errorf("%v.\n* Are you trying to connect to a TLS-enabled daemon without TLS?", err)
		}

		if scheme == "https" && strings.Contains(err.Error(), "bad certificate") {
			return serverResp, fmt.Errorf("The server probably has client authentication (--tlsverify) enabled. Please check your TLS client certification settings: %v", err)
		}

		// Don't decorate context sentinel errors; users may be comparing to
		// them directly.
		switch err {
		case context.Canceled, context.DeadlineExceeded:
			return serverResp, err
		}

		if nErr, ok := err.(*url.Error); ok {
			if nErr, ok := nErr.Err.(*net.OpError); ok {
				if os.IsPermission(nErr.Err) {
					return serverResp, errors.Wrapf(err, "Got permission denied while trying to connect to the Docker daemon socket at %v", cli.host)
				}
			}
		}

		if err, ok := err.(net.Error); ok {
			if err.Timeout() {
				return serverResp, ErrorConnectionFailed(cli.host)
			}
			if !err.Temporary() {
				if strings.Contains(err.Error(), "connection refused") || strings.Contains(err.Error(), "dial unix") {
					return serverResp, ErrorConnectionFailed(cli.host)
				}
			}
		}

		return serverResp, errors.Wrap(err, "error during connect")
	}

	if resp != nil {
		serverResp.statusCode = resp.StatusCode
	}

	if serverResp.statusCode < 200 || serverResp.statusCode >= 400 {
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return serverResp, err
		}
		if len(body) == 0 {
			return serverResp, fmt.Errorf("Error: request returned %s for API route and version %s, check if the server supports the requested API version", http.StatusText(serverResp.statusCode), req.URL)
		}

		var errorMessage string
		if (cli.version == "" || versions.GreaterThan(cli.version, "1.23")) &&
			resp.Header.Get("Content-Type") == "application/json" {
			var errorResponse types.ErrorResponse
			if err := json.Unmarshal(body, &errorResponse); err != nil {
				return serverResp, fmt.Errorf("Error reading JSON: %v", err)
			}
			errorMessage = errorResponse.Message
		} else {
			errorMessage = string(body)
		}

		return serverResp, fmt.Errorf("Error response from daemon: %s", strings.TrimSpace(errorMessage))
	}

	serverResp.body = resp.Body
	serverResp.header = resp.Header
	return serverResp, nil
}

func (cli *Client) newRequest(method, path string, query url.Values, body io.Reader, headers map[string][]string) (*http.Request, error) {
	apiPath := cli.getAPIPath(path, query)
	req, err := http.NewRequest(method, apiPath, body)
	if err != nil {
		return nil, err
	}

	// Add CLI Config's HTTP Headers BEFORE we set the Docker headers
	// then the user can't change OUR headers
	for k, v := range cli.customHTTPHeaders {
		req.Header.Set(k, v)
	}

	if headers != nil {
		for k, v := range headers {
			req.Header[k] = v
		}
	}

	return req, nil
}

func encodeData(data interface{}) (*bytes.Buffer, error) {
	params := bytes.NewBuffer(nil)
	if data != nil {
		if err := json.NewEncoder(params).Encode(data); err != nil {
			return nil, err
		}
	}
	return params, nil
}

func ensureReaderClosed(response serverResponse) {
	if body := response.body; body != nil {
		// Drain up to 512 bytes and close the body to let the Transport reuse the connection
		io.CopyN(ioutil.Discard, body, 512)
		response.body.Close()
	}
}
<|endoftext|>


<commit_before>package imgscale

import (
)

/*
	Configure returns Handler which implement http.Handler
	Filename is the configuration file in json, content looks something like this

	{
		"Path": "./data",
		"Prefix": "img",
		"Formats": [
			{"Prefix": "100x100", "Height": 100, "Ratio": 1.0, "Thumbnail": true},
			{"Prefix": "66x100", "Height": 100, "Ratio": 0.67, "Thumbnail": true},
			{"Prefix": "100x75", "Height": 75, "Ratio": 1.335, "Thumbnail": true},
			{"Prefix": "100x0", "Height": 100, "Ratio": 0.0, "Thumbnail": true},
			{"Prefix": "originalx1", "Height": 0, "Ratio": 1.0, "Thumbnail": false},
			{"Prefix": "original", "Height": 0, "Ratio": 0.0, "Thumbnail": false}
		],
		"Exts": ["jpg", "png"],
		"Comment": "Copyright"
	}

	The return handler could use as middleware handler

	Negroni middleware:

	n := negroni.New()

	handler := imgscale.Configure("./config/formats.json")

	handler.SetImageProvider(imgscale.NewImageProviderHTTP(""))

	n.UseHandler(handler)

	http.ListenAndServe(fmt.Sprintf("%s:%d", "127.0.0.1", 8081), n)

	Martini middleware:

	app := martini.Classic()

	app.Use(imgscale.Configure("./config/formats.json").ServeHTTP)

	http.ListenAndServe(fmt.Sprintf("%s:%d", "127.0.0.1", 8080), app)

	http.Handler:

	handler := imgscale.Configure("./config/formats.json")

	handler.SetImageProvider(imgscale.NewImageProviderHTTP("http://127.0.0.1:8080/img/original/"))

	http.Handle("/", handler)

	http.ListenAndServe(fmt.Sprintf("%s:%d", "", 8082), nil)

*/
func Configure(filename string) Handler {
	config := LoadConfig(filename)
	return configure(config)
}
<commit_msg>formatting docstring<commit_after>package imgscale

import (
)

/*
	Configure returns Handler which implement http.Handler
	Filename is the configuration file in json, content looks something like this

		{
			"Path": "./data",
			"Prefix": "img",
			"Formats": [
				{"Prefix": "100x100", "Height": 100, "Ratio": 1.0, "Thumbnail": true},
				{"Prefix": "66x100", "Height": 100, "Ratio": 0.67, "Thumbnail": true},
				{"Prefix": "100x75", "Height": 75, "Ratio": 1.335, "Thumbnail": true},
				{"Prefix": "100x0", "Height": 100, "Ratio": 0.0, "Thumbnail": true},
				{"Prefix": "originalx1", "Height": 0, "Ratio": 1.0, "Thumbnail": false},
				{"Prefix": "original", "Height": 0, "Ratio": 0.0, "Thumbnail": false}
			],
			"Exts": ["jpg", "png"],
			"Comment": "Copyright"
		}

	The return handler could use as middleware handler

	Negroni middleware:

		n := negroni.New()

		handler := imgscale.Configure("./config/formats.json")

		handler.SetImageProvider(imgscale.NewImageProviderHTTP(""))

		n.UseHandler(handler)

		http.ListenAndServe(fmt.Sprintf("%s:%d", "127.0.0.1", 8081), n)

	Martini middleware:

		app := martini.Classic()

		app.Use(imgscale.Configure("./config/formats.json").ServeHTTP)

		http.ListenAndServe(fmt.Sprintf("%s:%d", "127.0.0.1", 8080), app)

	http.Handler:

		handler := imgscale.Configure("./config/formats.json")

		handler.SetImageProvider(imgscale.NewImageProviderHTTP("http://127.0.0.1:8080/img/original/"))

		http.Handle("/", handler)

		http.ListenAndServe(fmt.Sprintf("%s:%d", "", 8082), nil)

*/
func Configure(filename string) Handler {
	config := LoadConfig(filename)
	return configure(config)
}
<|endoftext|>


<commit_before>package common

import (
	"fmt"
	"net/http"
	"net/http/httputil"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"
)

func ValidBarcode8(s string) bool {
	re := regexp.MustCompile("^[A-Z0-9]{8,8}$")
	return re.MatchString(s)
}

func ValidBarcode7(s string) bool {
	re := regexp.MustCompile("^[A-Z0-9]{7,7}$")
	return re.MatchString(s)
}

func ValidCarton20(s string) bool {
	re := regexp.MustCompile("^[0-9]{20,20}$")
	return re.MatchString(s)
}

func ReverseProxy(proxyPort string, pathMap map[string]string) {

	for urlPath, targetPort := range pathMap {
		u, _ := url.Parse("http://127.0.0.1:" + targetPort)
		http.Handle(urlPath, httputil.NewSingleHostReverseProxy(u))
	}

	http.ListenAndServe(":"+proxyPort, nil)

}

func TimeNowString() string {
	return fmt.Sprintf("%v", time.Unix(0, time.Now().UnixNano()/(int64(time.Millisecond)/int64(time.Nanosecond))*int64(time.Millisecond)))[:23]
}

func EscapeLatex(s string) string {
	s2 := strings.Replace(s, "\\", "\\textbackslash", -1)
	s2 = strings.Replace(s2, "&", "\\&", -1)
	s2 = strings.Replace(s2, "%", "\\%", -1)
	s2 = strings.Replace(s2, "$", "\\$", -1)
	s2 = strings.Replace(s2, "#", "\\#", -1)
	s2 = strings.Replace(s2, "_", "\\_", -1)
	s2 = strings.Replace(s2, "{", "\\{", -1)
	s2 = strings.Replace(s2, "}", "\\}", -1)
	s2 = strings.Replace(s2, "~", "\\textasciitilde", -1)
	return strings.Replace(s2, "^", "\\textasciicircum", -1)

}

func PadZero(s string) string {
	if s[0] == '.' {
		return "0" + s
	} else {
		return s
	}
}

type TmpRow7 struct {
	Str1   string
	Str2   string
	Str3   string
	Str4   string
	Str5   string
	Str6   string
	Str7   string
	Int1   int64
	Int2   int64
	Int3   int64
	Int4   int64
	Int5   int64
	Int6   int64
	Int7   int64
	Float1 float64
	Float2 float64
	Float3 float64
	Float4 float64
	Float5 float64
	Float6 float64
	Float7 float64
}

type TmpStr struct {
	Idx   int
	Value string
}

type TmpInt struct {
	Idx   int
	Value int64
}

type TmpFloat struct {
	Idx   int
	Value float64
}

func IndexOf(target int, intSlice []int) int {
	for i, v := range intSlice {
		if v == target {
			return i
		}
	}
	return -1
}

func StringToRows7(data string, config []string) []TmpRow7 {
	var translate [21]int
	strPosition := 1
	intPosition := 8
	floatPosition := 15
	var result []TmpRow7

	for j, t := range config {
		if t == "string" {
			translate[j] = strPosition
			strPosition++
		} else if t == "int64" {
			translate[j] = intPosition
			intPosition++

		} else if t == "float64" {
			translate[j] = floatPosition
			floatPosition++
		}

	}

	lines := strings.Split(data, "\n")
	for _, v := range lines {
		if v == "" {
			continue
		}
		columns := strings.Split(v, "\t")
		row := TmpRow7{}
		index := 0
		for j, col := range columns {
			index = translate[j]
			switch {
			case index == 1:
				row.Str1 = col
			case index == 2:
				row.Str2 = col
			case index == 3:
				row.Str3 = col
			case index == 4:
				row.Str4 = col
			case index == 5:
				row.Str5 = col
			case index == 6:
				row.Str6 = col
			case index == 7:
				row.Str7 = col
			case index >= 7 && index <= 14:
				tmpInt, err := strconv.ParseInt(col, 10, 64)
				if err != nil {
					tmpInt = 0
				}
				switch {
				case index == 8:
					row.Int1 = tmpInt
				case index == 9:
					row.Int2 = tmpInt
				case index == 10:
					row.Int3 = tmpInt
				case index == 11:
					row.Int4 = tmpInt
				case index == 12:
					row.Int5 = tmpInt
				case index == 13:
					row.Int6 = tmpInt
				case index == 14:
					row.Int7 = tmpInt
				}
			case index >= 15 && index <= 21:
				tmpFloat, err := strconv.ParseFloat(col, 64)
				if err != nil {
					tmpFloat = 0
				}
				switch {
				case index == 15:
					row.Float1 = tmpFloat
				case index == 16:
					row.Float2 = tmpFloat
				case index == 17:
					row.Float3 = tmpFloat
				case index == 18:
					row.Float4 = tmpFloat
				case index == 19:
					row.Float5 = tmpFloat
				case index == 20:
					row.Float6 = tmpFloat
				case index == 21:
					row.Float7 = tmpFloat
				}

			}
		}

		result = append(result, row)
	}
	return result
}
<commit_msg>cleanup<commit_after>package common

import (
	"fmt"
	"net/http"
	"net/http/httputil"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"
)

func ValidBarcode8(s string) bool {
	re := regexp.MustCompile("^[A-Z0-9]{8,8}$")
	return re.MatchString(s)
}

func ValidBarcode7(s string) bool {
	re := regexp.MustCompile("^[A-Z0-9]{7,7}$")
	return re.MatchString(s)
}

func ValidCarton20(s string) bool {
	re := regexp.MustCompile("^[0-9]{20,20}$")
	return re.MatchString(s)
}

func ReverseProxy(proxyPort string, pathMap map[string]string) {

	for urlPath, targetPort := range pathMap {
		u, _ := url.Parse("http://127.0.0.1:" + targetPort)
		http.Handle(urlPath, httputil.NewSingleHostReverseProxy(u))
	}

	http.ListenAndServe(":"+proxyPort, nil)

}

func TimeNowString() string {
	return fmt.Sprintf("%v", time.Unix(0, time.Now().UnixNano()/(int64(time.Millisecond)/int64(time.Nanosecond))*int64(time.Millisecond)))[:23]
}

func EscapeLatex(s string) string {
	s2 := strings.Replace(s, "\\", "\\textbackslash", -1)
	s2 = strings.Replace(s2, "&", "\\&", -1)
	s2 = strings.Replace(s2, "%", "\\%", -1)
	s2 = strings.Replace(s2, "$", "\\$", -1)
	s2 = strings.Replace(s2, "#", "\\#", -1)
	s2 = strings.Replace(s2, "_", "\\_", -1)
	s2 = strings.Replace(s2, "{", "\\{", -1)
	s2 = strings.Replace(s2, "}", "\\}", -1)
	s2 = strings.Replace(s2, "~", "\\textasciitilde", -1)
	return strings.Replace(s2, "^", "\\textasciicircum", -1)

}

func PadZero(s string) string {
	if s[0] == '.' {
		return "0" + s
	} else {
		return s
	}
}

type TmpRow7 struct {
	Str1   string
	Str2   string
	Str3   string
	Str4   string
	Str5   string
	Str6   string
	Str7   string
	Int1   int64
	Int2   int64
	Int3   int64
	Int4   int64
	Int5   int64
	Int6   int64
	Int7   int64
	Float1 float64
	Float2 float64
	Float3 float64
	Float4 float64
	Float5 float64
	Float6 float64
	Float7 float64
}

func IndexOf(target int, intSlice []int) int {
	for i, v := range intSlice {
		if v == target {
			return i
		}
	}
	return -1
}

func StringToRows7(data string, config []string) []TmpRow7 {
	var translate [21]int
	strPosition := 1
	intPosition := 8
	floatPosition := 15
	var result []TmpRow7

	for j, t := range config {
		if t == "string" {
			translate[j] = strPosition
			strPosition++
		} else if t == "int64" {
			translate[j] = intPosition
			intPosition++

		} else if t == "float64" {
			translate[j] = floatPosition
			floatPosition++
		}

	}

	lines := strings.Split(data, "\n")
	for _, v := range lines {
		if v == "" {
			continue
		}
		columns := strings.Split(v, "\t")
		row := TmpRow7{}
		index := 0
		for j, col := range columns {
			index = translate[j]
			switch {
			case index == 1:
				row.Str1 = col
			case index == 2:
				row.Str2 = col
			case index == 3:
				row.Str3 = col
			case index == 4:
				row.Str4 = col
			case index == 5:
				row.Str5 = col
			case index == 6:
				row.Str6 = col
			case index == 7:
				row.Str7 = col
			case index >= 7 && index <= 14:
				tmpInt, err := strconv.ParseInt(col, 10, 64)
				if err != nil {
					tmpInt = 0
				}
				switch {
				case index == 8:
					row.Int1 = tmpInt
				case index == 9:
					row.Int2 = tmpInt
				case index == 10:
					row.Int3 = tmpInt
				case index == 11:
					row.Int4 = tmpInt
				case index == 12:
					row.Int5 = tmpInt
				case index == 13:
					row.Int6 = tmpInt
				case index == 14:
					row.Int7 = tmpInt
				}
			case index >= 15 && index <= 21:
				tmpFloat, err := strconv.ParseFloat(col, 64)
				if err != nil {
					tmpFloat = 0
				}
				switch {
				case index == 15:
					row.Float1 = tmpFloat
				case index == 16:
					row.Float2 = tmpFloat
				case index == 17:
					row.Float3 = tmpFloat
				case index == 18:
					row.Float4 = tmpFloat
				case index == 19:
					row.Float5 = tmpFloat
				case index == 20:
					row.Float6 = tmpFloat
				case index == 21:
					row.Float7 = tmpFloat
				}

			}
		}

		result = append(result, row)
	}
	return result
}
<|endoftext|>


<commit_before>package openweathermap

var (
	baseUrl      string = "http://api.openweathermap.org/data/2.5/weather?%s"
	iconUrl      string = "http://openweathermap.org/img/w/%s"
	stationUrl   string = "http://api.openweathermap.org/data/2.5/station?id=%d"
	forecastBase string = "http://api.openweathermap.org/data/2.5/forecast/daily?%s=%s&mode=json&units=%s&cnt=%d"
	dataUnits           = [3]string{"metric", "imperial", "internal"}
)

// Config will hold default settings to be passed into the
// "New..." function.
type Config struct {
	Mode  string // JSON or XML
	Units string // Imperial, metric, or internal
}

// APIError returned on failed API calls.
type APIError struct {
	Message string `json:"message"`
	COD     string `json:"cod"`
}

// Coordinates struct holds longitude and latitude data
// in returned JSON or as parameter data for requests
// using longitude and latitude.
type Coordinates struct {
	Longitude float64 `json:"lon"`
	Latitude  float64 `json:"lat"`
}

// Sys struct contains general information about the request and the
// surrounding area for where the request was made.
type Sys struct {
	Type    int     `json:"type"`
	Id      int     `json:"id"`
	Message float64 `json:"message"`
	Country string  `json:"country"`
	Sunrise int     `json:"sunrise"`
	Sunset  int     `json:"sunset"`
}

// Wind struct contains the speed and degree of the wind.
type Wind struct {
	Speed float64 `json:"speed"`
	Deg   int     `json:"deg"`
}

// Weather struct holds high-level, basic info on the returned
// data.
type Weather struct {
	Id          int    `json:"id"`
	Main        string `json:"main"`
	Description string `json:"description"`
	Icon        string `json:"icon"`
}

// Main struct contains the meat and potatos of the request.
type Main struct {
	Temp     float64 `json:"temp"`
	TempMin  float64 `json:"temp_min"`
	TempMax  float64 `json:"temp_max"`
	Pressure int     `json:"pressure"`
	Humidity int     `json:"humidity"`
}

// Clouds struct holds data regarding cloud cover.
type Clouds struct {
	All int `json:"all"`
}
<commit_msg>Added function to check provided data unit<commit_after>package openweathermap

var (
	baseUrl      string = "http://api.openweathermap.org/data/2.5/weather?%s"
	iconUrl      string = "http://openweathermap.org/img/w/%s"
	stationUrl   string = "http://api.openweathermap.org/data/2.5/station?id=%d"
	forecastBase string = "http://api.openweathermap.org/data/2.5/forecast/daily?%s=%s&mode=json&units=%s&cnt=%d"
	dataUnits           = [3]string{"metric", "imperial", "internal"}
)

// Config will hold default settings to be passed into the
// "New..." function.
type Config struct {
	Mode  string // JSON or XML
	Units string // Imperial, metric, or internal
}

// APIError returned on failed API calls.
type APIError struct {
	Message string `json:"message"`
	COD     string `json:"cod"`
}

// Coordinates struct holds longitude and latitude data
// in returned JSON or as parameter data for requests
// using longitude and latitude.
type Coordinates struct {
	Longitude float64 `json:"lon"`
	Latitude  float64 `json:"lat"`
}

// Sys struct contains general information about the request and the
// surrounding area for where the request was made.
type Sys struct {
	Type    int     `json:"type"`
	Id      int     `json:"id"`
	Message float64 `json:"message"`
	Country string  `json:"country"`
	Sunrise int     `json:"sunrise"`
	Sunset  int     `json:"sunset"`
}

// Wind struct contains the speed and degree of the wind.
type Wind struct {
	Speed float64 `json:"speed"`
	Deg   int     `json:"deg"`
}

// Weather struct holds high-level, basic info on the returned
// data.
type Weather struct {
	Id          int    `json:"id"`
	Main        string `json:"main"`
	Description string `json:"description"`
	Icon        string `json:"icon"`
}

// Main struct contains the meat and potatos of the request.
type Main struct {
	Temp     float64 `json:"temp"`
	TempMin  float64 `json:"temp_min"`
	TempMax  float64 `json:"temp_max"`
	Pressure int     `json:"pressure"`
	Humidity int     `json:"humidity"`
}

// Clouds struct holds data regarding cloud cover.
type Clouds struct {
	All int `json:"all"`
}

// ValidDataUnit makes sure the string passed in is an accepted
// unit of measure to be used for the return data.
func ValidDataUnit(h *HistoricalWeatherData) bool {
	for _, m := range dataUnits {
		if h.Units == m {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package QesyGo

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"strconv"
	"strings"
	"time"
)

type RandWeiht struct {
	Name   string
	Weight int
}

var randSeek int64 = 0

type RandWeihtArr []RandWeiht

func Substr(str string, start int, end int) string {
	var endNum int
	s := []byte(str)
	if end > 0 {
		endNum = start + end
	} else {
		endNum = len(str) + end
	}
	return string(s[start:endNum])
}

func Rand(Min int, Max int) int {
	tempNum := Max - Min
	if randSeek > 9999999999 {
		randSeek = 0
	} else {
		randSeek++
	}
	rand.Seed(time.Now().UnixNano() + randSeek)
	return Min + rand.Intn(tempNum)
}

func Rate(num int) bool {
	rand := Rand(1, 100)
	if rand <= num {
		return true
	} else {
		return false
	}
}

/*
* RandWeihtArr := &lib.RandWeihtArr{{"user1",8}, {"user2",1},{"user3",1}}
* who := RandWeihtArr.RandWeight()
 */
func (arr *RandWeihtArr) RandWeight() string {
	var all int
	for _, v := range *arr {
		all += v.Weight
	}
	plusNum := 0
	tempArr := make(map[string][2]int)
	for _, v := range *arr {
		plusNum += v.Weight
		tempArr[v.Name] = [2]int{plusNum - v.Weight, plusNum}
	}
	randNum := Rand(0, all) + 1
	var ret string
	for k, v := range tempArr {
		if randNum > v[0] && randNum <= v[1] {
			ret = k
			break
		}
	}
	return ret
}

func ReadFile(str string) ([]byte, error) {
	return ioutil.ReadFile(str)
}

func JsonEncode(arr interface{}) ([]byte, error) {
	return json.Marshal(arr)
}

func JsonDecode(str []byte, jsonArr interface{}) error {
	strNew := string(str)
	if strNew == "null" || strNew == "" {
		return nil
	}
	err := json.Unmarshal(str, jsonArr)
	return err

}

func Printf(format string, a ...interface{}) {
	fmt.Printf(format, a)
}

func Fprintf(w http.ResponseWriter, str string) {
	fmt.Fprintf(w, str)
}

func Die(v interface{}) {
	log.Fatal(v)
}

func Implode(arr []string, sep string) string {
	return strings.Join(arr, sep)
}

func Explode(str string, sep string) []string {
	if str == "" {
		return []string{}
	}
	return strings.Split(str, sep)
}

func Err(str string) error {
	return errors.New(str)
}

func Println(str ...interface{}) {
	fmt.Println(str)
}

func Time(str string) int64 {
	now := time.Now()
	t := now.UnixNano()
	switch str {
	case "Millisecond":
		t = now.UnixNano() / 1000
	case "Microsecond":
		t = now.UnixNano() / 1000000
	case "Second":
		t = now.UnixNano() / 1000000000
	}
	return t
}

func TimeStr(str string) string {
	t := Time(str)
	return strconv.FormatInt(t, 10)
}

func TimeInt(str string) int {
	t := Time(str)
	ret, _ := Int64ToInt(t)
	return ret
}

//-- format : "2006-01-02 03:04:05 PM" --
/*
月份 1,01,Jan,January
日　 2,02,_2
时　 3,03,15,PM,pm,AM,am
分　 4,04
秒　 5,05
年　 06,2006
周几 Mon,Monday
时区时差表示 -07,-0700,Z0700,Z07:00,-07:00,MST
时区字母缩写 MST
*/
func Date(timestamp int64, format string) string {
	tm := time.Unix(timestamp, 0)
	return tm.Format(format)
}

//-- "01/02/2006", "02/08/2015" --
func StrToTime(format string, input string) int64 {
	tm2, _ := time.Parse(format, input)
	return tm2.Unix()
}

func Int64ToInt(num int64) (int, error) {
	str := strconv.FormatInt(num, 10)
	return strconv.Atoi(str)
}

func Unset(arr []string, str string) []string {
	newArr := []string{}
	for _, v := range arr {
		if v != str && v != "" {
			newArr = append(newArr, v)
		}
	}
	return newArr
}

//-- kind 0:纯数字，1：小写，2：大写，3：数字+大小写字幕 --
func Krand(size int, kind int) []byte {
	ikind, kinds, result := kind, [][]int{[]int{10, 48}, []int{26, 97}, []int{26, 65}}, make([]byte, size)
	is_all := kind > 2 || kind < 0
	rand.Seed(time.Now().UnixNano())
	for i := 0; i < size; i++ {
		if is_all { // random ikind
			ikind = Rand(1, 3)
		}
		scope, base := kinds[ikind][0], kinds[ikind][1]
		result[i] = uint8(base + Rand(1, scope))
	}
	return result
}
<commit_msg>strtoint add<commit_after>package QesyGo

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"strconv"
	"strings"
	"time"
)

type RandWeiht struct {
	Name   string
	Weight int
}

var randSeek int64 = 0

type RandWeihtArr []RandWeiht

func Substr(str string, start int, end int) string {
	var endNum int
	s := []byte(str)
	if end > 0 {
		endNum = start + end
	} else {
		endNum = len(str) + end
	}
	return string(s[start:endNum])
}

func Rand(Min int, Max int) int {
	tempNum := Max - Min
	if randSeek > 9999999999 {
		randSeek = 0
	} else {
		randSeek++
	}
	rand.Seed(time.Now().UnixNano() + randSeek)
	return Min + rand.Intn(tempNum)
}

func Rate(num int) bool {
	rand := Rand(1, 100)
	if rand <= num {
		return true
	} else {
		return false
	}
}

/*
* RandWeihtArr := &lib.RandWeihtArr{{"user1",8}, {"user2",1},{"user3",1}}
* who := RandWeihtArr.RandWeight()
 */
func (arr *RandWeihtArr) RandWeight() string {
	var all int
	for _, v := range *arr {
		all += v.Weight
	}
	plusNum := 0
	tempArr := make(map[string][2]int)
	for _, v := range *arr {
		plusNum += v.Weight
		tempArr[v.Name] = [2]int{plusNum - v.Weight, plusNum}
	}
	randNum := Rand(0, all) + 1
	var ret string
	for k, v := range tempArr {
		if randNum > v[0] && randNum <= v[1] {
			ret = k
			break
		}
	}
	return ret
}

func ReadFile(str string) ([]byte, error) {
	return ioutil.ReadFile(str)
}

func JsonEncode(arr interface{}) ([]byte, error) {
	return json.Marshal(arr)
}

func JsonDecode(str []byte, jsonArr interface{}) error {
	strNew := string(str)
	if strNew == "null" || strNew == "" {
		return nil
	}
	err := json.Unmarshal(str, jsonArr)
	return err

}

func Printf(format string, a ...interface{}) {
	fmt.Printf(format, a)
}

func Fprintf(w http.ResponseWriter, str string) {
	fmt.Fprintf(w, str)
}

func Die(v interface{}) {
	log.Fatal(v)
}

func Implode(arr []string, sep string) string {
	return strings.Join(arr, sep)
}

func Explode(str string, sep string) []string {
	if str == "" {
		return []string{}
	}
	return strings.Split(str, sep)
}

func Err(str string) error {
	return errors.New(str)
}

func Println(str ...interface{}) {
	fmt.Println(str)
}

func Time(str string) int64 {
	now := time.Now()
	t := now.UnixNano()
	switch str {
	case "Millisecond":
		t = now.UnixNano() / 1000
	case "Microsecond":
		t = now.UnixNano() / 1000000
	case "Second":
		t = now.UnixNano() / 1000000000
	}
	return t
}

func TimeStr(str string) string {
	t := Time(str)
	return strconv.FormatInt(t, 10)
}

func TimeInt(str string) int {
	t := Time(str)
	ret, _ := Int64ToInt(t)
	return ret
}

//-- format : "2006-01-02 03:04:05 PM" --
/*
月份 1,01,Jan,January
日　 2,02,_2
时　 3,03,15,PM,pm,AM,am
分　 4,04
秒　 5,05
年　 06,2006
周几 Mon,Monday
时区时差表示 -07,-0700,Z0700,Z07:00,-07:00,MST
时区字母缩写 MST
*/
func Date(timestamp int64, format string) string {
	tm := time.Unix(timestamp, 0)
	return tm.Format(format)
}

//-- "01/02/2006", "02/08/2015" --
func StrToTime(format string, input string) int64 {
	tm2, _ := time.Parse(format, input)
	return tm2.Unix()
}

func Int64ToInt(num int64) (int, error) {
	str := strconv.FormatInt(num, 10)
	return strconv.Atoi(str)
}

func StrToInt(str string) int {
	ret, _ := strconv.Atoi(str)
	return ret
}

func Unset(arr []string, str string) []string {
	newArr := []string{}
	for _, v := range arr {
		if v != str && v != "" {
			newArr = append(newArr, v)
		}
	}
	return newArr
}

//-- kind 0:纯数字，1：小写，2：大写，3：数字+大小写字幕 --
func Krand(size int, kind int) []byte {
	ikind, kinds, result := kind, [][]int{[]int{10, 48}, []int{26, 97}, []int{26, 65}}, make([]byte, size)
	is_all := kind > 2 || kind < 0
	rand.Seed(time.Now().UnixNano())
	for i := 0; i < size; i++ {
		if is_all { // random ikind
			ikind = Rand(1, 3)
		}
		scope, base := kinds[ikind][0], kinds[ikind][1]
		result[i] = uint8(base + Rand(1, scope))
	}
	return result
}
<|endoftext|>


<commit_before>package common

import (
	"net/http"
	"net/http/httputil"
	"net/url"
	"regexp"
)

func ValidBarcode8(s string) bool {
	re := regexp.MustCompile("^[A-Z0-9]{8,8}$")
	return re.MatchString(s)
}

func ValidBarcode7(s string) bool {
	re := regexp.MustCompile("^[A-Z0-9]{7,7}$")
	return re.MatchString(s)
}

func ValidCarton20(s string) bool {
	re := regexp.MustCompile("^[0-9]{20,20}$")
	return re.MatchString(s)
}

func ReverseProxy(proxyPort string, pathMap map[string]string) {

	for urlPath, targetPort := range pathMap {
		u, _ := url.Parse("http://127.0.0.1:" + targetPort)
		http.Handle(urlPath, httputil.NewSingleHostReverseProxy(u))
	}

	http.ListenAndServe(":"+proxyPort, nil)

}
<commit_msg>added TimeNowString<commit_after>package common

import (
	"fmt"
	"net/http"
	"net/http/httputil"
	"net/url"
	"regexp"
	"time"
)

func ValidBarcode8(s string) bool {
	re := regexp.MustCompile("^[A-Z0-9]{8,8}$")
	return re.MatchString(s)
}

func ValidBarcode7(s string) bool {
	re := regexp.MustCompile("^[A-Z0-9]{7,7}$")
	return re.MatchString(s)
}

func ValidCarton20(s string) bool {
	re := regexp.MustCompile("^[0-9]{20,20}$")
	return re.MatchString(s)
}

func ReverseProxy(proxyPort string, pathMap map[string]string) {

	for urlPath, targetPort := range pathMap {
		u, _ := url.Parse("http://127.0.0.1:" + targetPort)
		http.Handle(urlPath, httputil.NewSingleHostReverseProxy(u))
	}

	http.ListenAndServe(":"+proxyPort, nil)

}

func TimeNowString() string {
	return fmt.Sprintf("%v", time.Unix(0, time.Now().UnixNano()/(int64(time.Millisecond)/int64(time.Nanosecond))*int64(time.Millisecond)))[:23]
}
<|endoftext|>


<commit_before>package manet

import (
	"bytes"

	ma "github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
)

// Loopback Addresses
var (
	// IP4Loopback is the ip4 loopback multiaddr
	IP4Loopback = ma.StringCast("/ip4/127.0.0.1")

	// IP6Loopback is the ip6 loopback multiaddr
	IP6Loopback = ma.StringCast("/ip6/::1")

	// IP6LinkLocalLoopback is the ip6 link-local loopback multiaddr
	IP6LinkLocalLoopback = ma.StringCast("/ip6/fe80::1")
)

// Unspecified Addresses (used for )
var (
	IP4Unspecified = ma.StringCast("/ip4/0.0.0.0")
	IP6Unspecified = ma.StringCast("/ip6/::")
)

// IsThinWaist returns whether a Multiaddr starts with "Thin Waist" Protocols.
// This means: /{IP4, IP6}[/{TCP, UDP}]
func IsThinWaist(m ma.Multiaddr) bool {
	p := m.Protocols()

	// nothing? not even a waist.
	if len(p) == 0 {
		return false
	}

	if p[0].Code != ma.P_IP4 && p[0].Code != ma.P_IP6 {
		return false
	}

	// only IP? still counts.
	if len(p) == 1 {
		return true
	}

	switch p[1].Code {
	case ma.P_TCP, ma.P_UDP, ma.P_IP4, ma.P_IP6:
		return true
	default:
		return false
	}
}

// IsIPLoopback returns whether a Multiaddr is a "Loopback" IP address
// This means either /ip4/127.0.0.1 or /ip6/::1
func IsIPLoopback(m ma.Multiaddr) bool {
	b := m.Bytes()

	// /ip4/127 prefix (_entire_ /8 is loopback...)
	if bytes.HasPrefix(b, []byte{ma.P_IP4, 127}) {
		return true
	}

	// /ip6/::1
	if IP6Loopback.Equal(m) || IP6LinkLocalLoopback.Equal(m) {
		return true
	}

	return false
}

// IP6 Link Local addresses are non routable. The prefix is technically
// fe80::/10, but we test fe80::/16 for simplicity (no need to mask).
// So far, no hardware interfaces exist long enough to use those 2 bits.
// Send a PR if there is.
func IsIP6LinkLocal(m ma.Multiaddr) bool {
	return bytes.HasPrefix(m.Bytes(), []byte{ma.P_IP6, 0xfe, 0x80})
}

// IsIPUnspecified returns whether a Multiaddr is am Unspecified IP address
// This means either /ip4/0.0.0.0 or /ip6/::
func IsIPUnspecified(m ma.Multiaddr) bool {
	return IP4Unspecified.Equal(m) || IP6Unspecified.Equal(m)
}
<commit_msg>added todo<commit_after>package manet

import (
	"bytes"

	ma "github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
)

// Loopback Addresses
var (
	// IP4Loopback is the ip4 loopback multiaddr
	IP4Loopback = ma.StringCast("/ip4/127.0.0.1")

	// IP6Loopback is the ip6 loopback multiaddr
	IP6Loopback = ma.StringCast("/ip6/::1")

	// IP6LinkLocalLoopback is the ip6 link-local loopback multiaddr
	IP6LinkLocalLoopback = ma.StringCast("/ip6/fe80::1")
)

// Unspecified Addresses (used for )
var (
	IP4Unspecified = ma.StringCast("/ip4/0.0.0.0")
	IP6Unspecified = ma.StringCast("/ip6/::")
)

// IsThinWaist returns whether a Multiaddr starts with "Thin Waist" Protocols.
// This means: /{IP4, IP6}[/{TCP, UDP}]
func IsThinWaist(m ma.Multiaddr) bool {
	p := m.Protocols()

	// nothing? not even a waist.
	if len(p) == 0 {
		return false
	}

	if p[0].Code != ma.P_IP4 && p[0].Code != ma.P_IP6 {
		return false
	}

	// only IP? still counts.
	if len(p) == 1 {
		return true
	}

	switch p[1].Code {
	case ma.P_TCP, ma.P_UDP, ma.P_IP4, ma.P_IP6:
		return true
	default:
		return false
	}
}

// IsIPLoopback returns whether a Multiaddr is a "Loopback" IP address
// This means either /ip4/127.0.0.1 or /ip6/::1
// TODO: differentiate IsIPLoopback and OverIPLoopback
func IsIPLoopback(m ma.Multiaddr) bool {
	b := m.Bytes()

	// /ip4/127 prefix (_entire_ /8 is loopback...)
	if bytes.HasPrefix(b, []byte{ma.P_IP4, 127}) {
		return true
	}

	// /ip6/::1
	if IP6Loopback.Equal(m) || IP6LinkLocalLoopback.Equal(m) {
		return true
	}

	return false
}

// IP6 Link Local addresses are non routable. The prefix is technically
// fe80::/10, but we test fe80::/16 for simplicity (no need to mask).
// So far, no hardware interfaces exist long enough to use those 2 bits.
// Send a PR if there is.
func IsIP6LinkLocal(m ma.Multiaddr) bool {
	return bytes.HasPrefix(m.Bytes(), []byte{ma.P_IP6, 0xfe, 0x80})
}

// IsIPUnspecified returns whether a Multiaddr is am Unspecified IP address
// This means either /ip4/0.0.0.0 or /ip6/::
func IsIPUnspecified(m ma.Multiaddr) bool {
	return IP4Unspecified.Equal(m) || IP6Unspecified.Equal(m)
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 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 jaeger

import (
	"sync"
	"sync/atomic"
	"time"

	"github.com/opentracing/opentracing-go"

	"github.com/uber/jaeger-client-go/thrift-gen/zipkincore"
	"github.com/uber/jaeger-client-go/transport"
)

// Reporter is called by the tracer when a span is completed to report the span to the tracing collector.
type Reporter interface {
	// Report submits a new span to collectors, possibly asynchronously and/or with buffering.
	Report(span *span)

	// Close does a clean shutdown of the reporter, flushing any traces that may be buffered in memory.
	Close()
}

// ------------------------------

type nullReporter struct{}

// NewNullReporter creates a no-op reporter that ignores all reported spans.
func NewNullReporter() Reporter {
	return &nullReporter{}
}

// Report implements Report() method of Reporter by doing nothing.
func (r *nullReporter) Report(span *span) {
	// no-op
}

// Close implements Close() method of Reporter by doing nothing.
func (r *nullReporter) Close() {
	// no-op
}

// ------------------------------

type loggingReporter struct {
	logger Logger
}

// NewLoggingReporter creates a reporter that logs all reported spans to provided logger.
func NewLoggingReporter(logger Logger) Reporter {
	return &loggingReporter{logger}
}

// Report implements Report() method of Reporter by logging the span to the logger.
func (r *loggingReporter) Report(span *span) {
	r.logger.Infof("Reporting span %+v", span)
}

// Close implements Close() method of Reporter by doing nothing.
func (r *loggingReporter) Close() {
	// no-op
}

// ------------------------------

// InMemoryReporter is used for testing, and simply collects spans in memory.
type InMemoryReporter struct {
	spans []opentracing.Span
	lock  sync.Mutex
}

// NewInMemoryReporter creates a reporter that stores spans in memory.
// NOTE: the Tracer should be created with options.PoolSpans = false.
func NewInMemoryReporter() *InMemoryReporter {
	return &InMemoryReporter{
		spans: make([]opentracing.Span, 0, 10),
	}
}

// Report implements Report() method of Reporter by storing the span in the buffer.
func (r *InMemoryReporter) Report(span *span) {
	r.lock.Lock()
	r.spans = append(r.spans, span)
	r.lock.Unlock()
}

// Close implements Close() method of Reporter by doing nothing.
func (r *InMemoryReporter) Close() {
	// no-op
}

// SpansSubmitted returns the number of spans accumulated in the buffer.
func (r *InMemoryReporter) SpansSubmitted() int {
	r.lock.Lock()
	defer r.lock.Unlock()
	return len(r.spans)
}

// GetSpans returns accumulated spans as a copy of the buffer.
func (r *InMemoryReporter) GetSpans() []opentracing.Span {
	r.lock.Lock()
	defer r.lock.Unlock()
	copied := make([]opentracing.Span, len(r.spans))
	copy(copied, r.spans)
	return copied
}

// ------------------------------

type compositeReporter struct {
	reporters []Reporter
}

// NewCompositeReporter creates a reporter that ignores all reported spans.
func NewCompositeReporter(reporters ...Reporter) Reporter {
	return &compositeReporter{reporters: reporters}
}

// Report implements Report() method of Reporter by delegating to each underlying reporter.
func (r *compositeReporter) Report(span *span) {
	for _, reporter := range r.reporters {
		reporter.Report(span)
	}
}

// Close implements Close() method of Reporter by closing each underlying reporter.
func (r *compositeReporter) Close() {
	for _, reporter := range r.reporters {
		reporter.Close()
	}
}

// ------------------------------

const (
	defaultQueueSize           = 100
	defaultBufferFlushInterval = 10 * time.Second
)

type remoteReporter struct {
	ReporterOptions
	sender       transport.Transport
	queue        chan *zipkincore.Span
	queueLength  int64 // signed because metric's gauge is signed
	queueDrained sync.WaitGroup
	flushSignal  chan *sync.WaitGroup
}

// ReporterOptions control behavior of the reporter
type ReporterOptions struct {
	// QueueSize is the size of internal queue where reported spans are stored before they are processed in the background
	QueueSize int
	// BufferFlushInterval is how often the buffer is force-flushed, even if it's not full
	BufferFlushInterval time.Duration
	// Logger is used to log errors of span submissions
	Logger Logger
	// Metrics is used to record runtime stats
	Metrics *Metrics
}

// NewRemoteReporter creates a new reporter that sends spans out of process by means of Sender
func NewRemoteReporter(sender transport.Transport, options *ReporterOptions) Reporter {
	if options == nil {
		options = &ReporterOptions{}
	}
	if options.QueueSize <= 0 {
		options.QueueSize = defaultQueueSize
	}
	if options.BufferFlushInterval <= 0 {
		options.BufferFlushInterval = defaultBufferFlushInterval
	}
	if options.Logger == nil {
		options.Logger = NullLogger
	}
	if options.Metrics == nil {
		options.Metrics = NewMetrics(NullStatsReporter, nil)
	}

	reporter := &remoteReporter{
		ReporterOptions: *options,
		sender:          sender,
		queue:           make(chan *zipkincore.Span, options.QueueSize),
		flushSignal:     make(chan *sync.WaitGroup),
	}
	go reporter.processQueue()
	return reporter
}

// Report implements Report() method of Reporter.
// It passes the span to a background go-routine for submission to Jaeger.
func (r *remoteReporter) Report(span *span) {
	thriftSpan := buildThriftSpan(span)
	select {
	case r.queue <- thriftSpan:
		atomic.AddInt64(&r.queueLength, 1)
	default:
		r.Metrics.ReporterDropped.Inc(1)
	}
}

// Close implements Close() method of Reporter by waiting for the queue to be drained.
func (r *remoteReporter) Close() {
	r.queueDrained.Add(1)
	close(r.queue)
	r.queueDrained.Wait()
}

// processQueue reads spans from the queue, converts them to Thrift, and stores them in an internal buffer.
// When the buffer length reaches batchSize, it is flushed by submitting the accumulated spans to Jaeger.
// Buffer also gets flushed automatically every batchFlushInterval seconds, just in case the tracer stopped
// reporting new spans.
func (r *remoteReporter) processQueue() {
	timer := time.NewTicker(r.BufferFlushInterval)
	for {
		select {
		case span, ok := <-r.queue:
			if ok {
				atomic.AddInt64(&r.queueLength, -1)
				if flushed, err := r.sender.Append(span); err != nil {
					r.Metrics.ReporterFailure.Inc(int64(flushed))
					r.Logger.Error(err.Error())
				} else if flushed > 0 {
					r.Metrics.ReporterSuccess.Inc(int64(flushed))
					// to reduce the number of gauge stats, we only emit queue length on flush
					r.Metrics.ReporterQueueLength.Update(atomic.LoadInt64(&r.queueLength))
				}
			} else {
				// queue closed
				timer.Stop()
				r.flush()
				r.queueDrained.Done()
				return
			}
		case <-timer.C:
			r.flush()
		case wg := <-r.flushSignal: // for testing
			r.flush()
			wg.Done()
		}
	}
}

// flush causes the Sender to flush its accumulated spans and clear the buffer
func (r *remoteReporter) flush() {
	if flushed, err := r.sender.Flush(); err != nil {
		r.Metrics.ReporterFailure.Inc(int64(flushed))
		r.Logger.Error(err.Error())
	} else if flushed > 0 {
		r.Metrics.ReporterSuccess.Inc(int64(flushed))
	}
}
<commit_msg>Add InMemoryReporter.Reset() method<commit_after>// Copyright (c) 2016 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 jaeger

import (
	"sync"
	"sync/atomic"
	"time"

	"github.com/opentracing/opentracing-go"

	"github.com/uber/jaeger-client-go/thrift-gen/zipkincore"
	"github.com/uber/jaeger-client-go/transport"
)

// Reporter is called by the tracer when a span is completed to report the span to the tracing collector.
type Reporter interface {
	// Report submits a new span to collectors, possibly asynchronously and/or with buffering.
	Report(span *span)

	// Close does a clean shutdown of the reporter, flushing any traces that may be buffered in memory.
	Close()
}

// ------------------------------

type nullReporter struct{}

// NewNullReporter creates a no-op reporter that ignores all reported spans.
func NewNullReporter() Reporter {
	return &nullReporter{}
}

// Report implements Report() method of Reporter by doing nothing.
func (r *nullReporter) Report(span *span) {
	// no-op
}

// Close implements Close() method of Reporter by doing nothing.
func (r *nullReporter) Close() {
	// no-op
}

// ------------------------------

type loggingReporter struct {
	logger Logger
}

// NewLoggingReporter creates a reporter that logs all reported spans to provided logger.
func NewLoggingReporter(logger Logger) Reporter {
	return &loggingReporter{logger}
}

// Report implements Report() method of Reporter by logging the span to the logger.
func (r *loggingReporter) Report(span *span) {
	r.logger.Infof("Reporting span %+v", span)
}

// Close implements Close() method of Reporter by doing nothing.
func (r *loggingReporter) Close() {
	// no-op
}

// ------------------------------

// InMemoryReporter is used for testing, and simply collects spans in memory.
type InMemoryReporter struct {
	spans []opentracing.Span
	lock  sync.Mutex
}

// NewInMemoryReporter creates a reporter that stores spans in memory.
// NOTE: the Tracer should be created with options.PoolSpans = false.
func NewInMemoryReporter() *InMemoryReporter {
	return &InMemoryReporter{
		spans: make([]opentracing.Span, 0, 10),
	}
}

// Report implements Report() method of Reporter by storing the span in the buffer.
func (r *InMemoryReporter) Report(span *span) {
	r.lock.Lock()
	r.spans = append(r.spans, span)
	r.lock.Unlock()
}

// Close implements Close() method of Reporter by doing nothing.
func (r *InMemoryReporter) Close() {
	// no-op
}

// SpansSubmitted returns the number of spans accumulated in the buffer.
func (r *InMemoryReporter) SpansSubmitted() int {
	r.lock.Lock()
	defer r.lock.Unlock()
	return len(r.spans)
}

// GetSpans returns accumulated spans as a copy of the buffer.
func (r *InMemoryReporter) GetSpans() []opentracing.Span {
	r.lock.Lock()
	defer r.lock.Unlock()
	copied := make([]opentracing.Span, len(r.spans))
	copy(copied, r.spans)
	return copied
}

// Reset clears all accumulated spans.
func (r *InMemoryReporter) Reset() {
	r.lock.Lock()
	defer r.lock.Unlock()
	r.spans = nil
}

// ------------------------------

type compositeReporter struct {
	reporters []Reporter
}

// NewCompositeReporter creates a reporter that ignores all reported spans.
func NewCompositeReporter(reporters ...Reporter) Reporter {
	return &compositeReporter{reporters: reporters}
}

// Report implements Report() method of Reporter by delegating to each underlying reporter.
func (r *compositeReporter) Report(span *span) {
	for _, reporter := range r.reporters {
		reporter.Report(span)
	}
}

// Close implements Close() method of Reporter by closing each underlying reporter.
func (r *compositeReporter) Close() {
	for _, reporter := range r.reporters {
		reporter.Close()
	}
}

// ------------------------------

const (
	defaultQueueSize           = 100
	defaultBufferFlushInterval = 10 * time.Second
)

type remoteReporter struct {
	ReporterOptions
	sender       transport.Transport
	queue        chan *zipkincore.Span
	queueLength  int64 // signed because metric's gauge is signed
	queueDrained sync.WaitGroup
	flushSignal  chan *sync.WaitGroup
}

// ReporterOptions control behavior of the reporter
type ReporterOptions struct {
	// QueueSize is the size of internal queue where reported spans are stored before they are processed in the background
	QueueSize int
	// BufferFlushInterval is how often the buffer is force-flushed, even if it's not full
	BufferFlushInterval time.Duration
	// Logger is used to log errors of span submissions
	Logger Logger
	// Metrics is used to record runtime stats
	Metrics *Metrics
}

// NewRemoteReporter creates a new reporter that sends spans out of process by means of Sender
func NewRemoteReporter(sender transport.Transport, options *ReporterOptions) Reporter {
	if options == nil {
		options = &ReporterOptions{}
	}
	if options.QueueSize <= 0 {
		options.QueueSize = defaultQueueSize
	}
	if options.BufferFlushInterval <= 0 {
		options.BufferFlushInterval = defaultBufferFlushInterval
	}
	if options.Logger == nil {
		options.Logger = NullLogger
	}
	if options.Metrics == nil {
		options.Metrics = NewMetrics(NullStatsReporter, nil)
	}

	reporter := &remoteReporter{
		ReporterOptions: *options,
		sender:          sender,
		queue:           make(chan *zipkincore.Span, options.QueueSize),
		flushSignal:     make(chan *sync.WaitGroup),
	}
	go reporter.processQueue()
	return reporter
}

// Report implements Report() method of Reporter.
// It passes the span to a background go-routine for submission to Jaeger.
func (r *remoteReporter) Report(span *span) {
	thriftSpan := buildThriftSpan(span)
	select {
	case r.queue <- thriftSpan:
		atomic.AddInt64(&r.queueLength, 1)
	default:
		r.Metrics.ReporterDropped.Inc(1)
	}
}

// Close implements Close() method of Reporter by waiting for the queue to be drained.
func (r *remoteReporter) Close() {
	r.queueDrained.Add(1)
	close(r.queue)
	r.queueDrained.Wait()
}

// processQueue reads spans from the queue, converts them to Thrift, and stores them in an internal buffer.
// When the buffer length reaches batchSize, it is flushed by submitting the accumulated spans to Jaeger.
// Buffer also gets flushed automatically every batchFlushInterval seconds, just in case the tracer stopped
// reporting new spans.
func (r *remoteReporter) processQueue() {
	timer := time.NewTicker(r.BufferFlushInterval)
	for {
		select {
		case span, ok := <-r.queue:
			if ok {
				atomic.AddInt64(&r.queueLength, -1)
				if flushed, err := r.sender.Append(span); err != nil {
					r.Metrics.ReporterFailure.Inc(int64(flushed))
					r.Logger.Error(err.Error())
				} else if flushed > 0 {
					r.Metrics.ReporterSuccess.Inc(int64(flushed))
					// to reduce the number of gauge stats, we only emit queue length on flush
					r.Metrics.ReporterQueueLength.Update(atomic.LoadInt64(&r.queueLength))
				}
			} else {
				// queue closed
				timer.Stop()
				r.flush()
				r.queueDrained.Done()
				return
			}
		case <-timer.C:
			r.flush()
		case wg := <-r.flushSignal: // for testing
			r.flush()
			wg.Done()
		}
	}
}

// flush causes the Sender to flush its accumulated spans and clear the buffer
func (r *remoteReporter) flush() {
	if flushed, err := r.sender.Flush(); err != nil {
		r.Metrics.ReporterFailure.Inc(int64(flushed))
		r.Logger.Error(err.Error())
	} else if flushed > 0 {
		r.Metrics.ReporterSuccess.Inc(int64(flushed))
	}
}
<|endoftext|>


<commit_before>// Package travisci implements a library to query Travis-CI builds using their JSON API.
package travisci

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"time"

	"github.com/StalkR/goircbot/lib/tls"
)

// Build represents a Travis-CI build.
// Compared to the JSON:
// 1) Started/Finished replace StartedAt/FinishedAt and are of type time.Time
// 2) Success replaces Result and is of type bool
// When build state is in progress (e.g. not "finished"), Started/Finished are
// not set (zero value of time.Time) because Travis-CI does not provide them.
type Build struct {
	Id, RepositoryId, Number int
	State                    string
	Success                  bool
	Started, Finished        time.Time
	Duration                 int
	Commit, Branch, Message  string
	EventType                string
	BuildURL, CommitURL      string
}

func (b *Build) String() string {
	var status string
	if b.State == "finished" {
		status = "passed"
		if !b.Success {
			status = "errored"
		}
	} else {
		status = "in progress"
	}
	if b.Finished.IsZero() {
		return fmt.Sprintf("Build #%v: %v %v %v %v", b.Number, status,
			b.BuildURL, b.CommitURL, b.Message)
	}
	return fmt.Sprintf("Build #%v: %v (%v) %v %v %v", b.Number, status,
		b.Finished.Format("2006-01-02 15:04:05 UTC"), b.BuildURL, b.CommitURL, b.Message)
}

// buildJSON represents the builds.json replied by Travis-CI API.
// Some fields are pointers because they can be null, and we want to differentiate
// from value 0.
type buildJSON struct {
	Id           int    `json:"id"`
	RepositoryId int    `json:"repository_id"`
	Number       int    `json:"number,string"`
	State        string `json:"state"`
	Result       *int   `json:"result"`
	StartedAt    string `json:"started_at"`
	FinishedAt   string `json:"finished_at"`
	Duration     int    `json:"duration"`
	Commit       string `json:"commit"`
	Branch       string `json:"branch"`
	Message      string `json:"message"`
	EventType    string `json:"event_type"`
}

func timeoutDialer(d time.Duration) func(net, addr string) (net.Conn, error) {
	return func(netw, addr string) (net.Conn, error) {
		return net.DialTimeout(netw, addr, d)
	}
}

func httpClient(rawurl string) *http.Client {
	u, err := url.Parse(rawurl)
	if err != nil {
		panic(err)
	}
	return &http.Client{
		Transport: &http.Transport{
			Dial:            timeoutDialer(5 * time.Second),
			TLSClientConfig: tls.Config(u.Host),
		},
	}
}

func Builds(user, repo string) ([]Build, error) {
	url := fmt.Sprintf("https://api.travis-ci.org/repos/%s/%s/builds.json", user, repo)
	resp, err := httpClient(url).Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	js, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	var bjs []buildJSON
	if err := json.Unmarshal(js, &bjs); err != nil {
		return nil, err
	}
	var builds []Build
	for _, b := range bjs {
		var startedAt, finishedAt time.Time
		if b.StartedAt != "" {
			startedAt, err = time.Parse("2006-01-02T15:04:05Z", b.StartedAt)
			if err != nil {
				return nil, err
			}
		}
		if b.FinishedAt != "" {
			finishedAt, err = time.Parse("2006-01-02T15:04:05Z", b.FinishedAt)
			if err != nil {
				return nil, err
			}
		}

		success := false
		if b.Result != nil {
			if *b.Result != 0 {
				panic(fmt.Sprintf("build result has non-zero value %d", *b.Result))
			}
			success = true
		}

		builds = append(builds, Build{
			Id:           b.Id,
			RepositoryId: b.RepositoryId,
			Number:       b.Number,
			State:        b.State,
			Success:      success,
			Started:      startedAt,
			Finished:     finishedAt,
			Duration:     b.Duration,
			Commit:       b.Commit,
			Branch:       b.Branch,
			Message:      b.Message,
			EventType:    b.EventType,
			BuildURL:     fmt.Sprintf("https://travis-ci.org/%v/%v/builds/%v", user, repo, b.Id),
			CommitURL:    fmt.Sprintf("https://github.com/%v/%v/commit/%v", user, repo, b.Commit),
		})
	}
	return builds, nil
}
<commit_msg>travisci: handle other type of build status<commit_after>// Package travisci implements a library to query Travis-CI builds using their JSON API.
package travisci

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"time"

	"github.com/StalkR/goircbot/lib/tls"
)

// Build represents a Travis-CI build.
// Compared to the JSON:
// 1) Started/Finished replace StartedAt/FinishedAt and are of type time.Time
// 2) Success replaces Result and is of type bool
// When build state is in progress (e.g. not "finished"), Started/Finished are
// not set (zero value of time.Time) because Travis-CI does not provide them.
type Build struct {
	Id, RepositoryId, Number int
	State                    string
	Success                  bool
	Started, Finished        time.Time
	Duration                 int
	Commit, Branch, Message  string
	EventType                string
	BuildURL, CommitURL      string
}

func (b *Build) String() string {
	var status string
	if b.State == "finished" {
		status = "passed"
		if !b.Success {
			status = "errored"
		}
	} else {
		status = "in progress"
	}
	if b.Finished.IsZero() {
		return fmt.Sprintf("Build #%v: %v %v %v %v", b.Number, status,
			b.BuildURL, b.CommitURL, b.Message)
	}
	return fmt.Sprintf("Build #%v: %v (%v) %v %v %v", b.Number, status,
		b.Finished.Format("2006-01-02 15:04:05 UTC"), b.BuildURL, b.CommitURL, b.Message)
}

// buildJSON represents the builds.json replied by Travis-CI API.
// Some fields are pointers because they can be null, and we want to differentiate
// from value 0.
type buildJSON struct {
	Id           int    `json:"id"`
	RepositoryId int    `json:"repository_id"`
	Number       int    `json:"number,string"`
	State        string `json:"state"`
	Result       *int   `json:"result"`
	StartedAt    string `json:"started_at"`
	FinishedAt   string `json:"finished_at"`
	Duration     int    `json:"duration"`
	Commit       string `json:"commit"`
	Branch       string `json:"branch"`
	Message      string `json:"message"`
	EventType    string `json:"event_type"`
}

func timeoutDialer(d time.Duration) func(net, addr string) (net.Conn, error) {
	return func(netw, addr string) (net.Conn, error) {
		return net.DialTimeout(netw, addr, d)
	}
}

func httpClient(rawurl string) *http.Client {
	u, err := url.Parse(rawurl)
	if err != nil {
		panic(err)
	}
	return &http.Client{
		Transport: &http.Transport{
			Dial:            timeoutDialer(5 * time.Second),
			TLSClientConfig: tls.Config(u.Host),
		},
	}
}

func Builds(user, repo string) ([]Build, error) {
	url := fmt.Sprintf("https://api.travis-ci.org/repos/%s/%s/builds.json", user, repo)
	resp, err := httpClient(url).Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	js, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	var bjs []buildJSON
	if err := json.Unmarshal(js, &bjs); err != nil {
		return nil, err
	}
	var builds []Build
	for _, b := range bjs {
		var startedAt, finishedAt time.Time
		if b.StartedAt != "" {
			startedAt, err = time.Parse("2006-01-02T15:04:05Z", b.StartedAt)
			if err != nil {
				return nil, err
			}
		}
		if b.FinishedAt != "" {
			finishedAt, err = time.Parse("2006-01-02T15:04:05Z", b.FinishedAt)
			if err != nil {
				return nil, err
			}
		}

		success := false
		if b.Result != nil && *b.Result == 0 {
			success = true
		}

		builds = append(builds, Build{
			Id:           b.Id,
			RepositoryId: b.RepositoryId,
			Number:       b.Number,
			State:        b.State,
			Success:      success,
			Started:      startedAt,
			Finished:     finishedAt,
			Duration:     b.Duration,
			Commit:       b.Commit,
			Branch:       b.Branch,
			Message:      b.Message,
			EventType:    b.EventType,
			BuildURL:     fmt.Sprintf("https://travis-ci.org/%v/%v/builds/%v", user, repo, b.Id),
			CommitURL:    fmt.Sprintf("https://github.com/%v/%v/commit/%v", user, repo, b.Commit),
		})
	}
	return builds, nil
}
<|endoftext|>


<commit_before>package cli

import (
	"os"
	"path/filepath"
	"strings"
	"time"
)

type DepTracker struct {
	// Most recent .o modification time.
	MostRecent time.Time

	compiler *Compiler
}

func NewDepTracker(c *Compiler) DepTracker {
	tracker := DepTracker{
		MostRecent: time.Unix(0, 0),
		compiler:   c,
	}

	return tracker
}

// Parses a dependency (.d) file generated by gcc.  On success, the returned
// string array is populated with the dependency filenames.  This function
// expects the first line of a dependency file to have the following format:
//
// <file>.d: <file>.c a.h b.h c.h \
//  d.h e.h f.h
//
// This function ignores all lines except for the first.
func ParseDepsFile(filename string) ([]string, error) {
	lines, err := ReadLines(filename)
	if err != nil {
		return nil, err
	}

	if len(lines) == 0 {
		return []string{}, nil
	}

	// Assume only the first line is important.
	tokens := strings.Fields(lines[0])
	if len(tokens) == 0 {
		return nil, NewNewtError("Invalid Makefile dependency file; first " +
			"line is blank")
	}

	dFileTok := tokens[0]
	if dFileTok[len(dFileTok)-1:] != ":" {
		return nil, NewNewtError("Invalid Makefile dependency file; first " +
			"line missing ':'")
	}

	return tokens[1:], nil
}

// Determines if the specified C or assembly file needs to be built.  A compile
// is required if any of the following is true:
//     * The destination object file does not exist.
//     * The existing object file was built with a different compiler
//       invocation.
//     * The source file has a newer modification time than the object file.
//     * One or more included header files has a newer modification time than
//       the object file.
func (tracker *DepTracker) CompileRequired(srcFile string,
	compilerType int) (bool, error) {
	wd, _ := os.Getwd()
	objDir := wd + "/obj/" + tracker.compiler.TargetName + "/"

	objFile := objDir + strings.TrimSuffix(srcFile, filepath.Ext(srcFile)) +
		".o"
	depFile := objDir + strings.TrimSuffix(srcFile, filepath.Ext(srcFile)) +
		".d"

	// If the object was previously built with a different set of options, a
	// rebuild is necessary.
	cmd, err := tracker.compiler.CompileFileCmd(srcFile, compilerType)
	if err != nil {
		return false, err
	}
	if CommandHasChanged(objFile, cmd) {
		return true, nil
	}

	srcModTime, err := FileModificationTime(srcFile)
	if err != nil {
		return false, err
	}

	objModTime, err := FileModificationTime(objFile)
	if err != nil {
		return false, err
	}

	// If the object doesn't exist or is older than the source file, a build is
	// required; no need to check dependencies.
	if srcModTime.After(objModTime) {
		tracker.MostRecent = time.Now()
		return true, nil
	}

	// Cache the object modification time if it is more recent than the current
	// one.
	if objModTime.After(tracker.MostRecent) {
		tracker.MostRecent = objModTime
	}

	// Determine if the dependency (.d) file needs to be generated.  If it
	// doesn't exist or is older than the source file, it is out of date and
	// needs to be created.
	depModTime, err := FileModificationTime(depFile)
	if err != nil {
		return false, err
	}

	if srcModTime.After(depModTime) {
		err := tracker.compiler.GenDepsForFile(srcFile)
		if err != nil {
			return false, err
		}
	}

	// Extract the dependency filenames from the dependency file.
	deps, err := ParseDepsFile(depFile)
	if err != nil {
		return false, err
	}

	// Check if any dependencies are newer than the destination object file.
	for _, dep := range deps {
		depModTime, err := FileModificationTime(dep)
		if err != nil {
			return false, err
		}
		if depModTime.After(objModTime) {
			tracker.MostRecent = time.Now()
			return true, nil
		}
	}

	return false, nil
}

// Determines if the specified static library needs to be rearchived.  The
// library needs to be archived if any of the following is true:
//     * The destination library file does not exist.
//     * The existing library file was built with a different compiler
//       invocation.
//     * One or more source object files has a newer modification time than the
//       library file.
func (tracker *DepTracker) ArchiveRequired(archiveFile string,
	objFiles []string) (bool, error) {

	// If the archive was previously built with a different set of options, a
	// rebuild is required.
	cmd := tracker.compiler.CompileArchiveCmd(archiveFile, objFiles)
	if CommandHasChanged(archiveFile, cmd) {
		return true, nil
	}

	// If the archive doesn't exist or is older than any object file, a rebuild
	// is required.
	aModTime, err := FileModificationTime(archiveFile)
	if err != nil {
		return false, err
	}
	if tracker.MostRecent.After(aModTime) {
		return true, nil
	}

	// The library is up to date.
	return false, nil
}

// Determines if the specified elf file needs to be linked.  Linking is
// necessary if the elf file does not exist or has an older modification time
// than any source object or library file.
// Determines if the specified static library needs to be rearchived.  The
// library needs to be archived if any of the following is true:
//     * The destination library file does not exist.
//     * The existing library file was built with a different compiler
//       invocation.
//     * One or more source object files has a newer modification time than the
//       library file.
func (tracker *DepTracker) LinkRequired(dstFile string,
	options map[string]bool, objFiles []string) (bool, error) {

	// If the elf file was previously built with a different set of options, a
	// rebuild is required.
	cmd := tracker.compiler.CompileBinaryCmd(dstFile, options, objFiles)
	if CommandHasChanged(dstFile, cmd) {
		return true, nil
	}

	// If the elf file doesn't exist or is older than any input file, a rebuild
	// is required.
	dstModTime, err := FileModificationTime(dstFile)
	if err != nil {
		return false, err
	}
	if tracker.compiler.LinkerScript != "" {
		objFiles = append(objFiles, tracker.compiler.LinkerScript)
	}
	for _, obj := range objFiles {
		objModTime, err := FileModificationTime(obj)
		if err != nil {
			return false, err
		}

		if objModTime.After(dstModTime) {
			return true, nil
		}
	}

	return false, nil
}
<commit_msg>A deleted header file would not trigger a rebuild.<commit_after>package cli

import (
	"os"
	"path/filepath"
	"strings"
	"time"
)

type DepTracker struct {
	// Most recent .o modification time.
	MostRecent time.Time

	compiler *Compiler
}

func NewDepTracker(c *Compiler) DepTracker {
	tracker := DepTracker{
		MostRecent: time.Unix(0, 0),
		compiler:   c,
	}

	return tracker
}

// Parses a dependency (.d) file generated by gcc.  On success, the returned
// string array is populated with the dependency filenames.  This function
// expects the first line of a dependency file to have the following format:
//
// <file>.d: <file>.c a.h b.h c.h \
//  d.h e.h f.h
//
// This function ignores all lines except for the first.
func ParseDepsFile(filename string) ([]string, error) {
	lines, err := ReadLines(filename)
	if err != nil {
		return nil, err
	}

	if len(lines) == 0 {
		return []string{}, nil
	}

	// Assume only the first line is important.
	tokens := strings.Fields(lines[0])
	if len(tokens) == 0 {
		return nil, NewNewtError("Invalid Makefile dependency file; first " +
			"line is blank")
	}

	dFileTok := tokens[0]
	if dFileTok[len(dFileTok)-1:] != ":" {
		return nil, NewNewtError("Invalid Makefile dependency file; first " +
			"line missing ':'")
	}

	return tokens[1:], nil
}

// Determines if the specified C or assembly file needs to be built.  A compile
// is required if any of the following is true:
//     * The destination object file does not exist.
//     * The existing object file was built with a different compiler
//       invocation.
//     * The source file has a newer modification time than the object file.
//     * One or more included header files has a newer modification time than
//       the object file.
func (tracker *DepTracker) CompileRequired(srcFile string,
	compilerType int) (bool, error) {
	wd, _ := os.Getwd()
	objDir := wd + "/obj/" + tracker.compiler.TargetName + "/"

	objFile := objDir + strings.TrimSuffix(srcFile, filepath.Ext(srcFile)) +
		".o"
	depFile := objDir + strings.TrimSuffix(srcFile, filepath.Ext(srcFile)) +
		".d"

	// If the object was previously built with a different set of options, a
	// rebuild is necessary.
	cmd, err := tracker.compiler.CompileFileCmd(srcFile, compilerType)
	if err != nil {
		return false, err
	}
	if CommandHasChanged(objFile, cmd) {
		return true, nil
	}

	srcModTime, err := FileModificationTime(srcFile)
	if err != nil {
		return false, err
	}

	objModTime, err := FileModificationTime(objFile)
	if err != nil {
		return false, err
	}

	// If the object doesn't exist or is older than the source file, a build is
	// required; no need to check dependencies.
	if srcModTime.After(objModTime) {
		tracker.MostRecent = time.Now()
		return true, nil
	}

	// Cache the object modification time if it is more recent than the current
	// one.
	if objModTime.After(tracker.MostRecent) {
		tracker.MostRecent = objModTime
	}

	// Determine if the dependency (.d) file needs to be generated.  If it
	// doesn't exist or is older than the source file, it is out of date and
	// needs to be created.
	depModTime, err := FileModificationTime(depFile)
	if err != nil {
		return false, err
	}

	if srcModTime.After(depModTime) {
		err := tracker.compiler.GenDepsForFile(srcFile)
		if err != nil {
			return false, err
		}
	}

	// Extract the dependency filenames from the dependency file.
	deps, err := ParseDepsFile(depFile)
	if err != nil {
		return false, err
	}

	// Check if any dependencies are newer than the destination object file.
	for _, dep := range deps {
		if NodeNotExist(dep) {
			depModTime = time.Now()
		} else {
			depModTime, err = FileModificationTime(dep)
			if err != nil {
				return false, err
			}
		}

		if depModTime.After(objModTime) {
			tracker.MostRecent = time.Now()
			return true, nil
		}
	}

	return false, nil
}

// Determines if the specified static library needs to be rearchived.  The
// library needs to be archived if any of the following is true:
//     * The destination library file does not exist.
//     * The existing library file was built with a different compiler
//       invocation.
//     * One or more source object files has a newer modification time than the
//       library file.
func (tracker *DepTracker) ArchiveRequired(archiveFile string,
	objFiles []string) (bool, error) {

	// If the archive was previously built with a different set of options, a
	// rebuild is required.
	cmd := tracker.compiler.CompileArchiveCmd(archiveFile, objFiles)
	if CommandHasChanged(archiveFile, cmd) {
		return true, nil
	}

	// If the archive doesn't exist or is older than any object file, a rebuild
	// is required.
	aModTime, err := FileModificationTime(archiveFile)
	if err != nil {
		return false, err
	}
	if tracker.MostRecent.After(aModTime) {
		return true, nil
	}

	// The library is up to date.
	return false, nil
}

// Determines if the specified elf file needs to be linked.  Linking is
// necessary if the elf file does not exist or has an older modification time
// than any source object or library file.
// Determines if the specified static library needs to be rearchived.  The
// library needs to be archived if any of the following is true:
//     * The destination library file does not exist.
//     * The existing library file was built with a different compiler
//       invocation.
//     * One or more source object files has a newer modification time than the
//       library file.
func (tracker *DepTracker) LinkRequired(dstFile string,
	options map[string]bool, objFiles []string) (bool, error) {

	// If the elf file was previously built with a different set of options, a
	// rebuild is required.
	cmd := tracker.compiler.CompileBinaryCmd(dstFile, options, objFiles)
	if CommandHasChanged(dstFile, cmd) {
		return true, nil
	}

	// If the elf file doesn't exist or is older than any input file, a rebuild
	// is required.
	dstModTime, err := FileModificationTime(dstFile)
	if err != nil {
		return false, err
	}
	if tracker.compiler.LinkerScript != "" {
		objFiles = append(objFiles, tracker.compiler.LinkerScript)
	}
	for _, obj := range objFiles {
		objModTime, err := FileModificationTime(obj)
		if err != nil {
			return false, err
		}

		if objModTime.After(dstModTime) {
			return true, nil
		}
	}

	return false, nil
}
<|endoftext|>