<commit_before>// common.go
//
// This file implements the configuration part for when you need the API
// key to modify things in the Atlas configuration and manage measurements.

package atlas

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

	"github.com/pkg/errors"
)

const (
	apiEndpoint = "https://atlas.ripe.net/api/v2"
)

// getPageNum returns the value of the page= parameter
func getPageNum(url string) (page string) {
	re := regexp.MustCompile(`page=(\d+)`)
	if m := re.FindStringSubmatch(url); len(m) >= 1 {
		return m[1]
	}
	return ""
}

// AddQueryParameters adds query parameters to the URL.
func AddQueryParameters(baseURL string, queryParams map[string]string) string {
	if len(queryParams) == 0 {
		return baseURL
	}
	baseURL += "?"
	params := url.Values{}
	for key, value := range queryParams {
		params.Add(key, value)
	}
	return baseURL + params.Encode()
}

// addAPIKey insert the key into options if needed
func (c *Client) addAPIKey(opts map[string]string) map[string]string {
	key, ok := c.HasAPIKey()
	// Insert key
	if ok {
		opts["key"] = key
	}
	return opts
}

// prepareRequest insert all pre-defined stuff
func (c *Client) prepareRequest(method, what string, opts map[string]string) (req *http.Request) {
	var endPoint string

	// This is a hack to fetch direct urls for results
	if method == "FETCH" {
		endPoint = what
		method = "GET"
	} else {
		if c.config.endpoint != "" {
			endPoint = fmt.Sprintf("%s/%s", c.config.endpoint, what)
		}
	}

	c.mergeGlobalOptions(opts)
	c.debug("Options:\n%v", opts)
	baseURL := AddQueryParameters(endPoint, opts)

	req, err := http.NewRequest(method, baseURL, nil)
	if err != nil {
		c.log.Printf("error parsing %s: %v", baseURL, err)
		return &http.Request{}
	}

	c.debug("req.url=%s", baseURL)
	// We need these when we POST
	if method == "POST" {
		req.Header.Set("Content-Type", "application/json")
		req.Header.Set("Accept", "application/json")
	}

	return
}

// decodeAPIError does the deserialisation
func decodeAPIError(body []byte) (*APIError, error) {
	var e APIError

	err := json.Unmarshal(body, &e)
	return &e, err
}

// client.handleAPIResponse check status code & return undecoded APIError
func (c *Client) handleAPIResponse(r *http.Response) ([]byte, error) {
	if r == nil {
		return []byte{}, fmt.Errorf("error: r is nil")
	}

	// Everything is fine
	if r.StatusCode == http.StatusOK || r.StatusCode == 0 {
		return []byte{}, nil
	}

	// Everything is fine too (200-2xx)
	if r.StatusCode >= http.StatusOK && r.StatusCode < http.StatusMultipleChoices {
		return []byte{}, nil
	}

	// Check this condition (3xx are handled directly)
	if r.StatusCode >= http.StatusMultipleChoices && r.StatusCode < http.StatusBadRequest {
		return []byte{}, nil
	}

	// Everything else is an error
	body, err := ioutil.ReadAll(r.Body)
	defer r.Body.Close()

	if err != nil {
		return body, errors.Wrap(err, "read body")
	}

	var e APIError

	err = json.Unmarshal(body, &e)
	if err != nil {
		return body, errors.Wrapf(err, "decoding error raw=%v", body)
	}

	return body, e
}

func (c *Client) mergeGlobalOptions(opts map[string]string) {
	for k, v := range c.opts {
		opts[k] = v
	}
}
<commit_msg>Rewrite error handling, body is always fetched & returned.<commit_after>// common.go
//
// This file implements the configuration part for when you need the API
// key to modify things in the Atlas configuration and manage measurements.

package atlas

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

	"github.com/pkg/errors"
)

const (
	apiEndpoint = "https://atlas.ripe.net/api/v2"
)

// getPageNum returns the value of the page= parameter
func getPageNum(url string) (page string) {
	re := regexp.MustCompile(`page=(\d+)`)
	if m := re.FindStringSubmatch(url); len(m) >= 1 {
		return m[1]
	}
	return ""
}

// AddQueryParameters adds query parameters to the URL.
func AddQueryParameters(baseURL string, queryParams map[string]string) string {
	if len(queryParams) == 0 {
		return baseURL
	}
	baseURL += "?"
	params := url.Values{}
	for key, value := range queryParams {
		params.Add(key, value)
	}
	return baseURL + params.Encode()
}

// addAPIKey insert the key into options if needed
func (c *Client) addAPIKey(opts map[string]string) map[string]string {
	key, ok := c.HasAPIKey()
	// Insert key
	if ok {
		opts["key"] = key
	}
	return opts
}

// prepareRequest insert all pre-defined stuff
func (c *Client) prepareRequest(method, what string, opts map[string]string) (req *http.Request) {
	var endPoint string

	// This is a hack to fetch direct urls for results
	if method == "FETCH" {
		endPoint = what
		method = "GET"
	} else {
		if c.config.endpoint != "" {
			endPoint = fmt.Sprintf("%s/%s", c.config.endpoint, what)
		}
	}

	c.mergeGlobalOptions(opts)
	c.debug("Options:\n%v", opts)
	baseURL := AddQueryParameters(endPoint, opts)

	req, err := http.NewRequest(method, baseURL, nil)
	if err != nil {
		c.log.Printf("error parsing %s: %v", baseURL, err)
		return &http.Request{}
	}

	c.debug("req.url=%s", baseURL)
	// We need these when we POST
	if method == "POST" {
		req.Header.Set("Content-Type", "application/json")
		req.Header.Set("Accept", "application/json")
	}

	return
}

// decodeAPIError does the deserialisation
func decodeAPIError(body []byte) (*APIError, error) {
	var e APIError

	err := json.Unmarshal(body, &e)
	return &e, err
}

// client.handleAPIResponse check status code & return undecoded APIError
func (c *Client) handleAPIResponse(r *http.Response) ([]byte, error) {
	if r == nil {
		return []byte{}, fmt.Errorf("error: r is nil")
	}

	// Whatever it is, always fetch body, it will get unserialised by the caller
	body, err := ioutil.ReadAll(r.Body)
	defer r.Body.Close()

	if err != nil {
		return body, errors.Wrap(err, "read body")
	}

	// Everything is fine
	if r.StatusCode == http.StatusOK || r.StatusCode == 0 {
		return body, nil
	}

	// Everything is fine too (200-2xx)
	if r.StatusCode >= http.StatusOK && r.StatusCode < http.StatusMultipleChoices {
		return body, nil
	}

	// Check this condition (3xx are handled directly)
	if r.StatusCode >= http.StatusMultipleChoices && r.StatusCode < http.StatusBadRequest {
		return body, nil
	}

	c.debug("really bad stuff")
	// Everything else is an error

	c.debug("err=%s", string(body))

	apie, err := decodeAPIError(body)
	if err != nil {
		return body, errors.Wrap(err, "decodeAPIError")
	}

	return body, fmt.Errorf(apie.Error())
}

func (c *Client) mergeGlobalOptions(opts map[string]string) {
	for k, v := range c.opts {
		opts[k] = v
	}
}
<|endoftext|>


<commit_before>package awsauth

import (
	"bufio"
	"bytes"
	"crypto/hmac"
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"
)

func serviceAndRegion(host string) (string, string) {
	var region, service string
	parts := strings.Split(host, ".")

	service = parts[0]

	if len(parts) >= 4 {
		if parts[1] == "s3" {
			region = parts[0]
			service = parts[1]
		} else {
			region = parts[1]
		}
	} else {
		if strings.HasPrefix(parts[0], "s3-") {
			service = parts[0][:2]
			region = parts[0][3:]
		} else {
			region = "us-east-1" // default. http://docs.aws.amazon.com/general/latest/gr/rande.html
		}
	}

	return service, region
}

func checkKeys() {
	if Keys == nil {
		Keys = &Credentials{
			AccessKeyID:     os.Getenv(envAccessKeyID),
			SecretAccessKey: os.Getenv(envSecretAccessKey),
			SecurityToken:   os.Getenv(envSecurityToken),
		}
	}
	// if accesskey and the secretkey are blank, get the key from the role
	if Keys.AccessKeyID == "" && onEC2() {

		Keys = getIAMRoleCredentials()
	}

	// if the expiration is set and it's less than 5 minutes in the future, get a new key
	if Keys.expired() && onEC2() {
		Keys = getIAMRoleCredentials()
	}
}

func onEC2() bool {

	c, err := net.DialTimeout("tcp", "169.254.169.254:80", time.Second)

	if err != nil {
		return false
	} else {
		c.Close()
		return true
	}
}

// getIAMRoleList gets a list of the roles that are available to this instance
func getIAMRoleList() []string {

	var roles []string
	url := "http://169.254.169.254/latest/meta-data/iam/security-credentials/"

	client := &http.Client{}

	req, err := http.NewRequest("GET", url, nil)

	if err != nil {
		return roles
	}

	resp, err := client.Do(req)

	if err != nil {
		return roles
	}

	scanner := bufio.NewScanner(resp.Body)
	for scanner.Scan() {
		roles = append(roles, scanner.Text())
	}
	return roles
}

func getIAMRoleCredentials() *Credentials {

	roles := getIAMRoleList()

	if len(roles) < 1 {
		return &Credentials{}
	}

	// Use the first role in the list
	role := roles[0]

	url := "http://169.254.169.254/latest/meta-data/iam/security-credentials/"

	// Create the full URL of the role
	var buffer bytes.Buffer
	buffer.WriteString(url)
	buffer.WriteString(role)
	roleurl := buffer.String()

	// Get the role
	rolereq, err := http.NewRequest("GET", roleurl, nil)

	if err != nil {
		return &Credentials{}
	}

	roleresp, err := client.Do(rolereq)

	if err != nil {
		return &Credentials{}
	}

	rolebuf := new(bytes.Buffer)
	rolebuf.ReadFrom(roleresp.Body)

	creds := Credentials{}

	err = json.Unmarshal(rolebuf.Bytes(), &creds)

	if err != nil {
		return &Credentials{}
	}

	return &creds

}

func augmentRequestQuery(req *http.Request, values url.Values) *http.Request {
	for key, arr := range req.URL.Query() {
		for _, val := range arr {
			values.Set(key, val)
		}
	}

	req.URL.RawQuery = values.Encode()

	return req
}

func hmacSHA256(key []byte, content string) []byte {
	mac := hmac.New(sha256.New, key)
	mac.Write([]byte(content))
	return mac.Sum(nil)
}

func hmacSHA1(key []byte, content string) []byte {
	mac := hmac.New(sha1.New, key)
	mac.Write([]byte(content))
	return mac.Sum(nil)
}

func hashSHA256(content []byte) string {
	h := sha256.New()
	h.Write(content)
	return fmt.Sprintf("%x", h.Sum(nil))
}

func hashMD5(content []byte) string {
	h := md5.New()
	h.Write(content)
	return base64.StdEncoding.EncodeToString(h.Sum(nil))
}

func readAndReplaceBody(req *http.Request) []byte {
	if req.Body == nil {
		return []byte{}
	}
	payload, _ := ioutil.ReadAll(req.Body)
	req.Body = ioutil.NopCloser(bytes.NewReader(payload))
	return payload
}

func concat(delim string, str ...string) string {
	return strings.Join(str, delim)
}

var now = func() time.Time {
	return time.Now().UTC()
}
<commit_msg>caching whether or not we are on ec2<commit_after>package awsauth

import (
	"bufio"
	"bytes"
	"crypto/hmac"
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"
)

type location struct {
	ec2     bool
	checked bool
}

var loc *location

func serviceAndRegion(host string) (string, string) {
	var region, service string
	parts := strings.Split(host, ".")

	service = parts[0]

	if len(parts) >= 4 {
		if parts[1] == "s3" {
			region = parts[0]
			service = parts[1]
		} else {
			region = parts[1]
		}
	} else {
		if strings.HasPrefix(parts[0], "s3-") {
			service = parts[0][:2]
			region = parts[0][3:]
		} else {
			region = "us-east-1" // default. http://docs.aws.amazon.com/general/latest/gr/rande.html
		}
	}

	return service, region
}

func checkKeys() {
	if Keys == nil {
		Keys = &Credentials{
			AccessKeyID:     os.Getenv(envAccessKeyID),
			SecretAccessKey: os.Getenv(envSecretAccessKey),
			SecurityToken:   os.Getenv(envSecurityToken),
		}
	}
	// if accesskey and the secretkey are blank, get the key from the role
	if Keys.AccessKeyID == "" && onEC2() {

		Keys = getIAMRoleCredentials()
	}

	// if the expiration is set and it's less than 5 minutes in the future, get a new key
	if Keys.expired() && onEC2() {
		Keys = getIAMRoleCredentials()
	}
}

func onEC2() bool {
	if loc == nil {
		loc = &location{}
	}
	if !(loc.checked) {
		fmt.Println("Checking location...")
		c, err := net.DialTimeout("tcp", "169.254.169.254:80", time.Second)

		if err != nil {
			loc.ec2 = false
		} else {
			c.Close()
			loc.ec2 = true
		}
		loc.checked = true
	}

	return loc.ec2
}

// getIAMRoleList gets a list of the roles that are available to this instance
func getIAMRoleList() []string {

	var roles []string
	url := "http://169.254.169.254/latest/meta-data/iam/security-credentials/"

	client := &http.Client{}

	req, err := http.NewRequest("GET", url, nil)

	if err != nil {
		return roles
	}

	resp, err := client.Do(req)

	if err != nil {
		return roles
	}

	scanner := bufio.NewScanner(resp.Body)
	for scanner.Scan() {
		roles = append(roles, scanner.Text())
	}
	return roles
}

func getIAMRoleCredentials() *Credentials {

	roles := getIAMRoleList()

	if len(roles) < 1 {
		return &Credentials{}
	}

	// Use the first role in the list
	role := roles[0]

	url := "http://169.254.169.254/latest/meta-data/iam/security-credentials/"

	// Create the full URL of the role
	var buffer bytes.Buffer
	buffer.WriteString(url)
	buffer.WriteString(role)
	roleurl := buffer.String()

	// Get the role
	rolereq, err := http.NewRequest("GET", roleurl, nil)

	if err != nil {
		return &Credentials{}
	}

	roleresp, err := client.Do(rolereq)

	if err != nil {
		return &Credentials{}
	}

	rolebuf := new(bytes.Buffer)
	rolebuf.ReadFrom(roleresp.Body)

	creds := Credentials{}

	err = json.Unmarshal(rolebuf.Bytes(), &creds)

	if err != nil {
		return &Credentials{}
	}

	return &creds

}

func augmentRequestQuery(req *http.Request, values url.Values) *http.Request {
	for key, arr := range req.URL.Query() {
		for _, val := range arr {
			values.Set(key, val)
		}
	}

	req.URL.RawQuery = values.Encode()

	return req
}

func hmacSHA256(key []byte, content string) []byte {
	mac := hmac.New(sha256.New, key)
	mac.Write([]byte(content))
	return mac.Sum(nil)
}

func hmacSHA1(key []byte, content string) []byte {
	mac := hmac.New(sha1.New, key)
	mac.Write([]byte(content))
	return mac.Sum(nil)
}

func hashSHA256(content []byte) string {
	h := sha256.New()
	h.Write(content)
	return fmt.Sprintf("%x", h.Sum(nil))
}

func hashMD5(content []byte) string {
	h := md5.New()
	h.Write(content)
	return base64.StdEncoding.EncodeToString(h.Sum(nil))
}

func readAndReplaceBody(req *http.Request) []byte {
	if req.Body == nil {
		return []byte{}
	}
	payload, _ := ioutil.ReadAll(req.Body)
	req.Body = ioutil.NopCloser(bytes.NewReader(payload))
	return payload
}

func concat(delim string, str ...string) string {
	return strings.Join(str, delim)
}

var now = func() time.Time {
	return time.Now().UTC()
}
<|endoftext|>


<commit_before>package common

import (
	"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)
}
<commit_msg>barcode validation<commit_after>package common

import (
	"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)
}
<|endoftext|>


<commit_before>package estab

const Version = "0.1.3"
<commit_msg>v0.2.0<commit_after>package estab

const Version = "0.2.0"
<|endoftext|>


<commit_before>package gocb

import (
	"encoding/json"
	"time"

	gocbcore "github.com/couchbase/gocbcore/v8"
)

type jsonRowLocation struct {
	Field          string   `json:"field"`
	Term           string   `json:"term"`
	Position       uint32   `json:"position"`
	Start          uint32   `json:"start"`
	End            uint32   `json:"end"`
	ArrayPositions []uint32 `json:"array_positions"`
}

type jsonSearchFacet struct {
	Name    string `json:"name"`
	Field   string `json:"field"`
	Total   uint64 `json:"total"`
	Missing uint64 `json:"missing"`
	Other   uint64 `json:"other"`
}

type jsonSearchRowLocations map[string]map[string][]jsonRowLocation

type jsonSearchRow struct {
	Index       string                 `json:"index"`
	ID          string                 `json:"id"`
	Score       float64                `json:"score"`
	Explanation interface{}            `json:"explanation"`
	Locations   jsonSearchRowLocations `json:"locations"`
	Fragments   map[string][]string    `json:"fragments"`
	Fields      json.RawMessage        `json:"fields"`
}

type jsonSearchResponse struct {
	Errors    map[string]string          `json:"errors"`
	TotalHits uint64                     `json:"total_hits"`
	MaxScore  float64                    `json:"max_score"`
	Took      uint64                     `json:"took"`
	Facets    map[string]jsonSearchFacet `json:"facets"`
}

// SearchMetrics encapsulates various metrics gathered during a search queries execution.
type SearchMetrics struct {
	Took                  time.Duration
	TotalRows             uint64
	MaxScore              float64
	TotalPartitionCount   uint64
	SuccessPartitionCount uint64
	ErrorPartitionCount   uint64
}

func (metrics *SearchMetrics) fromData(data jsonSearchResponse) error {
	metrics.TotalRows = data.TotalHits
	metrics.MaxScore = data.MaxScore
	metrics.Took = time.Duration(data.Took) * time.Microsecond

	return nil
}

// SearchMetaData provides access to the meta-data properties of a search query result.
type SearchMetaData struct {
	Metrics SearchMetrics
	Errors  map[string]string
}

func (meta *SearchMetaData) fromData(data jsonSearchResponse) error {
	metrics := SearchMetrics{}
	if err := metrics.fromData(data); err != nil {
		return err
	}

	meta.Metrics = metrics
	meta.Errors = data.Errors

	return nil
}

// SearchFacetResult provides access to the result of a faceted query.
type SearchFacetResult struct {
	Name    string
	Field   string
	Total   uint64
	Missing uint64
	Other   uint64
}

func (fr *SearchFacetResult) fromData(data jsonSearchFacet) error {
	fr.Name = data.Name
	fr.Field = data.Field
	fr.Total = data.Total
	fr.Missing = data.Missing
	fr.Other = data.Other

	return nil
}

// SearchRowLocation represents the location of a row match
type SearchRowLocation struct {
	Position       uint32
	Start          uint32
	End            uint32
	ArrayPositions []uint32
}

func (rl *SearchRowLocation) fromData(data jsonRowLocation) error {
	rl.Position = data.Position
	rl.Start = data.Start
	rl.End = data.End
	rl.ArrayPositions = data.ArrayPositions

	return nil
}

// SearchResult allows access to the results of a N1QL query.
type SearchResult struct {
	reader *gocbcore.SearchRowReader

	index       string
	id          string
	score       float64
	explanation interface{}
	locations   map[string]map[string][]SearchRowLocation
	fragments   map[string][]string
	fieldsBytes []byte
}

func newSearchResult(reader *gocbcore.SearchRowReader) (*SearchResult, error) {
	return &SearchResult{
		reader: reader,
	}, nil
}

// Next assigns the next result from the results into the value pointer, returning whether the read was successful.
func (r *SearchResult) Next() bool {
	rowBytes := r.reader.NextRow()
	if rowBytes == nil {
		return false
	}

	var rowData jsonSearchRow
	if err := json.Unmarshal(rowBytes, &rowData); err == nil {
		r.index = rowData.Index
		r.id = rowData.ID
		r.score = rowData.Score
		r.explanation = rowData.Explanation
		r.fragments = rowData.Fragments
		r.fieldsBytes = rowData.Fields

		locations := make(map[string]map[string][]SearchRowLocation)
		for fieldName, fieldData := range rowData.Locations {
			terms := make(map[string][]SearchRowLocation)
			for termName, termData := range fieldData {
				locations := make([]SearchRowLocation, len(termData))
				for locIdx, locData := range termData {
					locations[locIdx].fromData(locData)
				}
				terms[termName] = locations
			}
			locations[fieldName] = terms
		}
		r.locations = locations
	}

	return true
}

// Index returns the index of the current hit.
func (r *SearchResult) Index() string {
	return r.index
}

// ID returns the id of the current hit.
func (r *SearchResult) ID() string {
	return r.id
}

// Score returns the score of the current hit.
func (r *SearchResult) Score() float64 {
	return r.score
}

// Explanation returns the explanation of the current hit.
func (r *SearchResult) Explanation() interface{} {
	return r.explanation
}

// Locations returns the locations of the current hit.
func (r *SearchResult) Locations() map[string]map[string][]SearchRowLocation {
	return r.locations
}

// Fragments returns the fragments of the current hit.
func (r *SearchResult) Fragments() map[string][]string {
	return r.fragments
}

// Fields returns the fields of the current hit.
func (r *SearchResult) Fields(fieldsPtr interface{}) error {
	return json.Unmarshal(r.fieldsBytes, fieldsPtr)
}

// Err returns any errors that have occurred on the stream
func (r *SearchResult) Err() error {
	return r.reader.Err()
}

// Close marks the results as closed, returning any errors that occurred during reading the results.
func (r *SearchResult) Close() error {
	return r.reader.Close()
}

func (r *SearchResult) getJSONResp() (jsonSearchResponse, error) {
	metaDataBytes, err := r.reader.MetaData()
	if err != nil {
		return jsonSearchResponse{}, err
	}

	var jsonResp jsonSearchResponse
	err = json.Unmarshal(metaDataBytes, &jsonResp)
	if err != nil {
		return jsonSearchResponse{}, err
	}

	return jsonResp, nil
}

// MetaData returns any meta-data that was available from this query.  Note that
// the meta-data will only be available once the object has been closed (either
// implicitly or explicitly).
func (r *SearchResult) MetaData() (*SearchMetaData, error) {
	jsonResp, err := r.getJSONResp()
	if err != nil {
		return nil, err
	}

	var metaData SearchMetaData
	err = metaData.fromData(jsonResp)
	if err != nil {
		return nil, err
	}

	return &metaData, nil
}

// Facets returns any facets that were returned with this query.  Note that the
// facets will only be available once the object has been closed (either
// implicitly or explicitly).
func (r *SearchResult) Facets() (map[string]SearchFacetResult, error) {
	jsonResp, err := r.getJSONResp()
	if err != nil {
		return nil, err
	}

	facets := make(map[string]SearchFacetResult)
	for facetName, facetData := range jsonResp.Facets {
		var facet SearchFacetResult
		err := facet.fromData(facetData)
		if err != nil {
			return nil, err
		}

		facets[facetName] = facet
	}

	return facets, nil
}

// SearchQuery executes the analytics query statement on the server.
func (c *Cluster) SearchQuery(query SearchQuery, opts *SearchOptions) (*SearchResult, error) {
	if opts == nil {
		opts = &SearchOptions{}
	}

	span := c.sb.Tracer.StartSpan("SearchQuery", opts.parentSpan).
		SetTag("couchbase.service", "search")
	defer span.Finish()

	timeout := c.sb.QueryTimeout
	if opts.Timeout != 0 && opts.Timeout < timeout {
		timeout = opts.Timeout
	}
	deadline := time.Now().Add(timeout)

	retryStrategy := c.sb.RetryStrategyWrapper
	if opts.RetryStrategy != nil {
		retryStrategy = newRetryStrategyWrapper(opts.RetryStrategy)
	}

	searchOpts, err := opts.toMap()
	if err != nil {
		return nil, SearchError{
			InnerError: wrapError(err, "failed to generate query options"),
			Query:      query,
		}
	}

	searchOpts["query"] = query

	return c.execSearchQuery(span, searchOpts, deadline, retryStrategy)
}

func maybeGetSearchOptionQuery(options map[string]interface{}) interface{} {
	if value, ok := options["query"]; ok {
		return value
	}
	return ""
}

func (c *Cluster) execSearchQuery(
	span requestSpan,
	options map[string]interface{},
	deadline time.Time,
	retryStrategy *retryStrategyWrapper,
) (*SearchResult, error) {
	provider, err := c.getSearchProvider()
	if err != nil {
		return nil, SearchError{
			InnerError: wrapError(err, "failed to get query provider"),
			Query:      maybeGetSearchOptionQuery(options),
		}
	}

	reqBytes, err := json.Marshal(options)
	if err != nil {
		return nil, SearchError{
			InnerError: wrapError(err, "failed to marshall query body"),
			Query:      maybeGetSearchOptionQuery(options),
		}
	}

	res, err := provider.SearchQuery(gocbcore.SearchQueryOptions{
		Payload:       reqBytes,
		RetryStrategy: retryStrategy,
		Deadline:      deadline,
	})
	if err != nil {
		return nil, maybeEnhanceSearchError(err)
	}

	return newSearchResult(res)
}
<commit_msg>GOCBC-738: Added missing index name parameter to SearchQuery.<commit_after>package gocb

import (
	"encoding/json"
	"time"

	gocbcore "github.com/couchbase/gocbcore/v8"
)

type jsonRowLocation struct {
	Field          string   `json:"field"`
	Term           string   `json:"term"`
	Position       uint32   `json:"position"`
	Start          uint32   `json:"start"`
	End            uint32   `json:"end"`
	ArrayPositions []uint32 `json:"array_positions"`
}

type jsonSearchFacet struct {
	Name    string `json:"name"`
	Field   string `json:"field"`
	Total   uint64 `json:"total"`
	Missing uint64 `json:"missing"`
	Other   uint64 `json:"other"`
}

type jsonSearchRowLocations map[string]map[string][]jsonRowLocation

type jsonSearchRow struct {
	Index       string                 `json:"index"`
	ID          string                 `json:"id"`
	Score       float64                `json:"score"`
	Explanation interface{}            `json:"explanation"`
	Locations   jsonSearchRowLocations `json:"locations"`
	Fragments   map[string][]string    `json:"fragments"`
	Fields      json.RawMessage        `json:"fields"`
}

type jsonSearchResponse struct {
	Errors    map[string]string          `json:"errors"`
	TotalHits uint64                     `json:"total_hits"`
	MaxScore  float64                    `json:"max_score"`
	Took      uint64                     `json:"took"`
	Facets    map[string]jsonSearchFacet `json:"facets"`
}

// SearchMetrics encapsulates various metrics gathered during a search queries execution.
type SearchMetrics struct {
	Took                  time.Duration
	TotalRows             uint64
	MaxScore              float64
	TotalPartitionCount   uint64
	SuccessPartitionCount uint64
	ErrorPartitionCount   uint64
}

func (metrics *SearchMetrics) fromData(data jsonSearchResponse) error {
	metrics.TotalRows = data.TotalHits
	metrics.MaxScore = data.MaxScore
	metrics.Took = time.Duration(data.Took) * time.Microsecond

	return nil
}

// SearchMetaData provides access to the meta-data properties of a search query result.
type SearchMetaData struct {
	Metrics SearchMetrics
	Errors  map[string]string
}

func (meta *SearchMetaData) fromData(data jsonSearchResponse) error {
	metrics := SearchMetrics{}
	if err := metrics.fromData(data); err != nil {
		return err
	}

	meta.Metrics = metrics
	meta.Errors = data.Errors

	return nil
}

// SearchFacetResult provides access to the result of a faceted query.
type SearchFacetResult struct {
	Name    string
	Field   string
	Total   uint64
	Missing uint64
	Other   uint64
}

func (fr *SearchFacetResult) fromData(data jsonSearchFacet) error {
	fr.Name = data.Name
	fr.Field = data.Field
	fr.Total = data.Total
	fr.Missing = data.Missing
	fr.Other = data.Other

	return nil
}

// SearchRowLocation represents the location of a row match
type SearchRowLocation struct {
	Position       uint32
	Start          uint32
	End            uint32
	ArrayPositions []uint32
}

func (rl *SearchRowLocation) fromData(data jsonRowLocation) error {
	rl.Position = data.Position
	rl.Start = data.Start
	rl.End = data.End
	rl.ArrayPositions = data.ArrayPositions

	return nil
}

// SearchResult allows access to the results of a N1QL query.
type SearchResult struct {
	reader *gocbcore.SearchRowReader

	index       string
	id          string
	score       float64
	explanation interface{}
	locations   map[string]map[string][]SearchRowLocation
	fragments   map[string][]string
	fieldsBytes []byte
}

func newSearchResult(reader *gocbcore.SearchRowReader) (*SearchResult, error) {
	return &SearchResult{
		reader: reader,
	}, nil
}

// Next assigns the next result from the results into the value pointer, returning whether the read was successful.
func (r *SearchResult) Next() bool {
	rowBytes := r.reader.NextRow()
	if rowBytes == nil {
		return false
	}

	var rowData jsonSearchRow
	if err := json.Unmarshal(rowBytes, &rowData); err == nil {
		r.index = rowData.Index
		r.id = rowData.ID
		r.score = rowData.Score
		r.explanation = rowData.Explanation
		r.fragments = rowData.Fragments
		r.fieldsBytes = rowData.Fields

		locations := make(map[string]map[string][]SearchRowLocation)
		for fieldName, fieldData := range rowData.Locations {
			terms := make(map[string][]SearchRowLocation)
			for termName, termData := range fieldData {
				locations := make([]SearchRowLocation, len(termData))
				for locIdx, locData := range termData {
					locations[locIdx].fromData(locData)
				}
				terms[termName] = locations
			}
			locations[fieldName] = terms
		}
		r.locations = locations
	}

	return true
}

// Index returns the index of the current hit.
func (r *SearchResult) Index() string {
	return r.index
}

// ID returns the id of the current hit.
func (r *SearchResult) ID() string {
	return r.id
}

// Score returns the score of the current hit.
func (r *SearchResult) Score() float64 {
	return r.score
}

// Explanation returns the explanation of the current hit.
func (r *SearchResult) Explanation() interface{} {
	return r.explanation
}

// Locations returns the locations of the current hit.
func (r *SearchResult) Locations() map[string]map[string][]SearchRowLocation {
	return r.locations
}

// Fragments returns the fragments of the current hit.
func (r *SearchResult) Fragments() map[string][]string {
	return r.fragments
}

// Fields returns the fields of the current hit.
func (r *SearchResult) Fields(fieldsPtr interface{}) error {
	return json.Unmarshal(r.fieldsBytes, fieldsPtr)
}

// Err returns any errors that have occurred on the stream
func (r *SearchResult) Err() error {
	return r.reader.Err()
}

// Close marks the results as closed, returning any errors that occurred during reading the results.
func (r *SearchResult) Close() error {
	return r.reader.Close()
}

func (r *SearchResult) getJSONResp() (jsonSearchResponse, error) {
	metaDataBytes, err := r.reader.MetaData()
	if err != nil {
		return jsonSearchResponse{}, err
	}

	var jsonResp jsonSearchResponse
	err = json.Unmarshal(metaDataBytes, &jsonResp)
	if err != nil {
		return jsonSearchResponse{}, err
	}

	return jsonResp, nil
}

// MetaData returns any meta-data that was available from this query.  Note that
// the meta-data will only be available once the object has been closed (either
// implicitly or explicitly).
func (r *SearchResult) MetaData() (*SearchMetaData, error) {
	jsonResp, err := r.getJSONResp()
	if err != nil {
		return nil, err
	}

	var metaData SearchMetaData
	err = metaData.fromData(jsonResp)
	if err != nil {
		return nil, err
	}

	return &metaData, nil
}

// Facets returns any facets that were returned with this query.  Note that the
// facets will only be available once the object has been closed (either
// implicitly or explicitly).
func (r *SearchResult) Facets() (map[string]SearchFacetResult, error) {
	jsonResp, err := r.getJSONResp()
	if err != nil {
		return nil, err
	}

	facets := make(map[string]SearchFacetResult)
	for facetName, facetData := range jsonResp.Facets {
		var facet SearchFacetResult
		err := facet.fromData(facetData)
		if err != nil {
			return nil, err
		}

		facets[facetName] = facet
	}

	return facets, nil
}

// SearchQuery executes the analytics query statement on the server.
func (c *Cluster) SearchQuery(indexName string, query SearchQuery, opts *SearchOptions) (*SearchResult, error) {
	if opts == nil {
		opts = &SearchOptions{}
	}

	span := c.sb.Tracer.StartSpan("SearchQuery", opts.parentSpan).
		SetTag("couchbase.service", "search")
	defer span.Finish()

	timeout := c.sb.QueryTimeout
	if opts.Timeout != 0 && opts.Timeout < timeout {
		timeout = opts.Timeout
	}
	deadline := time.Now().Add(timeout)

	retryStrategy := c.sb.RetryStrategyWrapper
	if opts.RetryStrategy != nil {
		retryStrategy = newRetryStrategyWrapper(opts.RetryStrategy)
	}

	searchOpts, err := opts.toMap()
	if err != nil {
		return nil, SearchError{
			InnerError: wrapError(err, "failed to generate query options"),
			Query:      query,
		}
	}

	searchOpts["query"] = query

	return c.execSearchQuery(span, indexName, searchOpts, deadline, retryStrategy)
}

func maybeGetSearchOptionQuery(options map[string]interface{}) interface{} {
	if value, ok := options["query"]; ok {
		return value
	}
	return ""
}

func (c *Cluster) execSearchQuery(
	span requestSpan,
	indexName string,
	options map[string]interface{},
	deadline time.Time,
	retryStrategy *retryStrategyWrapper,
) (*SearchResult, error) {
	provider, err := c.getSearchProvider()
	if err != nil {
		return nil, SearchError{
			InnerError: wrapError(err, "failed to get query provider"),
			Query:      maybeGetSearchOptionQuery(options),
		}
	}

	reqBytes, err := json.Marshal(options)
	if err != nil {
		return nil, SearchError{
			InnerError: wrapError(err, "failed to marshall query body"),
			Query:      maybeGetSearchOptionQuery(options),
		}
	}

	res, err := provider.SearchQuery(gocbcore.SearchQueryOptions{
		IndexName:     indexName,
		Payload:       reqBytes,
		RetryStrategy: retryStrategy,
		Deadline:      deadline,
	})
	if err != nil {
		return nil, maybeEnhanceSearchError(err)
	}

	return newSearchResult(res)
}
<|endoftext|>


<commit_before>package main

import (
	_ "expvar"
	"fmt"
	"net/http"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"path/filepath"
	"time"

	"github.com/boltdb/bolt"
	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
	gocontext "golang.org/x/net/context"
	"google.golang.org/grpc"

	"github.com/Sirupsen/logrus"
	"github.com/containerd/containerd"
	contentapi "github.com/containerd/containerd/api/services/content"
	api "github.com/containerd/containerd/api/services/execution"
	imagesapi "github.com/containerd/containerd/api/services/images"
	rootfsapi "github.com/containerd/containerd/api/services/rootfs"
	"github.com/containerd/containerd/content"
	"github.com/containerd/containerd/images"
	"github.com/containerd/containerd/log"
	"github.com/containerd/containerd/plugin"
	"github.com/containerd/containerd/snapshot"
	"github.com/containerd/containerd/sys"
	metrics "github.com/docker/go-metrics"
	"github.com/pkg/errors"
	"github.com/urfave/cli"
)

const usage = `
                    __        _                     __
  _________  ____  / /_____ _(_)___  ___  _________/ /
 / ___/ __ \/ __ \/ __/ __ ` + "`" + `/ / __ \/ _ \/ ___/ __  /
/ /__/ /_/ / / / / /_/ /_/ / / / / /  __/ /  / /_/ /
\___/\____/_/ /_/\__/\__,_/_/_/ /_/\___/_/   \__,_/

high performance container runtime
`

var (
	conf   = defaultConfig()
	global = log.WithModule(gocontext.Background(), "containerd")
)

func init() {
	cli.VersionPrinter = func(c *cli.Context) {
		fmt.Println(c.App.Name, containerd.Package, c.App.Version)
	}
}

func main() {
	app := cli.NewApp()
	app.Name = "containerd"
	app.Version = containerd.Version
	app.Usage = usage
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "config,c",
			Usage: "path to the configuration file (Use 'default' to output the default toml)",
			Value: defaultConfigPath,
		},
		cli.StringFlag{
			Name:  "log-level,l",
			Usage: "set the logging level [debug, info, warn, error, fatal, panic]",
		},
		cli.StringFlag{
			Name:  "state",
			Usage: "containerd state directory",
		},
		cli.StringFlag{
			Name:  "address,a",
			Usage: "address for containerd's GRPC server",
		},
		cli.StringFlag{
			Name:  "root",
			Usage: "containerd root directory",
		},
	}
	app.Commands = []cli.Command{
		configCommand,
	}
	app.Before = before
	app.Action = func(context *cli.Context) error {
		start := time.Now()
		// start the signal handler as soon as we can to make sure that
		// we don't miss any signals during boot
		signals := make(chan os.Signal, 2048)
		signal.Notify(signals, handledSignals...)
		if err := platformInit(context); err != nil {
			return err
		}
		log.G(global).Info("starting containerd boot...")

		// load all plugins into containerd
		if err := plugin.Load(filepath.Join(conf.Root, "plugins")); err != nil {
			return err
		}
		// start debug and metrics APIs
		if err := serveDebugAPI(); err != nil {
			return err
		}
		monitor, err := loadMonitor()
		if err != nil {
			return err
		}
		runtimes, err := loadRuntimes(monitor)
		if err != nil {
			return err
		}
		store, err := resolveContentStore()
		if err != nil {
			return err
		}
		meta, err := resolveMetaDB(context)
		if err != nil {
			return err
		}
		defer meta.Close()
		snapshotter, err := loadSnapshotter(store)
		if err != nil {
			return err
		}
		services, err := loadServices(runtimes, store, snapshotter, meta)
		if err != nil {
			return err
		}
		// start the GRPC api with the execution service registered
		server := newGRPCServer()
		for _, service := range services {
			if err := service.Register(server); err != nil {
				return err
			}
		}
		log.G(global).Info("starting GRPC API server...")
		if err := serveGRPC(server); err != nil {
			return err
		}
		// start the prometheus metrics API for containerd
		serveMetricsAPI()

		log.G(global).Infof("containerd successfully booted in %fs", time.Since(start).Seconds())
		return handleSignals(signals, server)
	}

	if err := app.Run(os.Args); err != nil {
		fmt.Fprintf(os.Stderr, "containerd: %s\n", err)
		os.Exit(1)
	}
}

func before(context *cli.Context) error {
	err := loadConfig(context.GlobalString("config"))
	if err != nil && !os.IsNotExist(err) {
		return err
	} else if err != nil && os.IsNotExist(err) {
		log.G(global).Infof("config %q does not exist. Creating it.", context.GlobalString("config"))
		fh, err := os.Create(context.GlobalString("config"))
		if err != nil {
			return err
		}
		if _, err := conf.WriteTo(fh); err != nil {
			fh.Close()
			return err
		}
		fh.Close()
	}

	// the order for config vs flag values is that flags will always override
	// the config values if they are set
	if err := setLevel(context); err != nil {
		return err
	}
	for _, v := range []struct {
		name string
		d    *string
	}{
		{
			name: "root",
			d:    &conf.Root,
		},
		{
			name: "state",
			d:    &conf.State,
		},
		{
			name: "address",
			d:    &conf.GRPC.Address,
		},
	} {
		if s := context.GlobalString(v.name); s != "" {
			*v.d = s
		}
	}
	return nil
}

func setLevel(context *cli.Context) error {
	l := context.GlobalString("log-level")
	if l == "" {
		l = conf.Debug.Level
	}
	if l != "" {
		lvl, err := logrus.ParseLevel(l)
		if err != nil {
			return err
		}
		logrus.SetLevel(lvl)
	}
	return nil
}

func serveMetricsAPI() {
	if conf.Metrics.Address != "" {
		log.G(global).WithField("metrics", conf.Metrics.Address).Info("starting metrics API...")
		h := newMetricsHandler()
		go func() {
			if err := http.ListenAndServe(conf.Metrics.Address, h); err != nil {
				log.G(global).WithError(err).Fatal("serve metrics API")
			}
		}()
	}
}

func newMetricsHandler() http.Handler {
	m := http.NewServeMux()
	m.Handle("/metrics", metrics.Handler())
	return m
}

func serveDebugAPI() error {
	path := conf.Debug.Address
	if path == "" {
		return errors.New("debug socket path cannot be empty")
	}
	l, err := sys.GetLocalListener(path, conf.GRPC.Uid, conf.GRPC.Gid)
	if err != nil {
		return err
	}
	log.G(global).WithField("debug", path).Info("starting debug API...")
	go func() {
		defer l.Close()
		// pprof and expvars are imported and automatically register their endpoints
		// under /debug
		if err := http.Serve(l, nil); err != nil {
			log.G(global).WithError(err).Fatal("serve debug API")
		}
	}()
	return nil
}

func resolveContentStore() (*content.Store, error) {
	cp := filepath.Join(conf.Root, "content")
	return content.NewStore(cp)
}

func resolveMetaDB(ctx *cli.Context) (*bolt.DB, error) {
	path := filepath.Join(conf.Root, "meta.db")

	db, err := bolt.Open(path, 0644, nil)
	if err != nil {
		return nil, err
	}

	// TODO(stevvooe): Break these down into components to be initialized.
	if err := images.InitDB(db); err != nil {
		return nil, err
	}

	return db, nil
}

func loadRuntimes(monitor plugin.ContainerMonitor) (map[string]containerd.Runtime, error) {
	o := make(map[string]containerd.Runtime)
	for name, rr := range plugin.Registrations() {
		if rr.Type != plugin.RuntimePlugin {
			continue
		}
		log.G(global).Infof("loading runtime plugin %q...", name)
		ic := &plugin.InitContext{
			Root:    conf.Root,
			State:   conf.State,
			Context: log.WithModule(global, fmt.Sprintf("runtime-%s", name)),
			Monitor: monitor,
		}
		if rr.Config != nil {
			if err := conf.decodePlugin(name, rr.Config); err != nil {
				return nil, err
			}
			ic.Config = rr.Config
		}
		vr, err := rr.Init(ic)
		if err != nil {
			return nil, err
		}
		o[name] = vr.(containerd.Runtime)
	}
	return o, nil
}

func loadMonitor() (plugin.ContainerMonitor, error) {
	var monitors []plugin.ContainerMonitor
	for name, m := range plugin.Registrations() {
		if m.Type != plugin.ContainerMonitorPlugin {
			continue
		}
		log.G(global).Infof("loading monitor plugin %q...", name)
		ic := &plugin.InitContext{
			Root:    conf.Root,
			State:   conf.State,
			Context: log.WithModule(global, fmt.Sprintf("monitor-%s", name)),
		}
		mm, err := m.Init(ic)
		if err != nil {
			return nil, err
		}
		monitors = append(monitors, mm.(plugin.ContainerMonitor))
	}
	if len(monitors) == 0 {
		return plugin.NewNoopMonitor(), nil
	}
	return plugin.NewMultiContainerMonitor(monitors...), nil
}

func loadSnapshotter(store *content.Store) (snapshot.Snapshotter, error) {
	for name, sr := range plugin.Registrations() {
		if sr.Type != plugin.SnapshotPlugin {
			continue
		}
		moduleName := fmt.Sprintf("snapshot-%s", conf.Snapshotter)
		if name != moduleName {
			continue
		}

		log.G(global).Infof("loading snapshot plugin %q...", name)
		ic := &plugin.InitContext{
			Root:    conf.Root,
			State:   conf.State,
			Content: store,
			Context: log.WithModule(global, moduleName),
		}
		if sr.Config != nil {
			if err := conf.decodePlugin(name, sr.Config); err != nil {
				return nil, err
			}
			ic.Config = sr.Config
		}
		sn, err := sr.Init(ic)
		if err != nil {
			return nil, err
		}

		return sn.(snapshot.Snapshotter), nil
	}
	return nil, fmt.Errorf("snapshotter not loaded: %v", conf.Snapshotter)
}

func newGRPCServer() *grpc.Server {
	s := grpc.NewServer(
		grpc.UnaryInterceptor(interceptor),
		grpc.StreamInterceptor(grpc_prometheus.StreamServerInterceptor),
	)
	return s
}

func loadServices(runtimes map[string]containerd.Runtime, store *content.Store, sn snapshot.Snapshotter, meta *bolt.DB) ([]plugin.Service, error) {
	var o []plugin.Service
	for name, sr := range plugin.Registrations() {
		if sr.Type != plugin.GRPCPlugin {
			continue
		}
		log.G(global).Infof("loading grpc service plugin %q...", name)
		ic := &plugin.InitContext{
			Root:        conf.Root,
			State:       conf.State,
			Context:     log.WithModule(global, fmt.Sprintf("service-%s", name)),
			Runtimes:    runtimes,
			Content:     store,
			Meta:        meta,
			Snapshotter: sn,
		}
		if sr.Config != nil {
			if err := conf.decodePlugin(name, sr.Config); err != nil {
				return nil, err
			}
			ic.Config = sr.Config
		}
		vs, err := sr.Init(ic)
		if err != nil {
			return nil, err
		}
		o = append(o, vs.(plugin.Service))
	}
	return o, nil
}

func serveGRPC(server *grpc.Server) error {
	path := conf.GRPC.Address
	if path == "" {
		return errors.New("--socket path cannot be empty")
	}
	l, err := sys.GetLocalListener(path, conf.GRPC.Uid, conf.GRPC.Gid)
	if err != nil {
		return err
	}
	go func() {
		defer l.Close()
		if err := server.Serve(l); err != nil {
			log.G(global).WithError(err).Fatal("serve GRPC")
		}
	}()
	return nil
}

func interceptor(ctx gocontext.Context,
	req interface{},
	info *grpc.UnaryServerInfo,
	handler grpc.UnaryHandler,
) (interface{}, error) {
	ctx = log.WithModule(ctx, "containerd")
	switch info.Server.(type) {
	case api.ContainerServiceServer:
		ctx = log.WithModule(ctx, "execution")
	case contentapi.ContentServer:
		ctx = log.WithModule(ctx, "content")
	case rootfsapi.RootFSServer:
		ctx = log.WithModule(ctx, "rootfs")
	case imagesapi.ImagesServer:
		ctx = log.WithModule(ctx, "images")
	default:
		fmt.Printf("unknown GRPC server type: %#v\n", info.Server)
	}
	return grpc_prometheus.UnaryServerInterceptor(ctx, req, info, handler)
}
<commit_msg>containerd: revert the auto config creation<commit_after>package main

import (
	_ "expvar"
	"fmt"
	"net/http"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"path/filepath"
	"time"

	"github.com/boltdb/bolt"
	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
	gocontext "golang.org/x/net/context"
	"google.golang.org/grpc"

	"github.com/Sirupsen/logrus"
	"github.com/containerd/containerd"
	contentapi "github.com/containerd/containerd/api/services/content"
	api "github.com/containerd/containerd/api/services/execution"
	imagesapi "github.com/containerd/containerd/api/services/images"
	rootfsapi "github.com/containerd/containerd/api/services/rootfs"
	"github.com/containerd/containerd/content"
	"github.com/containerd/containerd/images"
	"github.com/containerd/containerd/log"
	"github.com/containerd/containerd/plugin"
	"github.com/containerd/containerd/snapshot"
	"github.com/containerd/containerd/sys"
	metrics "github.com/docker/go-metrics"
	"github.com/pkg/errors"
	"github.com/urfave/cli"
)

const usage = `
                    __        _                     __
  _________  ____  / /_____ _(_)___  ___  _________/ /
 / ___/ __ \/ __ \/ __/ __ ` + "`" + `/ / __ \/ _ \/ ___/ __  /
/ /__/ /_/ / / / / /_/ /_/ / / / / /  __/ /  / /_/ /
\___/\____/_/ /_/\__/\__,_/_/_/ /_/\___/_/   \__,_/

high performance container runtime
`

var (
	conf   = defaultConfig()
	global = log.WithModule(gocontext.Background(), "containerd")
)

func init() {
	cli.VersionPrinter = func(c *cli.Context) {
		fmt.Println(c.App.Name, containerd.Package, c.App.Version)
	}
}

func main() {
	app := cli.NewApp()
	app.Name = "containerd"
	app.Version = containerd.Version
	app.Usage = usage
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "config,c",
			Usage: "path to the configuration file (Use 'default' to output the default toml)",
			Value: defaultConfigPath,
		},
		cli.StringFlag{
			Name:  "log-level,l",
			Usage: "set the logging level [debug, info, warn, error, fatal, panic]",
		},
		cli.StringFlag{
			Name:  "state",
			Usage: "containerd state directory",
		},
		cli.StringFlag{
			Name:  "address,a",
			Usage: "address for containerd's GRPC server",
		},
		cli.StringFlag{
			Name:  "root",
			Usage: "containerd root directory",
		},
	}
	app.Commands = []cli.Command{
		configCommand,
	}
	app.Before = before
	app.Action = func(context *cli.Context) error {
		start := time.Now()
		// start the signal handler as soon as we can to make sure that
		// we don't miss any signals during boot
		signals := make(chan os.Signal, 2048)
		signal.Notify(signals, handledSignals...)
		if err := platformInit(context); err != nil {
			return err
		}
		log.G(global).Info("starting containerd boot...")

		// load all plugins into containerd
		if err := plugin.Load(filepath.Join(conf.Root, "plugins")); err != nil {
			return err
		}
		// start debug and metrics APIs
		if err := serveDebugAPI(); err != nil {
			return err
		}
		monitor, err := loadMonitor()
		if err != nil {
			return err
		}
		runtimes, err := loadRuntimes(monitor)
		if err != nil {
			return err
		}
		store, err := resolveContentStore()
		if err != nil {
			return err
		}
		meta, err := resolveMetaDB(context)
		if err != nil {
			return err
		}
		defer meta.Close()
		snapshotter, err := loadSnapshotter(store)
		if err != nil {
			return err
		}
		services, err := loadServices(runtimes, store, snapshotter, meta)
		if err != nil {
			return err
		}
		// start the GRPC api with the execution service registered
		server := newGRPCServer()
		for _, service := range services {
			if err := service.Register(server); err != nil {
				return err
			}
		}
		log.G(global).Info("starting GRPC API server...")
		if err := serveGRPC(server); err != nil {
			return err
		}
		// start the prometheus metrics API for containerd
		serveMetricsAPI()

		log.G(global).Infof("containerd successfully booted in %fs", time.Since(start).Seconds())
		return handleSignals(signals, server)
	}

	if err := app.Run(os.Args); err != nil {
		fmt.Fprintf(os.Stderr, "containerd: %s\n", err)
		os.Exit(1)
	}
}

func before(context *cli.Context) error {
	err := loadConfig(context.GlobalString("config"))
	if err != nil && !os.IsNotExist(err) {
		return err
	}
	// the order for config vs flag values is that flags will always override
	// the config values if they are set
	if err := setLevel(context); err != nil {
		return err
	}
	for _, v := range []struct {
		name string
		d    *string
	}{
		{
			name: "root",
			d:    &conf.Root,
		},
		{
			name: "state",
			d:    &conf.State,
		},
		{
			name: "address",
			d:    &conf.GRPC.Address,
		},
	} {
		if s := context.GlobalString(v.name); s != "" {
			*v.d = s
		}
	}
	return nil
}

func setLevel(context *cli.Context) error {
	l := context.GlobalString("log-level")
	if l == "" {
		l = conf.Debug.Level
	}
	if l != "" {
		lvl, err := logrus.ParseLevel(l)
		if err != nil {
			return err
		}
		logrus.SetLevel(lvl)
	}
	return nil
}

func serveMetricsAPI() {
	if conf.Metrics.Address != "" {
		log.G(global).WithField("metrics", conf.Metrics.Address).Info("starting metrics API...")
		h := newMetricsHandler()
		go func() {
			if err := http.ListenAndServe(conf.Metrics.Address, h); err != nil {
				log.G(global).WithError(err).Fatal("serve metrics API")
			}
		}()
	}
}

func newMetricsHandler() http.Handler {
	m := http.NewServeMux()
	m.Handle("/metrics", metrics.Handler())
	return m
}

func serveDebugAPI() error {
	path := conf.Debug.Address
	if path == "" {
		return errors.New("debug socket path cannot be empty")
	}
	l, err := sys.GetLocalListener(path, conf.GRPC.Uid, conf.GRPC.Gid)
	if err != nil {
		return err
	}
	log.G(global).WithField("debug", path).Info("starting debug API...")
	go func() {
		defer l.Close()
		// pprof and expvars are imported and automatically register their endpoints
		// under /debug
		if err := http.Serve(l, nil); err != nil {
			log.G(global).WithError(err).Fatal("serve debug API")
		}
	}()
	return nil
}

func resolveContentStore() (*content.Store, error) {
	cp := filepath.Join(conf.Root, "content")
	return content.NewStore(cp)
}

func resolveMetaDB(ctx *cli.Context) (*bolt.DB, error) {
	path := filepath.Join(conf.Root, "meta.db")

	db, err := bolt.Open(path, 0644, nil)
	if err != nil {
		return nil, err
	}

	// TODO(stevvooe): Break these down into components to be initialized.
	if err := images.InitDB(db); err != nil {
		return nil, err
	}

	return db, nil
}

func loadRuntimes(monitor plugin.ContainerMonitor) (map[string]containerd.Runtime, error) {
	o := make(map[string]containerd.Runtime)
	for name, rr := range plugin.Registrations() {
		if rr.Type != plugin.RuntimePlugin {
			continue
		}
		log.G(global).Infof("loading runtime plugin %q...", name)
		ic := &plugin.InitContext{
			Root:    conf.Root,
			State:   conf.State,
			Context: log.WithModule(global, fmt.Sprintf("runtime-%s", name)),
			Monitor: monitor,
		}
		if rr.Config != nil {
			if err := conf.decodePlugin(name, rr.Config); err != nil {
				return nil, err
			}
			ic.Config = rr.Config
		}
		vr, err := rr.Init(ic)
		if err != nil {
			return nil, err
		}
		o[name] = vr.(containerd.Runtime)
	}
	return o, nil
}

func loadMonitor() (plugin.ContainerMonitor, error) {
	var monitors []plugin.ContainerMonitor
	for name, m := range plugin.Registrations() {
		if m.Type != plugin.ContainerMonitorPlugin {
			continue
		}
		log.G(global).Infof("loading monitor plugin %q...", name)
		ic := &plugin.InitContext{
			Root:    conf.Root,
			State:   conf.State,
			Context: log.WithModule(global, fmt.Sprintf("monitor-%s", name)),
		}
		mm, err := m.Init(ic)
		if err != nil {
			return nil, err
		}
		monitors = append(monitors, mm.(plugin.ContainerMonitor))
	}
	if len(monitors) == 0 {
		return plugin.NewNoopMonitor(), nil
	}
	return plugin.NewMultiContainerMonitor(monitors...), nil
}

func loadSnapshotter(store *content.Store) (snapshot.Snapshotter, error) {
	for name, sr := range plugin.Registrations() {
		if sr.Type != plugin.SnapshotPlugin {
			continue
		}
		moduleName := fmt.Sprintf("snapshot-%s", conf.Snapshotter)
		if name != moduleName {
			continue
		}

		log.G(global).Infof("loading snapshot plugin %q...", name)
		ic := &plugin.InitContext{
			Root:    conf.Root,
			State:   conf.State,
			Content: store,
			Context: log.WithModule(global, moduleName),
		}
		if sr.Config != nil {
			if err := conf.decodePlugin(name, sr.Config); err != nil {
				return nil, err
			}
			ic.Config = sr.Config
		}
		sn, err := sr.Init(ic)
		if err != nil {
			return nil, err
		}

		return sn.(snapshot.Snapshotter), nil
	}
	return nil, fmt.Errorf("snapshotter not loaded: %v", conf.Snapshotter)
}

func newGRPCServer() *grpc.Server {
	s := grpc.NewServer(
		grpc.UnaryInterceptor(interceptor),
		grpc.StreamInterceptor(grpc_prometheus.StreamServerInterceptor),
	)
	return s
}

func loadServices(runtimes map[string]containerd.Runtime, store *content.Store, sn snapshot.Snapshotter, meta *bolt.DB) ([]plugin.Service, error) {
	var o []plugin.Service
	for name, sr := range plugin.Registrations() {
		if sr.Type != plugin.GRPCPlugin {
			continue
		}
		log.G(global).Infof("loading grpc service plugin %q...", name)
		ic := &plugin.InitContext{
			Root:        conf.Root,
			State:       conf.State,
			Context:     log.WithModule(global, fmt.Sprintf("service-%s", name)),
			Runtimes:    runtimes,
			Content:     store,
			Meta:        meta,
			Snapshotter: sn,
		}
		if sr.Config != nil {
			if err := conf.decodePlugin(name, sr.Config); err != nil {
				return nil, err
			}
			ic.Config = sr.Config
		}
		vs, err := sr.Init(ic)
		if err != nil {
			return nil, err
		}
		o = append(o, vs.(plugin.Service))
	}
	return o, nil
}

func serveGRPC(server *grpc.Server) error {
	path := conf.GRPC.Address
	if path == "" {
		return errors.New("--socket path cannot be empty")
	}
	l, err := sys.GetLocalListener(path, conf.GRPC.Uid, conf.GRPC.Gid)
	if err != nil {
		return err
	}
	go func() {
		defer l.Close()
		if err := server.Serve(l); err != nil {
			log.G(global).WithError(err).Fatal("serve GRPC")
		}
	}()
	return nil
}

func interceptor(ctx gocontext.Context,
	req interface{},
	info *grpc.UnaryServerInfo,
	handler grpc.UnaryHandler,
) (interface{}, error) {
	ctx = log.WithModule(ctx, "containerd")
	switch info.Server.(type) {
	case api.ContainerServiceServer:
		ctx = log.WithModule(ctx, "execution")
	case contentapi.ContentServer:
		ctx = log.WithModule(ctx, "content")
	case rootfsapi.RootFSServer:
		ctx = log.WithModule(ctx, "rootfs")
	case imagesapi.ImagesServer:
		ctx = log.WithModule(ctx, "images")
	default:
		fmt.Printf("unknown GRPC server type: %#v\n", info.Server)
	}
	return grpc_prometheus.UnaryServerInterceptor(ctx, req, info, handler)
}
<|endoftext|>


<commit_before>// escargs reads lines from the standard input and prints shell-escaped
// versions. Unlinke xargs, blank lines on the standard input are not
// discarded.
package main

import (
	"bufio"
	"fmt"
	"os"

	"github.com/alessio/shellescape"
)

func main() {
	firstScan := true
	scanner := bufio.NewScanner(os.Stdin)

	for scanner.Scan() {
		if firstScan {
			firstScan = false
		} else {
			fmt.Printf(" ")
		}

		fmt.Printf("%s", shellescape.Quote(scanner.Text()))
	}
}
<commit_msg>escargs: add -D flag<commit_after>// escargs reads lines from the standard input and prints shell-escaped
// versions. Unlinke xargs, blank lines on the standard input are not
// discarded.
package main

import (
	"bufio"
	"flag"
	"fmt"
	"os"

	"github.com/alessio/shellescape"
)

var (
	flagDiscardBlankLines = flag.Bool("D", false, "ignore blank lines on the standard input.")
)

func main() {
	flag.Parse()

	firstScan := true
	scanner := bufio.NewScanner(os.Stdin)

	for scanner.Scan() {
		line := scanner.Text()
		if *flagDiscardBlankLines && len(line) == 0 {
			continue
		}

		if firstScan {
			firstScan = false
		} else {
			fmt.Printf(" ")
		}

		fmt.Printf("%s", shellescape.Quote(line))
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package main

import (
	"bytes"
	"crypto/sha256"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"

	"github.com/mvdan/basedir"
	"github.com/mvdan/fdroidcl"
)

var cmdUpdate = &Command{
	UsageLine: "update",
	Short:     "Update the index",
}

func init() {
	cmdUpdate.Run = runUpdate
}

func runUpdate(args []string) {
	if err := updateIndex(); err != nil {
		log.Fatalf("Could not update index: %v", err)
	}
}

func updateIndex() error {
	url := fmt.Sprintf("%s/%s", repoURL, "index.jar")
	if err := downloadEtag(url, indexPath(repoName), nil); err != nil {
		return err
	}
	return nil
}

func respEtag(resp *http.Response) string {
	etags, e := resp.Header["Etag"]
	if !e || len(etags) == 0 {
		return ""
	}
	return etags[0]
}

func downloadEtag(url, path string, sum []byte) error {
	fmt.Printf("Downloading %s... ", url)
	defer fmt.Println()
	client := &http.Client{}
	req, err := http.NewRequest("GET", url, nil)

	etagPath := path + "-etag"
	if _, err := os.Stat(path); err == nil {
		etag, _ := ioutil.ReadFile(etagPath)
		req.Header.Add("If-None-Match", string(etag))
	}

	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusNotModified {
		fmt.Printf("not modified")
		return nil
	}
	f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
	if err != nil {
		return err
	}
	defer f.Close()
	if sum == nil {
		_, err := io.Copy(f, resp.Body)
		if err != nil {
			return err
		}
	} else {
		data, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return err
		}
		got := sha256.Sum256(data)
		if !bytes.Equal(sum, got[:]) {
			return errors.New("sha256 mismatch")
		}
		if _, err := f.Write(data); err != nil {
			return err
		}
	}
	if err := ioutil.WriteFile(etagPath, []byte(respEtag(resp)), 0644); err != nil {
		return err
	}
	fmt.Printf("done")
	return nil
}

func indexPath(name string) string {
	cache, err := basedir.Cache()
	if err != nil {
		log.Fatalf("Could not determine cache dir: %v", err)
	}
	return filepath.Join(appSubdir(cache), repoName+".jar")
}

func appSubdir(dir string, subdir ...string) string {
	elems := append([]string{dir, "fdroidcl"}, subdir...)
	p := filepath.Join(elems...)
	if err := os.MkdirAll(p, 0755); err != nil {
		log.Fatalf("Could not create app dir: %v", err)
	}
	return p
}

func mustLoadIndex() *fdroidcl.Index {
	p := indexPath(repoName)
	f, err := os.Open(p)
	if err != nil {
		log.Fatalf("Could not open index file: %v", err)
	}
	stat, err := f.Stat()
	if err != nil {
		log.Fatalf("Could not stat index file: %v", err)
	}
	//pubkey, err := hex.DecodeString(repoPubkey)
	//if err != nil {
	//	log.Fatalf("Could not decode public key: %v", err)
	//}
	index, err := fdroidcl.LoadIndexJar(f, stat.Size(), nil)
	if err != nil {
		log.Fatalf("Could not load index: %v", err)
	}
	return index
}
<commit_msg>Store index jars in persistent storage<commit_after>// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package main

import (
	"bytes"
	"crypto/sha256"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"

	"github.com/mvdan/fdroidcl"
)

var cmdUpdate = &Command{
	UsageLine: "update",
	Short:     "Update the index",
}

func init() {
	cmdUpdate.Run = runUpdate
}

func runUpdate(args []string) {
	if err := updateIndex(); err != nil {
		log.Fatalf("Could not update index: %v", err)
	}
}

func updateIndex() error {
	url := fmt.Sprintf("%s/%s", repoURL, "index.jar")
	if err := downloadEtag(url, indexPath(repoName), nil); err != nil {
		return err
	}
	return nil
}

func respEtag(resp *http.Response) string {
	etags, e := resp.Header["Etag"]
	if !e || len(etags) == 0 {
		return ""
	}
	return etags[0]
}

func downloadEtag(url, path string, sum []byte) error {
	fmt.Printf("Downloading %s... ", url)
	defer fmt.Println()
	client := &http.Client{}
	req, err := http.NewRequest("GET", url, nil)

	etagPath := path + "-etag"
	if _, err := os.Stat(path); err == nil {
		etag, _ := ioutil.ReadFile(etagPath)
		req.Header.Add("If-None-Match", string(etag))
	}

	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusNotModified {
		fmt.Printf("not modified")
		return nil
	}
	f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
	if err != nil {
		return err
	}
	defer f.Close()
	if sum == nil {
		_, err := io.Copy(f, resp.Body)
		if err != nil {
			return err
		}
	} else {
		data, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return err
		}
		got := sha256.Sum256(data)
		if !bytes.Equal(sum, got[:]) {
			return errors.New("sha256 mismatch")
		}
		if _, err := f.Write(data); err != nil {
			return err
		}
	}
	if err := ioutil.WriteFile(etagPath, []byte(respEtag(resp)), 0644); err != nil {
		return err
	}
	fmt.Printf("done")
	return nil
}

func indexPath(name string) string {
	return filepath.Join(mustConfig(), repoName+".jar")
}

func mustLoadIndex() *fdroidcl.Index {
	p := indexPath(repoName)
	f, err := os.Open(p)
	if err != nil {
		log.Fatalf("Could not open index file: %v", err)
	}
	stat, err := f.Stat()
	if err != nil {
		log.Fatalf("Could not stat index file: %v", err)
	}
	//pubkey, err := hex.DecodeString(repoPubkey)
	//if err != nil {
	//	log.Fatalf("Could not decode public key: %v", err)
	//}
	index, err := fdroidcl.LoadIndexJar(f, stat.Size(), nil)
	if err != nil {
		log.Fatalf("Could not load index: %v", err)
	}
	return index
}
<|endoftext|>


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

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"errors"
	"os"
	"regexp"
	"text/template"

	"github.com/codegangsta/cli"
	"github.com/kubernetes/helm/pkg/format"
)

var errMissingDeploymentArg = errors.New("First argument, deployment name, is required. Try 'helm get --help'")

const defaultShowFormat = `Name: {{.Name}}
Status: {{.State.Status}}
{{with .State.Errors}}Errors:
{{range .}}  {{.}}{{end}}
{{end}}`

func init() {
	addCommands(deploymentCommands())
}

func deploymentCommands() cli.Command {
	return cli.Command{
		// Names following form prescribed here: http://is.gd/QUSEOF
		Name:    "deployment",
		Aliases: []string{"dep"},
		Usage:   "Perform deployment-centered operations.",
		Subcommands: []cli.Command{
			{
				Name:      "config",
				Usage:     "Dump the configuration file for this deployment.",
				ArgsUsage: "DEPLOYMENT",
			},
			{
				Name:      "delete",
				Aliases:   []string{"del"},
				Usage:     "Deletes the named deployment(s).",
				ArgsUsage: "DEPLOYMENT [DEPLOYMENT [...]]",
				Action:    func(c *cli.Context) { run(c, deleteDeployment) },
			},
			{
				Name:      "manifest",
				Usage:     "Dump the Kubernetes manifest file for this deployment.",
				ArgsUsage: "DEPLOYMENT",
			},
			{
				Name:      "show",
				Aliases:   []string{"info"},
				Usage:     "Provide details about this deployment.",
				ArgsUsage: "",
				Action:    func(c *cli.Context) { run(c, showDeployment) },
			},
			{
				Name:      "list",
				Aliases:   []string{"ls"},
				Usage:     "list all deployments, or filter by an optional regular expression.",
				ArgsUsage: "REGEXP",
				Action:    func(c *cli.Context) { run(c, listDeployments) },
			},
		},
	}
}

func listDeployments(c *cli.Context) error {
	list, err := NewClient(c).ListDeployments()
	if err != nil {
		return err
	}
	args := c.Args()
	if len(args) >= 1 {
		pattern := args[0]
		r, err := regexp.Compile(pattern)
		if err != nil {
			return err
		}

		newlist := []string{}
		for _, i := range list {
			if r.MatchString(i) {
				newlist = append(newlist, i)
			}
		}
		list = newlist
	}

	if len(list) == 0 {
		return errors.New("no deployments found")
	}

	format.List(list)
	return nil
}

func deleteDeployment(c *cli.Context) error {
	args := c.Args()
	if len(args) < 1 {
		return errMissingDeploymentArg
	}
	for _, name := range args {
		deployment, err := NewClient(c).DeleteDeployment(name)
		if err != nil {
			return err
		}
		format.Info("Deleted %q at %s", name, deployment.DeletedAt)
	}
	return nil
}

func showDeployment(c *cli.Context) error {
	args := c.Args()
	if len(args) < 1 {
		return errMissingDeploymentArg
	}
	name := args[0]
	deployment, err := NewClient(c).GetDeployment(name)
	if err != nil {
		return err
	}
	tmpl := template.Must(template.New("show").Parse(defaultShowFormat))
	return tmpl.Execute(os.Stdout, deployment)
}
<commit_msg>fix(cli): change deployment delete to remove<commit_after>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"errors"
	"os"
	"regexp"
	"text/template"

	"github.com/codegangsta/cli"
	"github.com/kubernetes/helm/pkg/format"
)

var errMissingDeploymentArg = errors.New("First argument, deployment name, is required. Try 'helm get --help'")

const defaultShowFormat = `Name: {{.Name}}
Status: {{.State.Status}}
{{with .State.Errors}}Errors:
{{range .}}  {{.}}{{end}}
{{end}}`

func init() {
	addCommands(deploymentCommands())
}

func deploymentCommands() cli.Command {
	return cli.Command{
		// Names following form prescribed here: http://is.gd/QUSEOF
		Name:    "deployment",
		Aliases: []string{"dep"},
		Usage:   "Perform deployment-centered operations.",
		Subcommands: []cli.Command{
			{
				Name:      "config",
				Usage:     "Dump the configuration file for this deployment.",
				ArgsUsage: "DEPLOYMENT",
			},
			{
				Name:      "remove",
				Aliases:   []string{"rm"},
				Usage:     "Deletes the named deployment(s).",
				ArgsUsage: "DEPLOYMENT [DEPLOYMENT [...]]",
				Action:    func(c *cli.Context) { run(c, deleteDeployment) },
			},
			{
				Name:      "manifest",
				Usage:     "Dump the Kubernetes manifest file for this deployment.",
				ArgsUsage: "DEPLOYMENT",
			},
			{
				Name:      "show",
				Aliases:   []string{"info"},
				Usage:     "Provide details about this deployment.",
				ArgsUsage: "",
				Action:    func(c *cli.Context) { run(c, showDeployment) },
			},
			{
				Name:      "list",
				Aliases:   []string{"ls"},
				Usage:     "list all deployments, or filter by an optional regular expression.",
				ArgsUsage: "REGEXP",
				Action:    func(c *cli.Context) { run(c, listDeployments) },
			},
		},
	}
}

func listDeployments(c *cli.Context) error {
	list, err := NewClient(c).ListDeployments()
	if err != nil {
		return err
	}
	args := c.Args()
	if len(args) >= 1 {
		pattern := args[0]
		r, err := regexp.Compile(pattern)
		if err != nil {
			return err
		}

		newlist := []string{}
		for _, i := range list {
			if r.MatchString(i) {
				newlist = append(newlist, i)
			}
		}
		list = newlist
	}

	if len(list) == 0 {
		return errors.New("no deployments found")
	}

	format.List(list)
	return nil
}

func deleteDeployment(c *cli.Context) error {
	args := c.Args()
	if len(args) < 1 {
		return errMissingDeploymentArg
	}
	for _, name := range args {
		deployment, err := NewClient(c).DeleteDeployment(name)
		if err != nil {
			return err
		}
		format.Info("Deleted %q at %s", name, deployment.DeletedAt)
	}
	return nil
}

func showDeployment(c *cli.Context) error {
	args := c.Args()
	if len(args) < 1 {
		return errMissingDeploymentArg
	}
	name := args[0]
	deployment, err := NewClient(c).GetDeployment(name)
	if err != nil {
		return err
	}
	tmpl := template.Must(template.New("show").Parse(defaultShowFormat))
	return tmpl.Execute(os.Stdout, deployment)
}
<|endoftext|>


<commit_before>package install

import (
	"os"
	"path/filepath"
)

type installer interface {
	Install(cmd, bin string) error
	Uninstall(cmd, bin string) error
}

// Install complete command given:
// cmd: is the command name
// asRoot: if true the completion will be installed in /etc/bash_complete.d
// otherwise the complete command will be added to the ~/.bashrc file.
func Install(cmd string, asRoot bool) error {
	bin, err := getBinaryPath()
	if err != nil {
		return err
	}
	return getInstaller(asRoot).Install(cmd, bin)
}

// Uninstall complete command given:
// cmd: is the command name
// asRoot: if true the completion will be removed from /etc/bash_complete.d
// otherwise the complete command will be removed from the ~/.bashrc file.
func Uninstall(cmd string, asRoot bool) error {
	bin, err := getBinaryPath()
	if err != nil {
		return err
	}
	return getInstaller(asRoot).Uninstall(cmd, bin)
}

func getInstaller(asRoot bool) installer {
	if asRoot {
		return root{}
	} else {
		return home{}
	}
}

func getBinaryPath() (string, error) {
	bin, err := os.Executable()
	if err != nil {
		return "", err
	}
	return filepath.Abs(bin)
}
<commit_msg>Fix one more vet<commit_after>package install

import (
	"os"
	"path/filepath"
)

type installer interface {
	Install(cmd, bin string) error
	Uninstall(cmd, bin string) error
}

// Install complete command given:
// cmd: is the command name
// asRoot: if true the completion will be installed in /etc/bash_complete.d
// otherwise the complete command will be added to the ~/.bashrc file.
func Install(cmd string, asRoot bool) error {
	bin, err := getBinaryPath()
	if err != nil {
		return err
	}
	return getInstaller(asRoot).Install(cmd, bin)
}

// Uninstall complete command given:
// cmd: is the command name
// asRoot: if true the completion will be removed from /etc/bash_complete.d
// otherwise the complete command will be removed from the ~/.bashrc file.
func Uninstall(cmd string, asRoot bool) error {
	bin, err := getBinaryPath()
	if err != nil {
		return err
	}
	return getInstaller(asRoot).Uninstall(cmd, bin)
}

func getInstaller(asRoot bool) installer {
	if asRoot {
		return root{}
	}
	return home{}
}

func getBinaryPath() (string, error) {
	bin, err := os.Executable()
	if err != nil {
		return "", err
	}
	return filepath.Abs(bin)
}
<|endoftext|>


<commit_before>/*

   Copyright 2016 Wenhui Shen <www.webx.top>

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

*/
package echo

import (
	"net/http"
	"net/url"
	"time"
)

type CookieOptions struct {
	Prefix string

	// MaxAge=0 means no 'Max-Age' attribute specified.
	// MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'.
	// MaxAge>0 means Max-Age attribute present and given in seconds.
	MaxAge int

	Path     string
	Domain   string
	Secure   bool
	HttpOnly bool
}

type Cookier interface {
	Get(key string) string
	Set(key string, val string, args ...interface{})
}

func NewCookier(ctx Context) Cookier {
	return &cookie{
		context: ctx,
	}
}

func NewCookie(name string, value string, opts ...*CookieOptions) *Cookie {
	opt := &CookieOptions{}
	if len(opts) > 0 {
		opt = opts[0]
	}
	if len(opt.Path) == 0 {
		opt.Path = `/`
	}
	cookie := &Cookie{
		cookie: &http.Cookie{
			Name:     opt.Prefix + name,
			Value:    value,
			Path:     opt.Path,
			Domain:   opt.Domain,
			MaxAge:   opt.MaxAge,
			Secure:   opt.Secure,
			HttpOnly: opt.HttpOnly,
		},
	}
	return cookie
}

type Cookie struct {
	cookie *http.Cookie
}

func (c *Cookie) Path(p string) *Cookie {
	c.cookie.Path = p
	return c
}

func (c *Cookie) Domain(p string) *Cookie {
	c.cookie.Domain = p
	return c
}

func (c *Cookie) MaxAge(p int) *Cookie {
	c.cookie.MaxAge = p
	return c
}

func (c *Cookie) Expires(p int64) *Cookie {
	if p > 0 {
		c.cookie.Expires = time.Unix(time.Now().Unix()+p, 0)
	} else if p < 0 {
		c.cookie.Expires = time.Unix(1, 0)
	}
	return c
}

func (c *Cookie) Secure(p bool) *Cookie {
	c.cookie.Secure = p
	return c
}

func (c *Cookie) HttpOnly(p bool) *Cookie {
	c.cookie.HttpOnly = p
	return c
}

func (c *Cookie) Send(ctx Context) {
	ctx.Response().Header().Set(HeaderSetCookie, c.cookie.String())
}

type cookie struct {
	context Context
}

func (c *cookie) Get(key string) string {
	var val string
	if v := c.context.Request().Cookie(c.context.CookieOptions().Prefix + key); v != `` {
		val, _ = url.QueryUnescape(v)
	}
	return val
}

func (c *cookie) Set(key string, val string, args ...interface{}) {
	val = url.QueryEscape(val)
	cookie := NewCookie(key, val, c.context.CookieOptions())
	switch len(args) {
	case 5:
		httpOnly, _ := args[4].(bool)
		cookie.HttpOnly(httpOnly)
		fallthrough
	case 4:
		secure, _ := args[3].(bool)
		cookie.Secure(secure)
		fallthrough
	case 3:
		domain, _ := args[2].(string)
		cookie.Domain(domain)
		fallthrough
	case 2:
		ppath, _ := args[1].(string)
		cookie.Path(ppath)
		fallthrough
	case 1:
		var liftTime int64
		switch args[0].(type) {
		case int:
			liftTime = int64(args[0].(int))
		case int64:
			liftTime = args[0].(int64)
		case time.Duration:
			liftTime = int64(args[0].(time.Duration).Seconds())
		}
		cookie.Expires(liftTime)
	}
	cookie.Send(c.context)
}
<commit_msg>update<commit_after>/*

   Copyright 2016 Wenhui Shen <www.webx.top>

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

*/
package echo

import (
	"net/http"
	"net/url"
	"time"
)

type CookieOptions struct {
	Prefix string

	// MaxAge=0 means no 'Max-Age' attribute specified.
	// MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'.
	// MaxAge>0 means Max-Age attribute present and given in seconds.
	MaxAge int

	Path     string
	Domain   string
	Secure   bool
	HttpOnly bool
}

type Cookier interface {
	Get(key string) string
	Set(key string, val string, args ...interface{}) Cookier
}

func NewCookier(ctx Context) Cookier {
	return &cookie{
		context: ctx,
	}
}

func NewCookie(name string, value string, opts ...*CookieOptions) *Cookie {
	opt := &CookieOptions{}
	if len(opts) > 0 {
		opt = opts[0]
	}
	if len(opt.Path) == 0 {
		opt.Path = `/`
	}
	cookie := &Cookie{
		cookie: &http.Cookie{
			Name:     opt.Prefix + name,
			Value:    value,
			Path:     opt.Path,
			Domain:   opt.Domain,
			MaxAge:   opt.MaxAge,
			Secure:   opt.Secure,
			HttpOnly: opt.HttpOnly,
		},
	}
	return cookie
}

type Cookie struct {
	cookie *http.Cookie
}

func (c *Cookie) Path(p string) *Cookie {
	c.cookie.Path = p
	return c
}

func (c *Cookie) Domain(p string) *Cookie {
	c.cookie.Domain = p
	return c
}

func (c *Cookie) MaxAge(p int) *Cookie {
	c.cookie.MaxAge = p
	return c
}

func (c *Cookie) Expires(p int64) *Cookie {
	if p > 0 {
		c.cookie.Expires = time.Unix(time.Now().Unix()+p, 0)
	} else if p < 0 {
		c.cookie.Expires = time.Unix(1, 0)
	}
	return c
}

func (c *Cookie) Secure(p bool) *Cookie {
	c.cookie.Secure = p
	return c
}

func (c *Cookie) HttpOnly(p bool) *Cookie {
	c.cookie.HttpOnly = p
	return c
}

func (c *Cookie) Send(ctx Context) {
	ctx.Response().Header().Set(HeaderSetCookie, c.cookie.String())
}

type cookie struct {
	context Context
}

func (c *cookie) Get(key string) string {
	var val string
	if v := c.context.Request().Cookie(c.context.CookieOptions().Prefix + key); v != `` {
		val, _ = url.QueryUnescape(v)
	}
	return val
}

func (c *cookie) Set(key string, val string, args ...interface{}) Cookier {
	val = url.QueryEscape(val)
	cookie := NewCookie(key, val, c.context.CookieOptions())
	switch len(args) {
	case 5:
		httpOnly, _ := args[4].(bool)
		cookie.HttpOnly(httpOnly)
		fallthrough
	case 4:
		secure, _ := args[3].(bool)
		cookie.Secure(secure)
		fallthrough
	case 3:
		domain, _ := args[2].(string)
		cookie.Domain(domain)
		fallthrough
	case 2:
		ppath, _ := args[1].(string)
		cookie.Path(ppath)
		fallthrough
	case 1:
		var liftTime int64
		switch args[0].(type) {
		case int:
			liftTime = int64(args[0].(int))
		case int64:
			liftTime = args[0].(int64)
		case time.Duration:
			liftTime = int64(args[0].(time.Duration).Seconds())
		}
		cookie.Expires(liftTime)
	}
	cookie.Send(c.context)
	return c
}
<|endoftext|>


<commit_before>package cookie

// Thanks to web.go (https://github.com/hoisie/web) for several of these functions

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha1"
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
	"strings"
	"time"
)

const (
	// Version number. Stable API within major version numbers.
	Version = 1.0

	DefaultCookieTime = 3600 * 24 // Login cookies should last for 24 hours, by default
)

// Get a secure cookie from a HTTP request
func SecureCookie(req *http.Request, name string, cookieSecret string) (string, bool) {
	for _, cookie := range req.Cookies() {
		if cookie.Name != name {
			continue
		}

		parts := strings.SplitN(cookie.Value, "|", 3)

		// fix potential out of range error
		if len(parts) != 3 {
			return "", false
		}

		val := parts[0]
		timestamp := parts[1]
		sig := parts[2]

		if CookieSig(cookieSecret, []byte(val), timestamp) != sig {
			return "", false
		}

		ts, _ := strconv.ParseInt(timestamp, 0, 64)
		if time.Now().Unix()-31*86400 > ts {
			return "", false
		}

		buf := bytes.NewBufferString(val)
		encoder := base64.NewDecoder(base64.StdEncoding, buf)

		res, _ := ioutil.ReadAll(encoder)
		return string(res), true
	}
	return "", false
}

// Set a cookie with an explicit path.
// age is the time-to-live, in seconds (0 means forever).
func SetCookiePath(w http.ResponseWriter, name, value string, age int64, path string) {
	var utctime time.Time
	if age == 0 {
		// 2^31 - 1 seconds (roughly 2038)
		utctime = time.Unix(2147483647, 0)
	} else {
		utctime = time.Unix(time.Now().Unix()+age, 0)
	}
	cookie := http.Cookie{Name: name, Value: value, Expires: utctime, Path: path}
	SetHeader(w, "Set-Cookie", cookie.String(), false)
}

// Clear the given cookie name, with a corresponding path
// Note that browsers *may* be configured to not delete the cookie.
func ClearCookie(w http.ResponseWriter, cookieName, cookiePath string) {
	ignoredContent := "BLUBLU" // random string
	cookie := fmt.Sprintf("%s=%s; path=%s; expires=Thu, 01 Jan 1970 00:00:00 GMT", cookieName, ignoredContent, cookiePath)
	SetHeader(w, "Set-Cookie", cookie, true)
}

// Set a secure cookie with an explicit path.
// age is the time-to-live, in seconds (0 means forever).
func SetSecureCookiePath(w http.ResponseWriter, name, val string, age int64, path string, cookieSecret string) {
	// base64 encode the value
	if len(cookieSecret) == 0 {
		log.Fatalln("Secret Key for secure cookies has not been set. Please use a non-empty secret.")
	}
	var buf bytes.Buffer
	encoder := base64.NewEncoder(base64.StdEncoding, &buf)
	encoder.Write([]byte(val))
	encoder.Close()
	vs := buf.String()
	vb := buf.Bytes()
	timestamp := strconv.FormatInt(time.Now().Unix(), 10)
	sig := CookieSig(cookieSecret, vb, timestamp)
	cookie := strings.Join([]string{vs, timestamp, sig}, "|")
	SetCookiePath(w, name, cookie, age, path)
}

// Get the cookie signature
func CookieSig(key string, val []byte, timestamp string) string {
	hm := hmac.New(sha1.New, []byte(key))

	hm.Write(val)
	hm.Write([]byte(timestamp))

	hex := fmt.Sprintf("%02x", hm.Sum(nil))
	return hex
}

// Used for setting cookies in the HTTP header
func SetHeader(w http.ResponseWriter, hdr, val string, unique bool) {
	if unique {
		w.Header().Set(hdr, val)
	} else {
		w.Header().Add(hdr, val)
	}
}
<commit_msg>Update API version number<commit_after>package cookie

// Thanks to @hoisie / [web.go](https://github.com/hoisie/web) for several of these functions

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha1"
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
	"strings"
	"time"
)

const (
	// Version number. Stable API within major version numbers.
	Version = 2.0

	DefaultCookieTime = 3600 * 24 // Login cookies should last for 24 hours, by default
)

// Get a secure cookie from a HTTP request
func SecureCookie(req *http.Request, name string, cookieSecret string) (string, bool) {
	for _, cookie := range req.Cookies() {
		if cookie.Name != name {
			continue
		}

		parts := strings.SplitN(cookie.Value, "|", 3)

		// fix potential out of range error
		if len(parts) != 3 {
			return "", false
		}

		val := parts[0]
		timestamp := parts[1]
		sig := parts[2]

		if CookieSig(cookieSecret, []byte(val), timestamp) != sig {
			return "", false
		}

		ts, _ := strconv.ParseInt(timestamp, 0, 64)
		if time.Now().Unix()-31*86400 > ts {
			return "", false
		}

		buf := bytes.NewBufferString(val)
		encoder := base64.NewDecoder(base64.StdEncoding, buf)

		res, _ := ioutil.ReadAll(encoder)
		return string(res), true
	}
	return "", false
}

// Set a cookie with an explicit path.
// age is the time-to-live, in seconds (0 means forever).
func SetCookiePath(w http.ResponseWriter, name, value string, age int64, path string) {
	var utctime time.Time
	if age == 0 {
		// 2^31 - 1 seconds (roughly 2038)
		utctime = time.Unix(2147483647, 0)
	} else {
		utctime = time.Unix(time.Now().Unix()+age, 0)
	}
	cookie := http.Cookie{Name: name, Value: value, Expires: utctime, Path: path}
	SetHeader(w, "Set-Cookie", cookie.String(), false)
}

// Clear the given cookie name, with a corresponding path
// Note that browsers *may* be configured to not delete the cookie.
func ClearCookie(w http.ResponseWriter, cookieName, cookiePath string) {
	ignoredContent := "SNUSNU" // random string
	cookie := fmt.Sprintf("%s=%s; path=%s; expires=Thu, 01 Jan 1970 00:00:00 GMT", cookieName, ignoredContent, cookiePath)
	SetHeader(w, "Set-Cookie", cookie, true)
}

// Set a secure cookie with an explicit path.
// age is the time-to-live, in seconds (0 means forever).
func SetSecureCookiePath(w http.ResponseWriter, name, val string, age int64, path string, cookieSecret string) {
	// base64 encode the value
	if len(cookieSecret) == 0 {
		log.Fatalln("Secret Key for secure cookies has not been set. Please use a non-empty secret.")
	}
	var buf bytes.Buffer
	encoder := base64.NewEncoder(base64.StdEncoding, &buf)
	encoder.Write([]byte(val))
	encoder.Close()
	vs := buf.String()
	vb := buf.Bytes()
	timestamp := strconv.FormatInt(time.Now().Unix(), 10)
	sig := CookieSig(cookieSecret, vb, timestamp)
	cookie := strings.Join([]string{vs, timestamp, sig}, "|")
	SetCookiePath(w, name, cookie, age, path)
}

// Get the cookie signature
func CookieSig(key string, val []byte, timestamp string) string {
	hm := hmac.New(sha1.New, []byte(key))

	hm.Write(val)
	hm.Write([]byte(timestamp))

	hex := fmt.Sprintf("%02x", hm.Sum(nil))
	return hex
}

// Used for setting cookies in the HTTP header
func SetHeader(w http.ResponseWriter, hdr, val string, unique bool) {
	if unique {
		w.Header().Set(hdr, val)
	} else {
		w.Header().Add(hdr, val)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"reflect"
	"regexp"
)

type TokenType int

const (
	TokenLiteral = iota
	TokenReference
)

type Token struct {
	Type  TokenType
	Value string
}

// Concatenator is an implementation of PostProcessor to de-reference (( grab me.data )) calls
type Concatenator struct {
	root map[interface{}]interface{}
}

// Action returns the Action string for the Concatenator
func (s Concatenator) Action() string {
	return "concatenator"
}

// PostProcess - resolves a value by seeing if it matches (( grab me.data )) and retrieves me.data's value
func (s Concatenator) PostProcess(o interface{}, node string) (interface{}, string, error) {
	if o != nil && reflect.TypeOf(o).Kind() == reflect.String {
		re := regexp.MustCompile(`^\Q((\E\s*concat\s+(.+)\s*\Q))\E$`)
		if re.MatchString(o.(string)) {
			keys := re.FindStringSubmatch(o.(string))

			tokens := parseWords(keys[1])
			str := ""
			for _, token := range tokens {
				if token.Type == TokenLiteral {
					str += token.Value
				} else {
					DEBUG("%s: resolving from %s", node, token.Value)
					val, err := resolveNode(token.Value, s.root)
					if err != nil {
						return nil, "error", fmt.Errorf("%s: Unable to resolve `%s`: `%s", node, token.Value, err.Error())
					}
					// error if val is not a string
					str += val.(string)
				}
			}

			return str, "replace", nil
		}
	}

	return nil, "ignore", nil
}

func splitQuoted(src string) []string {
	list := make([]string, 0, 0)

	buf := ""
	escaped := false
	quoted := false

	for _, c := range src {
		if escaped {
			buf += string(c)
			escaped = false
			continue
		}

		if c == '\\' {
			escaped = true
			continue
		}

		if c == ' ' || c == '\t' {
			if quoted {
				buf += string(c)
				continue
			} else if buf != "" {
				list = append(list, buf)
				buf = ""
			}
			continue
		}

		if c == '"' {
			buf += string(c)
			quoted = !quoted
			continue
		}

		buf += string(c)
	}

	if buf != "" {
		list = append(list, buf)
	}

	return list
}

func parseWords(src string) []Token {
	raw := splitQuoted(src)
	re := regexp.MustCompile(`^"(.*)"$`)
	tokens := make([]Token, len(raw), len(raw))
	for i, s := range raw {
		if re.MatchString(s) {
			keys := re.FindStringSubmatch(s)
			tokens[i] = Token{Type: TokenLiteral, Value: keys[1]}
			fmt.Printf("found literal {%s}\n", keys[1])
		} else {
			tokens[i] = Token{Type: TokenReference, Value: s}
			fmt.Printf("found reference [%s]\n", s)
		}
	}

	return tokens
}
<commit_msg>Fixed bad debugging<commit_after>package main

import (
	"fmt"
	"reflect"
	"regexp"
)

type TokenType int

const (
	TokenLiteral = iota
	TokenReference
)

type Token struct {
	Type  TokenType
	Value string
}

// Concatenator is an implementation of PostProcessor to de-reference (( grab me.data )) calls
type Concatenator struct {
	root map[interface{}]interface{}
}

// Action returns the Action string for the Concatenator
func (s Concatenator) Action() string {
	return "concatenator"
}

// PostProcess - resolves a value by seeing if it matches (( grab me.data )) and retrieves me.data's value
func (s Concatenator) PostProcess(o interface{}, node string) (interface{}, string, error) {
	if o != nil && reflect.TypeOf(o).Kind() == reflect.String {
		re := regexp.MustCompile(`^\Q((\E\s*concat\s+(.+)\s*\Q))\E$`)
		if re.MatchString(o.(string)) {
			keys := re.FindStringSubmatch(o.(string))

			tokens := parseWords(keys[1])
			str := ""
			for _, token := range tokens {
				if token.Type == TokenLiteral {
					str += token.Value
				} else {
					DEBUG("%s: resolving from %s", node, token.Value)
					val, err := resolveNode(token.Value, s.root)
					if err != nil {
						return nil, "error", fmt.Errorf("%s: Unable to resolve `%s`: `%s", node, token.Value, err.Error())
					}
					// error if val is not a string
					str += val.(string)
				}
			}

			return str, "replace", nil
		}
	}

	return nil, "ignore", nil
}

func splitQuoted(src string) []string {
	list := make([]string, 0, 0)

	buf := ""
	escaped := false
	quoted := false

	for _, c := range src {
		if escaped {
			buf += string(c)
			escaped = false
			continue
		}

		if c == '\\' {
			escaped = true
			continue
		}

		if c == ' ' || c == '\t' {
			if quoted {
				buf += string(c)
				continue
			} else if buf != "" {
				list = append(list, buf)
				buf = ""
			}
			continue
		}

		if c == '"' {
			buf += string(c)
			quoted = !quoted
			continue
		}

		buf += string(c)
	}

	if buf != "" {
		list = append(list, buf)
	}

	return list
}

func parseWords(src string) []Token {
	raw := splitQuoted(src)
	re := regexp.MustCompile(`^"(.*)"$`)
	tokens := make([]Token, len(raw), len(raw))
	for i, s := range raw {
		if re.MatchString(s) {
			keys := re.FindStringSubmatch(s)
			tokens[i] = Token{Type: TokenLiteral, Value: keys[1]}
		} else {
			tokens[i] = Token{Type: TokenReference, Value: s}
		}
	}

	return tokens
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"os/exec"
	"strings"

	"github.com/vpn-kill-switch/killswitch"
)

// PadRight add spaces for aligning the output
func PadRight(str, pad string, length int) string {
	for {
		str += pad
		if len(str) > length {
			return str[0:length]
		}
	}
}

func exit1(err error) {
	fmt.Println(err)
	os.Exit(1)
}

var version string

func main() {

	var (
		ip   = flag.String("ip", "", "VPN peer `IPv4`, killswitch tries to find this automatically")
		d    = flag.Bool("d", false, "`Disable` load /etc/pf.conf rules")
		e    = flag.Bool("e", false, "`Enable` load the pf rules")
		p    = flag.Bool("p", false, "`Print` the pf rules")
		v    = flag.Bool("v", false, fmt.Sprintf("Print version: %s", version))
		leak = flag.Bool("leak", false, "Allow ICMP (ping) and DNS requests outside VPN")
	)

	flag.Parse()

	if *v {
		fmt.Printf("%s\n", version)
		os.Exit(0)
	}

	if *d {
		exec.Command("pfctl", "-e").CombinedOutput()
		fmt.Printf("# %s\n", strings.Repeat("-", 62))
		fmt.Println("# Loading /etc/pf.conf rules")
		fmt.Printf("# %s\n", strings.Repeat("-", 62))
		out, _ := exec.Command("pfctl",
			"-Fa",
			"-f",
			"/etc/pf.conf").CombinedOutput()
		fmt.Printf("%s\n", out)
		out, _ = exec.Command("pfctl", "-sr").CombinedOutput()
		fmt.Printf("%s\n", out)
		return
	}

	ks, err := killswitch.New(*ip)
	if err != nil {
		exit1(err)
	}

	err = ks.GetActive()
	if err != nil {
		exit1(err)
	}

	if len(ks.UpInterfaces) == 0 {
		exit1(fmt.Errorf("No active interfaces found, verify network settings, use (\"%s -h\") for help.\n", os.Args[0]))
	}

	fmt.Println("Interface  MAC address         IP")
	for k, v := range ks.UpInterfaces {
		fmt.Printf("%s %s   %s\n", PadRight(k, " ", 10), v[0], v[1])
	}
	for k, v := range ks.P2PInterfaces {
		fmt.Printf("%s %s   %s\n", PadRight(k, " ", 10), PadRight(v[0], " ", 17), v[1])
	}
	// check for DNS leaks
	if ipDNS, err := killswitch.WhoamiDNS(); err == nil {
		if ipWWW, err := killswitch.WhoamiWWW(); err == nil {
			if ipDNS != ipWWW {
				fmt.Printf("\n%s:\n", killswitch.Red("DNS leaking"))
				fmt.Printf("Public IP address (DNS): %s\n", killswitch.Red(ipDNS))
				fmt.Printf("Public IP address (WWW): %s\n", killswitch.Red(ipWWW))
			} else {
				fmt.Printf("\nPublic IP address: %s\n", killswitch.Red(ipDNS))
			}
		}
	}

	// add some space
	println()

	if len(ks.P2PInterfaces) == 0 {
		exit1(fmt.Errorf("No VPN interface found, verify VPN is connected"))
	}

	fmt.Printf("PEER IP address:   %s\n", killswitch.Yellow(ks.PeerIP))

	if *ip != "" {
		if ipv4 := net.ParseIP(*ip); ipv4.To4() == nil {
			exit1(fmt.Errorf("%s is not a valid IPv4 address, use (\"%s -h\") for help.\n", *ip, os.Args[0]))
		}
	}

	ks.CreatePF(*leak)

	fmt.Printf("\n%s: %s\n", "To enable the kill switch run", killswitch.Green("sudo killswitch -e"))
	fmt.Printf("%s: %s\n\n", "To disable", killswitch.Yellow("sudo killswitch -d"))

	if *p {
		fmt.Printf("PF rules to be loaded:\n")
		fmt.Println(ks.PFRules.String())
	}

	if err = ioutil.WriteFile("/tmp/killswitch.pf.conf",
		ks.PFRules.Bytes(),
		0644,
	); err != nil {
		exit1(err)
	}

	if *e {
		fmt.Printf("# %s\n", strings.Repeat("-", 62))
		fmt.Println("# Loading rules")
		fmt.Printf("# %s\n", strings.Repeat("-", 62))
		out, _ := exec.Command("pfctl", "-e").CombinedOutput()
		fmt.Printf("%s\n", out)
		out, _ = exec.Command("pfctl",
			"-Fa",
			"-f",
			"/tmp/killswitch.pf.conf").CombinedOutput()
		fmt.Printf("%s\n", out)
		out, _ = exec.Command("pfctl", "-sr").CombinedOutput()
		fmt.Printf("%s\n", out)
	}
}
<commit_msg>error messages improved<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"os/exec"
	"strings"

	"github.com/vpn-kill-switch/killswitch"
)

// PadRight add spaces for aligning the output
func PadRight(str, pad string, length int) string {
	for {
		str += pad
		if len(str) > length {
			return str[0:length]
		}
	}
}

func exit1(err error) {
	fmt.Fprintln(os.Stderr, err)
	os.Exit(1)
}

var version string

func main() {

	var (
		ip   = flag.String("ip", "", "VPN peer `IPv4`, killswitch tries to find this automatically")
		d    = flag.Bool("d", false, "`Disable` load /etc/pf.conf rules")
		e    = flag.Bool("e", false, "`Enable` load the pf rules")
		p    = flag.Bool("p", false, "`Print` the pf rules")
		v    = flag.Bool("v", false, fmt.Sprintf("Print version: %s", version))
		leak = flag.Bool("leak", false, "Allow ICMP (ping) and DNS requests outside VPN")
	)

	flag.Parse()

	if *v {
		fmt.Printf("%s\n", version)
		os.Exit(0)
	}

	if *d {
		exec.Command("pfctl", "-e").CombinedOutput()
		_, err := exec.Command("pfctl",
			"-Fa",
			"-f",
			"/etc/pf.conf").CombinedOutput()
		if err != nil {
			exit1(fmt.Errorf(fmt.Sprintf("%s: %s\n%s",
				killswitch.Red("To disable use"),
				killswitch.Yellow("sudo killswitch -d"),
				err)),
			)
		}
		out, err := exec.Command("pfctl", "-sr").CombinedOutput()
		if err != nil {
			exit1(err)
		}
		fmt.Printf("%s\n", out)
		fmt.Println(killswitch.Yellow("killswitch disabled"))
		return
	}

	ks, err := killswitch.New(*ip)
	if err != nil {
		exit1(err)
	}

	err = ks.GetActive()
	if err != nil {
		exit1(err)
	}

	if len(ks.UpInterfaces) == 0 {
		exit1(fmt.Errorf("No active interfaces found, verify network settings, use (\"%s -h\") for help.\n", os.Args[0]))
	}

	fmt.Println("Interface  MAC address         IP")
	for k, v := range ks.UpInterfaces {
		fmt.Printf("%s %s   %s\n", PadRight(k, " ", 10), v[0], v[1])
	}
	for k, v := range ks.P2PInterfaces {
		fmt.Printf("%s %s   %s\n", PadRight(k, " ", 10), PadRight(v[0], " ", 17), v[1])
	}
	// check for DNS leaks
	if ipDNS, err := killswitch.WhoamiDNS(); err == nil {
		if ipWWW, err := killswitch.WhoamiWWW(); err == nil {
			if ipDNS != ipWWW {
				fmt.Printf("\n%s:\n", killswitch.Red("DNS leaking"))
				fmt.Printf("Public IP address (DNS): %s\n", killswitch.Red(ipDNS))
				fmt.Printf("Public IP address (WWW): %s\n", killswitch.Red(ipWWW))
			} else {
				fmt.Printf("\nPublic IP address: %s\n", killswitch.Red(ipDNS))
			}
		}
	}

	if len(ks.P2PInterfaces) == 0 {
		exit1(fmt.Errorf("No VPN interface found, verify VPN is connected"))
	}

	fmt.Printf("PEER IP address:   %s\n", killswitch.Yellow(ks.PeerIP))

	if *ip != "" {
		if ipv4 := net.ParseIP(*ip); ipv4.To4() == nil {
			exit1(fmt.Errorf("%s is not a valid IPv4 address, use (\"%s -h\") for help.\n", *ip, os.Args[0]))
		}
	}

	ks.CreatePF(*leak)

	if !*e {
		fmt.Printf("\n%s: %s\n", "To enable the kill switch run", killswitch.Green("sudo killswitch -e"))
		fmt.Printf("%s: %s\n", "To disable", killswitch.Yellow("sudo killswitch -d"))
	}

	if *p {
		fmt.Printf("PF rules to be loaded:\n")
		fmt.Println(ks.PFRules.String())
	}

	if err = ioutil.WriteFile("/tmp/killswitch.pf.conf",
		ks.PFRules.Bytes(),
		0644,
	); err != nil {
		exit1(err)
	}

	if *e {
		exec.Command("pfctl", "-e").CombinedOutput()
		_, err := exec.Command("pfctl",
			"-Fa",
			"-f",
			"/tmp/killswitch.pf.conf").CombinedOutput()
		if err != nil {
			exit1(fmt.Errorf(fmt.Sprintf("\n%s: %s\n%s",
				killswitch.Red("To enable use"),
				killswitch.Green("sudo killswitch -e"),
				err)),
			)
		}
		fmt.Printf("\n# %s\n", strings.Repeat("-", 62))
		fmt.Println("# Loading rules")
		fmt.Printf("# %s\n", strings.Repeat("-", 62))
		out, err := exec.Command("pfctl", "-sr").CombinedOutput()
		if err != nil {
			exit1(err)
		}
		fmt.Printf("%s\n", out)
		fmt.Println(killswitch.Green("killswitch enabled"))
	}
}
<|endoftext|>