<commit_before>package indicators

import (
	"github.com/thetruetrade/gotrade"
)

// A Linear Regression Intercept Indicator (LinRegInt)
type LinRegSlp struct {
	*LinRegWithoutStorage
	selectData gotrade.DataSelectionFunc

	// public variables
	Data []float64
}

// NewLinRegSlp creates a Linear Regression Slope Indicator (LinRegSlp) for online usage
func NewLinRegSlp(timePeriod int, selectData gotrade.DataSelectionFunc) (indicator *LinRegSlp, err error) {
	ind := LinRegSlp{selectData: selectData}
	ind.LinRegWithoutStorage, err = NewLinRegWithoutStorage(timePeriod,
		func(dataItem float64, slope float64, intercept float64, streamBarIndex int) {
			result := slope

			// update the maximum result value
			if result > ind.LinRegWithoutStorage.maxValue {
				ind.LinRegWithoutStorage.maxValue = result
			}

			// update the minimum result value
			if result < ind.LinRegWithoutStorage.minValue {
				ind.LinRegWithoutStorage.minValue = result
			}

			ind.Data = append(ind.Data, result)
		})

	return &ind, err
}

// NewDefaultLinRegSlp creates a Linear Regression Slope Indicator (LinRegSlp) for online usage with default parameters
//	- timePeriod: 14
func NewDefaultLinRegSlp() (indicator *LinRegSlp, err error) {
	timePeriod := 14
	return NewLinRegSlp(timePeriod, gotrade.UseClosePrice)
}

// NewLinRegSlpWithSrcLen creates a Linear Regression Slope Indicator (LinRegSlp) for offline usage
func NewLinRegSlpWithSrcLen(sourceLength uint, timePeriod int, selectData gotrade.DataSelectionFunc) (indicator *LinRegSlp, err error) {
	ind, err := NewLinRegSlp(timePeriod, selectData)

	// only initialise the storage if there is enough source data to require it
	if sourceLength-uint(ind.GetLookbackPeriod()) > 1 {
		ind.Data = make([]float64, 0, sourceLength-uint(ind.GetLookbackPeriod()))
	}

	return ind, err
}

// NewDefaultLinRegSlpWithSrcLen creates a Linear Regression Slope Indicator (LinRegSlp) for offline usage with default parameters
func NewDefaultLinRegSlpWithSrcLen(sourceLength uint) (indicator *LinRegSlp, err error) {
	ind, err := NewDefaultLinRegSlp()

	// only initialise the storage if there is enough source data to require it
	if sourceLength-uint(ind.GetLookbackPeriod()) > 1 {
		ind.Data = make([]float64, 0, sourceLength-uint(ind.GetLookbackPeriod()))
	}

	return ind, err
}

// NewLinRegSlpForStream creates a Linear Regression Slope Indicator (LinRegSlp) for online usage with a source data stream
func NewLinRegSlpForStream(priceStream gotrade.DOHLCVStreamSubscriber, timePeriod int, selectData gotrade.DataSelectionFunc) (indicator *LinRegSlp, err error) {
	ind, err := NewLinRegSlp(timePeriod, selectData)
	priceStream.AddTickSubscription(ind)
	return ind, err
}

// NewDefaultLinRegSlpForStream creates a Linear Regression Slope Indicator (LinRegSlp) for online usage with a source data stream
func NewDefaultLinRegSlpForStream(priceStream gotrade.DOHLCVStreamSubscriber) (indicator *LinRegSlp, err error) {
	ind, err := NewDefaultLinRegSlp()
	priceStream.AddTickSubscription(ind)
	return ind, err
}

// NewLinRegSlpForStreamWithSrcLen creates a Linear Regression Slope Indicator (LinRegSlp) for offline usage with a source data stream
func NewLinRegSlpForStreamWithSrcLen(sourceLength uint, priceStream gotrade.DOHLCVStreamSubscriber, timePeriod int, selectData gotrade.DataSelectionFunc) (indicator *LinRegSlp, err error) {
	ind, err := NewLinRegSlpWithSrcLen(sourceLength, timePeriod, selectData)
	priceStream.AddTickSubscription(ind)
	return ind, err
}

// NewDefaultLinRegSlpForStreamWithSrcLen creates a Linear Regression Slope Indicator (LinRegSlp) for offline usage with a source data stream
func NewDefaultLinRegSlpForStreamWithSrcLen(sourceLength uint, priceStream gotrade.DOHLCVStreamSubscriber) (indicator *LinRegSlp, err error) {
	ind, err := NewDefaultLinRegSlpWithSrcLen(sourceLength)
	priceStream.AddTickSubscription(ind)
	return ind, err
}

// ReceiveDOHLCVTick consumes a source data DOHLCV price tick
func (ind *LinRegSlp) ReceiveDOHLCVTick(tickData gotrade.DOHLCV, streamBarIndex int) {
	var selectedData = ind.selectData(tickData)
	ind.ReceiveTick(selectedData, streamBarIndex)
}
<commit_msg>#76 Remove duplication - linregslp<commit_after>package indicators

import (
	"github.com/thetruetrade/gotrade"
)

// A Linear Regression Intercept Indicator (LinRegInt)
type LinRegSlp struct {
	*LinRegWithoutStorage
	selectData gotrade.DataSelectionFunc

	// public variables
	Data []float64
}

// NewLinRegSlp creates a Linear Regression Slope Indicator (LinRegSlp) for online usage
func NewLinRegSlp(timePeriod int, selectData gotrade.DataSelectionFunc) (indicator *LinRegSlp, err error) {
	ind := LinRegSlp{selectData: selectData}
	ind.LinRegWithoutStorage, err = NewLinRegWithoutStorage(timePeriod,
		func(dataItem float64, slope float64, intercept float64, streamBarIndex int) {
			result := slope

			ind.UpdateMinMax(result, result)

			ind.Data = append(ind.Data, result)
		})

	return &ind, err
}

// NewDefaultLinRegSlp creates a Linear Regression Slope Indicator (LinRegSlp) for online usage with default parameters
//	- timePeriod: 14
func NewDefaultLinRegSlp() (indicator *LinRegSlp, err error) {
	timePeriod := 14
	return NewLinRegSlp(timePeriod, gotrade.UseClosePrice)
}

// NewLinRegSlpWithSrcLen creates a Linear Regression Slope Indicator (LinRegSlp) for offline usage
func NewLinRegSlpWithSrcLen(sourceLength uint, timePeriod int, selectData gotrade.DataSelectionFunc) (indicator *LinRegSlp, err error) {
	ind, err := NewLinRegSlp(timePeriod, selectData)

	// only initialise the storage if there is enough source data to require it
	if sourceLength-uint(ind.GetLookbackPeriod()) > 1 {
		ind.Data = make([]float64, 0, sourceLength-uint(ind.GetLookbackPeriod()))
	}

	return ind, err
}

// NewDefaultLinRegSlpWithSrcLen creates a Linear Regression Slope Indicator (LinRegSlp) for offline usage with default parameters
func NewDefaultLinRegSlpWithSrcLen(sourceLength uint) (indicator *LinRegSlp, err error) {
	ind, err := NewDefaultLinRegSlp()

	// only initialise the storage if there is enough source data to require it
	if sourceLength-uint(ind.GetLookbackPeriod()) > 1 {
		ind.Data = make([]float64, 0, sourceLength-uint(ind.GetLookbackPeriod()))
	}

	return ind, err
}

// NewLinRegSlpForStream creates a Linear Regression Slope Indicator (LinRegSlp) for online usage with a source data stream
func NewLinRegSlpForStream(priceStream gotrade.DOHLCVStreamSubscriber, timePeriod int, selectData gotrade.DataSelectionFunc) (indicator *LinRegSlp, err error) {
	ind, err := NewLinRegSlp(timePeriod, selectData)
	priceStream.AddTickSubscription(ind)
	return ind, err
}

// NewDefaultLinRegSlpForStream creates a Linear Regression Slope Indicator (LinRegSlp) for online usage with a source data stream
func NewDefaultLinRegSlpForStream(priceStream gotrade.DOHLCVStreamSubscriber) (indicator *LinRegSlp, err error) {
	ind, err := NewDefaultLinRegSlp()
	priceStream.AddTickSubscription(ind)
	return ind, err
}

// NewLinRegSlpForStreamWithSrcLen creates a Linear Regression Slope Indicator (LinRegSlp) for offline usage with a source data stream
func NewLinRegSlpForStreamWithSrcLen(sourceLength uint, priceStream gotrade.DOHLCVStreamSubscriber, timePeriod int, selectData gotrade.DataSelectionFunc) (indicator *LinRegSlp, err error) {
	ind, err := NewLinRegSlpWithSrcLen(sourceLength, timePeriod, selectData)
	priceStream.AddTickSubscription(ind)
	return ind, err
}

// NewDefaultLinRegSlpForStreamWithSrcLen creates a Linear Regression Slope Indicator (LinRegSlp) for offline usage with a source data stream
func NewDefaultLinRegSlpForStreamWithSrcLen(sourceLength uint, priceStream gotrade.DOHLCVStreamSubscriber) (indicator *LinRegSlp, err error) {
	ind, err := NewDefaultLinRegSlpWithSrcLen(sourceLength)
	priceStream.AddTickSubscription(ind)
	return ind, err
}

// ReceiveDOHLCVTick consumes a source data DOHLCV price tick
func (ind *LinRegSlp) ReceiveDOHLCVTick(tickData gotrade.DOHLCV, streamBarIndex int) {
	var selectedData = ind.selectData(tickData)
	ind.ReceiveTick(selectedData, streamBarIndex)
}
<|endoftext|>


<commit_before>package cloudformation

import (
	"encoding/base64"
	"strings"
)

// Note: Intrinsic objects are Base64 encoded, to prevent escaping (backslash) issues
// with nested intrinsic functions.

// Ref creates a CloudFormation Reference to another resource in the template
func Ref(logicalName string) string {
	return encode(`{ "Ref": "` + logicalName + `" }`)
}

// GetAtt returns the value of an attribute from a resource in the template.
func GetAtt(logicalName string, attribute string) string {
	return encode(`{ "Fn::GetAtt": [ "` + logicalName + `", "` + attribute + `" ] }`)
}

// ImportValue returns the value of an output exported by another stack. You typically use this function to create cross-stack references. In the following example template snippets, Stack A exports VPC security group values and Stack B imports them.
func ImportValue(name string) string {
	return encode(`{ "Fn::ImportValue": "` + name + `" }`)
}

// Base64 returns the Base64 representation of the input string. This function is typically used to pass encoded data to Amazon EC2 instances by way of the UserData property
func Base64(input string) string {
	return encode(`{ "Fn::Base64": "` + input + `" }`)
}

// CIDR returns an array of CIDR address blocks. The number of CIDR blocks returned is dependent on the count parameter.
func CIDR(ipBlock, count, cidrBits string) string {
	return encode(`{ "Fn::Cidr" : [ "` + ipBlock + `", "` + count + `", "` + cidrBits + `" ] }`)
}

// FindInMap returns the value corresponding to keys in a two-level map that is declared in the Mappings section.
func FindInMap(mapName, topLevelKey, secondLevelKey string) string {
	return encode(`{ "Fn::FindInMap" : [ "` + mapName + `", "` + topLevelKey + `", "` + secondLevelKey + `" ] }`)
}

// GetAZs returns an array that lists Availability Zones for a specified region. Because customers have access to different Availability Zones, the intrinsic function Fn::GetAZs enables template authors to write templates that adapt to the calling user's access. That way you don't have to hard-code a full list of Availability Zones for a specified region.
func GetAZs(region string) string {
	return encode(`{ "Fn::GetAZs": "` + region + `" }`)
}

// Join appends a set of values into a single value, separated by the specified delimiter. If a delimiter is the empty string, the set of values are concatenated with no delimiter.
func Join(delimiter string, values []string) string {
	return encode(`{ "Fn::Join": [ "` + delimiter + `", [ "` + strings.Trim(strings.Join(values, `", "`), `, "`) + `" ] ] }`)
}

// Select returns a single object from a list of objects by index.
func Select(index string, list []string) string {
	return encode(`{ "Fn::Select": [ "` + index + `", [ "` + strings.Trim(strings.Join(list, `", "`), `, "`) + `" ] ] }`)
}

// Split splits a string into a list of string values so that you can select an element from the resulting string list, use the Fn::Split intrinsic function. Specify the location of splits with a delimiter, such as , (a comma). After you split a string, use the Fn::Select function to pick a specific element.
func Split(delimiter, source string) string {
	return encode(`{ "Fn::Split" : [ "` + delimiter + `", "` + source + `" ] }`)
}

// Sub substitutes variables in an input string with values that you specify. In your templates, you can use this function to construct commands or outputs that include values that aren't available until you create or update a stack.
func Sub(value string) string {
	return encode(`{ "Fn::Sub" : "` + value + `" }`)
}

// encode takes a string representation of an intrinsic function, and base64 encodes it.
// This prevents the escaping issues when nesting multiple layers of intrinsic functions.
func encode(value string) string {
	return base64.StdEncoding.EncodeToString([]byte(value))
}
<commit_msg>Added support for composing templates with cloudformation conditionals (Fn::And, Fn::Or etc)<commit_after>package cloudformation

import (
	"encoding/base64"
	"strings"
)

// Note: Intrinsic objects are Base64 encoded, to prevent escaping (backslash) issues
// with nested intrinsic functions.

// Ref creates a CloudFormation Reference to another resource in the template
func Ref(logicalName string) string {
	return encode(`{ "Ref": "` + logicalName + `" }`)
}

// GetAtt returns the value of an attribute from a resource in the template.
func GetAtt(logicalName string, attribute string) string {
	return encode(`{ "Fn::GetAtt": [ "` + logicalName + `", "` + attribute + `" ] }`)
}

// ImportValue returns the value of an output exported by another stack. You typically use this function to create cross-stack references. In the following example template snippets, Stack A exports VPC security group values and Stack B imports them.
func ImportValue(name string) string {
	return encode(`{ "Fn::ImportValue": "` + name + `" }`)
}

// Base64 returns the Base64 representation of the input string. This function is typically used to pass encoded data to Amazon EC2 instances by way of the UserData property
func Base64(input string) string {
	return encode(`{ "Fn::Base64": "` + input + `" }`)
}

// CIDR returns an array of CIDR address blocks. The number of CIDR blocks returned is dependent on the count parameter.
func CIDR(ipBlock, count, cidrBits string) string {
	return encode(`{ "Fn::Cidr" : [ "` + ipBlock + `", "` + count + `", "` + cidrBits + `" ] }`)
}

// FindInMap returns the value corresponding to keys in a two-level map that is declared in the Mappings section.
func FindInMap(mapName, topLevelKey, secondLevelKey string) string {
	return encode(`{ "Fn::FindInMap" : [ "` + mapName + `", "` + topLevelKey + `", "` + secondLevelKey + `" ] }`)
}

// GetAZs returns an array that lists Availability Zones for a specified region. Because customers have access to different Availability Zones, the intrinsic function Fn::GetAZs enables template authors to write templates that adapt to the calling user's access. That way you don't have to hard-code a full list of Availability Zones for a specified region.
func GetAZs(region string) string {
	return encode(`{ "Fn::GetAZs": "` + region + `" }`)
}

// Join appends a set of values into a single value, separated by the specified delimiter. If a delimiter is the empty string, the set of values are concatenated with no delimiter.
func Join(delimiter string, values []string) string {
	return encode(`{ "Fn::Join": [ "` + delimiter + `", [ "` + strings.Trim(strings.Join(values, `", "`), `, "`) + `" ] ] }`)
}

// Select returns a single object from a list of objects by index.
func Select(index string, list []string) string {
	return encode(`{ "Fn::Select": [ "` + index + `", [ "` + strings.Trim(strings.Join(list, `", "`), `, "`) + `" ] ] }`)
}

// Split splits a string into a list of string values so that you can select an element from the resulting string list, use the Fn::Split intrinsic function. Specify the location of splits with a delimiter, such as , (a comma). After you split a string, use the Fn::Select function to pick a specific element.
func Split(delimiter, source string) string {
	return encode(`{ "Fn::Split" : [ "` + delimiter + `", "` + source + `" ] }`)
}

// Sub substitutes variables in an input string with values that you specify. In your templates, you can use this function to construct commands or outputs that include values that aren't available until you create or update a stack.
func Sub(value string) string {
	return encode(`{ "Fn::Sub" : "` + value + `" }`)
}

// And returns true if all the specified conditions evaluate to true, or returns false if any one of the conditions evaluates to false. Fn::And acts as an AND operator. The minimum number of conditions that you can include is 2, and the maximum is 10.
func And(condition string, list []string) string {
	return encode(`{ "Fn::And": [ "` + condition + `", [ "` + strings.Trim(strings.Join(list, `", "`), `, "`) + `" ] ] }`)
}

// Equals compares if two values are equal. Returns true if the two values are equal or false if they aren't.
func Equals(value1, value2 string) string {
	return encode(`{ "Fn::Equals" : [ "` + value1 + `", "` + value2 + `" ] }`)
}

// If returns one value if the specified condition evaluates to true and another value if the specified condition evaluates to false. Currently, AWS CloudFormation supports the Fn::If intrinsic function in the metadata attribute, update policy attribute, and property values in the Resources section and Outputs sections of a template. You can use the AWS::NoValue pseudo parameter as a return value to remove the corresponding property.
func If(value, ifEqual, ifNotEqual string) string {
	return encode(`{ "Fn::If" : [ "` + value + `", "` + ifEqual + `", "` + ifNotEqual + `" ] }`)
}

// Not returns true for a condition that evaluates to false or returns false for a condition that evaluates to true. Fn::Not acts as a NOT operator.
func Not(conditions []string) string {
	return encode(`{ "Fn::Not": [ "` + strings.Trim(strings.Join(conditions, `", "`), `, "`) + `" ] }`)
}

// Or returns true if any one of the specified conditions evaluate to true, or returns false if all of the conditions evaluates to false. Fn::Or acts as an OR operator. The minimum number of conditions that you can include is 2, and the maximum is 10.
func Or(conditions []string) string {
	return encode(`{ "Fn::Or": [ "` + strings.Trim(strings.Join(conditions, `", "`), `, "`) + `" ] }`)
}

// encode takes a string representation of an intrinsic function, and base64 encodes it.
// This prevents the escaping issues when nesting multiple layers of intrinsic functions.
func encode(value string) string {
	return base64.StdEncoding.EncodeToString([]byte(value))
}
<|endoftext|>


<commit_before>package pagerduty

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

const (
	eventsAPIPath = "generic/2010-04-15/create_event.json"

	ContextTypeLink  = "link"
	ContextTypeImage = "image"

	EventTypeAcknowledge = "acknowledge"
	EventTypeResolve     = "resolve"
	EventTypeTrigger     = "trigger"
)

// NewEventRequest creates an API request for the PagerDuty Events API. It has
// the same requirements and behaviors as Client.NewRequest.
func (c *Client) NewEventRequest(method, path string, body interface{}) (*http.Request, error) {
	return newRequest(c.EventsURL, method, path, body)
}

type EventResponse struct {
	Response *http.Response

	Status      string   `json:"status,omitempty"`
	Message     string   `json:"message,omitempty"`
	IncidentKey string   `json:"incident_key,omitempty"`
	Errors      []string `json:"errors,omitempty"`
}

// DoEventRequest sends a request to the PagerDuty Events API and returns the
// response.
func (c *Client) DoEventRequest(req *http.Request) (*EventResponse, error) {
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}

	eventResp := new(EventResponse)
	err = json.NewDecoder(resp.Body).Decode(eventResp)
	if err != nil {
		return nil, err
	}

	eventResp.Response = resp
	return eventResp, nil
}

// EventsService handles communication with the PagerDuty Events API.
//
// https://developer.pagerduty.com/documentation/integration/events
type EventsService struct {
	client *Client
}

type Event struct {
	Type        *string                `json:"event_type,omitempty"`
	ServiceKey  *string                `json:"service_key,omitempty"`
	Description *string                `json:"description,omitempty"`
	IncidentKey *string                `json:"incident_key,omitempty"`
	Client      *string                `json:"client,omitempty"`
	ClientURL   *string                `json:"client_url,omitempty"`
	Details     map[string]interface{} `json:"details,omitempty"`

	// NOTE: Contexts should contain only LinkContext or ImageContext structs.
	Contexts []interface{} `json:"contexts,omitempty"`
}

type LinkContext struct {
	// The type of context being attached to the incident. Possible values are
	// 'link' and 'image'.
	Type string `json:"type,omitempty"`

	// The link to either the incident being attached or image.
	Href string `json:"href,omitempty"`

	// Options information pertaining to the incident.
	Text string `json:"test,omitempty"`
}

type ImageContext struct {
	// The type of context being attached to the incident. Possible values are
	// 'link' and 'image'.
	Type string `json:"type,omitempty"`

	// The source of the image being attached to the incident. This must be
	// served via HTTPS.
	Source string `json:"src,omitempty"`

	// Optional link for the image.
	Href string `json:"href,omitempty"`

	// Optional alternative text for the image.
	Alt string `json:"alt,omitempty"`
}

// helper function to post an event and unmarshal the event response.
func (s *EventsService) postEvent(event *Event, eventType string) (*EventResponse, error) {
	if event == nil {
		return nil, fmt.Errorf("pagerduty: event cannot be nil")
	}

	event.Type = String(eventType)
	req, err := s.client.NewEventRequest(POST, eventsAPIPath, event)
	if err != nil {
		return nil, err
	}

	return s.client.DoEventRequest(req)
}

// Acknowledge an event (incident).
//
// https://developer.pagerduty.com/documentation/integration/events/acknowledge
func (s *EventsService) Acknowledge(event *Event) (*EventResponse, error) {
	return s.postEvent(event, EventTypeAcknowledge)
}

// Resolve an event (incident).
//
// https://developer.pagerduty.com/documentation/integration/events/resolve
func (s *EventsService) Resolve(event *Event) (*EventResponse, error) {
	return s.postEvent(event, EventTypeResolve)
}

// Trigger an event (incident).
//
// https://developer.pagerduty.com/documentation/integration/events/trigger
func (s *EventsService) Trigger(event *Event) (*EventResponse, error) {
	return s.postEvent(event, EventTypeTrigger)
}
<commit_msg>Added some public constants for detecting the outcome of an event request.<commit_after>package pagerduty

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

const (
	eventsAPIPath = "generic/2010-04-15/create_event.json"

	ContextTypeLink  = "link"
	ContextTypeImage = "image"

	EventTypeAcknowledge = "acknowledge"
	EventTypeResolve     = "resolve"
	EventTypeTrigger     = "trigger"

	EventStatusSuccess = "success"
	EventStatusError   = "invalid event"
)

// NewEventRequest creates an API request for the PagerDuty Events API. It has
// the same requirements and behaviors as Client.NewRequest.
func (c *Client) NewEventRequest(method, path string, body interface{}) (*http.Request, error) {
	return newRequest(c.EventsURL, method, path, body)
}

type EventResponse struct {
	Response *http.Response

	Status      string   `json:"status,omitempty"`
	Message     string   `json:"message,omitempty"`
	IncidentKey string   `json:"incident_key,omitempty"`
	Errors      []string `json:"errors,omitempty"`
}

// DoEventRequest sends a request to the PagerDuty Events API and returns the
// response.
func (c *Client) DoEventRequest(req *http.Request) (*EventResponse, error) {
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}

	eventResp := new(EventResponse)
	err = json.NewDecoder(resp.Body).Decode(eventResp)
	if err != nil {
		return nil, err
	}

	eventResp.Response = resp
	return eventResp, nil
}

// EventsService handles communication with the PagerDuty Events API.
//
// https://developer.pagerduty.com/documentation/integration/events
type EventsService struct {
	client *Client
}

type Event struct {
	Type        *string                `json:"event_type,omitempty"`
	ServiceKey  *string                `json:"service_key,omitempty"`
	Description *string                `json:"description,omitempty"`
	IncidentKey *string                `json:"incident_key,omitempty"`
	Client      *string                `json:"client,omitempty"`
	ClientURL   *string                `json:"client_url,omitempty"`
	Details     map[string]interface{} `json:"details,omitempty"`

	// NOTE: Contexts should contain only LinkContext or ImageContext structs.
	Contexts []interface{} `json:"contexts,omitempty"`
}

type LinkContext struct {
	// The type of context being attached to the incident. Possible values are
	// 'link' and 'image'.
	Type string `json:"type,omitempty"`

	// The link to either the incident being attached or image.
	Href string `json:"href,omitempty"`

	// Options information pertaining to the incident.
	Text string `json:"test,omitempty"`
}

type ImageContext struct {
	// The type of context being attached to the incident. Possible values are
	// 'link' and 'image'.
	Type string `json:"type,omitempty"`

	// The source of the image being attached to the incident. This must be
	// served via HTTPS.
	Source string `json:"src,omitempty"`

	// Optional link for the image.
	Href string `json:"href,omitempty"`

	// Optional alternative text for the image.
	Alt string `json:"alt,omitempty"`
}

// helper function to post an event and unmarshal the event response.
func (s *EventsService) postEvent(event *Event, eventType string) (*EventResponse, error) {
	if event == nil {
		return nil, fmt.Errorf("pagerduty: event cannot be nil")
	}

	event.Type = String(eventType)
	req, err := s.client.NewEventRequest(POST, eventsAPIPath, event)
	if err != nil {
		return nil, err
	}

	return s.client.DoEventRequest(req)
}

// Acknowledge an event (incident).
//
// https://developer.pagerduty.com/documentation/integration/events/acknowledge
func (s *EventsService) Acknowledge(event *Event) (*EventResponse, error) {
	return s.postEvent(event, EventTypeAcknowledge)
}

// Resolve an event (incident).
//
// https://developer.pagerduty.com/documentation/integration/events/resolve
func (s *EventsService) Resolve(event *Event) (*EventResponse, error) {
	return s.postEvent(event, EventTypeResolve)
}

// Trigger an event (incident).
//
// https://developer.pagerduty.com/documentation/integration/events/trigger
func (s *EventsService) Trigger(event *Event) (*EventResponse, error) {
	return s.postEvent(event, EventTypeTrigger)
}
<|endoftext|>


<commit_before>package app

import (
	"fmt"
	"gnd.la/app/profile"
	"gnd.la/loaders"
	"gnd.la/template"
	"gnd.la/template/assets"
	"gnd.la/util/internal/templateutil"
	"io"
	"net/http"
	"os"
	"text/template/parse"
)

var (
	reservedVariables     = []string{"Ctx", "Request"}
	internalAssetsManager = assets.NewManager(appAssets, assetsPrefix)
	profileHook           *template.Hook
)

type Template interface {
	Template() *template.Template
	Execute(w io.Writer, data interface{}) error
	ExecuteTemplate(w io.Writer, name string, data interface{}) error
	ExecuteVars(w io.Writer, data interface{}, vars map[string]interface{}) error
	ExecuteTemplateVars(w io.Writer, name string, data interface{}, vars map[string]interface{}) error
}

type TemplateProcessor func(*template.Template) (*template.Template, error)

type tmpl struct {
	tmpl *template.Template
	app  *App
}

func (t *tmpl) reverse(name string, args ...interface{}) (string, error) {
	if t.app != nil {
		return t.app.reverse(name, args)
	}
	return "", fmt.Errorf("can't reverse %s because the app is not available", name)
}

func newTemplate(app *App, loader loaders.Loader, manager *assets.Manager) *tmpl {
	t := &tmpl{}
	t.app = app
	t.tmpl = template.New(loader, manager)
	t.tmpl.Debug = app.TemplateDebug
	t.tmpl.Funcs(template.FuncMap{
		"reverse": t.reverse,
		"t":       nop,
		"tn":      nop,
		"tc":      nop,
		"tnc":     nop,
	})
	return t
}

func newAppTemplate(app *App) *tmpl {
	return newTemplate(app, app.templatesLoader, app.assetsManager)
}

func newInternalTemplate(app *App) *tmpl {
	return newTemplate(app, appAssets, internalAssetsManager)
}

func (t *tmpl) ParseVars(file string, vars template.VarMap) error {
	if vars != nil {
		for _, k := range reservedVariables {
			vars[k] = nil
		}
	}
	return t.tmpl.ParseVars(file, vars)
}

func (t *tmpl) Parse(file string) error {
	return t.ParseVars(file, nil)
}

func (t *tmpl) execute(w io.Writer, name string, data interface{}, vars template.VarMap) error {
	// TODO: Don't ignore received cars
	var context *Context
	var request *http.Request
	if context, _ = w.(*Context); context != nil {
		request = context.R
	}
	var tvars map[string]interface{}
	var err error
	if t.app.namespace != nil {
		tvars, err = t.app.namespace.eval(context)
		if err != nil {
			return err
		}
	} else {
		tvars = make(map[string]interface{})
	}
	tvars["Ctx"] = context
	tvars["Request"] = request
	if name == "" {
		name = t.tmpl.Root()
	}
	return t.tmpl.ExecuteTemplateVars(w, name, data, tvars)
}

func (t *tmpl) Template() *template.Template {
	return t.tmpl
}

func (t *tmpl) Execute(w io.Writer, data interface{}) error {
	return t.execute(w, "", data, nil)
}

func (t *tmpl) ExecuteTemplate(w io.Writer, name string, data interface{}) error {
	return t.execute(w, name, data, nil)
}

func (t *tmpl) ExecuteVars(w io.Writer, data interface{}, vars map[string]interface{}) error {
	return t.execute(w, "", data, vars)
}

func (t *tmpl) ExecuteTemplateVars(w io.Writer, name string, data interface{}, vars map[string]interface{}) error {
	return t.execute(w, name, data, vars)
}

func (t *tmpl) replaceNode(n, p parse.Node, fname string) error {
	nn := &parse.VariableNode{
		NodeType: parse.NodeVariable,
		Pos:      n.Position(),
		Ident:    []string{"$Vars", "Ctx", fname},
	}
	return templateutil.ReplaceNode(n, p, nn)
}

func (t *tmpl) rewriteTranslationFuncs() error {
	for _, tr := range t.tmpl.Trees() {
		var err error
		templateutil.WalkTree(tr, func(n, p parse.Node) {
			if err != nil {
				return
			}
			if n.Type() == parse.NodeIdentifier {
				id := n.(*parse.IdentifierNode)
				switch id.Ident {
				case "t":
					err = t.replaceNode(n, p, "T")
				case "tn":
					err = t.replaceNode(n, p, "Tn")
				case "tc":
					err = t.replaceNode(n, p, "Tc")
				case "tnc":
					err = t.replaceNode(n, p, "Tnc")
				}
			}
		})
		if err != nil {
			return err
		}
	}
	return nil
}

func (t *tmpl) prepare() error {
	if err := t.tmpl.Compile(); err != nil {
		return err
	}
	return nil
}

func nop() interface{} { return nil }

func init() {
	if profile.On {
		inDevServer = os.Getenv("GONDOLA_DEV_SERVER") != ""
		if inDevServer {
			t := newInternalTemplate(&App{})
			t.tmpl.Funcs(template.FuncMap{
				"_gondola_profile_info": getProfileInfo,
				"_gondola_internal_asset": func(arg string) string {
					return internalAssetsManager.URL(arg)
				},
			})
			if err := t.Parse("profile.html"); err != nil {
				panic(err)
			}
			profileHook = &template.Hook{Template: t.tmpl, Position: assets.Bottom}
		}
	}
}
<commit_msg>Mark reverse function as pure<commit_after>package app

import (
	"fmt"
	"gnd.la/app/profile"
	"gnd.la/loaders"
	"gnd.la/template"
	"gnd.la/template/assets"
	"gnd.la/util/internal/templateutil"
	"io"
	"net/http"
	"os"
	"text/template/parse"
)

var (
	reservedVariables     = []string{"Ctx", "Request"}
	internalAssetsManager = assets.NewManager(appAssets, assetsPrefix)
	profileHook           *template.Hook
)

type Template interface {
	Template() *template.Template
	Execute(w io.Writer, data interface{}) error
	ExecuteTemplate(w io.Writer, name string, data interface{}) error
	ExecuteVars(w io.Writer, data interface{}, vars map[string]interface{}) error
	ExecuteTemplateVars(w io.Writer, name string, data interface{}, vars map[string]interface{}) error
}

type TemplateProcessor func(*template.Template) (*template.Template, error)

type tmpl struct {
	tmpl *template.Template
	app  *App
}

func (t *tmpl) reverse(name string, args ...interface{}) (string, error) {
	if t.app != nil {
		return t.app.reverse(name, args)
	}
	return "", fmt.Errorf("can't reverse %s because the app is not available", name)
}

func newTemplate(app *App, loader loaders.Loader, manager *assets.Manager) *tmpl {
	t := &tmpl{}
	t.app = app
	t.tmpl = template.New(loader, manager)
	t.tmpl.Debug = app.TemplateDebug
	t.tmpl.Funcs(template.FuncMap{
		"#reverse": t.reverse,
		"t":        nop,
		"tn":       nop,
		"tc":       nop,
		"tnc":      nop,
	})
	return t
}

func newAppTemplate(app *App) *tmpl {
	return newTemplate(app, app.templatesLoader, app.assetsManager)
}

func newInternalTemplate(app *App) *tmpl {
	return newTemplate(app, appAssets, internalAssetsManager)
}

func (t *tmpl) ParseVars(file string, vars template.VarMap) error {
	if vars != nil {
		for _, k := range reservedVariables {
			vars[k] = nil
		}
	}
	return t.tmpl.ParseVars(file, vars)
}

func (t *tmpl) Parse(file string) error {
	return t.ParseVars(file, nil)
}

func (t *tmpl) execute(w io.Writer, name string, data interface{}, vars template.VarMap) error {
	// TODO: Don't ignore received cars
	var context *Context
	var request *http.Request
	if context, _ = w.(*Context); context != nil {
		request = context.R
	}
	var tvars map[string]interface{}
	var err error
	if t.app.namespace != nil {
		tvars, err = t.app.namespace.eval(context)
		if err != nil {
			return err
		}
	} else {
		tvars = make(map[string]interface{})
	}
	tvars["Ctx"] = context
	tvars["Request"] = request
	if name == "" {
		name = t.tmpl.Root()
	}
	return t.tmpl.ExecuteTemplateVars(w, name, data, tvars)
}

func (t *tmpl) Template() *template.Template {
	return t.tmpl
}

func (t *tmpl) Execute(w io.Writer, data interface{}) error {
	return t.execute(w, "", data, nil)
}

func (t *tmpl) ExecuteTemplate(w io.Writer, name string, data interface{}) error {
	return t.execute(w, name, data, nil)
}

func (t *tmpl) ExecuteVars(w io.Writer, data interface{}, vars map[string]interface{}) error {
	return t.execute(w, "", data, vars)
}

func (t *tmpl) ExecuteTemplateVars(w io.Writer, name string, data interface{}, vars map[string]interface{}) error {
	return t.execute(w, name, data, vars)
}

func (t *tmpl) replaceNode(n, p parse.Node, fname string) error {
	nn := &parse.VariableNode{
		NodeType: parse.NodeVariable,
		Pos:      n.Position(),
		Ident:    []string{"$Vars", "Ctx", fname},
	}
	return templateutil.ReplaceNode(n, p, nn)
}

func (t *tmpl) rewriteTranslationFuncs() error {
	for _, tr := range t.tmpl.Trees() {
		var err error
		templateutil.WalkTree(tr, func(n, p parse.Node) {
			if err != nil {
				return
			}
			if n.Type() == parse.NodeIdentifier {
				id := n.(*parse.IdentifierNode)
				switch id.Ident {
				case "t":
					err = t.replaceNode(n, p, "T")
				case "tn":
					err = t.replaceNode(n, p, "Tn")
				case "tc":
					err = t.replaceNode(n, p, "Tc")
				case "tnc":
					err = t.replaceNode(n, p, "Tnc")
				}
			}
		})
		if err != nil {
			return err
		}
	}
	return nil
}

func (t *tmpl) prepare() error {
	if err := t.tmpl.Compile(); err != nil {
		return err
	}
	return nil
}

func nop() interface{} { return nil }

func init() {
	if profile.On {
		inDevServer = os.Getenv("GONDOLA_DEV_SERVER") != ""
		if inDevServer {
			t := newInternalTemplate(&App{})
			t.tmpl.Funcs(template.FuncMap{
				"_gondola_profile_info": getProfileInfo,
				"_gondola_internal_asset": func(arg string) string {
					return internalAssetsManager.URL(arg)
				},
			})
			if err := t.Parse("profile.html"); err != nil {
				panic(err)
			}
			profileHook = &template.Hook{Template: t.tmpl, Position: assets.Bottom}
		}
	}
}
<|endoftext|>


<commit_before>package core6502

func SignExtend8To16(val uint8) uint16 {
	return uint16(int16(int8(val)))
}

func AddWithCarry8(a, b uint8, carry bool) (uint8, bool) {
	res := SignExtend8To16(a) + SignExtend8To16(b)
	if carry {
		res++
	}

	if res > 0xff {
		carry = true
	}

	return uint8(res), carry
}

func SubWithCarry8(a, b uint8, carry bool) (uint8, bool) {
	res := SignExtend8To16(a) - SignExtend8To16(b)
	if carry {
		res--
	}

	if res > 0xff {
		carry = true
	}

	return uint8(res), carry
}

// carry << val << carry
func LogicalShiftLeft8(a uint8, carry bool) (uint8, bool) {
	res := uint16(a) << 1
	if carry {
		res |= 1
	}

	if res > 0xff {
		carry = true
	}

	return uint8(res), carry
}

// carry >> val >> carry
func LogicalShiftRight8(a uint8, carry bool) (uint8, bool) {
	res := a >> 1
	if carry {
		res |= 0x80
	}

	if a&1 != 0 {
		carry = true
	}

	return res, carry
}

// carry >> val >> carry
func ArithmeticShiftRight8(a uint8) (uint8, bool) {
	res := int8(a) >> 1

	carry := false
	if a&1 != 0 {
		carry = true
	}

	return uint8(res), carry
}
<commit_msg>adding alu primatives<commit_after>package core6502

func SignExtend8To16(val uint8) uint16 {
	return uint16(int16(int8(val)))
}

func AddWithCarry8(a, b uint8, carry bool) (uint8, bool) {
	res := SignExtend8To16(a) + SignExtend8To16(b)
	if carry {
		res++
	}

	if res > 0xff {
		carry = true
	}

	return uint8(res), carry
}

func SubWithCarry8(a, b uint8, carry bool) (uint8, bool) {
	res := SignExtend8To16(a) - SignExtend8To16(b)
	if carry {
		res--
	}

	if res > 0xff {
		carry = true
	}

	return uint8(res), carry
}

// carry << val << carry
func LogicalShiftLeft8(a uint8, carry bool) (uint8, bool) {
	res := uint16(a) << 1
	if carry {
		res |= 1
	}

	if res > 0xff {
		carry = true
	}

	return uint8(res), carry
}

// carry >> val >> carry
func LogicalShiftRight8(a uint8, carry bool) (uint8, bool) {
	res := a >> 1
	if carry {
		res |= 0x80
	}

	if a&1 != 0 {
		carry = true
	}

	return res, carry
}

// msb(val) >> val >> carry
func ArithmeticShiftRight8(a uint8) (uint8, bool) {
	res := int8(a) >> 1

	carry := false
	if a&1 != 0 {
		carry = true
	}

	return uint8(res), carry
}
<|endoftext|>


<commit_before>package command

import (
	"fmt"

	"github.com/getantibody/antibody/shell"
	"github.com/urfave/cli"
)

// Init prints out the antibody's shell init script
var Init = cli.Command{
	Name:  "init",
	Usage: "Initializes the shell so Antibody can work as expected.",
	Action: func(ctx *cli.Context) error {
		fmt.Println(shell.Init())
		return nil
	},
}
<commit_msg>minor typo fix<commit_after>package command

import (
	"fmt"

	"github.com/getantibody/antibody/shell"
	"github.com/urfave/cli"
)

// Init prints out the antibody's shell init script
var Init = cli.Command{
	Name:  "init",
	Usage: "Initializes the shell so Antibody can work as expected",
	Action: func(ctx *cli.Context) error {
		fmt.Println(shell.Init())
		return nil
	},
}
<|endoftext|>


<commit_before>package cmd

import (
	"context"
	"crypto/sha1"
	"fmt"
	"io"
	"os"

	"github.com/immofon/databoard"
	"github.com/juju/errors"
	"github.com/spf13/cobra"
)

// publishCmd represents the publish command
var publishCmd = &cobra.Command{
	Use: "publish",
}

func init() {
	RootCmd.AddCommand(publishCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// publishCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// publishCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

	publishCmd.Run = func(cmd *cobra.Command, args []string) {
		if len(args) == 0 {
			publishCmd.Usage()
			exit(1)
		}

		switch {
		case owner == "":
			exit(2, "require owner")
		case repo == "":
			exit(3, "require repo")
		case token == "":
			exit(4, "require token")
		}

		passphare, err := getPassphare()
		if err != nil {
			exit(5, "require passphare\n", errors.ErrorStack(errors.Trace(err)))
		}

		// packet data.tar.gz.gpg
		basedir := fmt.Sprintf("/tmp/databoard-%d", os.Getpid())
		defer os.RemoveAll(basedir)
		asset, err := Packet(basedir, "", passphare, args)
		if err != nil {
			exit(6, errors.ErrorStack(errors.Trace(err)))
		}

		// generate tag name via sha1 sum
		tagName, err := sha1file(asset)
		if err != nil {
			exit(7, errors.ErrorStack(errors.Trace(err)))
		}

		tagName = "v." + tagName

		// create new release by tagName
		ctx := context.Background()

		d := databoard.New(nil, token)
		d.Owner = owner
		d.Repo = repo
		release, err := d.CreateRelease(ctx, tagName)
		if err != nil {
			exit(7, errors.ErrorStack(errors.Annotatef(err, "Databoard.CreateRelease <tag_name:%q>", tagName)))
		}
		release_id := *(release.ID)

		// upload data.tar.gz.gpg as release asset
		assetFile, err := os.Open(asset)
		if err != nil {
			exit(8, errors.ErrorStack(errors.Trace(err)))
		}

		_, err = d.UploadReleaseAsset(ctx, release_id, assetFile, "data.tar.gz.gpg")
		if err != nil {
			exit(9, errors.ErrorStack(errors.Annotatef(err, "Databoard.UploadReleaseAsset <release_id:%d>", release_id)))
		}
	}
}

func sha1file(file string) (sum string, err error) {
	f, err := os.Open(file)
	if err != nil {
		return "", errors.Trace(err)
	}
	defer f.Close()

	h := sha1.New()
	if _, err := io.Copy(h, f); err != nil {
		return "", errors.Trace(err)
	}

	return fmt.Sprintf("%x", h.Sum(nil)), nil
}
<commit_msg>fix: use func newDataboard in cmd publish<commit_after>package cmd

import (
	"context"
	"crypto/sha1"
	"fmt"
	"io"
	"os"

	"github.com/juju/errors"
	"github.com/spf13/cobra"
)

// publishCmd represents the publish command
var publishCmd = &cobra.Command{
	Use: "publish",
}

func init() {
	RootCmd.AddCommand(publishCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// publishCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// publishCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

	publishCmd.Run = func(cmd *cobra.Command, args []string) {
		if len(args) == 0 {
			publishCmd.Usage()
			exit(1)
		}

		switch {
		case owner == "":
			exit(2, "require owner")
		case repo == "":
			exit(3, "require repo")
		case token == "":
			exit(4, "require token")
		}

		passphare, err := getPassphare()
		if err != nil {
			exit(5, "require passphare\n", errors.ErrorStack(errors.Trace(err)))
		}

		// packet data.tar.gz.gpg
		basedir := fmt.Sprintf("/tmp/databoard-%d", os.Getpid())
		defer os.RemoveAll(basedir)
		asset, err := Packet(basedir, "", passphare, args)
		if err != nil {
			exit(6, errors.ErrorStack(errors.Trace(err)))
		}

		// generate tag name via sha1 sum
		tagName, err := sha1file(asset)
		if err != nil {
			exit(7, errors.ErrorStack(errors.Trace(err)))
		}

		tagName = "v." + tagName

		// create new release by tagName
		ctx := context.Background()
		d := newDataboard()

		release, err := d.CreateRelease(ctx, tagName)
		if err != nil {
			exit(7, errors.ErrorStack(errors.Annotatef(err, "Databoard.CreateRelease <tag_name:%q>", tagName)))
		}
		release_id := *(release.ID)

		// upload data.tar.gz.gpg as release asset
		assetFile, err := os.Open(asset)
		if err != nil {
			exit(8, errors.ErrorStack(errors.Trace(err)))
		}

		_, err = d.UploadReleaseAsset(ctx, release_id, assetFile, "data.tar.gz.gpg")
		if err != nil {
			exit(9, errors.ErrorStack(errors.Annotatef(err, "Databoard.UploadReleaseAsset <release_id:%d>", release_id)))
		}
	}
}

func sha1file(file string) (sum string, err error) {
	f, err := os.Open(file)
	if err != nil {
		return "", errors.Trace(err)
	}
	defer f.Close()

	h := sha1.New()
	if _, err := io.Copy(h, f); err != nil {
		return "", errors.Trace(err)
	}

	return fmt.Sprintf("%x", h.Sum(nil)), nil
}
<|endoftext|>


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

package main

import (
	"context"
	"crypto/tls"
	"flag"
	"io/ioutil"
	"log"
	"log/syslog"
	"net"
	"net/http"
	"os"
	"path"
	"strconv"
	"strings"
	"syscall"
	"time"

	"github.com/gorilla/handlers"
	"github.com/tsavola/confi"
	"github.com/tsavola/gate/runtime"
	"github.com/tsavola/gate/server"
	"github.com/tsavola/gate/server/monitor"
	"github.com/tsavola/gate/server/monitor/webmonitor"
	"github.com/tsavola/gate/server/sshkeys"
	"github.com/tsavola/gate/server/webserver"
	"github.com/tsavola/gate/server/webserver/accesstracker"
	"github.com/tsavola/gate/service"
	"github.com/tsavola/gate/service/origin"
	"github.com/tsavola/gate/service/plugin"
	"github.com/tsavola/gate/source/ipfs"
	"golang.org/x/crypto/acme"
	"golang.org/x/crypto/acme/autocert"
	"golang.org/x/net/netutil"
)

const (
	// stdio, syslog, runtime, listener, debug, autocert (guess)
	serverFileOverhead = 3 + 3 + 1 + 1 + 1 + 2

	// executable, process with debug
	forkFileOverhead = 1 + 6

	// guess
	pluginFileOverhead = 2

	// conn
	connFileOverhead = 1 + forkFileOverhead
)

type Config struct {
	Runtime runtime.Config

	Plugin struct {
		LibDir string
	}

	Service map[string]interface{}

	Server struct {
		server.Config
		MaxConns int
		Debug    string
	}

	Access struct {
		Policy string

		Public struct{}

		SSH struct {
			AuthorizedKeys string
		}
	}

	Principal struct {
		server.AccessConfig
	}

	Source struct {
		IPFS struct {
			ipfs.Config
		}
	}

	HTTP struct {
		Net  string
		Addr string
		webserver.Config
		AccessLog string

		TLS struct {
			Enabled bool
			Domains []string
		}
	}

	ACME struct {
		AcceptTOS    bool
		CacheDir     string
		RenewBefore  time.Duration
		DirectoryURL string
		Email        string
		ForceRSA     bool
	}

	Monitor struct {
		monitor.Config

		HTTP struct {
			Net  string
			Addr string
			webmonitor.Config
		}
	}

	Log struct {
		Syslog  bool
		Verbose bool
	}
}

func parseConfig(flags *flag.FlagSet, c *Config) {
	flags.Var(confi.FileReader(c), "f", "read TOML configuration file")
	flags.Var(confi.Assigner(c), "c", "set a configuration key (path.to.key=value)")
	flags.Parse(os.Args[1:])
}

func main() {
	var fileLimit syscall.Rlimit
	if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &fileLimit); err != nil {
		log.Fatal(err)
	}

	c := new(Config)
	c.Runtime.MaxProcs = runtime.DefaultMaxProcs
	c.Runtime.LibDir = "lib/gate/runtime"
	c.Runtime.Cgroup.Title = runtime.DefaultCgroupTitle
	c.Plugin.LibDir = "lib/gate/service"
	c.Server.PreforkProcs = server.DefaultPreforkProcs
	c.Principal.AccessConfig = server.DefaultAccessConfig
	c.HTTP.Net = "tcp"
	c.HTTP.Addr = "localhost:8888"
	c.HTTP.TLS.Domains = []string{"example.invalid"}
	c.ACME.CacheDir = "/var/lib/gate-server-acme"
	c.ACME.DirectoryURL = "https://acme-staging.api.letsencrypt.org/directory"
	c.Monitor.BufSize = monitor.DefaultBufSize
	c.Monitor.HTTP.Net = "tcp"
	c.Monitor.HTTP.StaticDir = "server/monitor/webmonitor"

	flags := flag.NewFlagSet("", flag.ContinueOnError)
	flags.SetOutput(ioutil.Discard)
	parseConfig(flags, c)

	plugins, err := plugin.List(c.Plugin.LibDir)
	if err != nil {
		log.Fatal(err)
	}

	c.Service = plugins.Config

	originConfig := origin.DefaultConfig
	c.Service["origin"] = &originConfig

	if c.Server.PreforkProcs <= 0 {
		c.Server.PreforkProcs = 1
	}

	constantFileOverhead := serverFileOverhead + forkFileOverhead*c.Server.PreforkProcs + pluginFileOverhead*len(c.Service)
	guessMaxConns := (int(fileLimit.Cur) - constantFileOverhead) / connFileOverhead

	if c.Server.MaxConns == 0 {
		if guessMaxConns <= 0 {
			log.Fatalf("file descriptor limit is too low (%d) or number of preforked processes is too high (%d)", fileLimit.Cur, c.Server.PreforkProcs)
		}
		c.Server.MaxConns = guessMaxConns
	} else if c.Server.MaxConns > guessMaxConns {
		log.Printf("maximum number of accepted connections (%d) exceeds estimated limit (%d) in regard to file descriptor limit (%d)", c.Server.MaxConns, guessMaxConns, fileLimit.Cur)
	}

	flag.Usage = confi.FlagUsage(nil, c)
	parseConfig(flag.CommandLine, c)

	ctx := context.Background()

	var (
		critLog *log.Logger
		errLog  *log.Logger
		infoLog *log.Logger
	)
	if c.Log.Syslog {
		tag := path.Base(os.Args[0])

		w, err := syslog.New(syslog.LOG_CRIT, tag)
		if err != nil {
			log.Fatal(err)
		}
		critLog = log.New(w, "", 0)

		w, err = syslog.New(syslog.LOG_ERR, tag)
		if err != nil {
			critLog.Fatal(err)
		}
		errLog = log.New(w, "", 0)

		if c.Log.Verbose {
			w, err = syslog.New(syslog.LOG_INFO, tag)
			if err != nil {
				critLog.Fatal(err)
			}
			infoLog = log.New(w, "", 0)
		}
	} else {
		critLog = log.New(os.Stderr, "", 0)
		errLog = critLog

		if c.Log.Verbose {
			infoLog = critLog
		}
	}
	c.Runtime.ErrorLog = errLog
	if infoLog != nil {
		c.Server.Monitor = server.ErrorEventLogger(errLog, infoLog)
	} else {
		c.Server.Monitor = server.ErrorLogger(errLog)
	}
	c.Monitor.HTTP.ErrorLog = errLog

	serviceConfig := &service.Config{
		Registry: new(service.Registry),
	}
	if err := plugins.InitServices(serviceConfig); err != nil {
		critLog.Fatal(err)
	}

	services := func() server.InstanceServices {
		o := origin.New(&originConfig)
		r := serviceConfig.Registry.Clone()
		r.Register(o)
		return server.NewInstanceServices(r, o)
	}

	if c.Monitor.HTTP.Addr != "" {
		if c.Monitor.HTTP.Origins == nil && strings.HasPrefix(c.Monitor.HTTP.Addr, "localhost:") {
			c.Monitor.HTTP.Origins = []string{"http://" + c.Monitor.HTTP.Addr}
		}

		monitor, handler := webmonitor.New(ctx, &c.Monitor.Config, &c.Monitor.HTTP.Config)
		c.Server.Monitor = server.MultiMonitor(c.Server.Monitor, monitor)

		listener, err := net.Listen(c.Monitor.HTTP.Net, c.Monitor.HTTP.Addr)
		if err != nil {
			critLog.Fatal(err)
		}

		server := http.Server{Handler: handler}
		go func() {
			critLog.Fatal(server.Serve(listener))
		}()
	}

	c.Server.Executor, err = runtime.NewExecutor(ctx, &c.Runtime)
	if err != nil {
		critLog.Fatal(err)
	}

	switch c.Access.Policy {
	case "public":
		c.Principal.AccessConfig.Services = services
		c.Server.AccessPolicy = &server.PublicAccess{
			AccessConfig: c.Principal.AccessConfig,
		}

	case "ssh":
		accessKeys := &sshkeys.AuthorizedKeys{
			AccessConfig: c.Principal.AccessConfig,
			Services:     func(uid string) server.InstanceServices { return services() },
		}

		uid := strconv.Itoa(os.Getuid())

		filename := c.Access.SSH.AuthorizedKeys
		if filename == "" {
			home := os.Getenv("HOME")
			if home == "" {
				critLog.Fatalf("access.ssh.authorizedkeys option or $HOME required")
			}
			filename = path.Join(home, ".ssh", "authorized_keys")
		}

		if err := accessKeys.ParseFile(uid, filename); err != nil {
			critLog.Fatal(err)
		}

		c.Server.AccessPolicy = accessKeys

	default:
		critLog.Fatalf("unknown access.policy option: %q", c.Access.Policy)
	}

	go func() {
		<-c.Server.Executor.Dead()
		critLog.Fatal("executor died")
	}()

	switch c.Server.Debug {
	case "":

	case "stderr":
		c.Server.Config.Debug = os.Stderr

	default:
		critLog.Fatalf("unknown server.debug option: %q", c.Server.Debug)
	}

	if c.HTTP.Authority != "" {
		c.HTTP.Authority = c.HTTP.Addr
	}
	c.HTTP.AccessState = accesstracker.NewDefault()

	c.HTTP.ModuleSources = make(map[string]server.Source)
	if c.Source.IPFS.Configured() {
		c.HTTP.ModuleSources[ipfs.Source] = ipfs.New(&c.Source.IPFS.Config)
	}

	var (
		acmeCache  autocert.Cache
		acmeClient *acme.Client
	)
	if c.ACME.AcceptTOS {
		acmeCache = autocert.DirCache(c.ACME.CacheDir)
		acmeClient = &acme.Client{DirectoryURL: c.ACME.DirectoryURL}
	}

	state := server.New(ctx, &c.Server.Config)
	handler := webserver.NewHandler(ctx, "/", &c.HTTP.Config, state)

	if c.HTTP.AccessLog != "" {
		f, err := os.OpenFile(c.HTTP.AccessLog, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
		if err != nil {
			critLog.Fatal(err)
		}
		defer f.Close()

		handler = handlers.LoggingHandler(f, handler)
	}

	l, err := net.Listen(c.HTTP.Net, c.HTTP.Addr)
	if err != nil {
		critLog.Fatal(err)
	}

	if n := c.Server.MaxConns; n > 0 {
		l = netutil.LimitListener(l, n)
	}

	if c.HTTP.TLS.Enabled {
		if !c.ACME.AcceptTOS {
			critLog.Fatal("http.tls requires acme.accepttos")
		}

		m := &autocert.Manager{
			Prompt:      autocert.AcceptTOS,
			Cache:       acmeCache,
			HostPolicy:  autocert.HostWhitelist(c.HTTP.TLS.Domains...),
			RenewBefore: c.ACME.RenewBefore,
			Client:      acmeClient,
			Email:       c.ACME.Email,
			ForceRSA:    c.ACME.ForceRSA,
		}

		l = tls.NewListener(l, &tls.Config{GetCertificate: m.GetCertificate})
	}

	s := http.Server{Handler: handler}
	critLog.Fatal(s.Serve(l))
}
<commit_msg>cmd: server: filesystem options<commit_after>// Copyright (c) 2016 Timo Savola. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"context"
	"crypto/tls"
	"flag"
	"io/ioutil"
	"log"
	"log/syslog"
	"net"
	"net/http"
	"os"
	"path"
	"strconv"
	"strings"
	"syscall"
	"time"

	"github.com/gorilla/handlers"
	"github.com/tsavola/confi"
	"github.com/tsavola/gate/image"
	"github.com/tsavola/gate/runtime"
	"github.com/tsavola/gate/server"
	"github.com/tsavola/gate/server/monitor"
	"github.com/tsavola/gate/server/monitor/webmonitor"
	"github.com/tsavola/gate/server/sshkeys"
	"github.com/tsavola/gate/server/webserver"
	"github.com/tsavola/gate/server/webserver/accesstracker"
	"github.com/tsavola/gate/service"
	"github.com/tsavola/gate/service/origin"
	"github.com/tsavola/gate/service/plugin"
	"github.com/tsavola/gate/source/ipfs"
	"golang.org/x/crypto/acme"
	"golang.org/x/crypto/acme/autocert"
	"golang.org/x/net/netutil"
)

const (
	DefaultInstanceStore  = "memory"
	DefaultProgramStorage = "memory"
)

const (
	// stdio, syslog, runtime, listener, debug, autocert (guess)
	serverFileOverhead = 3 + 3 + 1 + 1 + 1 + 2

	// executable, process with debug
	forkFileOverhead = 1 + 6

	// guess
	pluginFileOverhead = 2

	// conn
	connFileOverhead = 1 + forkFileOverhead
)

type Config struct {
	Runtime runtime.Config

	Image struct {
		Filesystem string
		PageSize   int
	}

	Plugin struct {
		LibDir string
	}

	Service map[string]interface{}

	Server struct {
		server.Config
		InstanceStore  string
		ProgramStorage string
		MaxConns       int
		Debug          string
	}

	Access struct {
		Policy string

		Public struct{}

		SSH struct {
			AuthorizedKeys string
		}
	}

	Principal struct {
		server.AccessConfig
	}

	Source struct {
		IPFS struct {
			ipfs.Config
		}
	}

	HTTP struct {
		Net  string
		Addr string
		webserver.Config
		AccessLog string

		TLS struct {
			Enabled bool
			Domains []string
		}
	}

	ACME struct {
		AcceptTOS    bool
		CacheDir     string
		RenewBefore  time.Duration
		DirectoryURL string
		Email        string
		ForceRSA     bool
	}

	Monitor struct {
		monitor.Config

		HTTP struct {
			Net  string
			Addr string
			webmonitor.Config
		}
	}

	Log struct {
		Syslog  bool
		Verbose bool
	}
}

func parseConfig(flags *flag.FlagSet, c *Config) {
	flags.Var(confi.FileReader(c), "f", "read TOML configuration file")
	flags.Var(confi.Assigner(c), "c", "set a configuration key (path.to.key=value)")
	flags.Parse(os.Args[1:])
}

func main() {
	var fileLimit syscall.Rlimit
	if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &fileLimit); err != nil {
		log.Fatal(err)
	}

	c := new(Config)
	c.Runtime.MaxProcs = runtime.DefaultMaxProcs
	c.Runtime.LibDir = "lib/gate/runtime"
	c.Runtime.Cgroup.Title = runtime.DefaultCgroupTitle
	c.Image.PageSize = os.Getpagesize()
	c.Plugin.LibDir = "lib/gate/service"
	c.Server.InstanceStore = DefaultInstanceStore
	c.Server.ProgramStorage = DefaultProgramStorage
	c.Server.PreforkProcs = server.DefaultPreforkProcs
	c.Principal.AccessConfig = server.DefaultAccessConfig
	c.HTTP.Net = "tcp"
	c.HTTP.Addr = "localhost:8888"
	c.HTTP.TLS.Domains = []string{"example.invalid"}
	c.ACME.CacheDir = "/var/lib/gate-server-acme"
	c.ACME.DirectoryURL = "https://acme-staging.api.letsencrypt.org/directory"
	c.Monitor.BufSize = monitor.DefaultBufSize
	c.Monitor.HTTP.Net = "tcp"
	c.Monitor.HTTP.StaticDir = "server/monitor/webmonitor"

	flags := flag.NewFlagSet("", flag.ContinueOnError)
	flags.SetOutput(ioutil.Discard)
	parseConfig(flags, c)

	plugins, err := plugin.List(c.Plugin.LibDir)
	if err != nil {
		log.Fatal(err)
	}

	c.Service = plugins.Config

	originConfig := origin.DefaultConfig
	c.Service["origin"] = &originConfig

	if c.Server.PreforkProcs <= 0 {
		c.Server.PreforkProcs = 1
	}

	constantFileOverhead := serverFileOverhead + forkFileOverhead*c.Server.PreforkProcs + pluginFileOverhead*len(c.Service)
	guessMaxConns := (int(fileLimit.Cur) - constantFileOverhead) / connFileOverhead

	if c.Server.MaxConns == 0 {
		if guessMaxConns <= 0 {
			log.Fatalf("file descriptor limit is too low (%d) or number of preforked processes is too high (%d)", fileLimit.Cur, c.Server.PreforkProcs)
		}
		c.Server.MaxConns = guessMaxConns
	} else if c.Server.MaxConns > guessMaxConns {
		log.Printf("maximum number of accepted connections (%d) exceeds estimated limit (%d) in regard to file descriptor limit (%d)", c.Server.MaxConns, guessMaxConns, fileLimit.Cur)
	}

	flag.Usage = confi.FlagUsage(nil, c)
	parseConfig(flag.CommandLine, c)

	ctx := context.Background()

	var (
		critLog *log.Logger
		errLog  *log.Logger
		infoLog *log.Logger
	)
	if c.Log.Syslog {
		tag := path.Base(os.Args[0])

		w, err := syslog.New(syslog.LOG_CRIT, tag)
		if err != nil {
			log.Fatal(err)
		}
		critLog = log.New(w, "", 0)

		w, err = syslog.New(syslog.LOG_ERR, tag)
		if err != nil {
			critLog.Fatal(err)
		}
		errLog = log.New(w, "", 0)

		if c.Log.Verbose {
			w, err = syslog.New(syslog.LOG_INFO, tag)
			if err != nil {
				critLog.Fatal(err)
			}
			infoLog = log.New(w, "", 0)
		}
	} else {
		critLog = log.New(os.Stderr, "", 0)
		errLog = critLog

		if c.Log.Verbose {
			infoLog = critLog
		}
	}
	c.Runtime.ErrorLog = errLog
	if infoLog != nil {
		c.Server.Monitor = server.ErrorEventLogger(errLog, infoLog)
	} else {
		c.Server.Monitor = server.ErrorLogger(errLog)
	}
	c.Monitor.HTTP.ErrorLog = errLog

	serviceConfig := &service.Config{
		Registry: new(service.Registry),
	}
	if err := plugins.InitServices(serviceConfig); err != nil {
		critLog.Fatal(err)
	}

	services := func() server.InstanceServices {
		o := origin.New(&originConfig)
		r := serviceConfig.Registry.Clone()
		r.Register(o)
		return server.NewInstanceServices(r, o)
	}

	if c.Monitor.HTTP.Addr != "" {
		if c.Monitor.HTTP.Origins == nil && strings.HasPrefix(c.Monitor.HTTP.Addr, "localhost:") {
			c.Monitor.HTTP.Origins = []string{"http://" + c.Monitor.HTTP.Addr}
		}

		monitor, handler := webmonitor.New(ctx, &c.Monitor.Config, &c.Monitor.HTTP.Config)
		c.Server.Monitor = server.MultiMonitor(c.Server.Monitor, monitor)

		listener, err := net.Listen(c.Monitor.HTTP.Net, c.Monitor.HTTP.Addr)
		if err != nil {
			critLog.Fatal(err)
		}

		server := http.Server{Handler: handler}
		go func() {
			critLog.Fatal(server.Serve(listener))
		}()
	}

	c.Server.Executor, err = runtime.NewExecutor(ctx, &c.Runtime)
	if err != nil {
		critLog.Fatal(err)
	}

	var fs *image.Filesystem
	if c.Image.Filesystem != "" {
		fs = image.NewFilesystem(c.Image.Filesystem, c.Image.PageSize)
	}

	switch c.Server.InstanceStore {
	case "memory":
		c.Server.Config.InstanceStore = image.Memory

	case "filesystem":
		c.Server.Config.InstanceStore = fs

	default:
		critLog.Fatalf("unknown server.instancestore option: %q", c.Server.InstanceStore)
	}

	switch c.Server.ProgramStorage {
	case "memory":
		c.Server.Config.ProgramStorage = image.Memory

	case "filesystem":
		c.Server.Config.ProgramStorage = fs

	default:
		critLog.Fatalf("unknown server.programstorage option: %q", c.Server.ProgramStorage)
	}

	switch c.Access.Policy {
	case "public":
		c.Principal.AccessConfig.Services = services
		c.Server.AccessPolicy = &server.PublicAccess{
			AccessConfig: c.Principal.AccessConfig,
		}

	case "ssh":
		accessKeys := &sshkeys.AuthorizedKeys{
			AccessConfig: c.Principal.AccessConfig,
			Services:     func(uid string) server.InstanceServices { return services() },
		}

		uid := strconv.Itoa(os.Getuid())

		filename := c.Access.SSH.AuthorizedKeys
		if filename == "" {
			home := os.Getenv("HOME")
			if home == "" {
				critLog.Fatalf("access.ssh.authorizedkeys option or $HOME required")
			}
			filename = path.Join(home, ".ssh", "authorized_keys")
		}

		if err := accessKeys.ParseFile(uid, filename); err != nil {
			critLog.Fatal(err)
		}

		c.Server.AccessPolicy = accessKeys

	default:
		critLog.Fatalf("unknown access.policy option: %q", c.Access.Policy)
	}

	go func() {
		<-c.Server.Executor.Dead()
		critLog.Fatal("executor died")
	}()

	switch c.Server.Debug {
	case "":

	case "stderr":
		c.Server.Config.Debug = os.Stderr

	default:
		critLog.Fatalf("unknown server.debug option: %q", c.Server.Debug)
	}

	if c.HTTP.Authority != "" {
		c.HTTP.Authority = c.HTTP.Addr
	}
	c.HTTP.AccessState = accesstracker.NewDefault()

	c.HTTP.ModuleSources = make(map[string]server.Source)
	if c.Source.IPFS.Configured() {
		c.HTTP.ModuleSources[ipfs.Source] = ipfs.New(&c.Source.IPFS.Config)
	}

	var (
		acmeCache  autocert.Cache
		acmeClient *acme.Client
	)
	if c.ACME.AcceptTOS {
		acmeCache = autocert.DirCache(c.ACME.CacheDir)
		acmeClient = &acme.Client{DirectoryURL: c.ACME.DirectoryURL}
	}

	state := server.New(ctx, &c.Server.Config)
	handler := webserver.NewHandler(ctx, "/", &c.HTTP.Config, state)

	if c.HTTP.AccessLog != "" {
		f, err := os.OpenFile(c.HTTP.AccessLog, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
		if err != nil {
			critLog.Fatal(err)
		}
		defer f.Close()

		handler = handlers.LoggingHandler(f, handler)
	}

	l, err := net.Listen(c.HTTP.Net, c.HTTP.Addr)
	if err != nil {
		critLog.Fatal(err)
	}

	if n := c.Server.MaxConns; n > 0 {
		l = netutil.LimitListener(l, n)
	}

	if c.HTTP.TLS.Enabled {
		if !c.ACME.AcceptTOS {
			critLog.Fatal("http.tls requires acme.accepttos")
		}

		m := &autocert.Manager{
			Prompt:      autocert.AcceptTOS,
			Cache:       acmeCache,
			HostPolicy:  autocert.HostWhitelist(c.HTTP.TLS.Domains...),
			RenewBefore: c.ACME.RenewBefore,
			Client:      acmeClient,
			Email:       c.ACME.Email,
			ForceRSA:    c.ACME.ForceRSA,
		}

		l = tls.NewListener(l, &tls.Config{GetCertificate: m.GetCertificate})
	}

	s := http.Server{Handler: handler}
	critLog.Fatal(s.Serve(l))
}
<|endoftext|>


<commit_before><commit_msg>remove the VERSION_NEGOTIATION_ERROR<commit_after><|endoftext|>


<commit_before><commit_msg>formatting some more<commit_after><|endoftext|>


<commit_before>package main

import (
  "log"
  "os/exec"
  "path/filepath"
  "strings"
  "os"
  "fmt"
)

func (ad *AppDeployer) processLibs() {
  for request := range ad.libsChannel {
    ad.processLibrary(request)
    ad.waitGroup.Done()
  }
}

func (ad *AppDeployer) processLibrary(request *DeployRequest) {
  libpath := request.FullPath()
  log.Printf("Processing library: %v", libpath)

  if _, ok := ad.processedLibs[libpath]; !ok {
    dependencies, err := ad.findLddDependencies(libpath)
    if (err == nil) {
      ad.processedLibs[libpath] = true

      ad.waitGroup.Add(1)
      go func(copyRequest *DeployRequest) {
        ad.copyChannel <- copyRequest
      }(request)

      for _, dependPath := range dependencies {
        if _, ok := ad.processedLibs[dependPath]; !ok {
          ad.waitGroup.Add(1)
          go func(dlp string, isLddDependency bool) {
            ad.libsChannel <- &DeployRequest{
              sourcePath: dlp,
              targetRoot: "lib",
              isLddDependency: isLddDependency,
            }
          }(dependPath, request.isLddDependency)
        }
      }
    } else {
      log.Printf("Error while dependency check: %v", err)
    }
  }
}

func (ad *AppDeployer) findLddDependencies(filepath string) ([]string, error) {
  log.Printf("Inspecting %v", filepath)

  out, err := exec.Command("ldd", filepath).Output()
  if err != nil { return nil, err }

  dependencies := make([]string, 0, 10)

  output := string(out)
  lines := strings.Split(output, "\n")
  for _, line := range lines {
    line = strings.TrimSpace(line)
    libname, libpath, err := parseLddOutputLine(line)

    if err == nil {
      if len(libpath) == 0 {
        libpath = ad.resolveLibrary(libname)
      }

      log.Printf("Extracted %v from ldd [%v]", libpath, line)
      dependencies = append(dependencies, libpath)
    } else {
      log.Printf("Cannot parse ldd line: %v", line)
    }
  }

  return dependencies, nil
}

func (ad *AppDeployer) addAdditionalLibPath(libpath string) {
  log.Printf("Adding addition libpath: %v", libpath)
  foundPath := libpath
  var err error

  if !filepath.IsAbs(foundPath) {
    if foundPath, err = filepath.Abs(foundPath); err == nil {
      log.Printf("Trying to resolve libpath to: %v", foundPath)

      if _, err = os.Stat(foundPath); os.IsNotExist(err) {
        exeDir := filepath.Dir(ad.targetExePath)
        foundPath = filepath.Join(exeDir, libpath)
        log.Printf("Trying to resolve libpath to: %v", foundPath)
      }
    }
  }

  if _, err := os.Stat(foundPath); os.IsNotExist(err) {
    log.Printf("Cannot find library path: %v", foundPath)
    return
  }

  log.Printf("Resolved additional libpath to: %v", foundPath)
  ad.additionalLibPaths = append(ad.additionalLibPaths, foundPath)
}

func (ad *AppDeployer) resolveLibrary(libname string) (foundPath string) {
  foundPath = libname

  for _, extraLibPath := range ad.additionalLibPaths {
    possiblePath := filepath.Join(extraLibPath, libname)

    if _, err := os.Stat(possiblePath); err == nil {
      foundPath = possiblePath
      break
    }
  }

  log.Printf("Resolving library %v to %v", libname, foundPath)
  return foundPath
}

func (ad *AppDeployer) processRunPathChangeRequests() {
  if _, err := exec.LookPath("patchelf"); err != nil {
    log.Printf("Patchelf cannot be found!")
    return
  }

  destinationRoot := ad.destinationPath

  for fullpath := range ad.rpathChannel {
    changeRPath(fullpath, destinationRoot)
    ad.waitGroup.Done()
  }
}

func changeRPath(fullpath, destinationRoot string) {
  relativePath, err := filepath.Rel(destinationRoot, fullpath)
  if err != nil {
    log.Println(err)
    return
  }

  rpath := fmt.Sprintf("$ORIGIN:$ORIGIN/%s", relativePath)
  log.Printf("Changing RPATH for %v to %v", fullpath, rpath)

  cmd := exec.Command("patchelf", "--set-rpath", rpath, fullpath)
  if err = cmd.Run(); err != nil {
    log.Println(err)
  }
}
<commit_msg>Fix for rpath dir<commit_after>package main

import (
  "log"
  "os/exec"
  "path/filepath"
  "strings"
  "os"
  "fmt"
)

func (ad *AppDeployer) processLibs() {
  for request := range ad.libsChannel {
    ad.processLibrary(request)
    ad.waitGroup.Done()
  }
}

func (ad *AppDeployer) processLibrary(request *DeployRequest) {
  libpath := request.FullPath()
  log.Printf("Processing library: %v", libpath)

  if _, ok := ad.processedLibs[libpath]; !ok {
    dependencies, err := ad.findLddDependencies(libpath)
    if (err == nil) {
      ad.processedLibs[libpath] = true

      ad.waitGroup.Add(1)
      go func(copyRequest *DeployRequest) {
        ad.copyChannel <- copyRequest
      }(request)

      for _, dependPath := range dependencies {
        if _, ok := ad.processedLibs[dependPath]; !ok {
          ad.waitGroup.Add(1)
          go func(dlp string, isLddDependency bool) {
            ad.libsChannel <- &DeployRequest{
              sourcePath: dlp,
              targetRoot: "lib",
              isLddDependency: isLddDependency,
            }
          }(dependPath, request.isLddDependency)
        }
      }
    } else {
      log.Printf("Error while dependency check: %v", err)
    }
  }
}

func (ad *AppDeployer) findLddDependencies(filepath string) ([]string, error) {
  log.Printf("Inspecting %v", filepath)

  out, err := exec.Command("ldd", filepath).Output()
  if err != nil { return nil, err }

  dependencies := make([]string, 0, 10)

  output := string(out)
  lines := strings.Split(output, "\n")
  for _, line := range lines {
    line = strings.TrimSpace(line)
    libname, libpath, err := parseLddOutputLine(line)

    if err == nil {
      if len(libpath) == 0 {
        libpath = ad.resolveLibrary(libname)
      }

      log.Printf("Parsed lib %v from ldd [%v]", libpath, line)
      dependencies = append(dependencies, libpath)
    } else {
      log.Printf("Cannot parse ldd line: %v", line)
    }
  }

  return dependencies, nil
}

func (ad *AppDeployer) addAdditionalLibPath(libpath string) {
  log.Printf("Adding addition libpath: %v", libpath)
  foundPath := libpath
  var err error

  if !filepath.IsAbs(foundPath) {
    if foundPath, err = filepath.Abs(foundPath); err == nil {
      log.Printf("Trying to resolve libpath to: %v", foundPath)

      if _, err = os.Stat(foundPath); os.IsNotExist(err) {
        exeDir := filepath.Dir(ad.targetExePath)
        foundPath = filepath.Join(exeDir, libpath)
        log.Printf("Trying to resolve libpath to: %v", foundPath)
      }
    }
  }

  if _, err := os.Stat(foundPath); os.IsNotExist(err) {
    log.Printf("Cannot find library path: %v", foundPath)
    return
  }

  log.Printf("Resolved additional libpath to: %v", foundPath)
  ad.additionalLibPaths = append(ad.additionalLibPaths, foundPath)
}

func (ad *AppDeployer) resolveLibrary(libname string) (foundPath string) {
  foundPath = libname

  for _, extraLibPath := range ad.additionalLibPaths {
    possiblePath := filepath.Join(extraLibPath, libname)

    if _, err := os.Stat(possiblePath); err == nil {
      foundPath = possiblePath
      break
    }
  }

  log.Printf("Resolving library %v to %v", libname, foundPath)
  return foundPath
}

func (ad *AppDeployer) processRunPathChangeRequests() {
  if _, err := exec.LookPath("patchelf"); err != nil {
    log.Printf("Patchelf cannot be found!")
    return
  }

  destinationRoot := ad.destinationPath

  for fullpath := range ad.rpathChannel {
    changeRPath(fullpath, destinationRoot)
    ad.waitGroup.Done()
  }
}

func changeRPath(fullpath, destinationRoot string) {
  libdir := filepath.Dir(fullpath)
  relativePath, err := filepath.Rel(destinationRoot, libdir)
  if err != nil {
    log.Println(err)
    return
  }

  rpath := fmt.Sprintf("$ORIGIN:$ORIGIN/%s/lib/", relativePath)
  log.Printf("Changing RPATH for %v to %v", fullpath, rpath)

  cmd := exec.Command("patchelf", "--set-rpath", rpath, fullpath)
  if err = cmd.Run(); err != nil {
    log.Println(err)
  }
}
<|endoftext|>


<commit_before>// Package inject 提供类似Guice Injector的依赖注入功能,可以用于简化服务的组装
package inject

import (
	"fmt"
	"reflect"
	"strings"

	c "github.com/d0ngw/go/common"
)

// Injector 类似Guice的注入器
// 绑定约束:相同类型的实例和名称在一个Injector中必须唯一
// Injector对于struct中可导出的字段进行注入,需要注入的字段应该使用inject tag进行说明
//  type InjectStruct struct{
//   s ServiceInterface{} `inject:"<name>,[optional]"`
//  }
// inject格式:
//  name: 绑定的名称,必须的,如果没有名称,使用`_`代替
//  optional: 标识可选的注入,即不是必须注入
type Injector struct {
	ununamed []*internalBind            //未命名的绑定
	named    map[string][]*internalBind //命名的绑定
	all      []*internalBind            //所有的绑定
}

// Inject tag常量
const (
	injectTagNoname = "_" //无名称注入
)

func (p *Injector) String() string {
	return fmt.Sprintf("Injector,unnamed binds:%v,named binds:%v", len(p.ununamed), len(p.named))
}

// NewInjector 创建一个Injector
func NewInjector(modules []*Module) *Injector {
	injector := &Injector{}
	injectorModule := NewModule()
	injectorModule.Bind(injector)
	modules = append(modules, injectorModule)
	unnamed, named, all := mergeBinds(modules)
	injector.ununamed = unnamed
	injector.named = named
	injector.all = all
	injector.injectModules()
	return injector
}

// Initialize 初始化injector
func (p *Injector) Initialize() error {
	// 执行初始化操作
	inits := p.GetInstancesByPrototype(struct{ s c.Initable }{})
	for _, init := range inits {
		if service, ok := init.(c.Service); ok {
			if !c.ServiceInit(service) {
				return fmt.Errorf("Init %s fail", service.Name())
			}
		} else {
			if err := init.(c.Initable).Init(); err != nil {
				return fmt.Errorf("Init %T fail,err:%s", init, err)
			}

		}
	}
	return nil
}

// Start 启动服务
func (p *Injector) Start() error {
	return p.startOrStop(true)
}

// Stop 停止服务
func (p *Injector) Stop() error {
	return p.startOrStop(false)
}

func (p *Injector) startOrStop(start bool) error {
	var services []c.Service
	for _, service := range p.GetInstancesByPrototype(struct{ s c.Service }{}) {
		services = append(services, service.(c.Service))
	}
	if len(services) == 0 {
		c.Infof("No service found,skip")
		return nil
	}

	sortedServices := c.NewServices(services, start)
	if start {
		if !sortedServices.Start() {
			return fmt.Errorf("Start servcie fail")
		}
	} else {
		if !sortedServices.Stop() {
			return fmt.Errorf("Stop servcie fail")
		}
	}
	return nil
}

// RequireInject 由Injector向targets注入服务
func (p *Injector) RequireInject(targets ...interface{}) {
	for _, target := range targets {
		p.injectInstance(target)
	}
}

// RequireInjectWithOverrideTags 由Injector向target注入服务,injectTags用于覆盖target struct字段中定义的inject tag
func (p *Injector) RequireInjectWithOverrideTags(target interface{}, injectTags map[string]string) {
	p.injectInstanceWithOverrideTags(target, injectTags)
}

// GetInstance 从Injector中查找与name和expectedType匹配的实例,如果没有找到返回nil
func (p *Injector) GetInstance(name string, expectedType reflect.Type) interface{} {
	bind := p.findBind(name, expectedType)
	if bind == nil {
		return nil
	}
	return bind.instance
}

// GetInstanceByPrototype 从Injector重查找与name和prototype匹配的实例,如果没有找到返回nil
func (p *Injector) GetInstanceByPrototype(name string, prototype interface{}) interface{} {
	return p.GetInstance(name, getFieldType(prototype, 0))
}

// GetInstancesByPrototype 从Injector里查找与prototype匹配的所有实例
func (p *Injector) GetInstancesByPrototype(prototype interface{}) []interface{} {
	expectedType := getFieldType(prototype, 0)
	var ret = p.findAllBind(p.all, expectedType)
	var retInstances []interface{}
	for _, bind := range ret {
		retInstances = append(retInstances, bind.instance)
	}
	return retInstances
}

func (p *Injector) findAllBind(binds []*internalBind, expectedType reflect.Type) []*internalBind {
	var ret []*internalBind
	for _, bind := range binds {
		canAssign := bind.injectType.AssignableTo(expectedType)
		if canAssign {
			ret = append(ret, bind)
		}
	}
	return ret
}

// findBind 寻找一个可用的绑定
func (p *Injector) findBind(name string, expectedType reflect.Type) *internalBind {
	var toFind []*internalBind
	if len(name) != 0 {
		//按名称查找
		if binds, ok := p.named[name]; ok {
			toFind = binds
		}
	} else {
		toFind = p.ununamed
	}

	var ret []*internalBind
	for _, bind := range toFind {
		canAssign := bind.injectType.AssignableTo(expectedType)
		if canAssign {
			ret = append(ret, bind)
		}
	}

	if len(ret) == 0 {
		return nil
	} else if len(ret) > 1 {
		bindsDesc := make([]string, 0, len(ret))
		for _, bind := range ret {
			bindsDesc = append(bindsDesc, bind.String())
		}
		panic(fmt.Errorf("Duplicate for %v#%s,available binds:[%v]", expectedType, name, strings.Join(bindsDesc, ",")))
	} else {
		return ret[0]
	}
}

// injectInstance 向target注入实例
func (p *Injector) injectInstance(target interface{}) {
	p.injectInstanceWithOverrideTags(target, map[string]string{})
}

// injectInstanceWithOverrideTAgs 向target注入实例,injectTags用于覆盖target struct中定义的inject tag定义
func (p *Injector) injectInstanceWithOverrideTags(target interface{}, injectTags map[string]string) {
	if len(injectTags) == 0 {
		if ok, injected := IsInjected(target); ok && injected {
			//已经完成注入,直接返回
			c.Debugf("%T has been injected,skip", target)
			return
		}
	}
	val := reflect.ValueOf(target)
	ind := reflect.Indirect(val)
	typ := ind.Type()

	//仅struct的指针才能被注入
	if val.Kind() != reflect.Ptr || ind.Kind() != reflect.Struct {
		c.Debugf("Skip inject:%#v", target)
		return
	}

	fieldNum := ind.NumField()
	for i := 0; i < fieldNum; i++ {
		field := typ.Field(i)
		fieldVal := ind.Field(i)
		if !fieldVal.CanSet() {
			c.Debugf("skip inject filed %s", field.Name)
			continue
		}

		if reflect.Indirect(fieldVal).Kind() == reflect.Struct {
			if fieldVal.Kind() == reflect.Ptr {
				p.injectInstanceWithOverrideTags(fieldVal.Interface(), injectTags)
			} else if fieldVal.CanAddr() && fieldVal.CanInterface() {
				p.injectInstanceWithOverrideTags(fieldVal.Addr().Interface(), injectTags)
			}
			continue
		}
		structField := typ.Field(i)
		sfTag := structField.Tag

		tag, ok := injectTags[structField.Name]
		if !ok {
			tag = sfTag.Get("inject")
		}
		found, name, optional := parseInjectTag(tag)
		if !found {
			continue
		}

		if name == injectTagNoname {
			name = ""
		}

		foundBind := p.findBind(name, structField.Type)
		if foundBind == nil {
			if !optional {
				panic(fmt.Errorf("Can't find bind instance for %v.%s with name %s", typ, structField.Name, name))
			} else {
				c.Infof("skip optional %s %s ", name, structField.Type)
				continue
			}
		}

		if !fieldVal.CanSet() {
			panic(fmt.Errorf("Can't inject unexported  %v.%s", typ, structField.Name))
		}

		fieldInjectDesc := fmt.Sprintf("%s.%s", typ.Name(), structField.Name)
		c.Debugf("Inject %T#%s to %s", foundBind.instance, foundBind.name, fieldInjectDesc)
		if foundBind.injectValue.Kind() == reflect.Ptr && foundBind.injectValue.Pointer() == val.Pointer() {
			injectSrcDesc := fmt.Sprintf("%#v(addr:%p)", foundBind.instance, foundBind.instance)
			injectTargetDesc := fmt.Sprintf("%s of %#v(addr:%p)", fieldInjectDesc, target, target)
			panic(fmt.Errorf("Found circular inject,src:%s,target:%s", injectSrcDesc, injectTargetDesc))
		}
		fieldVal.Set(foundBind.injectValue)
	}
}

// injectModules 注入Injector中各个Module中的绑定
func (p *Injector) injectModules() {
	c.Debugf("Inject internal")
	for _, bind := range p.ununamed {
		p.injectInstanceWithOverrideTags(bind.instance, bind.injectTags)
	}

	for _, binds := range p.named {
		for _, bind := range binds {
			p.injectInstanceWithOverrideTags(bind.instance, bind.injectTags)
		}
	}
}

// getFieldType 取得struct中field的类型
func getFieldType(structObj interface{}, fieldIndex int) reflect.Type {
	val := reflect.Indirect(reflect.ValueOf(structObj))
	return val.Field(fieldIndex).Type()
}

// parseInjectTag 解析inject tag,inject tag的格式
func parseInjectTag(tag string) (found bool, name string, optional bool) {
	tag = strings.TrimSpace(tag)
	if len(tag) == 0 {
		return
	}

	vals := strings.Split(tag, ",")
	if len(vals) > 0 {
		found = true
		name = strings.TrimSpace(vals[0])
	}

	others := vals[1:]
	for _, o := range others {
		o = strings.ToLower(strings.TrimSpace(o))
		if o == "optional" {
			optional = true
		}
	}
	return
}
<commit_msg>fix log<commit_after>// Package inject 提供类似Guice Injector的依赖注入功能,可以用于简化服务的组装
package inject

import (
	"fmt"
	"reflect"
	"strings"

	c "github.com/d0ngw/go/common"
)

// Injector 类似Guice的注入器
// 绑定约束:相同类型的实例和名称在一个Injector中必须唯一
// Injector对于struct中可导出的字段进行注入,需要注入的字段应该使用inject tag进行说明
//  type InjectStruct struct{
//   s ServiceInterface{} `inject:"<name>,[optional]"`
//  }
// inject格式:
//  name: 绑定的名称,必须的,如果没有名称,使用`_`代替
//  optional: 标识可选的注入,即不是必须注入
type Injector struct {
	ununamed []*internalBind            //未命名的绑定
	named    map[string][]*internalBind //命名的绑定
	all      []*internalBind            //所有的绑定
}

// Inject tag常量
const (
	injectTagNoname = "_" //无名称注入
)

func (p *Injector) String() string {
	return fmt.Sprintf("Injector,unnamed binds:%v,named binds:%v", len(p.ununamed), len(p.named))
}

// NewInjector 创建一个Injector
func NewInjector(modules []*Module) *Injector {
	injector := &Injector{}
	injectorModule := NewModule()
	injectorModule.Bind(injector)
	modules = append(modules, injectorModule)
	unnamed, named, all := mergeBinds(modules)
	injector.ununamed = unnamed
	injector.named = named
	injector.all = all
	injector.injectModules()
	return injector
}

// Initialize 初始化injector
func (p *Injector) Initialize() error {
	// 执行初始化操作
	inits := p.GetInstancesByPrototype(struct{ s c.Initable }{})
	for _, init := range inits {
		if service, ok := init.(c.Service); ok {
			if !c.ServiceInit(service) {
				return fmt.Errorf("Init %s fail", service.Name())
			}
		} else {
			if err := init.(c.Initable).Init(); err != nil {
				return fmt.Errorf("Init %T fail,err:%s", init, err)
			}

		}
	}
	return nil
}

// Start 启动服务
func (p *Injector) Start() error {
	return p.startOrStop(true)
}

// Stop 停止服务
func (p *Injector) Stop() error {
	return p.startOrStop(false)
}

func (p *Injector) startOrStop(start bool) error {
	var services []c.Service
	for _, service := range p.GetInstancesByPrototype(struct{ s c.Service }{}) {
		services = append(services, service.(c.Service))
	}
	if len(services) == 0 {
		c.Infof("No service found,skip")
		return nil
	}

	sortedServices := c.NewServices(services, start)
	if start {
		if !sortedServices.Start() {
			return fmt.Errorf("Start servcie fail")
		}
	} else {
		if !sortedServices.Stop() {
			return fmt.Errorf("Stop servcie fail")
		}
	}
	return nil
}

// RequireInject 由Injector向targets注入服务
func (p *Injector) RequireInject(targets ...interface{}) {
	for _, target := range targets {
		p.injectInstance(target)
	}
}

// RequireInjectWithOverrideTags 由Injector向target注入服务,injectTags用于覆盖target struct字段中定义的inject tag
func (p *Injector) RequireInjectWithOverrideTags(target interface{}, injectTags map[string]string) {
	p.injectInstanceWithOverrideTags(target, injectTags)
}

// GetInstance 从Injector中查找与name和expectedType匹配的实例,如果没有找到返回nil
func (p *Injector) GetInstance(name string, expectedType reflect.Type) interface{} {
	bind := p.findBind(name, expectedType)
	if bind == nil {
		return nil
	}
	return bind.instance
}

// GetInstanceByPrototype 从Injector重查找与name和prototype匹配的实例,如果没有找到返回nil
func (p *Injector) GetInstanceByPrototype(name string, prototype interface{}) interface{} {
	return p.GetInstance(name, getFieldType(prototype, 0))
}

// GetInstancesByPrototype 从Injector里查找与prototype匹配的所有实例
func (p *Injector) GetInstancesByPrototype(prototype interface{}) []interface{} {
	expectedType := getFieldType(prototype, 0)
	var ret = p.findAllBind(p.all, expectedType)
	var retInstances []interface{}
	for _, bind := range ret {
		retInstances = append(retInstances, bind.instance)
	}
	return retInstances
}

func (p *Injector) findAllBind(binds []*internalBind, expectedType reflect.Type) []*internalBind {
	var ret []*internalBind
	for _, bind := range binds {
		canAssign := bind.injectType.AssignableTo(expectedType)
		if canAssign {
			ret = append(ret, bind)
		}
	}
	return ret
}

// findBind 寻找一个可用的绑定
func (p *Injector) findBind(name string, expectedType reflect.Type) *internalBind {
	var toFind []*internalBind
	if len(name) != 0 {
		//按名称查找
		if binds, ok := p.named[name]; ok {
			toFind = binds
		}
	} else {
		toFind = p.ununamed
	}

	var ret []*internalBind
	for _, bind := range toFind {
		canAssign := bind.injectType.AssignableTo(expectedType)
		if canAssign {
			ret = append(ret, bind)
		}
	}

	if len(ret) == 0 {
		return nil
	} else if len(ret) > 1 {
		bindsDesc := make([]string, 0, len(ret))
		for _, bind := range ret {
			bindsDesc = append(bindsDesc, bind.String())
		}
		panic(fmt.Errorf("Duplicate for %v#%s,available binds:[%v]", expectedType, name, strings.Join(bindsDesc, ",")))
	} else {
		return ret[0]
	}
}

// injectInstance 向target注入实例
func (p *Injector) injectInstance(target interface{}) {
	p.injectInstanceWithOverrideTags(target, map[string]string{})
}

// injectInstanceWithOverrideTAgs 向target注入实例,injectTags用于覆盖target struct中定义的inject tag定义
func (p *Injector) injectInstanceWithOverrideTags(target interface{}, injectTags map[string]string) {
	if len(injectTags) == 0 {
		if ok, injected := IsInjected(target); ok && injected {
			//已经完成注入,直接返回
			c.Debugf("%T has been injected,skip", target)
			return
		}
	}
	val := reflect.ValueOf(target)
	ind := reflect.Indirect(val)
	typ := ind.Type()

	//仅struct的指针才能被注入
	if val.Kind() != reflect.Ptr || ind.Kind() != reflect.Struct {
		c.Debugf("Skip inject:%#v", target)
		return
	}

	fieldNum := ind.NumField()
	for i := 0; i < fieldNum; i++ {
		field := typ.Field(i)
		fieldVal := ind.Field(i)
		if !fieldVal.CanSet() {
			c.Debugf("skip inject filed %s", field.Name)
			continue
		}

		if reflect.Indirect(fieldVal).Kind() == reflect.Struct {
			if fieldVal.Kind() == reflect.Ptr {
				p.injectInstanceWithOverrideTags(fieldVal.Interface(), injectTags)
			} else if fieldVal.CanAddr() && fieldVal.CanInterface() {
				p.injectInstanceWithOverrideTags(fieldVal.Addr().Interface(), injectTags)
			}
			continue
		}
		structField := typ.Field(i)
		sfTag := structField.Tag

		tag, ok := injectTags[structField.Name]
		if !ok {
			tag = sfTag.Get("inject")
		}
		found, name, optional := parseInjectTag(tag)
		if !found {
			continue
		}

		if name == injectTagNoname {
			name = ""
		}

		foundBind := p.findBind(name, structField.Type)
		if foundBind == nil {
			if !optional {
				panic(fmt.Errorf("Can't find bind instance for %v.%s %s", typ, structField.Name, name))
			} else {
				c.Infof("skip optional %s %s ", name, structField.Type)
				continue
			}
		}

		if !fieldVal.CanSet() {
			panic(fmt.Errorf("Can't inject unexported  %v.%s", typ, structField.Name))
		}

		fieldInjectDesc := fmt.Sprintf("%s.%s", typ.Name(), structField.Name)
		c.Debugf("Inject %T#%s to %s", foundBind.instance, foundBind.name, fieldInjectDesc)
		if foundBind.injectValue.Kind() == reflect.Ptr && foundBind.injectValue.Pointer() == val.Pointer() {
			injectSrcDesc := fmt.Sprintf("%#v(addr:%p)", foundBind.instance, foundBind.instance)
			injectTargetDesc := fmt.Sprintf("%s of %#v(addr:%p)", fieldInjectDesc, target, target)
			panic(fmt.Errorf("Found circular inject,src:%s,target:%s", injectSrcDesc, injectTargetDesc))
		}
		fieldVal.Set(foundBind.injectValue)
	}
}

// injectModules 注入Injector中各个Module中的绑定
func (p *Injector) injectModules() {
	c.Debugf("Inject internal")
	for _, bind := range p.ununamed {
		p.injectInstanceWithOverrideTags(bind.instance, bind.injectTags)
	}

	for _, binds := range p.named {
		for _, bind := range binds {
			p.injectInstanceWithOverrideTags(bind.instance, bind.injectTags)
		}
	}
}

// getFieldType 取得struct中field的类型
func getFieldType(structObj interface{}, fieldIndex int) reflect.Type {
	val := reflect.Indirect(reflect.ValueOf(structObj))
	return val.Field(fieldIndex).Type()
}

// parseInjectTag 解析inject tag,inject tag的格式
func parseInjectTag(tag string) (found bool, name string, optional bool) {
	tag = strings.TrimSpace(tag)
	if len(tag) == 0 {
		return
	}

	vals := strings.Split(tag, ",")
	if len(vals) > 0 {
		found = true
		name = strings.TrimSpace(vals[0])
	}

	others := vals[1:]
	for _, o := range others {
		o = strings.ToLower(strings.TrimSpace(o))
		if o == "optional" {
			optional = true
		}
	}
	return
}
<|endoftext|>