<commit_before>package opencv

import (
	"bytes"
	"fmt"
	"gopkg.in/sensorbee/opencv.v0/bridge"
	"gopkg.in/sensorbee/sensorbee.v0/data"
	"image"
	"image/jpeg"
)

var (
	imagePath = data.MustCompilePath("image")
)

// TypeImageFormat is an ID of image format type.
type TypeImageFormat int

const (
	typeUnknownFormat TypeImageFormat = iota
	// TypeCVMAT is OpenCV cv::Mat_<cv::Vec3b> format
	TypeCVMAT
	// TypeCVMAT4b is OpenCV cv::Mat_<cv::Vec4b> format
	TypeCVMAT4b
	// TypeJPEG is JPEG format
	TypeJPEG
)

func (t TypeImageFormat) String() string {
	switch t {
	case TypeCVMAT:
		return "cvmat"
	case TypeCVMAT4b:
		return "cvmat4b"
	case TypeJPEG:
		return "jpeg"
	default:
		return "unknown"
	}
}

// GetTypeImageFormat returns image format type.
func GetTypeImageFormat(str string) TypeImageFormat {
	switch str {
	case "cvmat":
		return TypeCVMAT
	case "cvmat4b":
		return TypeCVMAT4b
	case "jpeg":
		return TypeJPEG
	default:
		return typeUnknownFormat
	}
}

// RawData is represented of `cv::Mat_<cv::Vec3b>` structure.
type RawData struct {
	Format TypeImageFormat
	Width  int
	Height int
	Data   []byte
}

// ToRawData converts MatVec3b to RawData.
func ToRawData(m bridge.MatVec3b) RawData {
	w, h, data := m.ToRawData()
	return RawData{
		Format: TypeCVMAT,
		Width:  w,
		Height: h,
		Data:   data,
	}
}

// ToMatVec3b converts RawData to MatVec3b. Returned MatVec3b is required to
// delete after using.
func (r *RawData) ToMatVec3b() (bridge.MatVec3b, error) {
	if r.Format != TypeCVMAT {
		return bridge.MatVec3b{}, fmt.Errorf("'%v' cannot convert to 'MatVec3b'",
			r.Format)
	}
	return bridge.ToMatVec3b(r.Width, r.Height, r.Data), nil
}

func toRawMap(m *bridge.MatVec3b) data.Map {
	r := ToRawData(*m)
	return data.Map{
		"format": data.String(r.Format.String()), // = cv::Mat_<cv::Vec3b> = "cvmat"
		"width":  data.Int(r.Width),
		"height": data.Int(r.Height),
		"image":  data.Blob(r.Data),
	}
}

// ConvertMapToRawData returns RawData from data.Map. This function is
// utility method for other plug-in.
func ConvertMapToRawData(dm data.Map) (RawData, error) {
	var width int64
	if w, err := dm.Get(widthPath); err != nil {
		return RawData{}, err
	} else if width, err = data.ToInt(w); err != nil {
		return RawData{}, err
	}

	var height int64
	if h, err := dm.Get(heightPath); err != nil {
		return RawData{}, err
	} else if height, err = data.ToInt(h); err != nil {
		return RawData{}, err
	}

	var img []byte
	if b, err := dm.Get(imagePath); err != nil {
		return RawData{}, err
	} else if img, err = data.ToBlob(b); err != nil {
		return RawData{}, err
	}

	var format TypeImageFormat
	if f, err := dm.Get(formatPath); err != nil {
		return RawData{}, err
	} else if fmtStr, err := data.AsString(f); err != nil {
		return RawData{}, err
	} else {
		format = GetTypeImageFormat(fmtStr)
		if format == typeUnknownFormat {
			return RawData{}, fmt.Errorf("'%v' is not supported", fmtStr)
		}
	}

	return RawData{
		Format: format,
		Width:  int(width),
		Height: int(height),
		Data:   img,
	}, nil
}

// ConvertToDataMap returns data.map. This function is utility method for
// other plug-in.
func (r *RawData) ConvertToDataMap() data.Map {
	return data.Map{
		"format": data.String(r.Format.String()),
		"width":  data.Int(r.Width),
		"height": data.Int(r.Height),
		"image":  data.Blob(r.Data),
	}
}

// ToJpegData convert JPGE format image bytes.
func (r *RawData) ToJpegData(quality int) ([]byte, error) {
	if r.Format == TypeJPEG {
		return r.Data, nil
	}
	// BGR to RGB
	rgba := image.NewRGBA(image.Rect(0, 0, r.Width, r.Height))
	if r.Format == TypeCVMAT {
		for i, j := 0, 0; i < len(rgba.Pix); i, j = i+4, j+3 {
			rgba.Pix[i+0] = r.Data[j+2]
			rgba.Pix[i+1] = r.Data[j+1]
			rgba.Pix[i+2] = r.Data[j+0]
			rgba.Pix[i+3] = 0xFF
		}
	} else if r.Format == TypeCVMAT4b {
		for i, j := 0, 0; i < len(rgba.Pix); i, j = i+4, j+3 {
			rgba.Pix[i+0] = r.Data[j+2]
			rgba.Pix[i+1] = r.Data[j+1]
			rgba.Pix[i+2] = r.Data[j+0]
			rgba.Pix[i+3] = r.Data[j+3]
		}
	} else {
		return []byte{}, fmt.Errorf("'%v' cannot convert to JPEG", r.Format)
	}
	w := bytes.NewBuffer([]byte{})
	err := jpeg.Encode(w, rgba, &jpeg.Options{Quality: quality})
	return w.Bytes(), err
}
<commit_msg>Factored out `ToImage` from `ToJpegData`<commit_after>package opencv

import (
	"bytes"
	"fmt"
	"gopkg.in/sensorbee/opencv.v0/bridge"
	"gopkg.in/sensorbee/sensorbee.v0/data"
	"image"
	"image/jpeg"
)

var (
	imagePath = data.MustCompilePath("image")
)

// TypeImageFormat is an ID of image format type.
type TypeImageFormat int

const (
	typeUnknownFormat TypeImageFormat = iota
	// TypeCVMAT is OpenCV cv::Mat_<cv::Vec3b> format
	TypeCVMAT
	// TypeCVMAT4b is OpenCV cv::Mat_<cv::Vec4b> format
	TypeCVMAT4b
	// TypeJPEG is JPEG format
	TypeJPEG
)

func (t TypeImageFormat) String() string {
	switch t {
	case TypeCVMAT:
		return "cvmat"
	case TypeCVMAT4b:
		return "cvmat4b"
	case TypeJPEG:
		return "jpeg"
	default:
		return "unknown"
	}
}

// GetTypeImageFormat returns image format type.
func GetTypeImageFormat(str string) TypeImageFormat {
	switch str {
	case "cvmat":
		return TypeCVMAT
	case "cvmat4b":
		return TypeCVMAT4b
	case "jpeg":
		return TypeJPEG
	default:
		return typeUnknownFormat
	}
}

// RawData is represented of `cv::Mat_<cv::Vec3b>` structure.
type RawData struct {
	Format TypeImageFormat
	Width  int
	Height int
	Data   []byte
}

// ToRawData converts MatVec3b to RawData.
func ToRawData(m bridge.MatVec3b) RawData {
	w, h, data := m.ToRawData()
	return RawData{
		Format: TypeCVMAT,
		Width:  w,
		Height: h,
		Data:   data,
	}
}

// ToMatVec3b converts RawData to MatVec3b. Returned MatVec3b is required to
// delete after using.
func (r *RawData) ToMatVec3b() (bridge.MatVec3b, error) {
	if r.Format != TypeCVMAT {
		return bridge.MatVec3b{}, fmt.Errorf("'%v' cannot convert to 'MatVec3b'",
			r.Format)
	}
	return bridge.ToMatVec3b(r.Width, r.Height, r.Data), nil
}

func toRawMap(m *bridge.MatVec3b) data.Map {
	r := ToRawData(*m)
	return data.Map{
		"format": data.String(r.Format.String()), // = cv::Mat_<cv::Vec3b> = "cvmat"
		"width":  data.Int(r.Width),
		"height": data.Int(r.Height),
		"image":  data.Blob(r.Data),
	}
}

// ConvertMapToRawData returns RawData from data.Map. This function is
// utility method for other plug-in.
func ConvertMapToRawData(dm data.Map) (RawData, error) {
	var width int64
	if w, err := dm.Get(widthPath); err != nil {
		return RawData{}, err
	} else if width, err = data.ToInt(w); err != nil {
		return RawData{}, err
	}

	var height int64
	if h, err := dm.Get(heightPath); err != nil {
		return RawData{}, err
	} else if height, err = data.ToInt(h); err != nil {
		return RawData{}, err
	}

	var img []byte
	if b, err := dm.Get(imagePath); err != nil {
		return RawData{}, err
	} else if img, err = data.ToBlob(b); err != nil {
		return RawData{}, err
	}

	var format TypeImageFormat
	if f, err := dm.Get(formatPath); err != nil {
		return RawData{}, err
	} else if fmtStr, err := data.AsString(f); err != nil {
		return RawData{}, err
	} else {
		format = GetTypeImageFormat(fmtStr)
		if format == typeUnknownFormat {
			return RawData{}, fmt.Errorf("'%v' is not supported", fmtStr)
		}
	}

	return RawData{
		Format: format,
		Width:  int(width),
		Height: int(height),
		Data:   img,
	}, nil
}

// ConvertToDataMap returns data.map. This function is utility method for
// other plug-in.
func (r *RawData) ConvertToDataMap() data.Map {
	return data.Map{
		"format": data.String(r.Format.String()),
		"width":  data.Int(r.Width),
		"height": data.Int(r.Height),
		"image":  data.Blob(r.Data),
	}
}

// ToImage converts to image.Image
func (r *RawData) ToImage() (image.Image, error) {
	// BGR to RGB
	rgba := image.NewRGBA(image.Rect(0, 0, r.Width, r.Height))
	if r.Format == TypeCVMAT {
		for i, j := 0, 0; i < len(rgba.Pix); i, j = i+4, j+3 {
			rgba.Pix[i+0] = r.Data[j+2]
			rgba.Pix[i+1] = r.Data[j+1]
			rgba.Pix[i+2] = r.Data[j+0]
			rgba.Pix[i+3] = 0xFF
		}
	} else if r.Format == TypeCVMAT4b {
		for i, j := 0, 0; i < len(rgba.Pix); i, j = i+4, j+3 {
			rgba.Pix[i+0] = r.Data[j+2]
			rgba.Pix[i+1] = r.Data[j+1]
			rgba.Pix[i+2] = r.Data[j+0]
			rgba.Pix[i+3] = r.Data[j+3]
		}
	} else {
		return nil, fmt.Errorf("'%v' cannot convert to image", r.Format)
	}
	return rgba, nil
}

// ToJpegData convert JPGE format image bytes.
func (r *RawData) ToJpegData(quality int) ([]byte, error) {
	if r.Format == TypeJPEG {
		return r.Data, nil
	}
	if rgba, err := r.ToImage(); err != nil {
		return []byte{}, err
	} else {
		w := bytes.NewBuffer([]byte{})
		err := jpeg.Encode(w, rgba, &jpeg.Options{Quality: quality})
		return w.Bytes(), err
	}
}
<|endoftext|>


<commit_before>package agouti

import (
	"fmt"
	"path/filepath"

	"github.com/sclevine/agouti/api"
	"github.com/sclevine/agouti/internal/element"
	"github.com/sclevine/agouti/internal/target"
)

type actionsFunc func(element.Element) error

func (s *Selection) forEachElement(actions actionsFunc) error {
	elements, err := s.elements.GetAtLeastOne()
	if err != nil {
		return fmt.Errorf("failed to select elements from %s: %s", s, err)
	}

	for _, element := range elements {
		if err := actions(element); err != nil {
			return err
		}
	}
	return nil
}

// Click clicks on all of the elements that the selection refers to.
func (s *Selection) Click() error {
	return s.forEachElement(func(selectedElement element.Element) error {
		if err := selectedElement.Click(); err != nil {
			return fmt.Errorf("failed to click on %s: %s", s, err)
		}
		return nil
	})
}

// DoubleClick double-clicks on all of the elements that the selection refers to.
func (s *Selection) DoubleClick() error {
	return s.forEachElement(func(selectedElement element.Element) error {
		if err := s.session.MoveTo(selectedElement.(*api.Element), nil); err != nil {
			return fmt.Errorf("failed to move mouse to %s: %s", s, err)
		}
		if err := s.session.DoubleClick(); err != nil {
			return fmt.Errorf("failed to double-click on %s: %s", s, err)
		}
		return nil
	})
}

// Fill fills all of the fields the selection refers to with the provided text.
func (s *Selection) Fill(text string) error {
	return s.forEachElement(func(selectedElement element.Element) error {
		if err := selectedElement.Clear(); err != nil {
			return fmt.Errorf("failed to clear %s: %s", s, err)
		}
		if err := selectedElement.Value(text); err != nil {
			return fmt.Errorf("failed to enter text into %s: %s", s, err)
		}
		return nil
	})
}

// UploadFile uploads the provided file to all selected <input type="file" />.
// The provided filename may be a relative or absolute path.
// Returns an error if elements of any other type are in the selection.
func (s *Selection) UploadFile(filename string) error {
	absFilePath, err := filepath.Abs(filename)
	if err != nil {
		return fmt.Errorf("failed to find absolute path for filename: %s", err)
	}
	return s.forEachElement(func(selectedElement element.Element) error {
		tagName, err := selectedElement.GetName()
		if err != nil {
			return fmt.Errorf("failed to determine tag name of %s: %s", s, err)
		}
		if tagName != "input" {
			return fmt.Errorf("element for %s is not an input element", s)
		}
		inputType, err := selectedElement.GetAttribute("type")
		if err != nil {
			return fmt.Errorf("failed to determine type attribute of %s: %s", s, err)
		}
		if inputType != "file" {
			return fmt.Errorf("element for %s is not a file uploader", s)
		}
		if err := selectedElement.Value(absFilePath); err != nil {
			return fmt.Errorf("failed to enter text into %s: %s", s, err)
		}
		return nil
	})
}

// Check checks all of the unchecked checkboxes that the selection refers to.
func (s *Selection) Check() error {
	return s.setChecked(true)
}

// Uncheck unchecks all of the checked checkboxes that the selection refers to.
func (s *Selection) Uncheck() error {
	return s.setChecked(false)
}

func (s *Selection) setChecked(checked bool) error {
	return s.forEachElement(func(selectedElement element.Element) error {
		elementType, err := selectedElement.GetAttribute("type")
		if err != nil {
			return fmt.Errorf("failed to retrieve type attribute of %s: %s", s, err)
		}

		if elementType != "checkbox" {
			return fmt.Errorf("%s does not refer to a checkbox", s)
		}

		elementChecked, err := selectedElement.IsSelected()
		if err != nil {
			return fmt.Errorf("failed to retrieve state of %s: %s", s, err)
		}

		if elementChecked != checked {
			if err := selectedElement.Click(); err != nil {
				return fmt.Errorf("failed to click on %s: %s", s, err)
			}
		}
		return nil
	})
}

// Select may be called on a selection of any number of <select> elements to select
// any <option> elements under those <select> elements that match the provided text.
func (s *Selection) Select(text string) error {
	return s.forEachElement(func(selectedElement element.Element) error {
		optionXPath := fmt.Sprintf(`./option[normalize-space()="%s"]`, text)
		optionToSelect := target.Selector{Type: target.XPath, Value: optionXPath}
		options, err := selectedElement.GetElements(optionToSelect.API())
		if err != nil {
			return fmt.Errorf("failed to select specified option for %s: %s", s, err)
		}

		if len(options) == 0 {
			return fmt.Errorf(`no options with text "%s" found for %s`, text, s)
		}

		for _, option := range options {
			if err := option.Click(); err != nil {
				return fmt.Errorf(`failed to click on option with text "%s" for %s: %s`, text, s, err)
			}
		}
		return nil
	})
}

// Submit submits all selected forms. The selection may refer to a form itself
// or any input element contained within a form.
func (s *Selection) Submit() error {
	return s.forEachElement(func(selectedElement element.Element) error {
		if err := selectedElement.Submit(); err != nil {
			return fmt.Errorf("failed to submit %s: %s", s, err)
		}
		return nil
	})
}

// Tap performs the provided Tap event on each element in the selection.
func (s *Selection) Tap(event Tap) error {
	var touchFunc func(*api.Element) error
	switch event {
	case SingleTap:
		touchFunc = s.session.TouchClick
	case DoubleTap:
		touchFunc = s.session.TouchDoubleClick
	case LongTap:
		touchFunc = s.session.TouchLongClick
	default:
		return fmt.Errorf("failed to %s on %s: invalid tap event", event, s)
	}

	return s.forEachElement(func(selectedElement element.Element) error {
		if err := touchFunc(selectedElement.(*api.Element)); err != nil {
			return fmt.Errorf("failed to %s on %s: %s", event, s, err)
		}
		return nil
	})
}

// Touch performs the provided Touch event at the location of each element in the
// selection.
func (s *Selection) Touch(event Touch) error {
	var touchFunc func(x, y int) error
	switch event {
	case HoldFinger:
		touchFunc = s.session.TouchDown
	case ReleaseFinger:
		touchFunc = s.session.TouchUp
	case MoveFinger:
		touchFunc = s.session.TouchMove
	default:
		return fmt.Errorf("failed to %s on %s: invalid touch event", event, s)
	}

	return s.forEachElement(func(selectedElement element.Element) error {
		x, y, err := selectedElement.GetLocation()
		if err != nil {
			return fmt.Errorf("failed to retrieve location of %s: %s", s, err)
		}
		if err := touchFunc(x, y); err != nil {
			return fmt.Errorf("failed to flick finger on %s: %s", s, err)
		}
		return nil
	})
}

// FlickFinger performs a flick touch action by the provided offset and at the
// provided speed on exactly one element.
func (s *Selection) FlickFinger(xOffset, yOffset int, speed uint) error {
	selectedElement, err := s.elements.GetExactlyOne()
	if err != nil {
		return fmt.Errorf("failed to select element from %s: %s", s, err)
	}

	if err := s.session.TouchFlick(selectedElement.(*api.Element), api.XYOffset{X: xOffset, Y: yOffset}, api.ScalarSpeed(speed)); err != nil {
		return fmt.Errorf("failed to flick finger on %s: %s", s, err)
	}
	return nil
}

// ScrollFinger performs a scroll touch action by the provided offset on exactly
// one element.
func (s *Selection) ScrollFinger(xOffset, yOffset int) error {
	selectedElement, err := s.elements.GetExactlyOne()
	if err != nil {
		return fmt.Errorf("failed to select element from %s: %s", s, err)
	}

	if err := s.session.TouchScroll(selectedElement.(*api.Element), api.XYOffset{X: xOffset, Y: yOffset}); err != nil {
		return fmt.Errorf("failed to scroll finger on %s: %s", s, err)
	}
	return nil
}
<commit_msg>add support for SendKeys<commit_after>package agouti

import (
	"fmt"
	"path/filepath"

	"github.com/sclevine/agouti/api"
	"github.com/sclevine/agouti/internal/element"
	"github.com/sclevine/agouti/internal/target"
)

type actionsFunc func(element.Element) error

func (s *Selection) forEachElement(actions actionsFunc) error {
	elements, err := s.elements.GetAtLeastOne()
	if err != nil {
		return fmt.Errorf("failed to select elements from %s: %s", s, err)
	}

	for _, element := range elements {
		if err := actions(element); err != nil {
			return err
		}
	}
	return nil
}

// Click clicks on all of the elements that the selection refers to.
func (s *Selection) Click() error {
	return s.forEachElement(func(selectedElement element.Element) error {
		if err := selectedElement.Click(); err != nil {
			return fmt.Errorf("failed to click on %s: %s", s, err)
		}
		return nil
	})
}

// DoubleClick double-clicks on all of the elements that the selection refers to.
func (s *Selection) DoubleClick() error {
	return s.forEachElement(func(selectedElement element.Element) error {
		if err := s.session.MoveTo(selectedElement.(*api.Element), nil); err != nil {
			return fmt.Errorf("failed to move mouse to %s: %s", s, err)
		}
		if err := s.session.DoubleClick(); err != nil {
			return fmt.Errorf("failed to double-click on %s: %s", s, err)
		}
		return nil
	})
}

// Fill fills all of the fields the selection refers to with the provided text.
func (s *Selection) Fill(text string) error {
	return s.forEachElement(func(selectedElement element.Element) error {
		if err := selectedElement.Clear(); err != nil {
			return fmt.Errorf("failed to clear %s: %s", s, err)
		}
		if err := selectedElement.Value(text); err != nil {
			return fmt.Errorf("failed to enter text into %s: %s", s, err)
		}
		return nil
	})
}

// UploadFile uploads the provided file to all selected <input type="file" />.
// The provided filename may be a relative or absolute path.
// Returns an error if elements of any other type are in the selection.
func (s *Selection) UploadFile(filename string) error {
	absFilePath, err := filepath.Abs(filename)
	if err != nil {
		return fmt.Errorf("failed to find absolute path for filename: %s", err)
	}
	return s.forEachElement(func(selectedElement element.Element) error {
		tagName, err := selectedElement.GetName()
		if err != nil {
			return fmt.Errorf("failed to determine tag name of %s: %s", s, err)
		}
		if tagName != "input" {
			return fmt.Errorf("element for %s is not an input element", s)
		}
		inputType, err := selectedElement.GetAttribute("type")
		if err != nil {
			return fmt.Errorf("failed to determine type attribute of %s: %s", s, err)
		}
		if inputType != "file" {
			return fmt.Errorf("element for %s is not a file uploader", s)
		}
		if err := selectedElement.Value(absFilePath); err != nil {
			return fmt.Errorf("failed to enter text into %s: %s", s, err)
		}
		return nil
	})
}

// Check checks all of the unchecked checkboxes that the selection refers to.
func (s *Selection) Check() error {
	return s.setChecked(true)
}

// Uncheck unchecks all of the checked checkboxes that the selection refers to.
func (s *Selection) Uncheck() error {
	return s.setChecked(false)
}

func (s *Selection) setChecked(checked bool) error {
	return s.forEachElement(func(selectedElement element.Element) error {
		elementType, err := selectedElement.GetAttribute("type")
		if err != nil {
			return fmt.Errorf("failed to retrieve type attribute of %s: %s", s, err)
		}

		if elementType != "checkbox" {
			return fmt.Errorf("%s does not refer to a checkbox", s)
		}

		elementChecked, err := selectedElement.IsSelected()
		if err != nil {
			return fmt.Errorf("failed to retrieve state of %s: %s", s, err)
		}

		if elementChecked != checked {
			if err := selectedElement.Click(); err != nil {
				return fmt.Errorf("failed to click on %s: %s", s, err)
			}
		}
		return nil
	})
}

// Select may be called on a selection of any number of <select> elements to select
// any <option> elements under those <select> elements that match the provided text.
func (s *Selection) Select(text string) error {
	return s.forEachElement(func(selectedElement element.Element) error {
		optionXPath := fmt.Sprintf(`./option[normalize-space()="%s"]`, text)
		optionToSelect := target.Selector{Type: target.XPath, Value: optionXPath}
		options, err := selectedElement.GetElements(optionToSelect.API())
		if err != nil {
			return fmt.Errorf("failed to select specified option for %s: %s", s, err)
		}

		if len(options) == 0 {
			return fmt.Errorf(`no options with text "%s" found for %s`, text, s)
		}

		for _, option := range options {
			if err := option.Click(); err != nil {
				return fmt.Errorf(`failed to click on option with text "%s" for %s: %s`, text, s, err)
			}
		}
		return nil
	})
}

// Submit submits all selected forms. The selection may refer to a form itself
// or any input element contained within a form.
func (s *Selection) Submit() error {
	return s.forEachElement(func(selectedElement element.Element) error {
		if err := selectedElement.Submit(); err != nil {
			return fmt.Errorf("failed to submit %s: %s", s, err)
		}
		return nil
	})
}

// Tap performs the provided Tap event on each element in the selection.
func (s *Selection) Tap(event Tap) error {
	var touchFunc func(*api.Element) error
	switch event {
	case SingleTap:
		touchFunc = s.session.TouchClick
	case DoubleTap:
		touchFunc = s.session.TouchDoubleClick
	case LongTap:
		touchFunc = s.session.TouchLongClick
	default:
		return fmt.Errorf("failed to %s on %s: invalid tap event", event, s)
	}

	return s.forEachElement(func(selectedElement element.Element) error {
		if err := touchFunc(selectedElement.(*api.Element)); err != nil {
			return fmt.Errorf("failed to %s on %s: %s", event, s, err)
		}
		return nil
	})
}

// Touch performs the provided Touch event at the location of each element in the
// selection.
func (s *Selection) Touch(event Touch) error {
	var touchFunc func(x, y int) error
	switch event {
	case HoldFinger:
		touchFunc = s.session.TouchDown
	case ReleaseFinger:
		touchFunc = s.session.TouchUp
	case MoveFinger:
		touchFunc = s.session.TouchMove
	default:
		return fmt.Errorf("failed to %s on %s: invalid touch event", event, s)
	}

	return s.forEachElement(func(selectedElement element.Element) error {
		x, y, err := selectedElement.GetLocation()
		if err != nil {
			return fmt.Errorf("failed to retrieve location of %s: %s", s, err)
		}
		if err := touchFunc(x, y); err != nil {
			return fmt.Errorf("failed to flick finger on %s: %s", s, err)
		}
		return nil
	})
}

// FlickFinger performs a flick touch action by the provided offset and at the
// provided speed on exactly one element.
func (s *Selection) FlickFinger(xOffset, yOffset int, speed uint) error {
	selectedElement, err := s.elements.GetExactlyOne()
	if err != nil {
		return fmt.Errorf("failed to select element from %s: %s", s, err)
	}

	if err := s.session.TouchFlick(selectedElement.(*api.Element), api.XYOffset{X: xOffset, Y: yOffset}, api.ScalarSpeed(speed)); err != nil {
		return fmt.Errorf("failed to flick finger on %s: %s", s, err)
	}
	return nil
}

// ScrollFinger performs a scroll touch action by the provided offset on exactly
// one element.
func (s *Selection) ScrollFinger(xOffset, yOffset int) error {
	selectedElement, err := s.elements.GetExactlyOne()
	if err != nil {
		return fmt.Errorf("failed to select element from %s: %s", s, err)
	}

	if err := s.session.TouchScroll(selectedElement.(*api.Element), api.XYOffset{X: xOffset, Y: yOffset}); err != nil {
		return fmt.Errorf("failed to scroll finger on %s: %s", s, err)
	}
	return nil
}

func (s *Selection) SendKeys(key string) error {
	return s.forEachElement(func(selectedElement element.Element) error {
		if err := selectedElement.Value(key); err != nil {
			return fmt.Errorf("failed to send key %s on %s: %s", key, s, err)
		}
		return nil
	})
}
<|endoftext|>


<commit_before>// (c) Copyright IBM Corp. 2021
// (c) Copyright Instana Inc. 2016

package instana

import (
	"context"
	"fmt"
	"sync"
	"time"
)

// A SpanRecorder handles all of the `RawSpan` data generated via an
// associated `Tracer` (see `NewStandardTracer`) instance. It also names
// the containing process and provides access to a straightforward tag map.
type SpanRecorder interface {
	// Implementations must determine whether and where to store `span`.
	RecordSpan(span *spanS)
	// Flush forces sending any buffered finished spans
	Flush(context.Context) error
}

// Recorder accepts spans, processes and queues them
// for delivery to the backend.
type Recorder struct {
	sync.RWMutex
	spans    []Span
	testMode bool
}

// NewRecorder initializes a new span recorder
func NewRecorder() *Recorder {
	r := &Recorder{}

	ticker := time.NewTicker(1 * time.Second)
	go func() {
		for range ticker.C {
			if sensor.Agent().Ready() {
				go r.Flush(context.Background())
			}
		}
	}()

	return r
}

// NewTestRecorder initializes a new span recorder that keeps all collected
// until they are requested. This recorder does not send spans to the agent (used for testing)
func NewTestRecorder() *Recorder {
	return &Recorder{
		testMode: true,
	}
}

// RecordSpan accepts spans to be recorded and and added to the span queue
// for eventual reporting to the host agent.
func (r *Recorder) RecordSpan(span *spanS) {
	// If we're not announced and not in test mode then just
	// return
	if !r.testMode && !sensor.Agent().Ready() {
		return
	}

	r.Lock()
	defer r.Unlock()

	if len(r.spans) == sensor.options.MaxBufferedSpans {
		r.spans = r.spans[1:]
	}

	r.spans = append(r.spans, newSpan(span))

	if r.testMode || !sensor.Agent().Ready() {
		return
	}

	if len(r.spans) >= sensor.options.ForceTransmissionStartingAt {
		sensor.logger.Debug("forcing ", len(r.spans), "span(s) to the agent")
		go r.Flush(context.Background())
	}
}

// QueuedSpansCount returns the number of queued spans
//   Used only in tests currently.
func (r *Recorder) QueuedSpansCount() int {
	r.RLock()
	defer r.RUnlock()
	return len(r.spans)
}

// GetQueuedSpans returns a copy of the queued spans and clears the queue.
func (r *Recorder) GetQueuedSpans() []Span {
	r.Lock()
	defer r.Unlock()

	// Copy queued spans
	queuedSpans := make([]Span, len(r.spans))
	copy(queuedSpans, r.spans)

	// and clear out the source
	r.clearQueuedSpans()
	return queuedSpans
}

// Flush sends queued spans to the agent
func (r *Recorder) Flush(ctx context.Context) error {
	spansToSend := r.GetQueuedSpans()
	if len(spansToSend) == 0 {
		return nil
	}

	if err := sensor.Agent().SendSpans(spansToSend); err != nil {
		r.spans = append(r.spans, spansToSend...)
		return fmt.Errorf("failed to send collected spans to the agent: %s", err)
	}

	return nil
}

// clearQueuedSpans brings the span queue to empty/0/nada
//   This function doesn't take the Lock so make sure to have
//   the write lock before calling.
//   This is meant to be called from GetQueuedSpans which handles
//   locking.
func (r *Recorder) clearQueuedSpans() {
	r.spans = r.spans[:0]
}
<commit_msg>Acquire the recorder lock before re-queueing spans on error<commit_after>// (c) Copyright IBM Corp. 2021
// (c) Copyright Instana Inc. 2016

package instana

import (
	"context"
	"fmt"
	"sync"
	"time"
)

// A SpanRecorder handles all of the `RawSpan` data generated via an
// associated `Tracer` (see `NewStandardTracer`) instance. It also names
// the containing process and provides access to a straightforward tag map.
type SpanRecorder interface {
	// Implementations must determine whether and where to store `span`.
	RecordSpan(span *spanS)
	// Flush forces sending any buffered finished spans
	Flush(context.Context) error
}

// Recorder accepts spans, processes and queues them
// for delivery to the backend.
type Recorder struct {
	sync.RWMutex
	spans    []Span
	testMode bool
}

// NewRecorder initializes a new span recorder
func NewRecorder() *Recorder {
	r := &Recorder{}

	ticker := time.NewTicker(1 * time.Second)
	go func() {
		for range ticker.C {
			if sensor.Agent().Ready() {
				go r.Flush(context.Background())
			}
		}
	}()

	return r
}

// NewTestRecorder initializes a new span recorder that keeps all collected
// until they are requested. This recorder does not send spans to the agent (used for testing)
func NewTestRecorder() *Recorder {
	return &Recorder{
		testMode: true,
	}
}

// RecordSpan accepts spans to be recorded and and added to the span queue
// for eventual reporting to the host agent.
func (r *Recorder) RecordSpan(span *spanS) {
	// If we're not announced and not in test mode then just
	// return
	if !r.testMode && !sensor.Agent().Ready() {
		return
	}

	r.Lock()
	defer r.Unlock()

	if len(r.spans) == sensor.options.MaxBufferedSpans {
		r.spans = r.spans[1:]
	}

	r.spans = append(r.spans, newSpan(span))

	if r.testMode || !sensor.Agent().Ready() {
		return
	}

	if len(r.spans) >= sensor.options.ForceTransmissionStartingAt {
		sensor.logger.Debug("forcing ", len(r.spans), "span(s) to the agent")
		go r.Flush(context.Background())
	}
}

// QueuedSpansCount returns the number of queued spans
//   Used only in tests currently.
func (r *Recorder) QueuedSpansCount() int {
	r.RLock()
	defer r.RUnlock()
	return len(r.spans)
}

// GetQueuedSpans returns a copy of the queued spans and clears the queue.
func (r *Recorder) GetQueuedSpans() []Span {
	r.Lock()
	defer r.Unlock()

	// Copy queued spans
	queuedSpans := make([]Span, len(r.spans))
	copy(queuedSpans, r.spans)

	// and clear out the source
	r.clearQueuedSpans()
	return queuedSpans
}

// Flush sends queued spans to the agent
func (r *Recorder) Flush(ctx context.Context) error {
	spansToSend := r.GetQueuedSpans()
	if len(spansToSend) == 0 {
		return nil
	}

	if err := sensor.Agent().SendSpans(spansToSend); err != nil {
		r.Lock()
		defer r.Unlock()

		r.spans = append(r.spans, spansToSend...)

		return fmt.Errorf("failed to send collected spans to the agent: %s", err)
	}

	return nil
}

// clearQueuedSpans brings the span queue to empty/0/nada
//   This function doesn't take the Lock so make sure to have
//   the write lock before calling.
//   This is meant to be called from GetQueuedSpans which handles
//   locking.
func (r *Recorder) clearQueuedSpans() {
	r.spans = r.spans[:0]
}
<|endoftext|>


<commit_before>// Package plate provides a Recorder for testing Go's HTML templates.
package plate

import (
	"bytes"
	"io"
	"sync"
)

// Execution represents one occurence of template being executed.
// It provides access to the output produced,
// the context that was passed to the template
// and the error returned from the Execute*() function, if any.
type Execution struct {
	Output  []byte
	Context interface{}

	Error error
}

// Recorder wraps an Executor and
// records results of executions for later checks.
type Recorder struct {
	// The original template to wrap.
	Template Executor

	// Go's templates are already safe to be used in parallel,
	// this mutex only protects our own fields, like `execs`.
	mu sync.RWMutex
	// Stores exucution info
	execs []Execution
}

func (r *Recorder) save(exec Execution) {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.execs = append(r.execs, exec)
}

// Execute executes the wrapped template,
// saving information into the Recorder.
func (r *Recorder) Execute(wr io.Writer, data interface{}) error {
	exec := Execution{Context: data}

	// Substitute the reader
	buf := &bytes.Buffer{}
	writer := io.MultiWriter(buf, wr)

	// Execute and fill out the results
	err := r.Template.Execute(writer, data)
	exec.Output = buf.Bytes()
	exec.Error = err

	r.save(exec)
	return err
}

// ExecuteTemplate is like Execute, but for named teplates.
func (r *Recorder) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
	exec := Execution{Context: data}

	// Substitute the reader
	buf := &bytes.Buffer{}
	writer := io.MultiWriter(buf, wr)

	// Execute and fill out the results
	err := r.Template.ExecuteTemplate(writer, name, data)
	exec.Output = buf.Bytes()
	exec.Error = err

	r.save(exec)
	return err
}

// Executions returns all executions that have occured
// since the construction of a Recorder (or since Reset()).
func (r *Recorder) Executions() []Execution {
	tmpExecs := make([]Execution, len(r.execs))
	// We do a copy, because callee may mess around with internal []Execution
	// and we do not want this.
	r.mu.RLock()
	defer r.mu.RUnlock()
	copy(tmpExecs, r.execs)
	return tmpExecs
}

// LastExecution returns the information of the latest execution.
// It panics if no executions have occured yet.
func (r *Recorder) LastExecution() Execution {
	if len(r.execs) < 1 {
		panic("No executions are available yet.")
	}
	r.mu.RLock()
	defer r.mu.RUnlock()
	return r.execs[len(r.execs)-1]
}

// TimesExecuted returns the count of times
// template has been executed
// since construction or calling Reset().
func (r *Recorder) TimesExecuted() int {
	return len(r.execs)
}

// FailedExecutions returns all executions that have Error != nil
func (r *Recorder) FailedExecutions() []Execution {
	failedExecs := make([]Execution, 0)
	r.mu.RLock()
	defer r.mu.RUnlock()
	for _, exec := range r.execs {
		if exec.Error != nil {
			failedExecs = append(failedExecs, exec)
		}
	}

	return failedExecs
}

// Reset clears all executions. Recorder is thus restored to its initial state.
func (r *Recorder) Reset() {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.execs = make([]Execution, 0)
}

// Ensure interface compliance
var _ Executor = &Recorder{}
<commit_msg>A trivial constructor<commit_after>// Package plate provides a Recorder for testing Go's HTML templates.
package plate

import (
	"bytes"
	"io"
	"sync"
)

// Execution represents one occurence of template being executed.
// It provides access to the output produced,
// the context that was passed to the template
// and the error returned from the Execute*() function, if any.
type Execution struct {
	Output  []byte
	Context interface{}

	Error error
}

// Recorder wraps an Executor and
// records results of executions for later checks.
type Recorder struct {
	// The original template to wrap.
	Template Executor

	// Go's templates are already safe to be used in parallel,
	// this mutex only protects our own fields, like `execs`.
	mu sync.RWMutex
	// Stores exucution info
	execs []Execution
}

func New(tmpl Executor) {
	return Recorder{Template: tmpl}
}

func (r *Recorder) save(exec Execution) {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.execs = append(r.execs, exec)
}

// Execute executes the wrapped template,
// saving information into the Recorder.
func (r *Recorder) Execute(wr io.Writer, data interface{}) error {
	exec := Execution{Context: data}

	// Substitute the reader
	buf := &bytes.Buffer{}
	writer := io.MultiWriter(buf, wr)

	// Execute and fill out the results
	err := r.Template.Execute(writer, data)
	exec.Output = buf.Bytes()
	exec.Error = err

	r.save(exec)
	return err
}

// ExecuteTemplate is like Execute, but for named teplates.
func (r *Recorder) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
	exec := Execution{Context: data}

	// Substitute the reader
	buf := &bytes.Buffer{}
	writer := io.MultiWriter(buf, wr)

	// Execute and fill out the results
	err := r.Template.ExecuteTemplate(writer, name, data)
	exec.Output = buf.Bytes()
	exec.Error = err

	r.save(exec)
	return err
}

// Executions returns all executions that have occured
// since the construction of a Recorder (or since Reset()).
func (r *Recorder) Executions() []Execution {
	tmpExecs := make([]Execution, len(r.execs))
	// We do a copy, because callee may mess around with internal []Execution
	// and we do not want this.
	r.mu.RLock()
	defer r.mu.RUnlock()
	copy(tmpExecs, r.execs)
	return tmpExecs
}

// LastExecution returns the information of the latest execution.
// It panics if no executions have occured yet.
func (r *Recorder) LastExecution() Execution {
	if len(r.execs) < 1 {
		panic("No executions are available yet.")
	}
	r.mu.RLock()
	defer r.mu.RUnlock()
	return r.execs[len(r.execs)-1]
}

// TimesExecuted returns the count of times
// template has been executed
// since construction or calling Reset().
func (r *Recorder) TimesExecuted() int {
	return len(r.execs)
}

// FailedExecutions returns all executions that have Error != nil
func (r *Recorder) FailedExecutions() []Execution {
	failedExecs := make([]Execution, 0)
	r.mu.RLock()
	defer r.mu.RUnlock()
	for _, exec := range r.execs {
		if exec.Error != nil {
			failedExecs = append(failedExecs, exec)
		}
	}

	return failedExecs
}

// Reset clears all executions. Recorder is thus restored to its initial state.
func (r *Recorder) Reset() {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.execs = make([]Execution, 0)
}

// Ensure interface compliance
var _ Executor = &Recorder{}
<|endoftext|>


<commit_before>package water

import (
	"fmt"
	"net/http"
	"runtime"
)

func Recovery() HandlerFunc {
	return func(ctx *Context) {
		defer func() {
			if err := recover(); err != nil {
				content := fmt.Sprintf("HandlerFunc crashed with error: %v", err)
				for skip := 1; ; skip += 1 {
					//当前goroutine的栈上的函数调用信息，主要有当前的PC值和被调用的文件及其行号.
					//skip==0表示当前栈,这里是指Recovery().
					_, file, line, ok := runtime.Caller(skip)
					if !ok {
						break
					} else {
						content += "\n"
					}
					content += fmt.Sprintf("%v %v", file, line)
				}

				if !ctx.written {
					ctx.WriteHeader(http.StatusInternalServerError)
				}

				ctx.router.logger.Printf("panic : %v\n", content)

				if Status != Stable {
					ctx.WriteString(content)
				}
			} else {
				if !ctx.written {
					ctx.WriteHeader(http.StatusOK)
				}
			}
		}()

		ctx.Next()
	}
}
<commit_msg>+ panic's time<commit_after>package water

import (
	"fmt"
	"net/http"
	"runtime"
	"time"
)

func Recovery() HandlerFunc {
	return func(ctx *Context) {
		defer func() {
			if err := recover(); err != nil {
				content := fmt.Sprintf("HandlerFunc crashed with error: %v", err)
				for skip := 1; ; skip += 1 {
					//当前goroutine的栈上的函数调用信息，主要有当前的PC值和被调用的文件及其行号.
					//skip==0表示当前栈,这里是指Recovery().
					_, file, line, ok := runtime.Caller(skip)
					if !ok {
						break
					} else {
						content += "\n"
					}
					content += fmt.Sprintf("%v %v", file, line)
				}

				if !ctx.written {
					ctx.WriteHeader(http.StatusInternalServerError)
				}

				ctx.router.logger.Printf("panic %s : %s\n", time.Now().Format(LogTimeFormat), content)

				if Status != Stable {
					ctx.WriteString(content)
				}
			} else {
				if !ctx.written {
					ctx.WriteHeader(http.StatusOK)
				}
			}
		}()

		ctx.Next()
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2014-2017 Bitmark Inc.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package keypair

import (
	"crypto/rand"
	"encoding/hex"
	"github.com/bitmark-inc/bitmarkd/account"
	"github.com/bitmark-inc/bitmarkd/fault"
	"github.com/bitmark-inc/bitmarkd/util"
	"golang.org/x/crypto/sha3"
)

var (
	ErrKeyLength        = fault.InvalidError("key length is invalid")
	ErrNotFoundIdentity = fault.NotFoundError("identity name not found")
)

type KeyPair struct {
	Seed       string
	PublicKey  []byte
	PrivateKey []byte
}

type RawKeyPair struct {
	Seed       string `json:"seed"`
	PublicKey  string `json:"public_key"`
	PrivateKey string `json:"private_key"`
}

func MakeRawKeyPair(test bool) (*RawKeyPair, *KeyPair, error) {

	// generate new seed
	seedCore := make([]byte, 32)
	n, err := rand.Read(seedCore)
	if nil != err {
		return nil, nil, err
	}
	if 32 != n {
		panic("too few random bytes")
	}
	net := 0x00
	if test {
		net = 0x01
	}
	packedSeed := []byte{0x5a, 0xfe, 0x01, byte(net)}
	packedSeed = append(packedSeed, seedCore...)
	checksum := sha3.Sum256(packedSeed)
	packedSeed = append(packedSeed, checksum[:4]...)

	seed := util.ToBase58(packedSeed)

	return MakeRawKeyPairFromSeed(seed, test)
}

func MakeRawKeyPairFromSeed(seed string, test bool) (*RawKeyPair, *KeyPair, error) {

	privateKey, err := account.PrivateKeyFromBase58Seed(seed)
	if nil != err {
		return nil, nil, err
	}

	keyPair := KeyPair{
		Seed:       seed,
		PublicKey:  privateKey.Account().PublicKeyBytes(),
		PrivateKey: privateKey.PrivateKeyBytes(),
	}

	rawKeyPair := RawKeyPair{
		Seed:       seed,
		PublicKey:  hex.EncodeToString(privateKey.Account().PublicKeyBytes()),
		PrivateKey: hex.EncodeToString(privateKey.PrivateKeyBytes()),
	}

	return &rawKeyPair, &keyPair, nil
}

func AccountFromHexPublicKey(publicKey string, test bool) (*account.Account, error) {

	k, err := hex.DecodeString(publicKey)
	if nil != err {
		return nil, err
	}

	account := &account.Account{
		AccountInterface: &account.ED25519Account{
			Test:      test,
			PublicKey: k,
		},
	}
	return account, nil
}
<commit_msg>[keypair] add a NewSeed function<commit_after>// Copyright (c) 2014-2017 Bitmark Inc.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package keypair

import (
	"crypto/rand"
	"encoding/hex"
	"github.com/bitmark-inc/bitmarkd/account"
	"github.com/bitmark-inc/bitmarkd/fault"
	"github.com/bitmark-inc/bitmarkd/util"
	"golang.org/x/crypto/sha3"
)

var (
	ErrKeyLength        = fault.InvalidError("key length is invalid")
	ErrNotFoundIdentity = fault.NotFoundError("identity name not found")
)

type KeyPair struct {
	Seed       string
	PublicKey  []byte
	PrivateKey []byte
}

type RawKeyPair struct {
	Seed       string `json:"seed"`
	PublicKey  string `json:"public_key"`
	PrivateKey string `json:"private_key"`
}

func NewSeed(test bool) (string, error) {
	// generate new seed
	seedCore := make([]byte, 32)
	n, err := rand.Read(seedCore)
	if nil != err {
		return "", err
	}
	if 32 != n {
		panic("too few random bytes")
	}
	net := 0x00
	if test {
		net = 0x01
	}
	packedSeed := []byte{0x5a, 0xfe, 0x01, byte(net)}
	packedSeed = append(packedSeed, seedCore...)
	checksum := sha3.Sum256(packedSeed)
	packedSeed = append(packedSeed, checksum[:4]...)

	seed := util.ToBase58(packedSeed)
	return seed, nil
}

func MakeRawKeyPair(test bool) (*RawKeyPair, *KeyPair, error) {
	seed, err := NewSeed(test)
	if err != nil {
		return nil, nil, err
	}
	return MakeRawKeyPairFromSeed(seed, test)
}

func MakeRawKeyPairFromSeed(seed string, test bool) (*RawKeyPair, *KeyPair, error) {

	privateKey, err := account.PrivateKeyFromBase58Seed(seed)
	if nil != err {
		return nil, nil, err
	}

	keyPair := KeyPair{
		Seed:       seed,
		PublicKey:  privateKey.Account().PublicKeyBytes(),
		PrivateKey: privateKey.PrivateKeyBytes(),
	}

	rawKeyPair := RawKeyPair{
		Seed:       seed,
		PublicKey:  hex.EncodeToString(privateKey.Account().PublicKeyBytes()),
		PrivateKey: hex.EncodeToString(privateKey.PrivateKeyBytes()),
	}

	return &rawKeyPair, &keyPair, nil
}

func AccountFromHexPublicKey(publicKey string, test bool) (*account.Account, error) {

	k, err := hex.DecodeString(publicKey)
	if nil != err {
		return nil, err
	}

	account := &account.Account{
		AccountInterface: &account.ED25519Account{
			Test:      test,
			PublicKey: k,
		},
	}
	return account, nil
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"strconv"
	"sync"

	"github.com/gorilla/websocket"
)

type Regestry struct {
	sync.RWMutex
	connections map[int][]*UserConnection
}

func (registry *Regestry) ListenRabbit() {
	for message := range GetMessagesChannel() {
		message.Ack(false)
		matches := re.FindStringSubmatch(message.RoutingKey)
		if len(matches) == 0 {
			continue
		}
		user_id, _ := strconv.Atoi(matches[len(matches)-1])
		ws_connection, ok := registry.GetConnection(user_id)
		log.Printf("Message for user(is online - %v) %d: '%s'", ok, user_id, string(message.Body))
		if ok == false && *defatul_ttl > 0 {
			ttl := *defatul_ttl
			if ttl_header, ok := message.Headers["ttl"]; ok && ttl_header != nil {
				if ttl_int, ok := ttl_header.(int32); ok {
					ttl = int64(ttl_int)
				}
			}
			PublishUndeliveredMessage(user_id, message.Body, ttl)
			continue
		}
		ws_connection.ws.WriteMessage(websocket.TextMessage, message.Body)
	}
}

func (registry *Regestry) SendUndeliveredMessages(user_id int, messages chan []byte) {
	for message := range messages {
		if ws_connection, ok := registry.GetConnection(user_id); ok {
			ws_connection.ws.WriteMessage(websocket.TextMessage, message)
		}
	}
}

func (registry *Regestry) GetConnection(user_id int) (*UserConnection, bool) {
	registry.Lock()
	defer registry.Unlock()
	ws_connections, ok := registry.connections[user_id]
	if ok == false || len(ws_connections) == 0 {
		return nil, false
	}
	return ws_connections[0], true
}

func (registry *Regestry) Register(uc *UserConnection) bool {
	registry.Lock()
	defer registry.Unlock()
	connectionsCount.Add(1)
	first_connection := false
	if _, ok := registry.connections[uc.UserId]; ok == false {
		usersCount.Add(1)
		first_connection = true
		registry.connections[uc.UserId] = make([]*UserConnection, 0)
	}
	registry.connections[uc.UserId] = append(registry.connections[uc.UserId], uc)
	return first_connection
}

func (registry *Regestry) Unregister(uc *UserConnection) {
	registry.Lock()
	if _, ok := registry.connections[uc.UserId]; ok {
		var index int = 0
		for i := 0; i < len(registry.connections[uc.UserId]); i++ {
			if registry.connections[uc.UserId][i] == uc {
				index = i
				break
			}
		}
		registry.connections[uc.UserId] = append(registry.connections[uc.UserId][:index], registry.connections[uc.UserId][index+1:]...)

		connectionsCount.Add(-1)
		if len(registry.connections[uc.UserId]) == 0 {
			usersCount.Add(-1)
			delete(registry.connections, uc.UserId)

		}
	}
	registry.Unlock()
}
<commit_msg>undelivered message logging<commit_after>package main

import (
	"log"
	"strconv"
	"sync"

	"github.com/gorilla/websocket"
)

type Regestry struct {
	sync.RWMutex
	connections map[int][]*UserConnection
}

func (registry *Regestry) ListenRabbit() {
	for message := range GetMessagesChannel() {
		message.Ack(false)
		matches := re.FindStringSubmatch(message.RoutingKey)
		if len(matches) == 0 {
			continue
		}
		user_id, _ := strconv.Atoi(matches[len(matches)-1])
		ws_connection, ok := registry.GetConnection(user_id)
		log.Printf("Message for user(is online - %v) %d: '%s'", ok, user_id, string(message.Body))
		if ok == false && *defatul_ttl > 0 {
			ttl := *defatul_ttl
			if ttl_header, ok := message.Headers["ttl"]; ok && ttl_header != nil {
				if ttl_int, ok := ttl_header.(int32); ok {
					ttl = int64(ttl_int)
				}
			}
			PublishUndeliveredMessage(user_id, message.Body, ttl)
			continue
		}
		ws_connection.ws.WriteMessage(websocket.TextMessage, message.Body)
	}
}

func (registry *Regestry) SendUndeliveredMessages(user_id int, messages chan []byte) {
	for message := range messages {
		if ws_connection, ok := registry.GetConnection(user_id); ok {
			log.Printf("Message for user(is online - %v) %d: '%s'", ok, user_id, string(message))
			ws_connection.ws.WriteMessage(websocket.TextMessage, message)
		}
	}
}

func (registry *Regestry) GetConnection(user_id int) (*UserConnection, bool) {
	registry.Lock()
	defer registry.Unlock()
	ws_connections, ok := registry.connections[user_id]
	if ok == false || len(ws_connections) == 0 {
		return nil, false
	}
	return ws_connections[0], true
}

func (registry *Regestry) Register(uc *UserConnection) bool {
	registry.Lock()
	defer registry.Unlock()
	connectionsCount.Add(1)
	first_connection := false
	if _, ok := registry.connections[uc.UserId]; ok == false {
		usersCount.Add(1)
		first_connection = true
		registry.connections[uc.UserId] = make([]*UserConnection, 0)
	}
	registry.connections[uc.UserId] = append(registry.connections[uc.UserId], uc)
	return first_connection
}

func (registry *Regestry) Unregister(uc *UserConnection) {
	registry.Lock()
	if _, ok := registry.connections[uc.UserId]; ok {
		var index int = 0
		for i := 0; i < len(registry.connections[uc.UserId]); i++ {
			if registry.connections[uc.UserId][i] == uc {
				index = i
				break
			}
		}
		registry.connections[uc.UserId] = append(registry.connections[uc.UserId][:index], registry.connections[uc.UserId][index+1:]...)

		connectionsCount.Add(-1)
		if len(registry.connections[uc.UserId]) == 0 {
			usersCount.Add(-1)
			delete(registry.connections, uc.UserId)

		}
	}
	registry.Unlock()
}
<|endoftext|>


<commit_before>package realm

import "github.com/miekg/dns"

// RecordsEntry is used to hold a mapping of DNS request types to DNS records
type RecordsEntry map[uint16][]dns.RR

// GetRecords will fetch the appropriate DNS records to the requested type
func (entry RecordsEntry) GetRecords(rrType uint16) []dns.RR {
	var records []dns.RR
	records = make([]dns.RR, 0)

	if rrType == dns.TypeANY {
		for _, rrs := range entry {
			records = append(records, rrs...)
		}
	} else if rrs, ok := entry[rrType]; ok {
		records = append(records, rrs...)
	}

	return records
}

// DomainEntry is used to hold a mapping of DNS request classes to RecordEntrys
type DomainEntry map[uint16]RecordsEntry

// AddEntry is used to add a new DNS record to this mapping
func (entry DomainEntry) AddEntry(record dns.RR) {
	var header *dns.RR_Header
	header = record.Header()

	if _, ok := entry[header.Class]; !ok {
		entry[header.Class] = make(RecordsEntry)
	}
	if _, ok := entry[header.Class][header.Rrtype]; !ok {
		entry[header.Class][header.Rrtype] = make([]dns.RR, 0)
	}

	entry[header.Class][header.Rrtype] = append(entry[header.Class][header.Rrtype], record)
}

// GetEntries is used to find the appropriate RecordEntrys for the requested DNS class
func (entry DomainEntry) GetEntries(rrClass uint16) []RecordsEntry {
	var entries []RecordsEntry
	entries = make([]RecordsEntry, 0)

	if rrClass == dns.ClassANY {
		for _, entry := range entry {
			entries = append(entries, entry)
		}
	} else if entry, ok := entry[rrClass]; ok {
		entries = append(entries, entry)
	}

	return entries
}

// Registry is a container for looking up DNS records for any request
type Registry struct {
	records map[string]DomainEntry
}

// NewRegistry will allocate and return a new *Registry
func NewRegistry() *Registry {
	return &Registry{
		records: make(map[string]DomainEntry),
	}
}

// addRecord is used to add a new DNS record to this registry
func (r *Registry) addRecord(record dns.RR) {
	var header *dns.RR_Header
	header = record.Header()

	var name string
	name = dns.Fqdn(header.Name)

	if _, ok := r.records[name]; !ok {
		r.records[name] = make(DomainEntry)
	}
	r.records[name].AddEntry(record)

	// If this record is an SOA record then also store under the Mbox name
	if header.Rrtype == dns.TypeSOA {
		var soa *dns.SOA
		soa = record.(*dns.SOA)

		if _, ok := r.records[soa.Mbox]; !ok {
			r.records[soa.Mbox] = make(DomainEntry)
		}
		r.records[soa.Mbox].AddEntry(record)
	}
}

// AddZone is used to add the records from a *Zone into this *Registry
func (r *Registry) AddZone(z *Zone) {
	for _, record := range z.Records() {
		r.addRecord(record)
	}
}

// Lookup will find all records which we should respond with for the given name, request type, and request class.
func (r *Registry) Lookup(name string, reqType uint16, reqClass uint16) []dns.RR {
	name = dns.Fqdn(name)
	var records []dns.RR
	records = make([]dns.RR, 0)

	var domainEntry DomainEntry
	var ok bool
	domainEntry, ok = r.records[name]
	if !ok {
		return records
	}

	var recordEntries []RecordsEntry
	recordEntries = domainEntry.GetEntries(reqClass)

	for _, recordEntry := range recordEntries {
		var rrs []dns.RR
		rrs = recordEntry.GetRecords(reqType)
		records = append(records, rrs...)

		if len(rrs) == 0 && reqType == dns.TypeA {
			rrs = recordEntry.GetRecords(dns.TypeCNAME)
			for _, rr := range rrs {
				records = append(records, rr)
				var header *dns.RR_Header
				header = rr.Header()
				if header.Rrtype == dns.TypeCNAME && reqType != dns.TypeCNAME {
					// Attempt to resolve this CNAME record
					var cname *dns.CNAME
					cname = rr.(*dns.CNAME)
					var cnameRecords []dns.RR
					cnameRecords = r.Lookup(dns.Fqdn(cname.Target), reqType, reqClass)
					records = append(records, cnameRecords...)
				}

			}
		}

	}
	return records
}
<commit_msg>always lowercase domain names when looking up<commit_after>package realm

import (
	"strings"

	"github.com/miekg/dns"
)

// RecordsEntry is used to hold a mapping of DNS request types to DNS records
type RecordsEntry map[uint16][]dns.RR

// GetRecords will fetch the appropriate DNS records to the requested type
func (entry RecordsEntry) GetRecords(rrType uint16) []dns.RR {
	var records []dns.RR
	records = make([]dns.RR, 0)

	if rrType == dns.TypeANY {
		for _, rrs := range entry {
			records = append(records, rrs...)
		}
	} else if rrs, ok := entry[rrType]; ok {
		records = append(records, rrs...)
	}

	return records
}

// DomainEntry is used to hold a mapping of DNS request classes to RecordEntrys
type DomainEntry map[uint16]RecordsEntry

// AddEntry is used to add a new DNS record to this mapping
func (entry DomainEntry) AddEntry(record dns.RR) {
	var header *dns.RR_Header
	header = record.Header()

	if _, ok := entry[header.Class]; !ok {
		entry[header.Class] = make(RecordsEntry)
	}
	if _, ok := entry[header.Class][header.Rrtype]; !ok {
		entry[header.Class][header.Rrtype] = make([]dns.RR, 0)
	}

	entry[header.Class][header.Rrtype] = append(entry[header.Class][header.Rrtype], record)
}

// GetEntries is used to find the appropriate RecordEntrys for the requested DNS class
func (entry DomainEntry) GetEntries(rrClass uint16) []RecordsEntry {
	var entries []RecordsEntry
	entries = make([]RecordsEntry, 0)

	if rrClass == dns.ClassANY {
		for _, entry := range entry {
			entries = append(entries, entry)
		}
	} else if entry, ok := entry[rrClass]; ok {
		entries = append(entries, entry)
	}

	return entries
}

// Registry is a container for looking up DNS records for any request
type Registry struct {
	records map[string]DomainEntry
}

// NewRegistry will allocate and return a new *Registry
func NewRegistry() *Registry {
	return &Registry{
		records: make(map[string]DomainEntry),
	}
}

// addRecord is used to add a new DNS record to this registry
func (r *Registry) addRecord(record dns.RR) {
	var header *dns.RR_Header
	header = record.Header()

	var name string
	name = dns.Fqdn(header.Name)
	name = strings.ToLower(name)

	if _, ok := r.records[name]; !ok {
		r.records[name] = make(DomainEntry)
	}
	r.records[name].AddEntry(record)

	// If this record is an SOA record then also store under the Mbox name
	if header.Rrtype == dns.TypeSOA {
		var soa *dns.SOA
		soa = record.(*dns.SOA)

		if _, ok := r.records[soa.Mbox]; !ok {
			r.records[soa.Mbox] = make(DomainEntry)
		}
		r.records[soa.Mbox].AddEntry(record)
	}
}

// AddZone is used to add the records from a *Zone into this *Registry
func (r *Registry) AddZone(z *Zone) {
	for _, record := range z.Records() {
		r.addRecord(record)
	}
}

// Lookup will find all records which we should respond with for the given name, request type, and request class.
func (r *Registry) Lookup(name string, reqType uint16, reqClass uint16) []dns.RR {
	name = dns.Fqdn(name)
	name = strings.ToLower(name)

	var records []dns.RR
	records = make([]dns.RR, 0)

	var domainEntry DomainEntry
	var ok bool
	domainEntry, ok = r.records[name]
	if !ok {
		return records
	}

	var recordEntries []RecordsEntry
	recordEntries = domainEntry.GetEntries(reqClass)

	for _, recordEntry := range recordEntries {
		var rrs []dns.RR
		rrs = recordEntry.GetRecords(reqType)
		records = append(records, rrs...)

		if len(rrs) == 0 && reqType == dns.TypeA {
			rrs = recordEntry.GetRecords(dns.TypeCNAME)
			for _, rr := range rrs {
				records = append(records, rr)
				var header *dns.RR_Header
				header = rr.Header()
				if header.Rrtype == dns.TypeCNAME && reqType != dns.TypeCNAME {
					// Attempt to resolve this CNAME record
					var cname *dns.CNAME
					cname = rr.(*dns.CNAME)
					var cnameRecords []dns.RR
					cnameRecords = r.Lookup(cname.Target, reqType, reqClass)
					records = append(records, cnameRecords...)
				}

			}
		}

	}
	return records
}
<|endoftext|>


<commit_before>package server

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"

	"github.com/bouk/httprouter"
	"github.com/influxdata/chronograf"
)

type dashboardLinks struct {
	Self string `json:"self"` // Self link mapping to this resource
}

type dashboardResponse struct {
	chronograf.Dashboard
	Links dashboardLinks `json:"links"`
}

type getDashboardsResponse struct {
	Dashboards []dashboardResponse `json:"dashboards"`
}

func newDashboardResponse(d chronograf.Dashboard) dashboardResponse {
	base := "/chronograf/v1/dashboards"
	return dashboardResponse{
		Dashboard: d,
		Links: dashboardLinks{
			Self: fmt.Sprintf("%s/%d", base, d.ID),
		},
	}
}

// Dashboards returns all dashboards within the store
func (s *Service) Dashboards(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	dashboards, err := s.DashboardsStore.All(ctx)
	if err != nil {
		Error(w, http.StatusInternalServerError, "Error loading dashboards", s.Logger)
		return
	}

	res := getDashboardsResponse{
		Dashboards: []dashboardResponse{},
	}

	for _, dashboard := range dashboards {
		res.Dashboards = append(res.Dashboards, newDashboardResponse(dashboard))
	}

	encodeJSON(w, http.StatusOK, res, s.Logger)
}

// DashboardID returns a single specified dashboard
func (s *Service) DashboardID(w http.ResponseWriter, r *http.Request) {
	id, err := paramID("id", r)
	if err != nil {
		Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger)
		return
	}

	ctx := r.Context()
	e, err := s.DashboardsStore.Get(ctx, chronograf.DashboardID(id))
	if err != nil {
		notFound(w, id, s.Logger)
		return
	}

	res := newDashboardResponse(*e)
	encodeJSON(w, http.StatusOK, res, s.Logger)
}

// NewDashboard creates and returns a new dashboard object
func (s *Service) NewDashboard(w http.ResponseWriter, r *http.Request) {
	var dashboard *chronograf.Dashboard
	if err := json.NewDecoder(r.Body).Decode(&dashboard); err != nil {
		invalidJSON(w, s.Logger)
		return
	}

	var err error
	if dashboard, err = s.DashboardsStore.Add(r.Context(), dashboard); err != nil {
		msg := fmt.Errorf("Error storing dashboard %v: %v", dashboard, err)
		unknownErrorWithMessage(w, msg, s.Logger)
		return
	}

	res := newDashboardResponse(*dashboard)
	w.Header().Add("Location", res.Links.Self)
	encodeJSON(w, http.StatusCreated, res, s.Logger)
}

// RemoveDashboard deletes a dashboard
func (s *Service) RemoveDashboard(w http.ResponseWriter, r *http.Request) {
	id, err := paramID("id", r)
	if err != nil {
		Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger)
		return
	}

	ctx := r.Context()
	e, err := s.DashboardsStore.Get(ctx, chronograf.DashboardID(id))
	if err != nil {
		notFound(w, id, s.Logger)
		return
	}

	if err := s.DashboardsStore.Delete(ctx, e); err != nil {
		unknownErrorWithMessage(w, err, s.Logger)
		return
	}
	w.WriteHeader(http.StatusNoContent)
}

// UpdateDashboard replaces a dashboard
func (s *Service) UpdateDashboard(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	idParam, err := strconv.Atoi(httprouter.GetParamFromContext(ctx, "id"))
	if err != nil {
		msg := fmt.Sprintf("Could not parse dashboard ID: %s", err)
		Error(w, http.StatusInternalServerError, msg, s.Logger)
	}
	id := chronograf.DashboardID(idParam)

	_, err = s.DashboardsStore.Get(ctx, id)
	if err != nil {
		Error(w, http.StatusNotFound, fmt.Sprintf("ID %s not found", id), s.Logger)
		return
	}

	var req *chronograf.Dashboard
	if err := json.NewDecoder(r.Body).Decode(req); err != nil {
		invalidJSON(w, s.Logger)
		return
	}
	req.ID = id

	if err := s.DashboardsStore.Update(ctx, req); err != nil {
		msg := fmt.Sprintf("Error updating dashboard ID %s: %v", id, err)
		Error(w, http.StatusInternalServerError, msg, s.Logger)
		return
	}

	res := newDashboardResponse(*req)
	encodeJSON(w, http.StatusOK, res, s.Logger)
}
<commit_msg>add dashboard validation<commit_after>package server

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"

	"github.com/bouk/httprouter"
	"github.com/influxdata/chronograf"
)

type dashboardLinks struct {
	Self string `json:"self"` // Self link mapping to this resource
}

type dashboardResponse struct {
	chronograf.Dashboard
	Links dashboardLinks `json:"links"`
}

type getDashboardsResponse struct {
	Dashboards []dashboardResponse `json:"dashboards"`
}

func newDashboardResponse(d chronograf.Dashboard) dashboardResponse {
	base := "/chronograf/v1/dashboards"
	return dashboardResponse{
		Dashboard: d,
		Links: dashboardLinks{
			Self: fmt.Sprintf("%s/%d", base, d.ID),
		},
	}
}

// Dashboards returns all dashboards within the store
func (s *Service) Dashboards(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	dashboards, err := s.DashboardsStore.All(ctx)
	if err != nil {
		Error(w, http.StatusInternalServerError, "Error loading dashboards", s.Logger)
		return
	}

	res := getDashboardsResponse{
		Dashboards: []dashboardResponse{},
	}

	for _, dashboard := range dashboards {
		res.Dashboards = append(res.Dashboards, newDashboardResponse(dashboard))
	}

	encodeJSON(w, http.StatusOK, res, s.Logger)
}

// DashboardID returns a single specified dashboard
func (s *Service) DashboardID(w http.ResponseWriter, r *http.Request) {
	id, err := paramID("id", r)
	if err != nil {
		Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger)
		return
	}

	ctx := r.Context()
	e, err := s.DashboardsStore.Get(ctx, chronograf.DashboardID(id))
	if err != nil {
		notFound(w, id, s.Logger)
		return
	}

	res := newDashboardResponse(*e)
	encodeJSON(w, http.StatusOK, res, s.Logger)
}

// NewDashboard creates and returns a new dashboard object
func (s *Service) NewDashboard(w http.ResponseWriter, r *http.Request) {
	var dashboard *chronograf.Dashboard
	if err := json.NewDecoder(r.Body).Decode(&dashboard); err != nil {
		invalidJSON(w, s.Logger)
		return
	}

	if err := ValidDashboardRequest(dashboard); err != nil {
		invalidData(w, err, s.Logger)
		return
	}

	var err error
	if dashboard, err = s.DashboardsStore.Add(r.Context(), dashboard); err != nil {
		msg := fmt.Errorf("Error storing dashboard %v: %v", dashboard, err)
		unknownErrorWithMessage(w, msg, s.Logger)
		return
	}

	res := newDashboardResponse(*dashboard)
	w.Header().Add("Location", res.Links.Self)
	encodeJSON(w, http.StatusCreated, res, s.Logger)
}

// RemoveDashboard deletes a dashboard
func (s *Service) RemoveDashboard(w http.ResponseWriter, r *http.Request) {
	id, err := paramID("id", r)
	if err != nil {
		Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger)
		return
	}

	ctx := r.Context()
	e, err := s.DashboardsStore.Get(ctx, chronograf.DashboardID(id))
	if err != nil {
		notFound(w, id, s.Logger)
		return
	}

	if err := s.DashboardsStore.Delete(ctx, e); err != nil {
		unknownErrorWithMessage(w, err, s.Logger)
		return
	}
	w.WriteHeader(http.StatusNoContent)
}

// UpdateDashboard replaces a dashboard
func (s *Service) UpdateDashboard(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	idParam, err := strconv.Atoi(httprouter.GetParamFromContext(ctx, "id"))
	if err != nil {
		msg := fmt.Sprintf("Could not parse dashboard ID: %s", err)
		Error(w, http.StatusInternalServerError, msg, s.Logger)
	}
	id := chronograf.DashboardID(idParam)

	_, err = s.DashboardsStore.Get(ctx, id)
	if err != nil {
		Error(w, http.StatusNotFound, fmt.Sprintf("ID %s not found", id), s.Logger)
		return
	}

	var req *chronograf.Dashboard
	if err := json.NewDecoder(r.Body).Decode(req); err != nil {
		invalidJSON(w, s.Logger)
		return
	}
	req.ID = id

	if err := ValidDashboardRequest(dashboard); err != nil {
		invalidData(w, err, s.Logger)
		return
	}

	if err := s.DashboardsStore.Update(ctx, req); err != nil {
		msg := fmt.Sprintf("Error updating dashboard ID %s: %v", id, err)
		Error(w, http.StatusInternalServerError, msg, s.Logger)
		return
	}

	res := newDashboardResponse(*req)
	encodeJSON(w, http.StatusOK, res, s.Logger)
}

// ValidDashboardRequest verifies that the dashboard cells have a query
func ValidDashboardRequest(d chronograf.Dashboard) error {
	if len(d.Cells) == 0 {
		return fmt.Errorf("cells are required")
	}

	for _, c := range d.Cells {
		for _, q := range c.Queries {
			if len(q) == 0 {
				return ftm.Errorf("query required")
			}
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package trousseau

import (
	"bytes"
	"code.google.com/p/go.crypto/ssh"
	"crypto"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"io"
	"io/ioutil"
	"strings"
)

type ScpStorage struct {
	host      string
	port      string
	connexion *ssh.ClientConn

	Keychain *Keychain
	User     string
	Endpoint string
}

type Keychain struct {
	key *rsa.PrivateKey
}

func NewScpStorage(host, port, user string, keychain *Keychain) *ScpStorage {
	return &ScpStorage{
		Keychain: keychain,
		User:     user,
		Endpoint: strings.Join([]string{host, port}, ":"),
		host:     host,
		port:     port,
	}
}

func NewKeychain(key *rsa.PrivateKey) *Keychain {
	return &Keychain{
		key: key,
	}
}

func DecodePrivateKeyFromFile(privateKeyPath string) (*rsa.PrivateKey, error) {
	keyContent, err := ioutil.ReadFile(privateKeyPath)
	if err != nil {
		return nil, err
	}

	block, _ := pem.Decode([]byte(keyContent))
	rsakey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		return nil, err
	}

	return rsakey, nil
}

func (k *Keychain) Key(i int) (key ssh.PublicKey, err error) {
	if i != 0 {
		return nil, nil
	}
	return &k.key.PublicKey, nil
}

func (k *Keychain) Sign(i int, rand io.Reader, data []byte) (sig []byte, err error) {
	hashFunc := crypto.SHA1
	h := hashFunc.New()
	h.Write(data)
	digest := h.Sum(nil)
	return rsa.SignPKCS1v15(rand, k.key, hashFunc, digest)
}

func (ss *ScpStorage) Connect() error {
	var err error

	clientConfig := &ssh.ClientConfig{
		User: ss.User,
		Auth: []ssh.ClientAuth{
			ssh.ClientAuthKeyring(ss.Keychain),
		},
	}

	ss.connexion, err = ssh.Dial("tcp", ss.Endpoint, clientConfig)
	if err != nil {
		return fmt.Errorf("Failed to dial: %s", err.Error())
	}

	return nil
}

func (ss *ScpStorage) Push(remoteName string) error {
	session, err := ss.connexion.NewSession()
	if err != nil {
		return fmt.Errorf("Failed to create session: %s", err.Error())
	}
	defer session.Close()

	go func() {
		w, _ := session.StdinPipe()
		defer w.Close()

		content, _ := ioutil.ReadFile(gStorePath)

		fmt.Fprintln(w, "C0755", len(content), remoteName)
		fmt.Fprint(w, string(content))
		fmt.Fprint(w, "\x00")
	}()

	if err := session.Run("/usr/bin/scp -qrt ./"); err != nil {
		return fmt.Errorf("Failed to run: %s", err.Error())
	}

	return nil
}

func (ss *ScpStorage) Pull(remoteName string) error {
	session, err := ss.connexion.NewSession()
	if err != nil {
		return fmt.Errorf("Failed to create session: %s", err.Error())
	}
	defer session.Close()

	var remoteFileBuffer bytes.Buffer
	session.Stdout = &remoteFileBuffer

	if err := session.Run(fmt.Sprintf("cat %s", remoteName)); err != nil {
		return fmt.Errorf("Failed to run: %s", err.Error())
	}

	err = ioutil.WriteFile(gStorePath, remoteFileBuffer.Bytes(), 0744)
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>Fix ssh.Publickey usage with rsa.Publickey in scp_storage<commit_after>package trousseau

import (
	"bytes"
	"code.google.com/p/go.crypto/ssh"
	"crypto"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"io"
	"io/ioutil"
	"strings"
)

type ScpStorage struct {
	host      string
	port      string
	connexion *ssh.ClientConn

	Keychain *Keychain
	User     string
	Endpoint string
}

type Keychain struct {
	key *rsa.PrivateKey
}

func NewScpStorage(host, port, user string, keychain *Keychain) *ScpStorage {
	return &ScpStorage{
		Keychain: keychain,
		User:     user,
		Endpoint: strings.Join([]string{host, port}, ":"),
		host:     host,
		port:     port,
	}
}

func NewKeychain(key *rsa.PrivateKey) *Keychain {
	return &Keychain{
		key: key,
	}
}

func DecodePrivateKeyFromFile(privateKeyPath string) (*rsa.PrivateKey, error) {
	keyContent, err := ioutil.ReadFile(privateKeyPath)
	if err != nil {
		return nil, err
	}

	block, _ := pem.Decode([]byte(keyContent))
	rsakey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		return nil, err
	}

	return rsakey, nil
}

func (k *Keychain) Key(i int) (key ssh.PublicKey, err error) {
	if i != 0 {
		return nil, nil
	}

    // Transform the rsa key into an ssh key
    ssh_publickey, _ := ssh.NewPublicKey(k.key.PublicKey)

	return ssh_publickey, nil
}

func (k *Keychain) Sign(i int, rand io.Reader, data []byte) (sig []byte, err error) {
	hashFunc := crypto.SHA1
	h := hashFunc.New()
	h.Write(data)
	digest := h.Sum(nil)
	return rsa.SignPKCS1v15(rand, k.key, hashFunc, digest)
}

func (ss *ScpStorage) Connect() error {
	var err error

	clientConfig := &ssh.ClientConfig{
		User: ss.User,
		Auth: []ssh.ClientAuth{
			ssh.ClientAuthKeyring(ss.Keychain),
		},
	}

	ss.connexion, err = ssh.Dial("tcp", ss.Endpoint, clientConfig)
	if err != nil {
		return fmt.Errorf("Failed to dial: %s", err.Error())
	}

	return nil
}

func (ss *ScpStorage) Push(remoteName string) error {
	session, err := ss.connexion.NewSession()
	if err != nil {
		return fmt.Errorf("Failed to create session: %s", err.Error())
	}
	defer session.Close()

	go func() {
		w, _ := session.StdinPipe()
		defer w.Close()

		content, _ := ioutil.ReadFile(gStorePath)

		fmt.Fprintln(w, "C0755", len(content), remoteName)
		fmt.Fprint(w, string(content))
		fmt.Fprint(w, "\x00")
	}()

	if err := session.Run("/usr/bin/scp -qrt ./"); err != nil {
		return fmt.Errorf("Failed to run: %s", err.Error())
	}

	return nil
}

func (ss *ScpStorage) Pull(remoteName string) error {
	session, err := ss.connexion.NewSession()
	if err != nil {
		return fmt.Errorf("Failed to create session: %s", err.Error())
	}
	defer session.Close()

	var remoteFileBuffer bytes.Buffer
	session.Stdout = &remoteFileBuffer

	if err := session.Run(fmt.Sprintf("cat %s", remoteName)); err != nil {
		return fmt.Errorf("Failed to run: %s", err.Error())
	}

	err = ioutil.WriteFile(gStorePath, remoteFileBuffer.Bytes(), 0744)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package filesystem

import (
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

// MemoryFileSystem is a fake file system.
type memoryFileSystem struct {
	files map[string][]byte
}

// NewMemoryFileSystem creates an in-memory file system.
func NewMemoryFileSystem() *MemoryFileSystem {
	return &memoryFileSystem{
		files: map[string][]byte{string(filepath.Separator): nil},
	}
}

// fileCloser is to implement Close function.
type fileCloser struct {
	bytes.Buffer
	files *map[string][]byte
	path string
}

// Close commits the buffer to the file system.
func (w *fileCloser) Close() error {
	buf, err := ioutil.ReadAll(w)
	if err != nil {
		return err
	}
	(*w.files)[w.path] = buf
	return nil
}

// MkdirAll creates a directory named path, along with any necessary
// parents, and returns nil. The parameter perm is just for
// compatibility and does nothing. If path is already a directory,
// MkdirAll does nothing and returns nil.
func (mfs memoryFileSystem) MkdirAll(path string, perm os.FileMode) error {
	current := filepath.Clean(path)
	for current != "." && current != string(filepath.Separator) {
		mfs.files[current+string(filepath.Separator)] = nil
		current = filepath.Dir(current)
	}
	return nil
}

// RemoveAll removes path and any children it contains. It removes
// everything it can but returns the first error it encounters. If the
// path does not exist, RemoveAll returns nil (no error).
func (mfs memoryFileSystem) RemoveAll(path string) error {
	cleaned := filepath.Clean(path) + string(filepath.Separator)
	for k, _ := range mfs.files {
		if strings.HasPrefix(k, cleaned) {
			delete(mfs.files, k)
		}
	}
	return nil
}

// Open opens the named file for reading. If successful, methods on
// the returned file can be used for reading.
func (mfs memoryFileSystem) Open(name string) (io.ReadCloser, error) {
	cleaned := filepath.Clean(name)
	content, ok := mfs.files[cleaned]
	if !ok {
		return nil, os.ErrNotExist
	}
	return ioutil.NopCloser(bytes.NewReader(content)), nil
}

// Create creates the named file, truncating it if it already
// exists, and returns a writer to the file.
func (mfs memoryFileSystem) Create(name string) (io.ReadWriteCloser, error) {
	cleaned := filepath.Clean(name)
	mfs.files[cleaned] = make([]byte, 0, 10)
	f := fileCloser{
		*bytes.NewBuffer(mfs.files[cleaned]),
		&mfs.files,
		name,
	}
	return &f, nil
}

// Remove removes the named file or directory. If there is an error,
// it will be of type *PathError.
func (mfs memoryFileSystem) Remove(name string) error {
	cleaned := filepath.Clean(name)
	delete(mfs.files, cleaned)
	return nil
}
<commit_msg>Fixed typo.<commit_after>package filesystem

import (
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

// MemoryFileSystem is a fake file system.
type memoryFileSystem struct {
	files map[string][]byte
}

// NewMemoryFileSystem creates an in-memory file system.
func NewMemoryFileSystem() *memoryFileSystem {
	return &memoryFileSystem{
		files: map[string][]byte{string(filepath.Separator): nil},
	}
}

// fileCloser is to implement Close function.
type fileCloser struct {
	bytes.Buffer
	files *map[string][]byte
	path string
}

// Close commits the buffer to the file system.
func (w *fileCloser) Close() error {
	buf, err := ioutil.ReadAll(w)
	if err != nil {
		return err
	}
	(*w.files)[w.path] = buf
	return nil
}

// MkdirAll creates a directory named path, along with any necessary
// parents, and returns nil. The parameter perm is just for
// compatibility and does nothing. If path is already a directory,
// MkdirAll does nothing and returns nil.
func (mfs memoryFileSystem) MkdirAll(path string, perm os.FileMode) error {
	current := filepath.Clean(path)
	for current != "." && current != string(filepath.Separator) {
		mfs.files[current+string(filepath.Separator)] = nil
		current = filepath.Dir(current)
	}
	return nil
}

// RemoveAll removes path and any children it contains. It removes
// everything it can but returns the first error it encounters. If the
// path does not exist, RemoveAll returns nil (no error).
func (mfs memoryFileSystem) RemoveAll(path string) error {
	cleaned := filepath.Clean(path) + string(filepath.Separator)
	for k, _ := range mfs.files {
		if strings.HasPrefix(k, cleaned) {
			delete(mfs.files, k)
		}
	}
	return nil
}

// Open opens the named file for reading. If successful, methods on
// the returned file can be used for reading.
func (mfs memoryFileSystem) Open(name string) (io.ReadCloser, error) {
	cleaned := filepath.Clean(name)
	content, ok := mfs.files[cleaned]
	if !ok {
		return nil, os.ErrNotExist
	}
	return ioutil.NopCloser(bytes.NewReader(content)), nil
}

// Create creates the named file, truncating it if it already
// exists, and returns a writer to the file.
func (mfs memoryFileSystem) Create(name string) (io.ReadWriteCloser, error) {
	cleaned := filepath.Clean(name)
	mfs.files[cleaned] = make([]byte, 0, 10)
	f := fileCloser{
		*bytes.NewBuffer(mfs.files[cleaned]),
		&mfs.files,
		name,
	}
	return &f, nil
}

// Remove removes the named file or directory. If there is an error,
// it will be of type *PathError.
func (mfs memoryFileSystem) Remove(name string) error {
	cleaned := filepath.Clean(name)
	delete(mfs.files, cleaned)
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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 client

import (
	"fmt"

	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/kubernetes/pkg/api/v1"
	"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
)

// Retrieve a namespace pod constructed from the namespace limitations.
// Limitations cover pod resource limits and node selector if available
func RetrieveNamespacePod(client clientset.Interface, namespace string) (*v1.Pod, error) {
	ns, err := client.Core().Namespaces().Get(namespace, metav1.GetOptions{})
	if err != nil {
		return nil, fmt.Errorf("Namespace %v not found: %v", namespace, err)
	}

	// Iterate through all limit ranges and pick the minimum of all related to pod constraints
	limits, err := client.Core().LimitRanges(namespace).List(metav1.ListOptions{})
	if err != nil {
		return nil, fmt.Errorf("Could not retrieve limit ranges for %v namespaces: %v", namespace, err)
	}

	resources := make(map[v1.ResourceName]*resource.Quantity)

	// TODO(jchaloup): extend the list of considered resources with other types
	resources[v1.ResourceMemory] = nil
	resources[v1.ResourceCPU] = nil
	resources[v1.ResourceNvidiaGPU] = nil

	for _, limit := range limits.Items {
		for _, item := range limit.Spec.Limits {
			if item.Type != v1.LimitTypePod {
				continue
			}

			for resourceType := range resources {
				amount, ok := item.Max[resourceType]
				if !ok {
					continue
				}
				if resources[resourceType] == nil || resources[resourceType].Cmp(amount) == 1 {
					resources[resourceType] = &amount
				}
			}
		}
	}

	nonzero := false
	for _, quantity := range resources {
		if quantity == nil {
			continue
		}

		if !quantity.IsZero() {
			nonzero = true
			break
		}
	}

	if !nonzero {
		return nil, fmt.Errorf("No resource limit set for pod in %v namespace", namespace)
	}

	limitsResourceList := make(map[v1.ResourceName]resource.Quantity)
	requestsResourceList := make(map[v1.ResourceName]resource.Quantity)
	for key, val := range resources {
		if val == nil {
			continue
		}
		limitsResourceList[key] = *val
		requestsResourceList[key] = *val
	}

	namespacePod := v1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "cluster-capacity-stub-container",
			Namespace: namespace,
		},
		Spec: v1.PodSpec{
			Containers: []v1.Container{
				v1.Container{
					Name:            "cluster-capacity-stub-container",
					Image:           "gcr.io/google_containers/pause:2.0",
					ImagePullPolicy: v1.PullAlways,
					Resources: v1.ResourceRequirements{
						Limits:   limitsResourceList,
						Requests: requestsResourceList,
					},
				},
			},
			RestartPolicy: v1.RestartPolicyOnFailure,
			DNSPolicy:     v1.DNSDefault,
		},
	}

	annotations := ns.GetAnnotations()
	if key, ok := annotations["openshift.io/node-selector"]; ok {
		nodeSelector, err := labels.ConvertSelectorToLabelsMap(key)
		if err != nil {
			return nil, fmt.Errorf("Unable to parse openshift.io/node-selector in %v namespace: %v", key, err)
		}
		namespacePod.Spec.NodeSelector = nodeSelector
	}

	return &namespacePod, nil
}
<commit_msg>Fix genpod to exhibit similar behavior as cluster-capacity when no resource limits are set on a namespace.<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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 client

import (
	"fmt"

	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/kubernetes/pkg/api/v1"
	"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
)

// Retrieve a namespace pod constructed from the namespace limitations.
// Limitations cover pod resource limits and node selector if available
func RetrieveNamespacePod(client clientset.Interface, namespace string) (*v1.Pod, error) {
	ns, err := client.Core().Namespaces().Get(namespace, metav1.GetOptions{})
	if err != nil {
		return nil, fmt.Errorf("Namespace %v not found: %v", namespace, err)
	}

	namespacePod := v1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "cluster-capacity-stub-container",
			Namespace: namespace,
		},
		Spec: v1.PodSpec{
			Containers: []v1.Container{
				v1.Container{
					Name:            "cluster-capacity-stub-container",
					Image:           "gcr.io/google_containers/pause:2.0",
					ImagePullPolicy: v1.PullAlways,
				},
			},
			RestartPolicy: v1.RestartPolicyOnFailure,
			DNSPolicy:     v1.DNSDefault,
		},
	}

	// Iterate through all limit ranges and pick the minimum of all related to pod constraints
	limits, err := client.Core().LimitRanges(namespace).List(metav1.ListOptions{})
	if err != nil {
		return nil, fmt.Errorf("Could not retrieve limit ranges for %v namespaces: %v", namespace, err)
	}

	resources := make(map[v1.ResourceName]*resource.Quantity)

	// TODO(jchaloup): extend the list of considered resources with other types
	resources[v1.ResourceMemory] = nil
	resources[v1.ResourceCPU] = nil
	resources[v1.ResourceNvidiaGPU] = nil

	for _, limit := range limits.Items {
		for _, item := range limit.Spec.Limits {
			if item.Type != v1.LimitTypePod {
				continue
			}

			for resourceType := range resources {
				amount, ok := item.Max[resourceType]
				if !ok {
					continue
				}
				if resources[resourceType] == nil || resources[resourceType].Cmp(amount) == 1 {
					resources[resourceType] = &amount
				}
			}
		}
	}

	nonzero := false
	for _, quantity := range resources {
		if quantity == nil {
			continue
		}

		if !quantity.IsZero() {
			nonzero = true
			break
		}
	}

	if nonzero {
		limitsResourceList := make(map[v1.ResourceName]resource.Quantity)
		requestsResourceList := make(map[v1.ResourceName]resource.Quantity)
		for key, val := range resources {
			if val == nil {
				continue
			}
			limitsResourceList[key] = *val
			requestsResourceList[key] = *val
		}

		namespacePod.Spec.Containers[0].Resources = v1.ResourceRequirements{
			Limits:   limitsResourceList,
			Requests: requestsResourceList,
		}

	}

	annotations := ns.GetAnnotations()
	if key, ok := annotations["openshift.io/node-selector"]; ok {
		nodeSelector, err := labels.ConvertSelectorToLabelsMap(key)
		if err != nil {
			return nil, fmt.Errorf("Unable to parse openshift.io/node-selector in %v namespace: %v", key, err)
		}
		namespacePod.Spec.NodeSelector = nodeSelector
	}

	return &namespacePod, nil
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"log"
	"os"
	"os/exec"
	"strings"

	"github.com/jwfriese/iossimulator"
)

func main() {
	programCall := os.Args
	if len(programCall) < 3 {
		log.Fatal(errors.New("Usage: ./test <runtime> <device type>"))
	}

	args := programCall[1:]
	iosVersion := args[0]
	deviceVersion := args[1]

	testInitReport := fmt.Sprintf("Running Fleet unit tests with iOS version '%s' on  device type '%s'\n", iosVersion, deviceVersion)
	_, err := os.Stdout.Write([]byte(testInitReport))
	if err != nil {
		log.Fatal(err)
	}

	availabilityErr := iossimulator.IsDeviceAvailable(iosVersion, deviceVersion)
	if availabilityErr != nil {
		log.Fatal(availabilityErr)
	}

	iosVersionNumber := strings.Trim(iosVersion, "iOS ")
	destinationString := fmt.Sprintf("platform=iOS Simulator,OS=%s,name=%s", iosVersionNumber, deviceVersion)
	unitTestCommand := exec.Command("xcodebuild", "test", "-workspace", "Fleet.xcworkspace", "-scheme", "Fleet", "-destination", destinationString)
	xcprettyCommand := exec.Command("xcpretty")
	xcprettyCommand.Stdin, err = unitTestCommand.StdoutPipe()
	if err != nil {
		log.Fatal(err)
	}
	xcprettyCommand.Stdout = os.Stdout
	xcprettyCommand.Stderr = os.Stderr
	err = xcprettyCommand.Start()
	if err != nil {
		log.Fatal(err)
	}

	err = unitTestCommand.Run()
	if err != nil {
		log.Fatal(err)
	}

	err = xcprettyCommand.Wait()
	if err != nil {
		log.Fatal(err)
	}

	_, err = os.Stdout.Write([]byte("Fleet unit tests passed...\n"))
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Run both iOS and tvOS test suite as part of `test` script<commit_after>package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"

	"github.com/jwfriese/iossimulator"
)

func main() {
	runTestsForiOS()
	runTestsFortvOS()
}

func runTestsForiOS() {
	iOSConfig := &testConfig{
		os:         "iOS",
		osVersion:  "10.3",
		device:     "iPhone 7",
		schemeName: "Fleet",
	}

	runFor(iOSConfig)
}

func runTestsFortvOS() {
	tvOSConfig := &testConfig{
		os:         "tvOS",
		osVersion:  "10.2",
		device:     "Apple TV 1080p",
		schemeName: "Fleet-tvOS",
	}

	runFor(tvOSConfig)
}

type testConfig struct {
	os         string
	osVersion  string
	device     string
	schemeName string
}

func runFor(config *testConfig) {
	testInitReport := fmt.Sprintf("Running Fleet unit tests with %s version '%s' on device type '%s'\n", config.os, config.osVersion, config.device)
	_, err := os.Stdout.Write([]byte(testInitReport))
	if err != nil {
		log.Fatal(err)
	}

	if config.os == "iOS" {
		iosVersion := fmt.Sprintf("iOS %s", config.osVersion)
		availabilityErr := iossimulator.IsDeviceAvailable(iosVersion, config.device)
		if availabilityErr != nil {
			log.Fatal(availabilityErr)
		}
	}

	destinationString := fmt.Sprintf("platform=%s Simulator,OS=%s,name=%s", config.os, config.osVersion, config.device)
	unitTestCommand := exec.Command("xcodebuild", "test", "-workspace", "Fleet.xcworkspace", "-scheme", config.schemeName, "-destination", destinationString)
	xcprettyCommand := exec.Command("xcpretty")
	xcprettyCommand.Stdin, err = unitTestCommand.StdoutPipe()
	if err != nil {
		log.Fatal(err)
	}
	xcprettyCommand.Stdout = os.Stdout
	xcprettyCommand.Stderr = os.Stderr
	err = xcprettyCommand.Start()
	if err != nil {
		log.Fatal(err)
	}

	err = unitTestCommand.Run()
	if err != nil {
		log.Fatal(err)
	}

	err = xcprettyCommand.Wait()
	if err != nil {
		log.Fatal(err)
	}

	_, err = os.Stdout.Write([]byte("Fleet unit tests passed...\n"))
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


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

package golang

import (
	"encoding/json"
	"fmt"
	"go/build"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

type Environ struct {
	build.Context
}

// Default is the default build environment comprised of the default GOPATH,
// GOROOT, GOOS, GOARCH, and CGO_ENABLED values.
func Default() Environ {
	return Environ{Context: build.Default}
}

// PackageByPath retrieves information about a package by its file system path.
//
// `path` is assumed to be the directory containing the package.
func (c Environ) PackageByPath(path string) (*build.Package, error) {
	abs, err := filepath.Abs(path)
	if err != nil {
		return nil, err
	}
	return c.Context.ImportDir(abs, 0)
}

// Package retrieves information about a package by its Go import path.
func (c Environ) Package(importPath string) (*build.Package, error) {
	return c.Context.Import(importPath, "", 0)
}

// ListPackage matches a subset of the JSON output of the `go list -json`
// command.
//
// See `go help list` for the full structure.
//
// This currently contains an incomplete list of dependencies.
type ListPackage struct {
	Dir        string
	Deps       []string
	GoFiles    []string
	SFiles     []string
	HFiles     []string
	Goroot     bool
	Root       string
	ImportPath string
}

func (c Environ) goCmd(args ...string) *exec.Cmd {
	cmd := exec.Command(filepath.Join(c.GOROOT, "bin", "go"), args...)
	cmd.Env = append(os.Environ(), c.Env()...)
	return cmd
}

// Deps lists all dependencies of the package given by `importPath`.
func (c Environ) Deps(importPath string) (*ListPackage, error) {
	// The output of this is almost the same as build.Import, except for
	// the dependencies.
	cmd := c.goCmd("list", "-json", importPath)
	out, err := cmd.CombinedOutput()
	if err != nil {
		return nil, err
	}

	var p ListPackage
	if err := json.Unmarshal(out, &p); err != nil {
		return nil, err
	}
	return &p, nil
}

func (c Environ) Env() []string {
	var env []string
	if c.GOARCH != "" {
		env = append(env, fmt.Sprintf("GOARCH=%s", c.GOARCH))
	}
	if c.GOOS != "" {
		env = append(env, fmt.Sprintf("GOOS=%s", c.GOOS))
	}
	if c.GOROOT != "" {
		env = append(env, fmt.Sprintf("GOROOT=%s", c.GOROOT))
	}
	if c.GOPATH != "" {
		env = append(env, fmt.Sprintf("GOPATH=%s", c.GOPATH))
	}
	var cgo int8
	if c.CgoEnabled {
		cgo = 1
	}
	env = append(env, fmt.Sprintf("CGO_ENABLED=%d", cgo))
	return env
}

func (c Environ) String() string {
	return strings.Join(c.Env(), " ")
}

// Optional arguments to Environ.Build.
type BuildOpts struct {
	// ExtraArgs to `go build`.
	ExtraArgs []string
}

// Build compiles the package given by `importPath`, writing the build object
// to `binaryPath`.
func (c Environ) Build(importPath string, binaryPath string, opts BuildOpts) error {
	p, err := c.Package(importPath)
	if err != nil {
		return err
	}

	return c.BuildDir(p.Dir, binaryPath, opts)
}

// BuildDir compiles the package in the directory `dirPath`, writing the build
// object to `binaryPath`.
func (c Environ) BuildDir(dirPath string, binaryPath string, opts BuildOpts) error {
	args := []string{
		"build",
		"-a", // Force rebuilding of packages.
		"-o", binaryPath,
		"-installsuffix", "uroot",
		"-ldflags", "-s -w", // Strip all symbols.
	}
	if len(c.BuildTags) > 0 {
		args = append(args, []string{"-tags", strings.Join(c.BuildTags, " ")}...)
	}
	if opts.ExtraArgs != nil {
		args = append(args, opts.ExtraArgs...)
	}
	// We always set the working directory, so this is always '.'.
	args = append(args, ".")

	cmd := c.goCmd(args...)
	cmd.Dir = dirPath

	if o, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("error building go package in %q: %v, %v", dirPath, string(o), err)
	}
	return nil
}
<commit_msg>pkg/golang: add package comment<commit_after>// Copyright 2015-2018 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package golang is an API to the Go compiler.
package golang

import (
	"encoding/json"
	"fmt"
	"go/build"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

type Environ struct {
	build.Context
}

// Default is the default build environment comprised of the default GOPATH,
// GOROOT, GOOS, GOARCH, and CGO_ENABLED values.
func Default() Environ {
	return Environ{Context: build.Default}
}

// PackageByPath retrieves information about a package by its file system path.
//
// `path` is assumed to be the directory containing the package.
func (c Environ) PackageByPath(path string) (*build.Package, error) {
	abs, err := filepath.Abs(path)
	if err != nil {
		return nil, err
	}
	return c.Context.ImportDir(abs, 0)
}

// Package retrieves information about a package by its Go import path.
func (c Environ) Package(importPath string) (*build.Package, error) {
	return c.Context.Import(importPath, "", 0)
}

// ListPackage matches a subset of the JSON output of the `go list -json`
// command.
//
// See `go help list` for the full structure.
//
// This currently contains an incomplete list of dependencies.
type ListPackage struct {
	Dir        string
	Deps       []string
	GoFiles    []string
	SFiles     []string
	HFiles     []string
	Goroot     bool
	Root       string
	ImportPath string
}

func (c Environ) goCmd(args ...string) *exec.Cmd {
	cmd := exec.Command(filepath.Join(c.GOROOT, "bin", "go"), args...)
	cmd.Env = append(os.Environ(), c.Env()...)
	return cmd
}

// Deps lists all dependencies of the package given by `importPath`.
func (c Environ) Deps(importPath string) (*ListPackage, error) {
	// The output of this is almost the same as build.Import, except for
	// the dependencies.
	cmd := c.goCmd("list", "-json", importPath)
	out, err := cmd.CombinedOutput()
	if err != nil {
		return nil, err
	}

	var p ListPackage
	if err := json.Unmarshal(out, &p); err != nil {
		return nil, err
	}
	return &p, nil
}

func (c Environ) Env() []string {
	var env []string
	if c.GOARCH != "" {
		env = append(env, fmt.Sprintf("GOARCH=%s", c.GOARCH))
	}
	if c.GOOS != "" {
		env = append(env, fmt.Sprintf("GOOS=%s", c.GOOS))
	}
	if c.GOROOT != "" {
		env = append(env, fmt.Sprintf("GOROOT=%s", c.GOROOT))
	}
	if c.GOPATH != "" {
		env = append(env, fmt.Sprintf("GOPATH=%s", c.GOPATH))
	}
	var cgo int8
	if c.CgoEnabled {
		cgo = 1
	}
	env = append(env, fmt.Sprintf("CGO_ENABLED=%d", cgo))
	return env
}

func (c Environ) String() string {
	return strings.Join(c.Env(), " ")
}

// Optional arguments to Environ.Build.
type BuildOpts struct {
	// ExtraArgs to `go build`.
	ExtraArgs []string
}

// Build compiles the package given by `importPath`, writing the build object
// to `binaryPath`.
func (c Environ) Build(importPath string, binaryPath string, opts BuildOpts) error {
	p, err := c.Package(importPath)
	if err != nil {
		return err
	}

	return c.BuildDir(p.Dir, binaryPath, opts)
}

// BuildDir compiles the package in the directory `dirPath`, writing the build
// object to `binaryPath`.
func (c Environ) BuildDir(dirPath string, binaryPath string, opts BuildOpts) error {
	args := []string{
		"build",
		"-a", // Force rebuilding of packages.
		"-o", binaryPath,
		"-installsuffix", "uroot",
		"-ldflags", "-s -w", // Strip all symbols.
	}
	if len(c.BuildTags) > 0 {
		args = append(args, []string{"-tags", strings.Join(c.BuildTags, " ")}...)
	}
	if opts.ExtraArgs != nil {
		args = append(args, opts.ExtraArgs...)
	}
	// We always set the working directory, so this is always '.'.
	args = append(args, ".")

	cmd := c.goCmd(args...)
	cmd.Dir = dirPath

	if o, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("error building go package in %q: %v, %v", dirPath, string(o), err)
	}
	return nil
}
<|endoftext|>