<commit_before>// Copyright 2014 The Prometheus 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 storage

import (
	"context"
	"errors"
	"fmt"

	"github.com/prometheus/prometheus/pkg/exemplar"
	"github.com/prometheus/prometheus/pkg/labels"
	"github.com/prometheus/prometheus/tsdb/chunkenc"
	"github.com/prometheus/prometheus/tsdb/chunks"
)

// The errors exposed.
var (
	ErrNotFound                    = errors.New("not found")
	ErrOutOfOrderSample            = errors.New("out of order sample")
	ErrDuplicateSampleForTimestamp = errors.New("duplicate sample for timestamp")
	ErrOutOfBounds                 = errors.New("out of bounds")
	ErrOutOfOrderExemplar          = errors.New("out of order exemplar")
	ErrDuplicateExemplar           = errors.New("duplicate exemplar")
	ErrExemplarLabelLength         = fmt.Errorf("label length for exemplar exceeds maximum of %d UTF-8 characters", exemplar.ExemplarMaxLabelSetLength)
)

// Appendable allows creating appenders.
type Appendable interface {
	// Appender returns a new appender for the storage. The implementation
	// can choose whether or not to use the context, for deadlines or to check
	// for errors.
	Appender(ctx context.Context) Appender
}

// SampleAndChunkQueryable allows retrieving samples as well as encoded samples in form of chunks.
type SampleAndChunkQueryable interface {
	Queryable
	ChunkQueryable
}

// Storage ingests and manages samples, along with various indexes. All methods
// are goroutine-safe. Storage implements storage.Appender.
type Storage interface {
	SampleAndChunkQueryable
	Appendable

	// StartTime returns the oldest timestamp stored in the storage.
	StartTime() (int64, error)

	// Close closes the storage and all its underlying resources.
	Close() error
}

// ExemplarStorage ingests and manages exemplars, along with various indexes. All methods are
// goroutine-safe. ExemplarStorage implements storage.ExemplarAppender and storage.ExemplarQuerier.
type ExemplarStorage interface {
	ExemplarQueryable
	ExemplarAppender
}

// A Queryable handles queries against a storage.
// Use it when you need to have access to all samples without chunk encoding abstraction e.g promQL.
type Queryable interface {
	// Querier returns a new Querier on the storage.
	Querier(ctx context.Context, mint, maxt int64) (Querier, error)
}

// Querier provides querying access over time series data of a fixed time range.
type Querier interface {
	LabelQuerier

	// Select returns a set of series that matches the given label matchers.
	// Caller can specify if it requires returned series to be sorted. Prefer not requiring sorting for better performance.
	// It allows passing hints that can help in optimising select, but it's up to implementation how this is used if used at all.
	Select(sortSeries bool, hints *SelectHints, matchers ...*labels.Matcher) SeriesSet
}

// A ChunkQueryable handles queries against a storage.
// Use it when you need to have access to samples in encoded format.
type ChunkQueryable interface {
	// ChunkQuerier returns a new ChunkQuerier on the storage.
	ChunkQuerier(ctx context.Context, mint, maxt int64) (ChunkQuerier, error)
}

// ChunkQuerier provides querying access over time series data of a fixed time range.
type ChunkQuerier interface {
	LabelQuerier

	// Select returns a set of series that matches the given label matchers.
	// Caller can specify if it requires returned series to be sorted. Prefer not requiring sorting for better performance.
	// It allows passing hints that can help in optimising select, but it's up to implementation how this is used if used at all.
	Select(sortSeries bool, hints *SelectHints, matchers ...*labels.Matcher) ChunkSeriesSet
}

// LabelQuerier provides querying access over labels.
type LabelQuerier interface {
	// LabelValues returns all potential values for a label name.
	// It is not safe to use the strings beyond the lifefime of the querier.
	// If matchers are specified the returned result set is reduced
	// to label values of metrics matching the matchers.
	LabelValues(name string, matchers ...*labels.Matcher) ([]string, Warnings, error)

	// LabelNames returns all the unique label names present in the block in sorted order.
	// TODO(yeya24): support matchers or hints.
	LabelNames() ([]string, Warnings, error)

	// Close releases the resources of the Querier.
	Close() error
}

type ExemplarQueryable interface {
	// ExemplarQuerier returns a new ExemplarQuerier on the storage.
	ExemplarQuerier(ctx context.Context) (ExemplarQuerier, error)
}

// Querier provides reading access to time series data.
type ExemplarQuerier interface {
	// Select all the exemplars that match the matchers.
	// Within a single slice of matchers, it is an intersection. Between the slices, it is a union.
	Select(start, end int64, matchers ...[]*labels.Matcher) ([]exemplar.QueryResult, error)
}

// SelectHints specifies hints passed for data selections.
// This is used only as an option for implementation to use.
type SelectHints struct {
	Start int64 // Start time in milliseconds for this select.
	End   int64 // End time in milliseconds for this select.

	Step int64  // Query step size in milliseconds.
	Func string // String representation of surrounding function or aggregation.

	Grouping []string // List of label names used in aggregation.
	By       bool     // Indicate whether it is without or by.
	Range    int64    // Range vector selector range in milliseconds.
}

// TODO(bwplotka): Move to promql/engine_test.go?
// QueryableFunc is an adapter to allow the use of ordinary functions as
// Queryables. It follows the idea of http.HandlerFunc.
type QueryableFunc func(ctx context.Context, mint, maxt int64) (Querier, error)

// Querier calls f() with the given parameters.
func (f QueryableFunc) Querier(ctx context.Context, mint, maxt int64) (Querier, error) {
	return f(ctx, mint, maxt)
}

// Appender provides batched appends against a storage.
// It must be completed with a call to Commit or Rollback and must not be reused afterwards.
//
// Operations on the Appender interface are not goroutine-safe.
type Appender interface {
	// Append adds a sample pair for the given series.
	// An optional reference number can be provided to accelerate calls.
	// A reference number is returned which can be used to add further
	// samples in the same or later transactions.
	// Returned reference numbers are ephemeral and may be rejected in calls
	// to Append() at any point. Adding the sample via Append() returns a new
	// reference number.
	// If the reference is 0 it must not be used for caching.
	Append(ref uint64, l labels.Labels, t int64, v float64) (uint64, error)

	// Commit submits the collected samples and purges the batch. If Commit
	// returns a non-nil error, it also rolls back all modifications made in
	// the appender so far, as Rollback would do. In any case, an Appender
	// must not be used anymore after Commit has been called.
	Commit() error

	// Rollback rolls back all modifications made in the appender so far.
	// Appender has to be discarded after rollback.
	Rollback() error

	ExemplarAppender
}

// GetRef is an extra interface on Appenders used by downstream projects
// (e.g. Cortex) to avoid maintaining a parallel set of references.
type GetRef interface {
	// Returns reference number that can be used to pass to Appender.Append(),
	// and a set of labels that will not cause another copy when passed to Appender.Append().
	// 0 means the appender does not have a reference to this series.
	GetRef(lset labels.Labels) (uint64, labels.Labels)
}

// ExemplarAppender provides an interface for adding samples to exemplar storage, which
// within Prometheus is in-memory only.
type ExemplarAppender interface {
	// AppendExemplar adds an exemplar for the given series labels.
	// An optional reference number can be provided to accelerate calls.
	// A reference number is returned which can be used to add further
	// exemplars in the same or later transactions.
	// Returned reference numbers are ephemeral and may be rejected in calls
	// to Append() at any point. Adding the sample via Append() returns a new
	// reference number.
	// If the reference is 0 it must not be used for caching.
	// Note that in our current implementation of Prometheus' exemplar storage
	// calls to Append should generate the reference numbers, AppendExemplar
	// generating a new reference number should be considered possible erroneous behaviour and be logged.
	AppendExemplar(ref uint64, l labels.Labels, e exemplar.Exemplar) (uint64, error)
}

// SeriesSet contains a set of series.
type SeriesSet interface {
	Next() bool
	// At returns full series. Returned series should be iterable even after Next is called.
	At() Series
	// The error that iteration as failed with.
	// When an error occurs, set cannot continue to iterate.
	Err() error
	// A collection of warnings for the whole set.
	// Warnings could be return even iteration has not failed with error.
	Warnings() Warnings
}

var emptySeriesSet = errSeriesSet{}

// EmptySeriesSet returns a series set that's always empty.
func EmptySeriesSet() SeriesSet {
	return emptySeriesSet
}

type errSeriesSet struct {
	err error
}

func (s errSeriesSet) Next() bool         { return false }
func (s errSeriesSet) At() Series         { return nil }
func (s errSeriesSet) Err() error         { return s.err }
func (s errSeriesSet) Warnings() Warnings { return nil }

// ErrSeriesSet returns a series set that wraps an error.
func ErrSeriesSet(err error) SeriesSet {
	return errSeriesSet{err: err}
}

var emptyChunkSeriesSet = errChunkSeriesSet{}

// EmptyChunkSeriesSet returns a chunk series set that's always empty.
func EmptyChunkSeriesSet() ChunkSeriesSet {
	return emptyChunkSeriesSet
}

type errChunkSeriesSet struct {
	err error
}

func (s errChunkSeriesSet) Next() bool         { return false }
func (s errChunkSeriesSet) At() ChunkSeries    { return nil }
func (s errChunkSeriesSet) Err() error         { return s.err }
func (s errChunkSeriesSet) Warnings() Warnings { return nil }

// ErrChunkSeriesSet returns a chunk series set that wraps an error.
func ErrChunkSeriesSet(err error) ChunkSeriesSet {
	return errChunkSeriesSet{err: err}
}

// Series exposes a single time series and allows iterating over samples.
type Series interface {
	Labels
	SampleIterable
}

// ChunkSeriesSet contains a set of chunked series.
type ChunkSeriesSet interface {
	Next() bool
	// At returns full chunk series. Returned series should be iterable even after Next is called.
	At() ChunkSeries
	// The error that iteration has failed with.
	// When an error occurs, set cannot continue to iterate.
	Err() error
	// A collection of warnings for the whole set.
	// Warnings could be return even iteration has not failed with error.
	Warnings() Warnings
}

// ChunkSeries exposes a single time series and allows iterating over chunks.
type ChunkSeries interface {
	Labels
	ChunkIterable
}

// Labels represents an item that has labels e.g. time series.
type Labels interface {
	// Labels returns the complete set of labels. For series it means all labels identifying the series.
	Labels() labels.Labels
}

type SampleIterable interface {
	// Iterator returns a new, independent iterator of the data of the series.
	Iterator() chunkenc.Iterator
}

type ChunkIterable interface {
	// Iterator returns a new, independent iterator that iterates over potentially overlapping
	// chunks of the series, sorted by min time.
	Iterator() chunks.Iterator
}

type Warnings []error
<commit_msg>Fix golint issue<commit_after>// Copyright 2014 The Prometheus 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 storage

import (
	"context"
	"errors"
	"fmt"

	"github.com/prometheus/prometheus/pkg/exemplar"
	"github.com/prometheus/prometheus/pkg/labels"
	"github.com/prometheus/prometheus/tsdb/chunkenc"
	"github.com/prometheus/prometheus/tsdb/chunks"
)

// The errors exposed.
var (
	ErrNotFound                    = errors.New("not found")
	ErrOutOfOrderSample            = errors.New("out of order sample")
	ErrDuplicateSampleForTimestamp = errors.New("duplicate sample for timestamp")
	ErrOutOfBounds                 = errors.New("out of bounds")
	ErrOutOfOrderExemplar          = errors.New("out of order exemplar")
	ErrDuplicateExemplar           = errors.New("duplicate exemplar")
	ErrExemplarLabelLength         = fmt.Errorf("label length for exemplar exceeds maximum of %d UTF-8 characters", exemplar.ExemplarMaxLabelSetLength)
)

// Appendable allows creating appenders.
type Appendable interface {
	// Appender returns a new appender for the storage. The implementation
	// can choose whether or not to use the context, for deadlines or to check
	// for errors.
	Appender(ctx context.Context) Appender
}

// SampleAndChunkQueryable allows retrieving samples as well as encoded samples in form of chunks.
type SampleAndChunkQueryable interface {
	Queryable
	ChunkQueryable
}

// Storage ingests and manages samples, along with various indexes. All methods
// are goroutine-safe. Storage implements storage.Appender.
type Storage interface {
	SampleAndChunkQueryable
	Appendable

	// StartTime returns the oldest timestamp stored in the storage.
	StartTime() (int64, error)

	// Close closes the storage and all its underlying resources.
	Close() error
}

// ExemplarStorage ingests and manages exemplars, along with various indexes. All methods are
// goroutine-safe. ExemplarStorage implements storage.ExemplarAppender and storage.ExemplarQuerier.
type ExemplarStorage interface {
	ExemplarQueryable
	ExemplarAppender
}

// A Queryable handles queries against a storage.
// Use it when you need to have access to all samples without chunk encoding abstraction e.g promQL.
type Queryable interface {
	// Querier returns a new Querier on the storage.
	Querier(ctx context.Context, mint, maxt int64) (Querier, error)
}

// Querier provides querying access over time series data of a fixed time range.
type Querier interface {
	LabelQuerier

	// Select returns a set of series that matches the given label matchers.
	// Caller can specify if it requires returned series to be sorted. Prefer not requiring sorting for better performance.
	// It allows passing hints that can help in optimising select, but it's up to implementation how this is used if used at all.
	Select(sortSeries bool, hints *SelectHints, matchers ...*labels.Matcher) SeriesSet
}

// A ChunkQueryable handles queries against a storage.
// Use it when you need to have access to samples in encoded format.
type ChunkQueryable interface {
	// ChunkQuerier returns a new ChunkQuerier on the storage.
	ChunkQuerier(ctx context.Context, mint, maxt int64) (ChunkQuerier, error)
}

// ChunkQuerier provides querying access over time series data of a fixed time range.
type ChunkQuerier interface {
	LabelQuerier

	// Select returns a set of series that matches the given label matchers.
	// Caller can specify if it requires returned series to be sorted. Prefer not requiring sorting for better performance.
	// It allows passing hints that can help in optimising select, but it's up to implementation how this is used if used at all.
	Select(sortSeries bool, hints *SelectHints, matchers ...*labels.Matcher) ChunkSeriesSet
}

// LabelQuerier provides querying access over labels.
type LabelQuerier interface {
	// LabelValues returns all potential values for a label name.
	// It is not safe to use the strings beyond the lifefime of the querier.
	// If matchers are specified the returned result set is reduced
	// to label values of metrics matching the matchers.
	LabelValues(name string, matchers ...*labels.Matcher) ([]string, Warnings, error)

	// LabelNames returns all the unique label names present in the block in sorted order.
	// TODO(yeya24): support matchers or hints.
	LabelNames() ([]string, Warnings, error)

	// Close releases the resources of the Querier.
	Close() error
}

type ExemplarQueryable interface {
	// ExemplarQuerier returns a new ExemplarQuerier on the storage.
	ExemplarQuerier(ctx context.Context) (ExemplarQuerier, error)
}

// ExemplarQuerier provides reading access to time series data.
type ExemplarQuerier interface {
	// Select all the exemplars that match the matchers.
	// Within a single slice of matchers, it is an intersection. Between the slices, it is a union.
	Select(start, end int64, matchers ...[]*labels.Matcher) ([]exemplar.QueryResult, error)
}

// SelectHints specifies hints passed for data selections.
// This is used only as an option for implementation to use.
type SelectHints struct {
	Start int64 // Start time in milliseconds for this select.
	End   int64 // End time in milliseconds for this select.

	Step int64  // Query step size in milliseconds.
	Func string // String representation of surrounding function or aggregation.

	Grouping []string // List of label names used in aggregation.
	By       bool     // Indicate whether it is without or by.
	Range    int64    // Range vector selector range in milliseconds.
}

// TODO(bwplotka): Move to promql/engine_test.go?
// QueryableFunc is an adapter to allow the use of ordinary functions as
// Queryables. It follows the idea of http.HandlerFunc.
type QueryableFunc func(ctx context.Context, mint, maxt int64) (Querier, error)

// Querier calls f() with the given parameters.
func (f QueryableFunc) Querier(ctx context.Context, mint, maxt int64) (Querier, error) {
	return f(ctx, mint, maxt)
}

// Appender provides batched appends against a storage.
// It must be completed with a call to Commit or Rollback and must not be reused afterwards.
//
// Operations on the Appender interface are not goroutine-safe.
type Appender interface {
	// Append adds a sample pair for the given series.
	// An optional reference number can be provided to accelerate calls.
	// A reference number is returned which can be used to add further
	// samples in the same or later transactions.
	// Returned reference numbers are ephemeral and may be rejected in calls
	// to Append() at any point. Adding the sample via Append() returns a new
	// reference number.
	// If the reference is 0 it must not be used for caching.
	Append(ref uint64, l labels.Labels, t int64, v float64) (uint64, error)

	// Commit submits the collected samples and purges the batch. If Commit
	// returns a non-nil error, it also rolls back all modifications made in
	// the appender so far, as Rollback would do. In any case, an Appender
	// must not be used anymore after Commit has been called.
	Commit() error

	// Rollback rolls back all modifications made in the appender so far.
	// Appender has to be discarded after rollback.
	Rollback() error

	ExemplarAppender
}

// GetRef is an extra interface on Appenders used by downstream projects
// (e.g. Cortex) to avoid maintaining a parallel set of references.
type GetRef interface {
	// Returns reference number that can be used to pass to Appender.Append(),
	// and a set of labels that will not cause another copy when passed to Appender.Append().
	// 0 means the appender does not have a reference to this series.
	GetRef(lset labels.Labels) (uint64, labels.Labels)
}

// ExemplarAppender provides an interface for adding samples to exemplar storage, which
// within Prometheus is in-memory only.
type ExemplarAppender interface {
	// AppendExemplar adds an exemplar for the given series labels.
	// An optional reference number can be provided to accelerate calls.
	// A reference number is returned which can be used to add further
	// exemplars in the same or later transactions.
	// Returned reference numbers are ephemeral and may be rejected in calls
	// to Append() at any point. Adding the sample via Append() returns a new
	// reference number.
	// If the reference is 0 it must not be used for caching.
	// Note that in our current implementation of Prometheus' exemplar storage
	// calls to Append should generate the reference numbers, AppendExemplar
	// generating a new reference number should be considered possible erroneous behaviour and be logged.
	AppendExemplar(ref uint64, l labels.Labels, e exemplar.Exemplar) (uint64, error)
}

// SeriesSet contains a set of series.
type SeriesSet interface {
	Next() bool
	// At returns full series. Returned series should be iterable even after Next is called.
	At() Series
	// The error that iteration as failed with.
	// When an error occurs, set cannot continue to iterate.
	Err() error
	// A collection of warnings for the whole set.
	// Warnings could be return even iteration has not failed with error.
	Warnings() Warnings
}

var emptySeriesSet = errSeriesSet{}

// EmptySeriesSet returns a series set that's always empty.
func EmptySeriesSet() SeriesSet {
	return emptySeriesSet
}

type errSeriesSet struct {
	err error
}

func (s errSeriesSet) Next() bool         { return false }
func (s errSeriesSet) At() Series         { return nil }
func (s errSeriesSet) Err() error         { return s.err }
func (s errSeriesSet) Warnings() Warnings { return nil }

// ErrSeriesSet returns a series set that wraps an error.
func ErrSeriesSet(err error) SeriesSet {
	return errSeriesSet{err: err}
}

var emptyChunkSeriesSet = errChunkSeriesSet{}

// EmptyChunkSeriesSet returns a chunk series set that's always empty.
func EmptyChunkSeriesSet() ChunkSeriesSet {
	return emptyChunkSeriesSet
}

type errChunkSeriesSet struct {
	err error
}

func (s errChunkSeriesSet) Next() bool         { return false }
func (s errChunkSeriesSet) At() ChunkSeries    { return nil }
func (s errChunkSeriesSet) Err() error         { return s.err }
func (s errChunkSeriesSet) Warnings() Warnings { return nil }

// ErrChunkSeriesSet returns a chunk series set that wraps an error.
func ErrChunkSeriesSet(err error) ChunkSeriesSet {
	return errChunkSeriesSet{err: err}
}

// Series exposes a single time series and allows iterating over samples.
type Series interface {
	Labels
	SampleIterable
}

// ChunkSeriesSet contains a set of chunked series.
type ChunkSeriesSet interface {
	Next() bool
	// At returns full chunk series. Returned series should be iterable even after Next is called.
	At() ChunkSeries
	// The error that iteration has failed with.
	// When an error occurs, set cannot continue to iterate.
	Err() error
	// A collection of warnings for the whole set.
	// Warnings could be return even iteration has not failed with error.
	Warnings() Warnings
}

// ChunkSeries exposes a single time series and allows iterating over chunks.
type ChunkSeries interface {
	Labels
	ChunkIterable
}

// Labels represents an item that has labels e.g. time series.
type Labels interface {
	// Labels returns the complete set of labels. For series it means all labels identifying the series.
	Labels() labels.Labels
}

type SampleIterable interface {
	// Iterator returns a new, independent iterator of the data of the series.
	Iterator() chunkenc.Iterator
}

type ChunkIterable interface {
	// Iterator returns a new, independent iterator that iterates over potentially overlapping
	// chunks of the series, sorted by min time.
	Iterator() chunks.Iterator
}

type Warnings []error
<|endoftext|>


<commit_before>package m

import (
	"encoding/json"
	"log"
)

type M map[string]interface{}

func (d M) JSON() []byte {
	s, err := json.Marshal(d)
	if err != nil {
		log.Println("[ERROR]: Failed to JSON encode err:" + err.Error())
	}
	return s
}
<commit_msg>Added a comment, so m.go's puspose is clearer<commit_after>package m

import (
	"encoding/json"
	"log"
)

type M map[string]interface{}

//Converts some mapping from a string to an anything into JSON
func (d M) JSON() []byte {
	s, err := json.Marshal(d)
	if err != nil {
		log.Println("[ERROR]: Failed to JSON encode err:" + err.Error())
	}
	return s
}
<|endoftext|>


<commit_before>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package context

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

	"github.com/juju/cmd"
	"github.com/juju/errors"
	"gopkg.in/juju/charm.v5"
	"gopkg.in/yaml.v1"
	"launchpad.net/gnuflag"

	"github.com/juju/juju/process"
)

// TODO(ericsnow) How to convert endpoints (charm.Process.Ports[].Name)
// into actual ports? For now we should error out with such definitions
// (and recommend overriding).

// baseCommand implements the common portions of the workload process
// hook env commands.
type baseCommand struct {
	cmd.CommandBase

	ctx     HookContext
	compCtx Component

	// Name is the name of the process in charm metadata.
	Name string
	// info is the process info for the named workload process.
	info *process.Info
}

func newCommand(ctx HookContext) (*baseCommand, error) {
	compCtx, err := ContextComponent(ctx)
	if err != nil {
		// The component wasn't registered properly.
		return nil, errors.Trace(err)
	}
	return &baseCommand{
		ctx:     ctx,
		compCtx: compCtx,
	}, nil
}

// Init implements cmd.Command.
func (c *baseCommand) Init(args []string) error {
	if len(args) == 0 {
		return errors.Errorf("missing process name")
	}
	return errors.Trace(c.init(args[0]))
}

func (c *baseCommand) init(name string) error {
	if name == "" {
		return errors.Errorf("got empty name")
	}
	c.Name = name

	pInfo, err := c.compCtx.Get(c.Name)
	if err != nil && !errors.IsNotFound(err) {
		return errors.Trace(err)
	}
	c.info = pInfo

	return nil
}

// registeringCommand is the base for commands that register a process
// that has been launched.
type registeringCommand struct {
	baseCommand

	// Details is the launch details returned from the process plugin.
	Details process.Details

	// Overrides overwrite the process definition.
	Overrides []string

	// Additions extend the process definition.
	Additions []string

	// UpdatedProcess stores the new process, if there were any overrides OR additions.
	UpdatedProcess *charm.Process

	// Definition is the file definition of the process.
	Definition cmd.FileVar

	// ReadMetadata extracts charm metadata from the given file.
	ReadMetadata func(filename string) (*charm.Meta, error)
}

func newRegisteringCommand(ctx HookContext) (*registeringCommand, error) {
	base, err := newCommand(ctx)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return &registeringCommand{
		baseCommand:  *base,
		ReadMetadata: readMetadata,
	}, nil
}

func readMetadata(filename string) (*charm.Meta, error) {
	file, err := os.Open(filename)
	if err != nil {
		return nil, errors.Trace(err)
	}
	defer file.Close()

	meta, err := charm.ReadMeta(file)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return meta, nil
}

// SetFlags implements cmd.Command.
func (c *registeringCommand) SetFlags(f *gnuflag.FlagSet) {
	f.Var(&c.Definition, "definition", "process definition filename (use \"-\" for STDIN)")
	f.Var(cmd.NewAppendStringsValue(&c.Overrides), "override", "override process definition")
	f.Var(cmd.NewAppendStringsValue(&c.Additions), "extend", "extend process definition")
}

func (c *registeringCommand) init(name string) error {
	if err := c.baseCommand.init(name); err != nil {
		return errors.Trace(err)
	}

	if c.info != nil {
		return errors.Errorf("process %q already registered", c.Name)
	}

	if err := c.checkSpace(); err != nil {
		return errors.Trace(err)
	}

	// Either the named process must already be defined or the command
	// must have been run with the --definition option.
	if c.Definition.Path != "" {
		if c.info != nil {
			return errors.Errorf("process %q already defined", c.Name)
		}
	}

	return nil
}

// register updates the hook context with the information for the
// registered workload process. An error is returned if the process
// was already registered.
func (c *registeringCommand) register(ctx *cmd.Context) error {
	info, err := c.findValidInfo(ctx)
	if err != nil {
		return errors.Trace(err)
	}

	newProcess, err := c.parseUpdates(info.Process)
	if err != nil {
		return errors.Trace(err)
	}
	c.UpdatedProcess = newProcess
	info.Process = *newProcess

	info.Details = c.Details

	if err := c.compCtx.Set(c.Name, info); err != nil {
		return errors.Trace(err)
	}

	// We flush to state immedeiately so that status reflects the
	// process correctly.
	if err := c.compCtx.Flush(); err != nil {
		return errors.Trace(err)
	}

	return nil
}

func (c *registeringCommand) findValidInfo(ctx *cmd.Context) (*process.Info, error) {
	if c.info != nil {
		copied := *c.info
		return &copied, nil
	}

	var definition charm.Process
	if c.Definition.Path == "" {
		filename := filepath.Join(ctx.Dir, "metadata.yaml")
		charmDef, err := c.defFromMetadata(c.Name, filename)
		if err != nil {
			return nil, errors.Trace(err)
		}
		definition = *charmDef
	} else {
		// c.info must be nil at this point.
		data, err := c.Definition.Read(ctx)
		if err != nil {
			return nil, errors.Trace(err)
		}
		cliDef, err := parseDefinition(c.Name, data)
		if err != nil {
			return nil, errors.Trace(err)
		}
		definition = *cliDef
	}
	info := &process.Info{Process: definition}
	c.info = info

	// validate
	if err := info.Validate(); err != nil {
		return nil, errors.Trace(err)
	}
	if info.IsRegistered() {
		return nil, errors.Errorf("already registered")
	}
	return info, nil
}

func (c *registeringCommand) defFromMetadata(name, filename string) (*charm.Process, error) {
	meta, err := c.ReadMetadata(filename)
	if err != nil {
		return nil, errors.Trace(err)
	}
	for _, definition := range meta.Processes {
		if name == definition.Name {
			return &definition, nil
		}
	}
	return nil, errors.NotFoundf(name)
}

func parseDefinition(name string, data []byte) (*charm.Process, error) {
	raw := make(map[interface{}]interface{})
	if err := yaml.Unmarshal(data, raw); err != nil {
		return nil, errors.Trace(err)
	}
	definition, err := charm.ParseProcess(name, raw)
	if err != nil {
		return nil, errors.Trace(err)
	}
	if definition.Name == "" {
		definition.Name = name
	} else if definition.Name != name {
		return nil, errors.Errorf("process name mismatch; %q != %q", definition.Name, name)
	}
	return definition, nil
}

// checkSpace ensures that the requested network space is available
// to the hook.
func (c *registeringCommand) checkSpace() error {
	// TODO(wwitzel3) implement this to ensure that the endpoints provided exist in this space
	return nil
}

func (c *registeringCommand) parseUpdates(definition charm.Process) (*charm.Process, error) {
	overrides, err := parseUpdates(c.Overrides)
	if err != nil {
		return nil, errors.Annotate(err, "override")
	}

	additions, err := parseUpdates(c.Additions)
	if err != nil {
		return nil, errors.Annotate(err, "extend")
	}

	newDefinition, err := definition.Apply(overrides, additions)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return newDefinition, nil
}

// parseUpdate builds a charm.ProcessFieldValue from an update string.
func parseUpdate(update string) (charm.ProcessFieldValue, error) {
	var pfv charm.ProcessFieldValue

	parts := strings.SplitN(update, ":", 2)
	if len(parts) == 1 {
		return pfv, errors.Errorf("missing value")
	}
	pfv.Field, pfv.Value = parts[0], parts[1]

	if pfv.Field == "" {
		return pfv, errors.Errorf("missing field")
	}
	if pfv.Value == "" {
		return pfv, errors.Errorf("missing value")
	}

	fieldParts := strings.SplitN(pfv.Field, "/", 2)
	if len(fieldParts) == 2 {
		pfv.Field = fieldParts[0]
		pfv.Subfield = fieldParts[1]
	}

	return pfv, nil
}

// parseUpdates parses the updates list in to a charm.ProcessFieldValue list.
func parseUpdates(updates []string) ([]charm.ProcessFieldValue, error) {
	var results []charm.ProcessFieldValue
	for _, update := range updates {
		pfv, err := parseUpdate(update)
		if err != nil {
			return nil, errors.Trace(err)
		}
		results = append(results, pfv)
	}
	return results, nil
}
<commit_msg>refactor parseUpdates calls<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package context

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

	"github.com/juju/cmd"
	"github.com/juju/errors"
	"github.com/juju/loggo"
	"gopkg.in/juju/charm.v5"
	"gopkg.in/yaml.v1"
	"launchpad.net/gnuflag"

	"github.com/juju/juju/process"
)

var logger = loggo.GetLogger("juju.process.persistence")

// TODO(ericsnow) How to convert endpoints (charm.Process.Ports[].Name)
// into actual ports? For now we should error out with such definitions
// (and recommend overriding).

// baseCommand implements the common portions of the workload process
// hook env commands.
type baseCommand struct {
	cmd.CommandBase

	ctx     HookContext
	compCtx Component

	// Name is the name of the process in charm metadata.
	Name string
	// info is the process info for the named workload process.
	info *process.Info
}

func newCommand(ctx HookContext) (*baseCommand, error) {
	compCtx, err := ContextComponent(ctx)
	if err != nil {
		// The component wasn't registered properly.
		return nil, errors.Trace(err)
	}
	return &baseCommand{
		ctx:     ctx,
		compCtx: compCtx,
	}, nil
}

// Init implements cmd.Command.
func (c *baseCommand) Init(args []string) error {
	if len(args) == 0 {
		return errors.Errorf("missing process name")
	}
	return errors.Trace(c.init(args[0]))
}

func (c *baseCommand) init(name string) error {
	if name == "" {
		return errors.Errorf("got empty name")
	}
	c.Name = name

	pInfo, err := c.compCtx.Get(c.Name)
	if err != nil && !errors.IsNotFound(err) {
		return errors.Trace(err)
	}
	c.info = pInfo

	return nil
}

// registeringCommand is the base for commands that register a process
// that has been launched.
type registeringCommand struct {
	baseCommand

	// Details is the launch details returned from the process plugin.
	Details process.Details

	// Overrides overwrite the process definition.
	Overrides []string

	// Additions extend the process definition.
	Additions []string

	// UpdatedProcess stores the new process, if there were any overrides OR additions.
	UpdatedProcess *charm.Process

	// Definition is the file definition of the process.
	Definition cmd.FileVar

	// ReadMetadata extracts charm metadata from the given file.
	ReadMetadata func(filename string) (*charm.Meta, error)
}

func newRegisteringCommand(ctx HookContext) (*registeringCommand, error) {
	base, err := newCommand(ctx)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return &registeringCommand{
		baseCommand:  *base,
		ReadMetadata: readMetadata,
	}, nil
}

func readMetadata(filename string) (*charm.Meta, error) {
	file, err := os.Open(filename)
	if err != nil {
		return nil, errors.Trace(err)
	}
	defer file.Close()

	meta, err := charm.ReadMeta(file)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return meta, nil
}

// SetFlags implements cmd.Command.
func (c *registeringCommand) SetFlags(f *gnuflag.FlagSet) {
	f.Var(&c.Definition, "definition", "process definition filename (use \"-\" for STDIN)")
	f.Var(cmd.NewAppendStringsValue(&c.Overrides), "override", "override process definition")
	f.Var(cmd.NewAppendStringsValue(&c.Additions), "extend", "extend process definition")
}

func (c *registeringCommand) init(name string) error {
	if err := c.baseCommand.init(name); err != nil {
		return errors.Trace(err)
	}

	if c.info != nil {
		return errors.Errorf("process %q already registered", c.Name)
	}

	if err := c.checkSpace(); err != nil {
		return errors.Trace(err)
	}

	// Either the named process must already be defined or the command
	// must have been run with the --definition option.
	if c.Definition.Path != "" {
		if c.info != nil {
			return errors.Errorf("process %q already defined", c.Name)
		}
	}

	return nil
}

// register updates the hook context with the information for the
// registered workload process. An error is returned if the process
// was already registered.
func (c *registeringCommand) register(ctx *cmd.Context) error {
	info, err := c.findValidInfo(ctx)
	if err != nil {
		return errors.Trace(err)
	}

	info.Details = c.Details

	if err := c.compCtx.Set(c.Name, info); err != nil {
		return errors.Trace(err)
	}

	// We flush to state immedeiately so that status reflects the
	// process correctly.
	if err := c.compCtx.Flush(); err != nil {
		return errors.Trace(err)
	}

	return nil
}

func (c *registeringCommand) findValidInfo(ctx *cmd.Context) (*process.Info, error) {
	if c.info != nil {
		logger.Debugf("using existing process.Info")
		copied := *c.info

		if c.UpdatedProcess == nil {
			logger.Debugf("parsing updates")
			newProcess, err := c.parseUpdates(c.info.Process)
			if err != nil {
				return nil, errors.Trace(err)
			}
			c.UpdatedProcess = newProcess
			copied.Process = *newProcess
		}
		return &copied, nil
	}

	var definition charm.Process
	if c.Definition.Path == "" {
		filename := filepath.Join(ctx.Dir, "metadata.yaml")
		charmDef, err := c.defFromMetadata(c.Name, filename)
		if err != nil {
			return nil, errors.Trace(err)
		}
		definition = *charmDef
	} else {
		// c.info must be nil at this point.
		data, err := c.Definition.Read(ctx)
		if err != nil {
			return nil, errors.Trace(err)
		}
		cliDef, err := parseDefinition(c.Name, data)
		if err != nil {
			return nil, errors.Trace(err)
		}
		definition = *cliDef
	}
	logger.Debugf("creating new process.Info")
	info := &process.Info{Process: definition}

	logger.Debugf("parsing updates")
	newProcess, err := c.parseUpdates(info.Process)
	if err != nil {
		return nil, errors.Trace(err)
	}
	c.UpdatedProcess = newProcess
	info.Process = *newProcess

	// validate
	if err := info.Validate(); err != nil {
		return nil, errors.Trace(err)
	}

	c.info = info

	if info.IsRegistered() {
		return nil, errors.Errorf("already registered")
	}
	return info, nil
}

func (c *registeringCommand) defFromMetadata(name, filename string) (*charm.Process, error) {
	meta, err := c.ReadMetadata(filename)
	if err != nil {
		return nil, errors.Trace(err)
	}
	for _, definition := range meta.Processes {
		if name == definition.Name {
			return &definition, nil
		}
	}
	return nil, errors.NotFoundf(name)
}

func parseDefinition(name string, data []byte) (*charm.Process, error) {
	raw := make(map[interface{}]interface{})
	if err := yaml.Unmarshal(data, raw); err != nil {
		return nil, errors.Trace(err)
	}
	definition, err := charm.ParseProcess(name, raw)
	if err != nil {
		return nil, errors.Trace(err)
	}
	if definition.Name == "" {
		definition.Name = name
	} else if definition.Name != name {
		return nil, errors.Errorf("process name mismatch; %q != %q", definition.Name, name)
	}
	return definition, nil
}

// checkSpace ensures that the requested network space is available
// to the hook.
func (c *registeringCommand) checkSpace() error {
	// TODO(wwitzel3) implement this to ensure that the endpoints provided exist in this space
	return nil
}

func (c *registeringCommand) parseUpdates(definition charm.Process) (*charm.Process, error) {
	overrides, err := parseUpdates(c.Overrides)
	if err != nil {
		return nil, errors.Annotate(err, "override")
	}

	additions, err := parseUpdates(c.Additions)
	if err != nil {
		return nil, errors.Annotate(err, "extend")
	}

	newDefinition, err := definition.Apply(overrides, additions)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return newDefinition, nil
}

// parseUpdate builds a charm.ProcessFieldValue from an update string.
func parseUpdate(update string) (charm.ProcessFieldValue, error) {
	var pfv charm.ProcessFieldValue

	parts := strings.SplitN(update, ":", 2)
	if len(parts) == 1 {
		return pfv, errors.Errorf("missing value")
	}
	pfv.Field, pfv.Value = parts[0], parts[1]

	if pfv.Field == "" {
		return pfv, errors.Errorf("missing field")
	}
	if pfv.Value == "" {
		return pfv, errors.Errorf("missing value")
	}

	fieldParts := strings.SplitN(pfv.Field, "/", 2)
	if len(fieldParts) == 2 {
		pfv.Field = fieldParts[0]
		pfv.Subfield = fieldParts[1]
	}

	return pfv, nil
}

// parseUpdates parses the updates list in to a charm.ProcessFieldValue list.
func parseUpdates(updates []string) ([]charm.ProcessFieldValue, error) {
	var results []charm.ProcessFieldValue
	for _, update := range updates {
		pfv, err := parseUpdate(update)
		if err != nil {
			return nil, errors.Trace(err)
		}
		results = append(results, pfv)
	}
	return results, nil
}
<|endoftext|>


<commit_before>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package context

import (
	"sort"

	"github.com/juju/errors"
	"github.com/juju/loggo"
	"gopkg.in/juju/charm.v5"

	"github.com/juju/juju/process"
)

var logger = loggo.GetLogger("juju.process.context")

// TODO(ericsnow) Normalize method names across all the arch. layers
// (e.g. List->AllProcesses, Get->Processes, Set->AddProcess).

// APIClient represents the API needs of a Context.
type APIClient interface {
	// ListProcesses requests the process info for the given ID.
	ListProcesses(ids ...string) ([]process.Info, error)
	// RegisterProcesses sends a request to update state with the provided processes.
	RegisterProcesses(procs ...process.Info) ([]string, error)
	// Untrack removes the processes from our list of processes to track.
	Untrack(ids []string) error
	// AllDefinitions returns the process definitions found in the
	// unit's metadata.
	AllDefinitions() ([]charm.Process, error)
}

// TODO(ericsnow) Rename Get and Set to more specifically describe what
// they are for.

// omponent provides the hook context data specific to workload processes.
type Component interface {
	// Get returns the process info corresponding to the given ID.
	Get(id string) (*process.Info, error)
	// Set records the process info in the hook context.
	Set(info process.Info) error
	// Untrack removes the process from our list of processes to track.
	Untrack(id string)
	// List returns the list of registered process IDs.
	List() ([]string, error)
	// ListDefinitions returns the charm-defined processes.
	ListDefinitions() ([]charm.Process, error)
	// Flush pushes the hook context data out to state.
	Flush() error
}

var _ Component = (*Context)(nil)

// Context is the workload process portion of the hook context.
type Context struct {
	api       APIClient
	processes map[string]process.Info
	updates   map[string]process.Info
	removes   map[string]struct{}
}

// NewContext returns a new jujuc.ContextComponent for workload processes.
func NewContext(api APIClient) *Context {
	return &Context{
		api:       api,
		processes: make(map[string]process.Info),
		updates:   make(map[string]process.Info),
		removes:   make(map[string]struct{}),
	}
}

// NewContextAPI returns a new jujuc.ContextComponent for workload processes.
func NewContextAPI(api APIClient) (*Context, error) {
	procs, err := api.ListProcesses()
	if err != nil {
		return nil, errors.Trace(err)
	}

	ctx := NewContext(api)
	for _, proc := range procs {
		ctx.processes[proc.ID()] = proc
	}
	return ctx, nil
}

// HookContext is the portion of jujuc.Context used in this package.
type HookContext interface {
	// Component implements jujuc.Context.
	Component(string) (Component, error)
}

// ContextComponent returns the hook context for the workload
// process component.
func ContextComponent(ctx HookContext) (Component, error) {
	compCtx, err := ctx.Component(process.ComponentName)
	if errors.IsNotFound(err) {
		return nil, errors.Errorf("component %q not registered", process.ComponentName)
	}
	if err != nil {
		return nil, errors.Trace(err)
	}
	if compCtx == nil {
		return nil, errors.Errorf("component %q disabled", process.ComponentName)
	}
	return compCtx, nil
}

// TODO(ericsnow) Should we build in refreshes in all the methods?

// Processes returns the processes known to the context.
func (c *Context) Processes() ([]process.Info, error) {
	processes := mergeProcMaps(c.processes, c.updates)
	var procs []process.Info
	for _, info := range processes {
		procs = append(procs, info)
	}

	return procs, nil
}

func mergeProcMaps(procs, updates map[string]process.Info) map[string]process.Info {
	// At this point procs and updates have already been checked for
	// nil values so we won't see any here.
	result := make(map[string]process.Info)
	for k, v := range procs {
		result[k] = v
	}
	for k, v := range updates {
		result[k] = v
	}
	return result
}

// Get returns the process info corresponding to the given ID.
func (c *Context) Get(id string) (*process.Info, error) {
	logger.Tracef("getting %q from hook context", id)

	actual, ok := c.updates[id]
	if !ok {
		actual, ok = c.processes[id]
		if !ok {
			return nil, errors.NotFoundf("%s", id)
		}
	}
	return &actual, nil
}

// List returns the sorted names of all registered processes.
func (c *Context) List() ([]string, error) {
	logger.Tracef("listing all procs in hook context")

	procs, err := c.Processes()
	if err != nil {
		return nil, errors.Trace(err)
	}
	if len(procs) == 0 {
		return nil, nil
	}
	var ids []string
	for _, proc := range procs {
		ids = append(ids, proc.ID())
	}
	sort.Strings(ids)
	return ids, nil
}

// TODO(ericsnow) rename to Track

// Set records the process info in the hook context.
func (c *Context) Set(info process.Info) error {
	// TODO(ericsnow) rename to Track
	logger.Tracef("adding %q to hook context: %#v", info.ID(), info)

	if err := info.Validate(); err != nil {
		return errors.Trace(err)
	}
	// TODO(ericsnow) We are likely missing mechanisim for local persistence.
	id := info.ID()
	c.updates[id] = info

	delete(c.removes, id)
	return nil
}

// Untrack tells juju to stop tracking this process.
func (c *Context) Untrack(id string) {
	c.removes[id] = struct{}{}
	delete(c.processes, id)
	delete(c.updates, id)
}

// ListDefinitions returns the unit's charm-defined processes.
func (c *Context) ListDefinitions() ([]charm.Process, error) {
	definitions, err := c.api.AllDefinitions()
	if err != nil {
		return nil, errors.Trace(err)
	}
	return definitions, nil
}

// TODO(ericsnow) The context machinery is not actually using this yet.

// Flush implements jujuc.ContextComponent. In this case that means all
// added and updated process.Info in the hook context are pushed to
// Juju state via the API.
func (c *Context) Flush() error {
	logger.Tracef("flushing from hook context to state")

	if len(c.updates) > 0 {
		var updates []process.Info
		for _, info := range c.updates {
			updates = append(updates, info)
		}
		if _, err := c.api.RegisterProcesses(updates...); err != nil {
			return errors.Trace(err)
		}
		for k, v := range c.updates {
			c.processes[k] = v
		}
		c.updates = map[string]process.Info{}
	}

	removes := make([]string, 0, len(c.removes))
	for id := range c.removes {
		removes = append(removes, id)
	}
	if len(removes) > 0 {
		c.api.Untrack(removes)
		c.removes = map[string]struct{}{}
	}
	return nil
}
<commit_msg>code review updates<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package context

import (
	"sort"

	"github.com/juju/errors"
	"github.com/juju/loggo"
	"gopkg.in/juju/charm.v5"

	"github.com/juju/juju/process"
)

var logger = loggo.GetLogger("juju.process.context")

// TODO(ericsnow) Normalize method names across all the arch. layers
// (e.g. List->AllProcesses, Get->Processes, Set->AddProcess).

// APIClient represents the API needs of a Context.
type APIClient interface {
	// ListProcesses requests the process info for the given ID.
	ListProcesses(ids ...string) ([]process.Info, error)
	// RegisterProcesses sends a request to update state with the provided processes.
	RegisterProcesses(procs ...process.Info) ([]string, error)
	// Untrack removes the processes from our list of processes to track.
	Untrack(ids []string) error
	// AllDefinitions returns the process definitions found in the
	// unit's metadata.
	AllDefinitions() ([]charm.Process, error)
}

// TODO(ericsnow) Rename Get and Set to more specifically describe what
// they are for.

// omponent provides the hook context data specific to workload processes.
type Component interface {
	// Get returns the process info corresponding to the given ID.
	Get(id string) (*process.Info, error)
	// Set records the process info in the hook context.
	Set(info process.Info) error
	// Untrack removes the process from our list of processes to track.
	Untrack(id string)
	// List returns the list of registered process IDs.
	List() ([]string, error)
	// ListDefinitions returns the charm-defined processes.
	ListDefinitions() ([]charm.Process, error)
	// Flush pushes the hook context data out to state.
	Flush() error
}

var _ Component = (*Context)(nil)

// Context is the workload process portion of the hook context.
type Context struct {
	api       APIClient
	processes map[string]process.Info
	updates   map[string]process.Info
	removes   map[string]struct{}
}

// NewContext returns a new jujuc.ContextComponent for workload processes.
func NewContext(api APIClient) *Context {
	return &Context{
		api:       api,
		processes: make(map[string]process.Info),
		updates:   make(map[string]process.Info),
		removes:   make(map[string]struct{}),
	}
}

// NewContextAPI returns a new jujuc.ContextComponent for workload processes.
func NewContextAPI(api APIClient) (*Context, error) {
	procs, err := api.ListProcesses()
	if err != nil {
		return nil, errors.Trace(err)
	}

	ctx := NewContext(api)
	for _, proc := range procs {
		ctx.processes[proc.ID()] = proc
	}
	return ctx, nil
}

// HookContext is the portion of jujuc.Context used in this package.
type HookContext interface {
	// Component implements jujuc.Context.
	Component(string) (Component, error)
}

// ContextComponent returns the hook context for the workload
// process component.
func ContextComponent(ctx HookContext) (Component, error) {
	compCtx, err := ctx.Component(process.ComponentName)
	if errors.IsNotFound(err) {
		return nil, errors.Errorf("component %q not registered", process.ComponentName)
	}
	if err != nil {
		return nil, errors.Trace(err)
	}
	if compCtx == nil {
		return nil, errors.Errorf("component %q disabled", process.ComponentName)
	}
	return compCtx, nil
}

// TODO(ericsnow) Should we build in refreshes in all the methods?

// Processes returns the processes known to the context.
func (c *Context) Processes() ([]process.Info, error) {
	processes := mergeProcMaps(c.processes, c.updates)
	var procs []process.Info
	for _, info := range processes {
		procs = append(procs, info)
	}

	return procs, nil
}

func mergeProcMaps(procs, updates map[string]process.Info) map[string]process.Info {
	// At this point procs and updates have already been checked for
	// nil values so we won't see any here.
	result := make(map[string]process.Info)
	for k, v := range procs {
		result[k] = v
	}
	for k, v := range updates {
		result[k] = v
	}
	return result
}

// Get returns the process info corresponding to the given ID.
func (c *Context) Get(id string) (*process.Info, error) {
	logger.Tracef("getting %q from hook context", id)

	actual, ok := c.updates[id]
	if !ok {
		actual, ok = c.processes[id]
		if !ok {
			return nil, errors.NotFoundf("%s", id)
		}
	}
	return &actual, nil
}

// List returns the sorted names of all registered processes.
func (c *Context) List() ([]string, error) {
	logger.Tracef("listing all procs in hook context")

	procs, err := c.Processes()
	if err != nil {
		return nil, errors.Trace(err)
	}
	if len(procs) == 0 {
		return nil, nil
	}
	var ids []string
	for _, proc := range procs {
		ids = append(ids, proc.ID())
	}
	sort.Strings(ids)
	return ids, nil
}

// TODO(ericsnow) rename to Track

// Set records the process info in the hook context.
func (c *Context) Set(info process.Info) error {
	// TODO(ericsnow) rename to Track
	logger.Tracef("adding %q to hook context: %#v", info.ID(), info)

	if err := info.Validate(); err != nil {
		return errors.Trace(err)
	}
	// TODO(ericsnow) We are likely missing mechanisim for local persistence.
	id := info.ID()
	c.updates[id] = info
	return nil
}

// Untrack tells juju to stop tracking this process.
func (c *Context) Untrack(id string) {
	// We assume that flush always gets called immediately after a set/untrack,
	// so we don't have to worry about conflicting updates/deletes.
	c.removes[id] = struct{}{}
}

// ListDefinitions returns the unit's charm-defined processes.
func (c *Context) ListDefinitions() ([]charm.Process, error) {
	definitions, err := c.api.AllDefinitions()
	if err != nil {
		return nil, errors.Trace(err)
	}
	return definitions, nil
}

// TODO(ericsnow) The context machinery is not actually using this yet.

// Flush implements jujuc.ContextComponent. In this case that means all
// added and updated process.Info in the hook context are pushed to
// Juju state via the API.
func (c *Context) Flush() error {
	logger.Tracef("flushing from hook context to state")

	// TODO(natefinch): make this a noop and move this code into set/untrack.

	if len(c.updates) > 0 {

		var updates []process.Info
		for _, info := range c.updates {
			updates = append(updates, info)
		}
		if _, err := c.api.RegisterProcesses(updates...); err != nil {
			return errors.Trace(err)
		}
		for k, v := range c.updates {
			c.processes[k] = v
		}
		c.updates = map[string]process.Info{}
	}

	if len(removes) > 0 {
		removes := make([]string, 0, len(c.removes))
		for id := range c.removes {
			removes = append(removes, id)
		}
		c.api.Untrack(removes)
		c.removes = map[string]struct{}{}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	//"os"
	"io/ioutil"
	"strings"
	"strconv"
)

const (
	BASE_DIR = "./Minimaps/"
)

func main() {
	files, _ := ioutil.ReadDir(BASE_DIR)
	for _, f := range files {
		compileMinimap(BASE_DIR + f.Name(), f.Name(), false)
	}
}

func compileMinimap(resultFileName string, minimapName string, noLiquid bool) {
	var foundNoLiquid = false
	var tiles = make(map[string]string);
	files, _ := ioutil.ReadDir(BASE_DIR + minimapName)
	for _, f := range files {
		var fullFileName = BASE_DIR + minimapName + "/" + f.Name()
		if strings.Contains(f.Name(), ".png") {
			var fName = strings.TrimRight(f.Name(), ".png")
			var fNameNoLiquid = strings.Contains(fName, "noLiquid")
			if fNameNoLiquid && !noLiquid {
				foundNoLiquid = true
			} else if !fNameNoLiquid && !noLiquid {
				tiles[strings.TrimLeft(fName, "map")] = fullFileName
			} else if fNameNoLiquid && noLiquid {
				tiles[strings.TrimLeft(fName, "noLiquid_map")] = fullFileName
			} else if !fNameNoLiquid && noLiquid {
				var trimmerFName = strings.TrimLeft(fName, "map")
				if _, ok := tiles[trimmerFName]; !ok {
					tiles[trimmerFName] = fullFileName
				}
			}
		}
	}

	if foundNoLiquid && !noLiquid {
		compileMinimap(resultFileName + "NoLiquid", minimapName, true)
	}

	buildMinimap(resultFileName, tiles)
}

func buildMinimap(resultFileName string, tiles map[string]string)  {
	//fmt.Printf("%v", tiles)
	fmt.Println("")
	fmt.Printf("%v", resultFileName)
	fmt.Println("")
	var hc, lc, hr, lr = calculateMinimapSize(tiles)
	fmt.Printf("%v", hc)
	fmt.Println("")
	fmt.Printf("%v", lc)
	fmt.Println("")
	fmt.Printf("%v", hr)
	fmt.Println("")
	fmt.Printf("%v", lr)
	fmt.Println("")
	var files = calculateMinimapTilePlacement(tiles, hc, lc, hr, lr)
	fmt.Printf("%v", files)
	fmt.Println("")
}

func calculateMinimapSize(tiles map[string]string) (hc, lc, hr, lr int) {
	hc = 1000
	lc = 0
	hr = 1000
	lr = 0
	for tile, _ := range tiles {
		var tileParts = strings.Split(tile, "_")
		var col, _ = strconv.Atoi(tileParts[0])
		var row, _ = strconv.Atoi(tileParts[1])
		if hc > col {
			hc = col
		}
		if lc < col {
			lc = col
		}
		if hr > row {
			hr = row
		}
		if lr < row {
			lr = row
		}
	}
	return
}

func calculateMinimapTilePlacement(tiles map[string]string, hc int, lc int, hr int, lr int) (map[string]string) {
	var files = make(map[string]string)

	var width = 0;
	var height = 0;

	for i := hc; i < lc; i++ {
		width += 256
		for j := hr; j < lr; j++ {
			if i == hc {
				height += 256
			}

			var si = strconv.Itoa(i)
			var sj = strconv.Itoa(j)
			fmt.Printf("%v", si + "_" + sj)
			if _, ok := tiles[si + "_" + sj]; !ok {
				files[si + "_" + sj] = tiles[si + "_" + sj]
			} else {
				files[si + "_" + sj] = "empty.png"
			}

			fmt.Printf("%v", files)
		}
	}

	return files
}
<commit_msg>Fully working stitcher, next up: make it a library<commit_after>package main

import (
	"fmt"
	"os"
	"log"
	"io/ioutil"
	"strings"
	"strconv"
	"image/draw"
	"image"
	"image/png"
)

const (
	SRC_DIR = "./Minimaps/"
	DST_DIR = "./StitchedMaps/"
	TILE_SIZE = 256
)

func main() {
	files, _ := ioutil.ReadDir(SRC_DIR)
	for _, f := range files {
		compileMinimap(DST_DIR + f.Name(), f.Name(), false)
	}
}

func compileMinimap(resultFileName string, minimapName string, noLiquid bool) {
	var foundNoLiquid = false
	var tiles = make(map[string]string);
	files, _ := ioutil.ReadDir(SRC_DIR + minimapName)
	for _, f := range files {
		var fullFileName = SRC_DIR + minimapName + "/" + f.Name()
		if strings.Contains(f.Name(), ".png") {
			var fName = strings.TrimRight(f.Name(), ".png")
			var fNameNoLiquid = strings.Contains(fName, "noLiquid")
			if fNameNoLiquid && !noLiquid {
				foundNoLiquid = true
			} else if !fNameNoLiquid && !noLiquid {
				tiles[strings.TrimLeft(fName, "map")] = fullFileName
			} else if fNameNoLiquid && noLiquid {
				tiles[strings.TrimLeft(fName, "noLiquid_map")] = fullFileName
			} else if !fNameNoLiquid && noLiquid {
				var trimmerFName = strings.TrimLeft(fName, "map")
				if _, ok := tiles[trimmerFName]; !ok {
					tiles[trimmerFName] = fullFileName
				}
			}
		}
	}

	if foundNoLiquid && !noLiquid {
		compileMinimap(resultFileName + "NoLiquid", minimapName, true)
	}

	buildMinimap(resultFileName, tiles)
}

func buildMinimap(resultFileName string, tiles map[string]string)  {
	var hc, lc, hr, lr = calculateMinimapSize(tiles)
	var files, width, height = calculateMinimapTilePlacement(tiles, hc, lc, hr, lr)
	createMinimapImage(resultFileName, width, height, files)
}

func calculateMinimapSize(tiles map[string]string) (hc, lc, hr, lr int) {
	hc = 1000
	lc = 0
	hr = 1000
	lr = 0
	for tile, _ := range tiles {
		var tileParts = strings.Split(tile, "_")
		var col, _ = strconv.Atoi(tileParts[0])
		var row, _ = strconv.Atoi(tileParts[1])
		if hc > col {
			hc = col
		}
		if lc < col {
			lc = col
		}
		if hr > row {
			hr = row
		}
		if lr < row {
			lr = row
		}
	}
	return
}

func calculateMinimapTilePlacement(tiles map[string]string, hc int, lc int, hr int, lr int) (map[string]string, int, int) {
	var files = make(map[string]string)

	var width = 0;
	var height = 0;

	for i := hc; i < lc; i++ {
		width += TILE_SIZE
		for j := hr; j < lr; j++ {
			if i == hc {
				height += TILE_SIZE
			}

			var si = strconv.Itoa(i)
			var sj = strconv.Itoa(j)
			var oi = strconv.Itoa((i - hc) * TILE_SIZE)
			var oj = strconv.Itoa((j - hr) * TILE_SIZE)
			if _, ok := tiles[si + "_" + sj]; ok {
				files[oi + "_" + oj] = tiles[si + "_" + sj]
			}
		}
	}

	return files, width, height
}

func createMinimapImage(resultFileName string, width int, height int, files map[string]string) {
	m := image.NewRGBA(image.Rect(0, 0, width, height))
	for coords, fileName := range files {
		var coordParts = strings.Split(coords, "_")
		var x, _ = strconv.Atoi(coordParts[0])
		var y, _ = strconv.Atoi(coordParts[1])

		tile, err := os.Open(fileName)
		if err != nil {
			log.Fatal(err)
		}
		defer tile.Close()

		tileImage, err := png.Decode(tile)
		if err != nil {
			fmt.Printf("%v", fileName)
			log.Fatal(err)
		}

		draw.Draw(m, image.Rect(x, y, x + TILE_SIZE, y + TILE_SIZE), tileImage, image.Point{0,0}, draw.Src)
	}

	toimg, _ := os.Create(resultFileName + ".png")
	png.Encode(toimg, m)
	defer toimg.Close()
}
<|endoftext|>


<commit_before>// ships
package main

type ship struct {
	Fatness int
	Numbers int
}
<commit_msg>Clumsy, but working rulesetting<commit_after>// ships
package main

type ship struct {
	Fatness int
	Numbers int
}

func newShip(F int, N int) ship {
	sh := new(ship)
	sh.Fatness = F
	sh.Numbers = N
	return *sh
}

func allShips() *map[string]ship {
	s := make(map[string]ship)
	s["battleship"] = newShip(4, 1)
	s["cruiser"] = newShip(3, 2)
	s["destroyer"] = newShip(2, 3)
	s["cutter"] = newShip(1, 4)
	return &s
}
<|endoftext|>


<commit_before>// Package mcstored implements the server for storage requests.
package main

import (
	"fmt"
	"net/http"
	"os"

	"github.com/inconshreveable/log15"
	"github.com/jessevdk/go-flags"
	"github.com/materials-commons/config"
	"github.com/materials-commons/mcstore/pkg/app"
	"github.com/materials-commons/mcstore/pkg/db"
	"github.com/materials-commons/mcstore/pkg/db/dai"
	"github.com/materials-commons/mcstore/pkg/domain"
	"github.com/materials-commons/mcstore/server/mcstore"
)

// Options for server startup
type serverOptions struct {
	MCDir    string `long:"mcdir" description:"Directory path to materials commons file storage"`
	PrintPid bool   `long:"print-pid" description:"Prints the server pid to stdout"`
	HTTPPort uint   `long:"http-port" description:"Port webserver listens on" default:"5010"`
	LogLevel string `long:"log-level" description:"Logging level for server (debug, info, warn, error, crit)" default:"info"`
}

// Options for the database
type databaseOptions struct {
	Connection string `long:"db-connect" description:"The database connection string"`
	Name       string `long:"db" description:"Database to use" default:"materialscommons"`
}

// Break the options into option groups.
type options struct {
	Server   serverOptions   `group:"Server Options"`
	Database databaseOptions `group:"Database Options"`
}

// configErrorHandler gives us a chance to handle configuration look up errors.
func configErrorHandler(key string, err error, args ...interface{}) {

}

// init initializes config for the server.
func init() {
	config.Init(config.TwelveFactorWithOverride)
	config.SetErrorHandler(configErrorHandler)
}

func main() {
	var opts options
	_, err := flags.Parse(&opts)

	if err != nil {
		os.Exit(1)
	}

	if opts.Server.PrintPid {
		fmt.Println(os.Getpid())
	}

	setupConfig(opts)
	server(opts.Server.HTTPPort)
}

// setupConfig sets up configuration overrides that were passed in on the command line.
func setupConfig(opts options) {
	configSetNotEmpty("MCDB_CONNECTION", opts.Database.Connection)
	configSetNotEmpty("MCDB_NAME", opts.Database.Name)
	configSetNotEmpty("MCDIR", opts.Server.MCDir)

	if lvl, err := log15.LvlFromString(opts.Server.LogLevel); err != nil {
		fmt.Printf("Invalid Log Level: %s, setting to info\n", opts.Server.LogLevel)
		app.SetLogLvl(log15.LvlInfo)
	} else {
		fmt.Println("Log level set to:", opts.Server.LogLevel)
		app.SetLogLvl(lvl)
	}
}

// configSetNotEmpty sets key if to value only if value isn't equal to the empty string.
func configSetNotEmpty(key, value string) {
	if value != "" {
		config.Set(key, value)
	}
}

// server implements the actual serve for mcstored. It sets up the http routes and handlers. This
// method never returns.
func server(port uint) {
	container := mcstore.NewServicesContainer()
	http.Handle("/", container)

	session := db.RSessionMust()
	access := domain.NewAccess(dai.NewRProjects(session), dai.NewRFiles(session), dai.NewRUsers(session))
	dataHandler := mcstore.NewDataHandler(access)
	http.Handle("/datafiles/static/", dataHandler)

	app.Log.Crit("http Server failed", "error", http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
}
<commit_msg>Create the container by passing in a SessionCreater.<commit_after>// Package mcstored implements the server for storage requests.
package main

import (
	"fmt"
	"net/http"
	"os"

	"github.com/inconshreveable/log15"
	"github.com/jessevdk/go-flags"
	"github.com/materials-commons/config"
	"github.com/materials-commons/mcstore/pkg/app"
	"github.com/materials-commons/mcstore/pkg/db"
	"github.com/materials-commons/mcstore/pkg/db/dai"
	"github.com/materials-commons/mcstore/pkg/domain"
	"github.com/materials-commons/mcstore/server/mcstore"
)

// Options for server startup
type serverOptions struct {
	MCDir    string `long:"mcdir" description:"Directory path to materials commons file storage"`
	PrintPid bool   `long:"print-pid" description:"Prints the server pid to stdout"`
	HTTPPort uint   `long:"http-port" description:"Port webserver listens on" default:"5010"`
	LogLevel string `long:"log-level" description:"Logging level for server (debug, info, warn, error, crit)" default:"info"`
}

// Options for the database
type databaseOptions struct {
	Connection string `long:"db-connect" description:"The database connection string"`
	Name       string `long:"db" description:"Database to use" default:"materialscommons"`
}

// Break the options into option groups.
type options struct {
	Server   serverOptions   `group:"Server Options"`
	Database databaseOptions `group:"Database Options"`
}

// configErrorHandler gives us a chance to handle configuration look up errors.
func configErrorHandler(key string, err error, args ...interface{}) {

}

// init initializes config for the server.
func init() {
	config.Init(config.TwelveFactorWithOverride)
	config.SetErrorHandler(configErrorHandler)
}

func main() {
	var opts options
	_, err := flags.Parse(&opts)

	if err != nil {
		os.Exit(1)
	}

	if opts.Server.PrintPid {
		fmt.Println(os.Getpid())
	}

	setupConfig(opts)
	server(opts.Server.HTTPPort)
}

// setupConfig sets up configuration overrides that were passed in on the command line.
func setupConfig(opts options) {
	configSetNotEmpty("MCDB_CONNECTION", opts.Database.Connection)
	configSetNotEmpty("MCDB_NAME", opts.Database.Name)
	configSetNotEmpty("MCDIR", opts.Server.MCDir)

	if lvl, err := log15.LvlFromString(opts.Server.LogLevel); err != nil {
		fmt.Printf("Invalid Log Level: %s, setting to info\n", opts.Server.LogLevel)
		app.SetLogLvl(log15.LvlInfo)
	} else {
		fmt.Println("Log level set to:", opts.Server.LogLevel)
		app.SetLogLvl(lvl)
	}
}

// configSetNotEmpty sets key if to value only if value isn't equal to the empty string.
func configSetNotEmpty(key, value string) {
	if value != "" {
		config.Set(key, value)
	}
}

// server implements the actual serve for mcstored. It sets up the http routes and handlers. This
// method never returns.
func server(port uint) {
	container := mcstore.NewServicesContainer(db.Sessions)
	http.Handle("/", container)

	session := db.RSessionMust()
	access := domain.NewAccess(dai.NewRProjects(session), dai.NewRFiles(session), dai.NewRUsers(session))
	dataHandler := mcstore.NewDataHandler(access)
	http.Handle("/datafiles/static/", dataHandler)

	app.Log.Crit("http Server failed", "error", http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
}
<|endoftext|>


<commit_before>package telegram

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
)

type ParseMode string

// Parse modes
const (
	ModeNone     ParseMode = ""
	ModeMarkdown ParseMode = "Markdown"
	ModeHTML     ParseMode = "HTML"
)

// Bot represent a Telegram bot.
type Bot struct {
	token     string
	baseURL   string
	client    *http.Client
	messageCh chan *Message
}

// New creates a new Telegram bot with the given token, which is given by
// Botfather. See https://core.telegram.org/bots#botfather
func New(token string) *Bot {
	return &Bot{
		token:     token,
		baseURL:   fmt.Sprintf("https://api.telegram.org/bot%v/", token),
		client:    &http.Client{Timeout: 30 * time.Second},
		messageCh: make(chan *Message),
	}
}

func (b *Bot) Handler() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		defer w.WriteHeader(http.StatusOK)

		var u Update
		_ = json.NewDecoder(r.Body).Decode(&u)
		b.messageCh <- &u.Payload
	}
}

func (b *Bot) Messages() <-chan *Message {
	return b.messageCh
}

// SetWebhook assigns bot's webhook url with the given url.
func (b *Bot) SetWebhook(webhook string) error {
	params := url.Values{}
	params.Set("url", webhook)

	var r struct {
		OK      bool   `json:"ok"`
		Desc    string `json:"description"`
		ErrCode int    `json:"error_code"`
	}
	err := b.sendCommand(nil, "setWebhook", params, &r)
	if err != nil {
		return err
	}

	if !r.OK {
		return fmt.Errorf("%v (%v)", r.Desc, r.ErrCode)
	}

	return nil
}

// SendMessage sends text message to the recipient. Callers can send plain
// text or markdown messages by setting mode parameter.
func (b *Bot) SendMessage(recipient int64, message string, opts ...SendOption) (Message, error) {
	const method = "sendMessage"
	params := url.Values{}
	params.Set("chat_id", strconv.FormatInt(recipient, 10))
	params.Set("text", message)
	mapSendOptions(&params, opts...)

	var r struct {
		OK      bool   `json:"ok"`
		Desc    string `json:"description"`
		ErrCode int    `json:"error_code"`
		Message Message
	}
	err := b.sendCommand(nil, "sendMessage", params, &r)
	if err != nil {
		return r.Message, err
	}

	if !r.OK {
		return Message{}, fmt.Errorf("%v (%v)", r.Desc, r.ErrCode)
	}
	return r.Message, nil
}

func (b *Bot) forwardMessage(recipient User, message Message) (Message, error) {
	panic("not implemented yet")
}

// SendPhoto sends given photo to recipient. Only remote URLs are supported for now.
// A trivial example is:
//
//  b := bot.New("your-token-here")
//  photo := bot.Photo{URL: "http://i.imgur.com/6S9naG6.png"}
//  err := b.SendPhoto(recipient, photo, "sample image", nil)
func (b *Bot) SendPhoto(recipient int64, photo Photo, opts ...SendOption) (Message, error) {
	const method = "sendPhoto"
	params := url.Values{}
	params.Set("chat_id", strconv.FormatInt(recipient, 10))
	params.Set("caption", photo.Caption)

	mapSendOptions(&params, opts...)
	var r struct {
		OK      bool    `json:"ok"`
		Desc    string  `json:"description"`
		ErrCode int     `json:"error_code"`
		Message Message `json:"message"`
	}

	var err error
	if photo.Exists() {
		params.Set("photo", photo.FileID)
		err = b.sendCommand(nil, method, params, &r)
	} else if photo.URL != "" {
		params.Set("photo", photo.URL)
		err = b.sendCommand(nil, method, params, &r)
	} else {
		err = b.sendFile(method, photo.File, "photo", params, &r)
	}

	if err != nil {
		return Message{}, err
	}

	if !r.OK {
		return Message{}, fmt.Errorf("%v (%v)", r.Desc, r.ErrCode)
	}

	return r.Message, nil
}

func (b *Bot) sendFile(method string, f File, form string, params url.Values, v interface{}) error {
	var buf bytes.Buffer
	w := multipart.NewWriter(&buf)
	part, err := w.CreateFormFile(form, f.Name)
	if err != nil {
		return err
	}

	_, err = io.Copy(part, f.Body)
	if err != nil {
		return err
	}

	for k, v := range params {
		w.WriteField(k, v[0])
	}

	err = w.Close()
	if err != nil {
		return err
	}

	resp, err := b.client.Post(b.baseURL+method, w.FormDataContentType(), &buf)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("Unexpected status code: %v", resp.StatusCode)
	}

	return json.NewDecoder(resp.Body).Decode(&v)
}

// SendAudio sends audio files, if you want Telegram clients to display
// them in the music player. audio must be in the .mp3 format and must not
// exceed 50 MB in size.
func (b *Bot) sendAudio(recipient int64, audio Audio, opts ...SendOption) (Message, error) {
	panic("not implemented yet")
}

// SendDocument sends general files. Documents must not exceed 50 MB in size.
func (b *Bot) sendDocument(recipient int64, document Document, opts ...SendOption) (Message, error) {
	panic("not implemented yet")
}

//SendSticker sends stickers with .webp extensions.
func (b *Bot) sendSticker(recipient int64, sticker Sticker, opts ...SendOption) (Message, error) {
	panic("not implemented yet")
}

// SendVideo sends video files. Telegram clients support mp4 videos (other
// formats may be sent as Document). Video files must not exceed 50 MB in size.
func (b *Bot) sendVideo(recipient int64, video Video, opts ...SendOption) (Message, error) {
	panic("not implemented yet")
}

// SendVoice sends audio files, if you want Telegram clients to display
// the file as a playable voice message. For this to work, your audio must be
// in an .ogg file encoded with OPUS (other formats may be sent as Audio or
// Document). audio must not exceed 50 MB in size.
func (b *Bot) sendVoice(recipient int64, audio Audio, opts ...SendOption) (Message, error) {
	panic("not implemented yet")
}

// SendLocation sends location point on the map.
func (b *Bot) SendLocation(recipient int64, location Location, opts ...SendOption) (Message, error) {
	const method = "sendLocation"
	params := url.Values{}
	params.Set("chat_id", strconv.FormatInt(recipient, 10))
	params.Set("latitude", strconv.FormatFloat(location.Lat, 'f', -1, 64))
	params.Set("longitude", strconv.FormatFloat(location.Long, 'f', -1, 64))

	mapSendOptions(&params, opts...)

	var r struct {
		OK      bool    `json:"ok"`
		Desc    string  `json:"description"`
		ErrCode int     `json:"error_code"`
		Message Message `json:"message"`
	}
	err := b.sendCommand(nil, method, params, &r)
	if err != nil {
		return Message{}, err
	}

	if !r.OK {
		return Message{}, fmt.Errorf("%v (%v)", r.Desc, r.ErrCode)
	}

	return r.Message, nil
}

// SendVenue sends information about a venue.
func (b *Bot) SendVenue(recipient int64, venue Venue, opts ...SendOption) (Message, error) {
	const method = "sendVenue"
	params := url.Values{}
	params.Set("chat_id", strconv.FormatInt(recipient, 10))
	params.Set("latitude", strconv.FormatFloat(venue.Location.Lat, 'f', -1, 64))
	params.Set("longitude", strconv.FormatFloat(venue.Location.Long, 'f', -1, 64))
	params.Set("title", venue.Title)
	params.Set("address", venue.Address)

	mapSendOptions(&params, opts...)

	var r struct {
		OK      bool    `json:"ok"`
		Desc    string  `json:"description"`
		ErrCode int     `json:"error_code"`
		Message Message `json:"message"`
	}
	err := b.sendCommand(nil, method, params, &r)
	if err != nil {
		return Message{}, err
	}

	if !r.OK {
		return Message{}, fmt.Errorf("%v (%v)", r.Desc, r.ErrCode)
	}
	return r.Message, nil
}

// SendChatAction broadcasts type of action to recipient, such as `typing`,
// `uploading a photo` etc.
func (b *Bot) SendChatAction(recipient int64, action Action) error {
	const method = "sendChatAction"
	params := url.Values{}
	params.Set("chat_id", strconv.FormatInt(recipient, 10))
	params.Set("action", string(action))

	var r response
	err := b.sendCommand(nil, method, params, &r)
	if err != nil {
		return err

	}
	if !r.OK {
		return fmt.Errorf("%v (%v)", r.Desc, r.ErrCode)
	}

	return nil
}

// sendOptions configure a SendMessage call. sendOptions are set by the
// SendOption values passed to SendMessage.
type sendOptions struct {
	replyTo int64

	parseMode ParseMode

	disableWebPagePreview bool

	disableNotification bool

	replyMarkup ReplyMarkup
}

// SendOption configures how we configure the message to be sent.
type SendOption func(*sendOptions)

// WithParseMode returns a SendOption which sets the message format, such as
// HTML, Markdown etc.
func WithParseMode(mode ParseMode) SendOption {
	return func(o *sendOptions) {
		o.parseMode = mode
	}
}

// WithReplyTo returns a SendOption which sets the message to be replied to.
func WithReplyTo(to int64) SendOption {
	return func(o *sendOptions) {
		o.replyTo = to
	}
}

// WithReplyMarkup returns a SendOption which configures a custom keyboard for
// the sent message.
func WithReplyMarkup(markup ReplyMarkup) SendOption {
	return func(o *sendOptions) {
		o.replyMarkup = markup
	}
}

// WithDisableWebPagePreview returns a SendOption which disables webpage
// previews if the message contains a link.
func WithDisableWebPagePreview(disable bool) SendOption {
	return func(o *sendOptions) {
		o.disableWebPagePreview = disable
	}
}

func WithDisableNotification(disable bool) SendOption {
	return func(o *sendOptions) {
		o.disableNotification = disable
	}
}

func (b *Bot) GetFile(fileID string) (File, error) {
	params := url.Values{}
	params.Set("file_id", fileID)

	var r struct {
		OK      bool   `json:"ok"`
		Desc    string `json:"description"`
		ErrCode int    `json:"error_code"`
		File    File   `json:"result"`
	}
	err := b.sendCommand(nil, "getFile", params, &r)
	if err != nil {
		return File{}, err
	}

	if !r.OK {
		return File{}, fmt.Errorf("%v (%v)", r.Desc, r.ErrCode)
	}

	return r.File, nil
}

func (b *Bot) GetFileDownloadURL(fileID string) (string, error) {
	f, err := b.GetFile(fileID)
	if err != nil {
		return "", err
	}

	u := "https://api.telegram.org/file/bot" + b.token + "/" + f.FilePath
	return u, nil
}

func (b *Bot) sendCommand(ctx context.Context, method string, params url.Values, v interface{}) error {
	req, err := http.NewRequest("POST", b.baseURL+method, strings.NewReader(params.Encode()))
	if err != nil {
		return err
	}

	if ctx == nil {
		ctx = context.Background()
	}

	req = req.WithContext(ctx)
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	resp, err := b.client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	return json.NewDecoder(resp.Body).Decode(&v)
}

func (b *Bot) getMe() (User, error) {
	var r struct {
		OK      bool   `json:"ok"`
		Desc    string `json:"description"`
		ErrCode int    `json:"error_code"`

		User User `json:"result"`
	}
	err := b.sendCommand(nil, "getMe", url.Values{}, &r)
	if err != nil {
		return User{}, err
	}

	if !r.OK {
		return User{}, fmt.Errorf("%v (%v)", r.Desc, r.ErrCode)
	}

	return r.User, nil
}

func mapSendOptions(m *url.Values, opts ...SendOption) {
	if len(opts) == 0 {
		return
	}

	var o sendOptions
	for _, opt := range opts {
		opt(&o)
	}

	if o.replyTo != 0 {
		m.Set("reply_to_message_id", strconv.FormatInt(o.replyTo, 10))
	}

	if o.disableWebPagePreview {
		m.Set("disable_web_page_preview", "true")
	}

	if o.disableNotification {
		m.Set("disable_notification", "true")
	}

	if o.parseMode != ModeNone {
		m.Set("parse_mode", string(o.parseMode))
	}

	// TODO: map ReplyMarkup options as well
}
<commit_msg>telegram: reuse generic response<commit_after>package telegram

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
)

type ParseMode string

// Parse modes
const (
	ModeNone     ParseMode = ""
	ModeMarkdown ParseMode = "Markdown"
	ModeHTML     ParseMode = "HTML"
)

// Bot represent a Telegram bot.
type Bot struct {
	token     string
	baseURL   string
	client    *http.Client
	messageCh chan *Message
}

// New creates a new Telegram bot with the given token, which is given by
// Botfather. See https://core.telegram.org/bots#botfather
func New(token string) *Bot {
	return &Bot{
		token:     token,
		baseURL:   fmt.Sprintf("https://api.telegram.org/bot%v/", token),
		client:    &http.Client{Timeout: 30 * time.Second},
		messageCh: make(chan *Message),
	}
}

func (b *Bot) Handler() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		defer w.WriteHeader(http.StatusOK)

		var u Update
		_ = json.NewDecoder(r.Body).Decode(&u)
		b.messageCh <- &u.Payload
	}
}

func (b *Bot) Messages() <-chan *Message {
	return b.messageCh
}

// SetWebhook assigns bot's webhook url with the given url.
func (b *Bot) SetWebhook(webhook string) error {
	params := url.Values{}
	params.Set("url", webhook)

	var r response
	err := b.sendCommand(nil, "setWebhook", params, &r)
	if err != nil {
		return err
	}

	if !r.OK {
		return fmt.Errorf("%v (%v)", r.Desc, r.ErrCode)
	}

	return nil
}

// SendMessage sends text message to the recipient. Callers can send plain
// text or markdown messages by setting mode parameter.
func (b *Bot) SendMessage(recipient int64, message string, opts ...SendOption) (Message, error) {
	const method = "sendMessage"
	params := url.Values{}
	params.Set("chat_id", strconv.FormatInt(recipient, 10))
	params.Set("text", message)
	mapSendOptions(&params, opts...)

	var r struct {
		response
		Message Message `json:"result"`
	}
	err := b.sendCommand(nil, "sendMessage", params, &r)
	if err != nil {
		return r.Message, err
	}

	if !r.OK {
		return Message{}, fmt.Errorf("%v (%v)", r.Desc, r.ErrCode)
	}
	return r.Message, nil
}

func (b *Bot) forwardMessage(recipient User, message Message) (Message, error) {
	panic("not implemented yet")
}

// SendPhoto sends given photo to recipient. Only remote URLs are supported for now.
// A trivial example is:
//
//  b := bot.New("your-token-here")
//  photo := bot.Photo{URL: "http://i.imgur.com/6S9naG6.png"}
//  err := b.SendPhoto(recipient, photo, "sample image", nil)
func (b *Bot) SendPhoto(recipient int64, photo Photo, opts ...SendOption) (Message, error) {
	const method = "sendPhoto"
	params := url.Values{}
	params.Set("chat_id", strconv.FormatInt(recipient, 10))
	params.Set("caption", photo.Caption)

	mapSendOptions(&params, opts...)
	var r struct {
		response
		Message Message `json:"result"`
	}

	var err error
	if photo.Exists() {
		params.Set("photo", photo.FileID)
		err = b.sendCommand(nil, method, params, &r)
	} else if photo.URL != "" {
		params.Set("photo", photo.URL)
		err = b.sendCommand(nil, method, params, &r)
	} else {
		err = b.sendFile(method, photo.File, "photo", params, &r)
	}

	if err != nil {
		return Message{}, err
	}

	if !r.OK {
		return Message{}, fmt.Errorf("%v (%v)", r.Desc, r.ErrCode)
	}

	return r.Message, nil
}

func (b *Bot) sendFile(method string, f File, form string, params url.Values, v interface{}) error {
	var buf bytes.Buffer
	w := multipart.NewWriter(&buf)
	part, err := w.CreateFormFile(form, f.Name)
	if err != nil {
		return err
	}

	_, err = io.Copy(part, f.Body)
	if err != nil {
		return err
	}

	for k, v := range params {
		w.WriteField(k, v[0])
	}

	err = w.Close()
	if err != nil {
		return err
	}

	resp, err := b.client.Post(b.baseURL+method, w.FormDataContentType(), &buf)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("unexpected status code: %v", resp.StatusCode)
	}

	return json.NewDecoder(resp.Body).Decode(&v)
}

// SendAudio sends audio files, if you want Telegram clients to display
// them in the music player. audio must be in the .mp3 format and must not
// exceed 50 MB in size.
func (b *Bot) sendAudio(recipient int64, audio Audio, opts ...SendOption) (Message, error) {
	panic("not implemented yet")
}

// SendDocument sends general files. Documents must not exceed 50 MB in size.
func (b *Bot) sendDocument(recipient int64, document Document, opts ...SendOption) (Message, error) {
	panic("not implemented yet")
}

//SendSticker sends stickers with .webp extensions.
func (b *Bot) sendSticker(recipient int64, sticker Sticker, opts ...SendOption) (Message, error) {
	panic("not implemented yet")
}

// SendVideo sends video files. Telegram clients support mp4 videos (other
// formats may be sent as Document). Video files must not exceed 50 MB in size.
func (b *Bot) sendVideo(recipient int64, video Video, opts ...SendOption) (Message, error) {
	panic("not implemented yet")
}

// SendVoice sends audio files, if you want Telegram clients to display
// the file as a playable voice message. For this to work, your audio must be
// in an .ogg file encoded with OPUS (other formats may be sent as Audio or
// Document). audio must not exceed 50 MB in size.
func (b *Bot) sendVoice(recipient int64, audio Audio, opts ...SendOption) (Message, error) {
	panic("not implemented yet")
}

// SendLocation sends location point on the map.
func (b *Bot) SendLocation(recipient int64, location Location, opts ...SendOption) (Message, error) {
	const method = "sendLocation"
	params := url.Values{}
	params.Set("chat_id", strconv.FormatInt(recipient, 10))
	params.Set("latitude", strconv.FormatFloat(location.Lat, 'f', -1, 64))
	params.Set("longitude", strconv.FormatFloat(location.Long, 'f', -1, 64))

	mapSendOptions(&params, opts...)

	var r struct {
		response
		Message Message `json:"result"`
	}
	err := b.sendCommand(nil, method, params, &r)
	if err != nil {
		return Message{}, err
	}

	if !r.OK {
		return Message{}, fmt.Errorf("%v (%v)", r.Desc, r.ErrCode)
	}

	return r.Message, nil
}

// SendVenue sends information about a venue.
func (b *Bot) SendVenue(recipient int64, venue Venue, opts ...SendOption) (Message, error) {
	const method = "sendVenue"
	params := url.Values{}
	params.Set("chat_id", strconv.FormatInt(recipient, 10))
	params.Set("latitude", strconv.FormatFloat(venue.Location.Lat, 'f', -1, 64))
	params.Set("longitude", strconv.FormatFloat(venue.Location.Long, 'f', -1, 64))
	params.Set("title", venue.Title)
	params.Set("address", venue.Address)

	mapSendOptions(&params, opts...)

	var r struct {
		response
		Message Message `json:"result"`
	}
	err := b.sendCommand(nil, method, params, &r)
	if err != nil {
		return Message{}, err
	}

	if !r.OK {
		return Message{}, fmt.Errorf("%v (%v)", r.Desc, r.ErrCode)
	}
	return r.Message, nil
}

// SendChatAction broadcasts type of action to recipient, such as `typing`,
// `uploading a photo` etc.
func (b *Bot) SendChatAction(recipient int64, action Action) error {
	const method = "sendChatAction"
	params := url.Values{}
	params.Set("chat_id", strconv.FormatInt(recipient, 10))
	params.Set("action", string(action))

	var r response
	err := b.sendCommand(nil, method, params, &r)
	if err != nil {
		return err

	}
	if !r.OK {
		return fmt.Errorf("%v (%v)", r.Desc, r.ErrCode)
	}

	return nil
}

// sendOptions configure a SendMessage call. sendOptions are set by the
// SendOption values passed to SendMessage.
type sendOptions struct {
	replyTo int64

	parseMode ParseMode

	disableWebPagePreview bool

	disableNotification bool

	replyMarkup ReplyMarkup
}

// SendOption configures how we configure the message to be sent.
type SendOption func(*sendOptions)

// WithParseMode returns a SendOption which sets the message format, such as
// HTML, Markdown etc.
func WithParseMode(mode ParseMode) SendOption {
	return func(o *sendOptions) {
		o.parseMode = mode
	}
}

// WithReplyTo returns a SendOption which sets the message to be replied to.
func WithReplyTo(to int64) SendOption {
	return func(o *sendOptions) {
		o.replyTo = to
	}
}

// WithReplyMarkup returns a SendOption which configures a custom keyboard for
// the sent message.
func WithReplyMarkup(markup ReplyMarkup) SendOption {
	return func(o *sendOptions) {
		o.replyMarkup = markup
	}
}

// WithDisableWebPagePreview returns a SendOption which disables webpage
// previews if the message contains a link.
func WithDisableWebPagePreview(disable bool) SendOption {
	return func(o *sendOptions) {
		o.disableWebPagePreview = disable
	}
}

func WithDisableNotification(disable bool) SendOption {
	return func(o *sendOptions) {
		o.disableNotification = disable
	}
}

func (b *Bot) GetFile(fileID string) (File, error) {
	params := url.Values{}
	params.Set("file_id", fileID)

	var r struct {
		response
		File File `json:"result"`
	}
	err := b.sendCommand(nil, "getFile", params, &r)
	if err != nil {
		return File{}, err
	}

	if !r.OK {
		return File{}, fmt.Errorf("%v (%v)", r.Desc, r.ErrCode)
	}

	return r.File, nil
}

func (b *Bot) GetFileDownloadURL(fileID string) (string, error) {
	f, err := b.GetFile(fileID)
	if err != nil {
		return "", err
	}

	u := "https://api.telegram.org/file/bot" + b.token + "/" + f.FilePath
	return u, nil
}

func (b *Bot) sendCommand(ctx context.Context, method string, params url.Values, v interface{}) error {
	req, err := http.NewRequest("POST", b.baseURL+method, strings.NewReader(params.Encode()))
	if err != nil {
		return err
	}

	if ctx == nil {
		ctx = context.Background()
	}

	req = req.WithContext(ctx)
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	resp, err := b.client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("unexpected status code: %v", resp.StatusCode)
	}
	return json.NewDecoder(resp.Body).Decode(&v)
}

func (b *Bot) getMe() (User, error) {
	var r struct {
		response
		User User `json:"result"`
	}
	err := b.sendCommand(nil, "getMe", url.Values{}, &r)
	if err != nil {
		return User{}, err
	}

	if !r.OK {
		return User{}, fmt.Errorf("%v (%v)", r.Desc, r.ErrCode)
	}

	return r.User, nil
}

func mapSendOptions(m *url.Values, opts ...SendOption) {
	if len(opts) == 0 {
		return
	}

	var o sendOptions
	for _, opt := range opts {
		opt(&o)
	}

	if o.replyTo != 0 {
		m.Set("reply_to_message_id", strconv.FormatInt(o.replyTo, 10))
	}

	if o.disableWebPagePreview {
		m.Set("disable_web_page_preview", "true")
	}

	if o.disableNotification {
		m.Set("disable_notification", "true")
	}

	if o.parseMode != ModeNone {
		m.Set("parse_mode", string(o.parseMode))
	}

	// TODO: map ReplyMarkup options as well
}

// response is a common response structure.
type response struct {
	OK      bool   `json:"ok"`
	Desc    string `json:"description"`
	ErrCode int    `json:"error_code"`
}
<|endoftext|>


<commit_before>package tempfile

import (
	"io/ioutil"
	"os"

	"github.com/stretchr/testify/require"
)

// TempFile is a temporary file that can be used with unit tests. TempFile
// reduces the boilerplate setup required in each test case by handling
// setup errors.
type TempFile struct {
	File *os.File
}

// NewTempFile returns a new temp file with contents
func NewTempFile(t require.TestingT, prefix string, content string) *TempFile {
	file, err := ioutil.TempFile("", prefix+"-")
	require.NoError(t, err)

	_, err = file.Write([]byte(content))
	require.NoError(t, err)
	file.Close()
	return &TempFile{File: file}
}

// Name returns the filename
func (f *TempFile) Name() string {
	return f.File.Name()
}

// Remove removes the file
func (f *TempFile) Remove() {
	os.Remove(f.Name())
}
<commit_msg>Fix copy when used with scratch and images with empty RootFS<commit_after>package tempfile

import (
	"io/ioutil"
	"os"

	"github.com/stretchr/testify/require"
)

// TempFile is a temporary file that can be used with unit tests. TempFile
// reduces the boilerplate setup required in each test case by handling
// setup errors.
type TempFile struct {
	File *os.File
}

// NewTempFile returns a new temp file with contents
func NewTempFile(t require.TestingT, prefix string, content string) *TempFile {
	file, err := ioutil.TempFile("", prefix+"-")
	require.NoError(t, err)

	_, err = file.Write([]byte(content))
	require.NoError(t, err)
	file.Close()
	return &TempFile{File: file}
}

// Name returns the filename
func (f *TempFile) Name() string {
	return f.File.Name()
}

// Remove removes the file
func (f *TempFile) Remove() {
	os.Remove(f.Name())
}

// TempDir is a temporary directory that can be used with unit tests. TempDir
// reduces the boilerplate setup required in each test case by handling
// setup errors.
type TempDir struct {
	Path string
}

// NewTempDir returns a new temp file with contents
func NewTempDir(t require.TestingT, prefix string) *TempDir {
	path, err := ioutil.TempDir("", prefix+"-")
	require.NoError(t, err)

	return &TempDir{Path: path}
}

// Remove removes the file
func (f *TempDir) Remove() {
	os.Remove(f.Path)
}
<|endoftext|>


<commit_before>package utp

import (
	"log"
	"math/rand"
	"net"
	"sync"
	"testing"
	"time"

	_ "github.com/anacrolix/envpprof"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"golang.org/x/net/nettest"
)

func init() {
	log.SetFlags(log.Flags() | log.Lshortfile)
}

func TestNettestLocalhostUDP(t *testing.T) {
	t.Parallel()
	nettest.TestConn(t, func() (c1, c2 net.Conn, stop func(), err error) {
		s, err := NewSocket("udp", "localhost:0")
		if err != nil {
			return
		}
		c1, c2 = connPairSocket(s)
		stop = func() {
			s.Close()
		}
		return
	})
}

var rander = rand.New(rand.NewSource(time.Now().UnixNano()))

func connPairSocket(s *Socket) (net.Conn, net.Conn) {
	var (
		wg               sync.WaitGroup
		dialed, accepted net.Conn
	)
	wg.Add(2)
	go func() {
		defer wg.Done()
		var err error
		dialed, err = s.Dial(s.Addr().String())
		if err != nil {
			panic(err)
		}
	}()
	go func() {
		defer wg.Done()
		var err error
		accepted, err = s.Accept()
		if err != nil {
			panic(err)
		}
	}()
	wg.Wait()
	switch rander.Intn(2) {
	case 0:
		log.Printf("first of conn pair is dialed")
		return dialed, accepted
	case 1:
		log.Print("first of conn pair is accepted")
		return accepted, dialed
	default:
		panic("ಠ_ಠ")
	}
}

const neverResponds = "localhost:1"

// Ensure that libutp dial timeouts out by itself.
func TestLibutpDialTimesOut(t *testing.T) {
	t.Parallel()
	if testing.Short() {
		t.SkipNow()
	}
	s, err := NewSocket("udp", "localhost:0")
	require.NoError(t, err)
	defer s.Close()
	_, err = s.Dial(neverResponds)
	require.Error(t, err)
}

// Ensure that our timeout is honored during dialing.
func TestDialTimeout(t *testing.T) {
	t.Parallel()
	s, err := NewSocket("udp", "localhost:0")
	require.NoError(t, err)
	defer s.Close()
	started := time.Now()
	_, err = s.DialTimeout(neverResponds, time.Second)
	require.Error(t, err)
	t.Log(err)
	assert.True(t, time.Now().Before(started.Add(2*time.Second)))
}

func TestConnSendBuffer(t *testing.T) {
	s0, err := NewSocket("udp", "localhost:0")
	require.NoError(t, err)
	defer s0.Close()
	s1, err := NewSocket("udp", "localhost:0")
	require.NoError(t, err)
	defer s1.Close()
	var (
		c1        net.Conn
		acceptErr error
		accepted  = make(chan struct{})
	)
	go func() {
		defer close(accepted)
		c1, acceptErr = s1.Accept()
	}()
	c0, err := s0.Dial(s1.Addr().String())
	require.NoError(t, err)
	<-accepted
	require.NoError(t, acceptErr)
	defer c0.Close()
	defer c1.Close()
	buf := make([]byte, 1024)
	written := 0
	for {
		require.NoError(t, c0.SetWriteDeadline(time.Now().Add(time.Second)))
		n, err := c0.Write(buf)
		written += n
		if err != nil {
			t.Logf("stopped writing after error: %s", err)
			break
		}
	}
	t.Logf("write buffered %d bytes", written)
}
<commit_msg>Do nettest.TestConn with dialed and accepted connections in each position<commit_after>package utp

import (
	"log"
	"math/rand"
	"net"
	"sync"
	"testing"
	"time"

	_ "github.com/anacrolix/envpprof"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"golang.org/x/net/nettest"
)

func init() {
	log.SetFlags(log.Flags() | log.Lshortfile)
}

func doNettestTestConn(t *testing.T, swapConns bool) {
	nettest.TestConn(t, func() (c1, c2 net.Conn, stop func(), err error) {
		s, err := NewSocket("udp", "localhost:0")
		if err != nil {
			return
		}
		c1, c2 = connPairSocket(s)
		if swapConns {
			c1, c2 = c2, c1
		}
		stop = func() {
			s.Close()
		}
		return
	})
}

func TestNettestTestConn(t *testing.T) {
	t.Parallel()
	doNettestTestConn(t, false)
}

func TestNettestTestConnSwapped(t *testing.T) {
	t.Parallel()
	doNettestTestConn(t, true)
}

var rander = rand.New(rand.NewSource(time.Now().UnixNano()))

func connPairSocket(s *Socket) (dialed net.Conn, accepted net.Conn) {
	var (
		wg sync.WaitGroup
	)
	wg.Add(2)
	go func() {
		defer wg.Done()
		var err error
		dialed, err = s.Dial(s.Addr().String())
		if err != nil {
			panic(err)
		}
	}()
	go func() {
		defer wg.Done()
		var err error
		accepted, err = s.Accept()
		if err != nil {
			panic(err)
		}
	}()
	wg.Wait()
	return
}

const neverResponds = "localhost:1"

// Ensure that libutp dial timeouts out by itself.
func TestLibutpDialTimesOut(t *testing.T) {
	t.Parallel()
	if testing.Short() {
		t.SkipNow()
	}
	s, err := NewSocket("udp", "localhost:0")
	require.NoError(t, err)
	defer s.Close()
	_, err = s.Dial(neverResponds)
	require.Error(t, err)
}

// Ensure that our timeout is honored during dialing.
func TestDialTimeout(t *testing.T) {
	t.Parallel()
	s, err := NewSocket("udp", "localhost:0")
	require.NoError(t, err)
	defer s.Close()
	started := time.Now()
	_, err = s.DialTimeout(neverResponds, time.Second)
	require.Error(t, err)
	t.Log(err)
	assert.True(t, time.Now().Before(started.Add(2*time.Second)))
}

func TestConnSendBuffer(t *testing.T) {
	s0, err := NewSocket("udp", "localhost:0")
	require.NoError(t, err)
	defer s0.Close()
	s1, err := NewSocket("udp", "localhost:0")
	require.NoError(t, err)
	defer s1.Close()
	var (
		c1        net.Conn
		acceptErr error
		accepted  = make(chan struct{})
	)
	go func() {
		defer close(accepted)
		c1, acceptErr = s1.Accept()
	}()
	c0, err := s0.Dial(s1.Addr().String())
	require.NoError(t, err)
	<-accepted
	require.NoError(t, acceptErr)
	defer c0.Close()
	defer c1.Close()
	buf := make([]byte, 1024)
	written := 0
	for {
		require.NoError(t, c0.SetWriteDeadline(time.Now().Add(time.Second)))
		n, err := c0.Write(buf)
		written += n
		if err != nil {
			t.Logf("stopped writing after error: %s", err)
			break
		}
	}
	t.Logf("write buffered %d bytes", written)
}
<|endoftext|>


<commit_before>package main

import (
	text "text/template"

	"html/template"

	"github.com/patrickalin/bloomsky-client-go/assembly"
)

//GetTemplate retrieve a template
func GetTemplate(templateName string, templateLocation string, funcs map[string]interface{}, dev bool) *text.Template {
	if dev {
		t, err := text.New(templateName).Funcs(funcs).ParseFiles(templateLocation)
		checkErr(err, funcName(), "Load template console", templateLocation)
		return t
	}

	assetBloomsky, err := assembly.Asset(templateLocation)
	t, err := text.New(templateName).Funcs(funcs).Parse(string(assetBloomsky[:]))
	checkErr(err, funcName(), "Load template console", templateLocation)
	return t
}

// GetHTMLTemplate "bloomsky_header.html","tmpl/bloomsky_header.html",map[string]interface{}{"T": config.translateFunc,}
func GetHTMLTemplate(templateName string, templatesLocation []string, funcs map[string]interface{}, dev bool) *template.Template {
	t := template.New(templateName)
	t.Funcs(funcs)
	if dev {
		t, err := t.ParseFiles(templatesLocation...)
		checkErr(err, funcName(), "ParseFiles")
		return t
	}

	for _, l := range templatesLocation {
		asset, err := assembly.Asset(l)
		checkErr(err, funcName(), "Assembly template", l)

		t, err = t.Parse(string(asset[:]))
		checkErr(err, funcName(), "Parse file")
	}

	return t
}
<commit_msg>shadow variable thanks "vet"<commit_after>package main

import (
	text "text/template"

	"html/template"

	"github.com/patrickalin/bloomsky-client-go/assembly"
)

//GetTemplate retrieve a template
func GetTemplate(templateName string, templateLocation string, funcs map[string]interface{}, dev bool) *text.Template {
	if dev {
		t, err := text.New(templateName).Funcs(funcs).ParseFiles(templateLocation)
		checkErr(err, funcName(), "Load template console", templateLocation)
		return t
	}

	assetBloomsky, err := assembly.Asset(templateLocation)
	t, err := text.New(templateName).Funcs(funcs).Parse(string(assetBloomsky[:]))
	checkErr(err, funcName(), "Load template console", templateLocation)
	return t
}

// GetHTMLTemplate "bloomsky_header.html","tmpl/bloomsky_header.html",map[string]interface{}{"T": config.translateFunc,}
func GetHTMLTemplate(templateName string, templatesLocation []string, funcs map[string]interface{}, dev bool) *template.Template {
	t := template.New(templateName)
	t.Funcs(funcs)

	if dev {
		tp, err := t.ParseFiles(templatesLocation...)
		checkErr(err, funcName(), "ParseFiles")
		return tp
	}

	for _, l := range templatesLocation {
		asset, err := assembly.Asset(l)
		checkErr(err, funcName(), "Assembly template", l)

		t, err = t.Parse(string(asset[:]))
		checkErr(err, funcName(), "Parse file")
	}

	return t
}
<|endoftext|>