<commit_before>package streamer_test

import (
	"bytes"
	"errors"
	"sync"
	"time"

	"runtime"

	"github.com/cloudfoundry-incubator/garden/server/streamer"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Streamer", func() {

	const testString = "x"

	var (
		graceTime time.Duration
		str       *streamer.Streamer

		stdoutChan        chan []byte
		stderrChan        chan []byte
		testByteSlice     []byte
		channelBufferSize int
	)

	JustBeforeEach(func() {
		str = streamer.New(graceTime)
		stdoutChan = make(chan []byte, channelBufferSize)
		stderrChan = make(chan []byte, channelBufferSize)
	})

	BeforeEach(func() {
		graceTime = 10 * time.Second
		channelBufferSize = 1

		testByteSlice = []byte(testString)
	})

	It("should stream standard output until it is stopped", func() {
		sid := str.Stream(stdoutChan, stderrChan)
		w := &syncBuffer{
			Buffer: new(bytes.Buffer),
		}
		go str.ServeStdout(sid, w)
		stdoutChan <- testByteSlice
		stdoutChan <- testByteSlice
		Eventually(w.String).Should(Equal("xx"))
		str.Stop(sid)
	})

	// The following test will not reliably fail if the implementation fails to drain messages.
	It("should stream the remaining standard output messages after being stopped", func() {
		sid := str.Stream(stdoutChan, stderrChan)
		str.Stop(sid)
		w := new(bytes.Buffer)
		stdoutChan <- testByteSlice
		str.ServeStdout(sid, w)
		Expect(w.String()).To(Equal(testString))
	})

	It("should stream standard error until it is stopped", func() {
		sid := str.Stream(stdoutChan, stderrChan)
		w := &syncBuffer{
			Buffer: new(bytes.Buffer),
		}
		go str.ServeStderr(sid, w)
		stderrChan <- testByteSlice
		stderrChan <- testByteSlice
		Eventually(w.String).Should(Equal("xx"))
		str.Stop(sid)
	})

	// The following test will not reliably fail if the implementation fails to drain messages.
	It("should stream the remaining standard error messages after being stopped", func() {
		sid := str.Stream(stdoutChan, stderrChan)
		str.Stop(sid)
		w := new(bytes.Buffer)
		stderrChan <- testByteSlice
		str.ServeStderr(sid, w)
		Consistently(w.String).Should(Equal(testString))
	})

	Context("when a grace time has been set", func() {
		BeforeEach(func() {
			graceTime = 100 * time.Millisecond

		})

		It("should not leak unused streams for longer than the grace time after streaming has been stopped", func() {
			sid := str.Stream(stdoutChan, stderrChan)
			str.Stop(sid)
			time.Sleep(200 * time.Millisecond)
			Expect(func() { str.Stop(sid) }).To(Panic(), "stream was not removed")
		})

		It("should not leak goroutines for longer than the grace time after streaming has been stopped", func() {
			initialNumGoroutine := runtime.NumGoroutine()

			sid := str.Stream(stdoutChan, stderrChan)
			str.Stop(sid)

			Eventually(func() int {
				return runtime.NumGoroutine()
			}, "200ms").Should(Equal(initialNumGoroutine))
		})
	})

	It("should terminate streaming output after a write error has occurred", func() {
		sid := str.Stream(stdoutChan, stderrChan)
		w := &syncBuffer{
			Buffer: new(bytes.Buffer),
			fail:   true,
		}
		go str.ServeStdout(sid, w)
		stdoutChan <- testByteSlice
		stdoutChan <- testByteSlice
		Consistently(w.String).Should(Equal(""))
		str.Stop(sid)
	})

	It("should terminate streaming errors after a write error has occurred", func() {
		sid := str.Stream(stdoutChan, stderrChan)
		w := &syncBuffer{
			Buffer: new(bytes.Buffer),
			fail:   true,
		}
		go str.ServeStderr(sid, w)
		stderrChan <- testByteSlice
		stderrChan <- testByteSlice
		Consistently(w.String).Should(Equal(""))
		str.Stop(sid)
	})
})

type syncBuffer struct {
	*bytes.Buffer
	fail bool
	mu   sync.Mutex
}

func (sb *syncBuffer) Write(p []byte) (int, error) {
	sb.mu.Lock()
	defer sb.mu.Unlock()
	if sb.fail {
		sb.fail = false
		return 0, errors.New("failed")
	}
	return sb.Buffer.Write(p)
}

func (sb *syncBuffer) String() string {
	sb.mu.Lock()
	defer sb.mu.Unlock()
	return sb.Buffer.String()
}
<commit_msg>Assert that goroutines exit properly<commit_after>package streamer_test

import (
	"bytes"
	"errors"
	"runtime/pprof"
	"sync"
	"time"

	"github.com/cloudfoundry-incubator/garden/server/streamer"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
)

var _ = Describe("Streamer", func() {

	const testString = "x"

	var (
		graceTime time.Duration
		str       *streamer.Streamer

		stdoutChan        chan []byte
		stderrChan        chan []byte
		testByteSlice     []byte
		channelBufferSize int
	)

	JustBeforeEach(func() {
		str = streamer.New(graceTime)
		stdoutChan = make(chan []byte, channelBufferSize)
		stderrChan = make(chan []byte, channelBufferSize)
	})

	BeforeEach(func() {
		graceTime = 50 * time.Millisecond
		channelBufferSize = 1

		testByteSlice = []byte(testString)
	})

	It("should stream standard output until it is stopped", func() {
		sid := str.Stream(stdoutChan, stderrChan)
		w := &syncBuffer{
			Buffer: new(bytes.Buffer),
		}
		go str.ServeStdout(sid, w)
		stdoutChan <- testByteSlice
		stdoutChan <- testByteSlice
		Eventually(w.String).Should(Equal("xx"))
		str.Stop(sid)
	})

	// The following test will not reliably fail if the implementation fails to drain messages.
	It("should stream the remaining standard output messages after being stopped", func() {
		sid := str.Stream(stdoutChan, stderrChan)
		str.Stop(sid)
		w := new(bytes.Buffer)
		stdoutChan <- testByteSlice
		str.ServeStdout(sid, w)
		Expect(w.String()).To(Equal(testString))
	})

	It("should stream standard error until it is stopped", func() {
		sid := str.Stream(stdoutChan, stderrChan)
		w := &syncBuffer{
			Buffer: new(bytes.Buffer),
		}
		go str.ServeStderr(sid, w)
		stderrChan <- testByteSlice
		stderrChan <- testByteSlice
		Eventually(w.String).Should(Equal("xx"))
		str.Stop(sid)
	})

	// The following test will not reliably fail if the implementation fails to drain messages.
	It("should stream the remaining standard error messages after being stopped", func() {
		sid := str.Stream(stdoutChan, stderrChan)
		str.Stop(sid)
		w := new(bytes.Buffer)
		stderrChan <- testByteSlice
		str.ServeStderr(sid, w)
		Consistently(w.String).Should(Equal(testString))
	})

	Context("when a grace time has been set", func() {
		BeforeEach(func() {
			graceTime = 100 * time.Millisecond
		})

		It("should not leak unused streams for longer than the grace time after streaming has been stopped", func() {
			sid := str.Stream(stdoutChan, stderrChan)
			str.Stop(sid)

			Eventually(func() []byte {
				buffer := gbytes.NewBuffer()
				defer buffer.Close()
				Expect(pprof.Lookup("goroutine").WriteTo(buffer, 1)).To(Succeed())

				return buffer.Contents()
			}, 10*graceTime).ShouldNot(ContainSubstring("streamer.go"))
		})

		It("should not leak unused streams for longer than the grace time after streaming has been stopped", func() {
			sid := str.Stream(stdoutChan, stderrChan)
			str.Stop(sid)
			time.Sleep(graceTime)
			Expect(func() { str.Stop(sid) }).To(Panic(), "stream was not removed")
		})
	})

	It("should terminate streaming output after a write error has occurred", func() {
		sid := str.Stream(stdoutChan, stderrChan)
		w := &syncBuffer{
			Buffer: new(bytes.Buffer),
			fail:   true,
		}
		go str.ServeStdout(sid, w)
		stdoutChan <- testByteSlice
		stdoutChan <- testByteSlice
		Consistently(w.String).Should(Equal(""))
		str.Stop(sid)
	})

	It("should terminate streaming errors after a write error has occurred", func() {
		sid := str.Stream(stdoutChan, stderrChan)
		w := &syncBuffer{
			Buffer: new(bytes.Buffer),
			fail:   true,
		}
		go str.ServeStderr(sid, w)
		stderrChan <- testByteSlice
		stderrChan <- testByteSlice
		Consistently(w.String).Should(Equal(""))
		str.Stop(sid)
	})
})

type syncBuffer struct {
	*bytes.Buffer
	fail bool
	mu   sync.Mutex
}

func (sb *syncBuffer) Write(p []byte) (int, error) {
	sb.mu.Lock()
	defer sb.mu.Unlock()
	if sb.fail {
		sb.fail = false
		return 0, errors.New("failed")
	}
	return sb.Buffer.Write(p)
}

func (sb *syncBuffer) String() string {
	sb.mu.Lock()
	defer sb.mu.Unlock()
	return sb.Buffer.String()
}
<|endoftext|>


<commit_before>package report

import(
	"strings"

	"golang.org/x/net/context"
	"google.golang.org/appengine/user"

	"github.com/skypies/flightdb2/metar"
)

// TODO: just embed / extract this data from the regular context
type ReportingContext struct {
	context.Context
	metar.Archive
	UserEmail       string
}

var(
	// Lower case everything
	ACLFOIA = []string{
		"adam@worrall.cc",
		"raymonde.guindon@gmail.com",
		"rguindon@alumni.stanford.edu",
		"meekgee@gmail.com",
		"nancyjordan650@gmail.com",
		"borg@smwlaw.com",
		"matt@classalameda.com",
		"jnelson@wiai.com",
		"robert.holbrook@gmail.com",
		"jtsunnyvaleair1@gmail.com",
	}
)

func (r *Report)setupReportingContext(ctx context.Context) error {
	r.ReportingContext.Context = ctx

	metar,err := metar.LookupArchive(ctx, "KSFO",
		r.Options.Start.AddDate(0,0,-1), r.Options.End.AddDate(0,0,1))
	if err != nil {
		return err
	}
	r.ReportingContext.Archive = *metar

	user := user.Current(ctx)
	if user != nil {
		r.ReportingContext.UserEmail = user.Email
	}

	r.AddACLs()

	//airframes := ref.NewAirframeCache(ctx)

	return nil
}

func (r *Report)AddACLs() {
	email := r.ReportingContext.UserEmail
	if userInList(email, ACLFOIA) {
		r.Options.CanSeeFOIA = true
	}
}

func userInList(user string, acl []string) bool {
	for _,e := range acl {
		if strings.ToLower(user) == strings.ToLower(e) { return true }
	}
	return false
}
<commit_msg>Add to the ACL<commit_after>package report

import(
	"strings"

	"golang.org/x/net/context"
	"google.golang.org/appengine/user"

	"github.com/skypies/flightdb2/metar"
)

// TODO: just embed / extract this data from the regular context
type ReportingContext struct {
	context.Context
	metar.Archive
	UserEmail       string
}

var(
	// Lower case everything
	ACLFOIA = []string{
		"adam@worrall.cc",
		"raymonde.guindon@gmail.com",
		"rguindon@alumni.stanford.edu",
		"meekgee@gmail.com",
		"nancyjordan650@gmail.com",
		"borg@smwlaw.com",
		"matt@classalameda.com",
		"jnelson@wiai.com",
		"robert.holbrook@gmail.com",
		"jtsunnyvaleair1@gmail.com",
		"mthurd2003@gmail.com",
	}
)

func (r *Report)setupReportingContext(ctx context.Context) error {
	r.ReportingContext.Context = ctx

	metar,err := metar.LookupArchive(ctx, "KSFO",
		r.Options.Start.AddDate(0,0,-1), r.Options.End.AddDate(0,0,1))
	if err != nil {
		return err
	}
	r.ReportingContext.Archive = *metar

	user := user.Current(ctx)
	if user != nil {
		r.ReportingContext.UserEmail = user.Email
	}

	r.AddACLs()

	//airframes := ref.NewAirframeCache(ctx)

	return nil
}

func (r *Report)AddACLs() {
	email := r.ReportingContext.UserEmail
	if userInList(email, ACLFOIA) {
		r.Options.CanSeeFOIA = true
	}
}

func userInList(user string, acl []string) bool {
	for _,e := range acl {
		if strings.ToLower(user) == strings.ToLower(e) { return true }
	}
	return false
}
<|endoftext|>


<commit_before>// Copyright 2020 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 promql

import (
	"encoding/json"
	"fmt"
	"strconv"
	"strings"

	"github.com/pkg/errors"
	"github.com/prometheus/prometheus/pkg/labels"
	"github.com/prometheus/prometheus/promql/parser"
	"github.com/prometheus/prometheus/storage"
)

func (Matrix) Type() parser.ValueType { return parser.ValueTypeMatrix }
func (Vector) Type() parser.ValueType { return parser.ValueTypeVector }
func (Scalar) Type() parser.ValueType { return parser.ValueTypeScalar }
func (String) Type() parser.ValueType { return parser.ValueTypeString }

// String represents a string value.
type String struct {
	T int64
	V string
}

func (s String) String() string {
	return s.V
}

func (s String) MarshalJSON() ([]byte, error) {
	return json.Marshal([...]interface{}{float64(s.T) / 1000, s.V})
}

// Scalar is a data point that's explicitly not associated with a metric.
type Scalar struct {
	T int64
	V float64
}

func (s Scalar) String() string {
	v := strconv.FormatFloat(s.V, 'f', -1, 64)
	return fmt.Sprintf("scalar: %v @[%v]", v, s.T)
}

func (s Scalar) MarshalJSON() ([]byte, error) {
	v := strconv.FormatFloat(s.V, 'f', -1, 64)
	return json.Marshal([...]interface{}{float64(s.T) / 1000, v})
}

// Series is a stream of data points belonging to a metric.
type Series struct {
	Metric labels.Labels `json:"metric"`
	Points []Point       `json:"values"`
}

func (s Series) String() string {
	vals := make([]string, len(s.Points))
	for i, v := range s.Points {
		vals[i] = v.String()
	}
	return fmt.Sprintf("%s =>\n%s", s.Metric, strings.Join(vals, "\n"))
}

// Point represents a single data point for a given timestamp.
type Point struct {
	T int64
	V float64
}

func (p Point) String() string {
	v := strconv.FormatFloat(p.V, 'f', -1, 64)
	return fmt.Sprintf("%v @[%v]", v, p.T)
}

// MarshalJSON implements json.Marshaler.
func (p Point) MarshalJSON() ([]byte, error) {
	v := strconv.FormatFloat(p.V, 'f', -1, 64)
	return json.Marshal([...]interface{}{float64(p.T) / 1000, v})
}

// Sample is a single sample belonging to a metric.
type Sample struct {
	Point

	Metric labels.Labels
}

func (s Sample) String() string {
	return fmt.Sprintf("%s => %s", s.Metric, s.Point)
}

func (s Sample) MarshalJSON() ([]byte, error) {
	v := struct {
		M labels.Labels `json:"metric"`
		V Point         `json:"value"`
	}{
		M: s.Metric,
		V: s.Point,
	}
	return json.Marshal(v)
}

// Vector is basically only an alias for model.Samples, but the
// contract is that in a Vector, all Samples have the same timestamp.
type Vector []Sample

func (vec Vector) String() string {
	entries := make([]string, len(vec))
	for i, s := range vec {
		entries[i] = s.String()
	}
	return strings.Join(entries, "\n")
}

// ContainsSameLabelset checks if a vector has samples with the same labelset
// Such a behavior is semantically undefined
// https://github.com/prometheus/prometheus/issues/4562
func (vec Vector) ContainsSameLabelset() bool {
	l := make(map[uint64]struct{}, len(vec))
	for _, s := range vec {
		hash := s.Metric.Hash()
		if _, ok := l[hash]; ok {
			return true
		}
		l[hash] = struct{}{}
	}
	return false
}

// Matrix is a slice of Series that implements sort.Interface and
// has a String method.
type Matrix []Series

func (m Matrix) String() string {
	// TODO(fabxc): sort, or can we rely on order from the querier?
	strs := make([]string, len(m))

	for i, ss := range m {
		strs[i] = ss.String()
	}

	return strings.Join(strs, "\n")
}

// TotalSamples returns the total number of samples in the series within a matrix.
func (m Matrix) TotalSamples() int {
	numSamples := 0
	for _, series := range m {
		numSamples += len(series.Points)
	}
	return numSamples
}

func (m Matrix) Len() int           { return len(m) }
func (m Matrix) Less(i, j int) bool { return labels.Compare(m[i].Metric, m[j].Metric) < 0 }
func (m Matrix) Swap(i, j int)      { m[i], m[j] = m[j], m[i] }

// ContainsSameLabelset checks if a matrix has samples with the same labelset
// Such a behavior is semantically undefined
// https://github.com/prometheus/prometheus/issues/4562
func (m Matrix) ContainsSameLabelset() bool {
	l := make(map[uint64]struct{}, len(m))
	for _, ss := range m {
		hash := ss.Metric.Hash()
		if _, ok := l[hash]; ok {
			return true
		}
		l[hash] = struct{}{}
	}
	return false
}

// Result holds the resulting value of an execution or an error
// if any occurred.
type Result struct {
	Err      error
	Value    parser.Value
	Warnings storage.Warnings
}

// Vector returns a Vector if the result value is one. An error is returned if
// the result was an error or the result value is not a Vector.
func (r *Result) Vector() (Vector, error) {
	if r.Err != nil {
		return nil, r.Err
	}
	v, ok := r.Value.(Vector)
	if !ok {
		return nil, errors.New("query result is not a Vector")
	}
	return v, nil
}

// Matrix returns a Matrix. An error is returned if
// the result was an error or the result value is not a Matrix.
func (r *Result) Matrix() (Matrix, error) {
	if r.Err != nil {
		return nil, r.Err
	}
	v, ok := r.Value.(Matrix)
	if !ok {
		return nil, errors.New("query result is not a range Vector")
	}
	return v, nil
}

// Scalar returns a Scalar value. An error is returned if
// the result was an error or the result value is not a Scalar.
func (r *Result) Scalar() (Scalar, error) {
	if r.Err != nil {
		return Scalar{}, r.Err
	}
	v, ok := r.Value.(Scalar)
	if !ok {
		return Scalar{}, errors.New("query result is not a Scalar")
	}
	return v, nil
}

func (r *Result) String() string {
	if r.Err != nil {
		return r.Err.Error()
	}
	if r.Value == nil {
		return ""
	}
	return r.Value.String()
}

// StorageSeries simulates promql.Series as storage.Series.
type StorageSeries struct {
	series Series
}

// NewStorageSeries returns a StorageSeries from a Series.
func NewStorageSeries(series Series) *StorageSeries {
	return &StorageSeries{
		series: series,
	}
}

func (ss *StorageSeries) Labels() labels.Labels {
	return ss.series.Metric
}

// Iterator returns a new iterator of the data of the series.
func (ss *StorageSeries) Iterator() storage.SeriesIterator {
	return newStorageSeriesIterator(ss.series)
}

type storageSeriesIterator struct {
	points []Point
	curr   int
}

func newStorageSeriesIterator(series Series) *storageSeriesIterator {
	return &storageSeriesIterator{
		points: series.Points,
		curr:   -1,
	}
}

func (ssi *storageSeriesIterator) Seek(t int64) bool {
	i := ssi.curr
	if i < 0 {
		i = 0
	}
	for ; i < len(ssi.points); i++ {
		if ssi.points[i].T >= t {
			ssi.curr = i
			return true
		}
	}
	ssi.curr = len(ssi.points) - 1
	return false
}

func (ssi *storageSeriesIterator) At() (t int64, v float64) {
	p := ssi.points[ssi.curr]
	return p.T, p.V
}

func (ssi *storageSeriesIterator) Next() bool {
	ssi.curr++
	return ssi.curr < len(ssi.points)
}

func (ssi *storageSeriesIterator) Err() error {
	return nil
}
<commit_msg>Unbump year number<commit_after>// Copyright 2017 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 promql

import (
	"encoding/json"
	"fmt"
	"strconv"
	"strings"

	"github.com/pkg/errors"
	"github.com/prometheus/prometheus/pkg/labels"
	"github.com/prometheus/prometheus/promql/parser"
	"github.com/prometheus/prometheus/storage"
)

func (Matrix) Type() parser.ValueType { return parser.ValueTypeMatrix }
func (Vector) Type() parser.ValueType { return parser.ValueTypeVector }
func (Scalar) Type() parser.ValueType { return parser.ValueTypeScalar }
func (String) Type() parser.ValueType { return parser.ValueTypeString }

// String represents a string value.
type String struct {
	T int64
	V string
}

func (s String) String() string {
	return s.V
}

func (s String) MarshalJSON() ([]byte, error) {
	return json.Marshal([...]interface{}{float64(s.T) / 1000, s.V})
}

// Scalar is a data point that's explicitly not associated with a metric.
type Scalar struct {
	T int64
	V float64
}

func (s Scalar) String() string {
	v := strconv.FormatFloat(s.V, 'f', -1, 64)
	return fmt.Sprintf("scalar: %v @[%v]", v, s.T)
}

func (s Scalar) MarshalJSON() ([]byte, error) {
	v := strconv.FormatFloat(s.V, 'f', -1, 64)
	return json.Marshal([...]interface{}{float64(s.T) / 1000, v})
}

// Series is a stream of data points belonging to a metric.
type Series struct {
	Metric labels.Labels `json:"metric"`
	Points []Point       `json:"values"`
}

func (s Series) String() string {
	vals := make([]string, len(s.Points))
	for i, v := range s.Points {
		vals[i] = v.String()
	}
	return fmt.Sprintf("%s =>\n%s", s.Metric, strings.Join(vals, "\n"))
}

// Point represents a single data point for a given timestamp.
type Point struct {
	T int64
	V float64
}

func (p Point) String() string {
	v := strconv.FormatFloat(p.V, 'f', -1, 64)
	return fmt.Sprintf("%v @[%v]", v, p.T)
}

// MarshalJSON implements json.Marshaler.
func (p Point) MarshalJSON() ([]byte, error) {
	v := strconv.FormatFloat(p.V, 'f', -1, 64)
	return json.Marshal([...]interface{}{float64(p.T) / 1000, v})
}

// Sample is a single sample belonging to a metric.
type Sample struct {
	Point

	Metric labels.Labels
}

func (s Sample) String() string {
	return fmt.Sprintf("%s => %s", s.Metric, s.Point)
}

func (s Sample) MarshalJSON() ([]byte, error) {
	v := struct {
		M labels.Labels `json:"metric"`
		V Point         `json:"value"`
	}{
		M: s.Metric,
		V: s.Point,
	}
	return json.Marshal(v)
}

// Vector is basically only an alias for model.Samples, but the
// contract is that in a Vector, all Samples have the same timestamp.
type Vector []Sample

func (vec Vector) String() string {
	entries := make([]string, len(vec))
	for i, s := range vec {
		entries[i] = s.String()
	}
	return strings.Join(entries, "\n")
}

// ContainsSameLabelset checks if a vector has samples with the same labelset
// Such a behavior is semantically undefined
// https://github.com/prometheus/prometheus/issues/4562
func (vec Vector) ContainsSameLabelset() bool {
	l := make(map[uint64]struct{}, len(vec))
	for _, s := range vec {
		hash := s.Metric.Hash()
		if _, ok := l[hash]; ok {
			return true
		}
		l[hash] = struct{}{}
	}
	return false
}

// Matrix is a slice of Series that implements sort.Interface and
// has a String method.
type Matrix []Series

func (m Matrix) String() string {
	// TODO(fabxc): sort, or can we rely on order from the querier?
	strs := make([]string, len(m))

	for i, ss := range m {
		strs[i] = ss.String()
	}

	return strings.Join(strs, "\n")
}

// TotalSamples returns the total number of samples in the series within a matrix.
func (m Matrix) TotalSamples() int {
	numSamples := 0
	for _, series := range m {
		numSamples += len(series.Points)
	}
	return numSamples
}

func (m Matrix) Len() int           { return len(m) }
func (m Matrix) Less(i, j int) bool { return labels.Compare(m[i].Metric, m[j].Metric) < 0 }
func (m Matrix) Swap(i, j int)      { m[i], m[j] = m[j], m[i] }

// ContainsSameLabelset checks if a matrix has samples with the same labelset
// Such a behavior is semantically undefined
// https://github.com/prometheus/prometheus/issues/4562
func (m Matrix) ContainsSameLabelset() bool {
	l := make(map[uint64]struct{}, len(m))
	for _, ss := range m {
		hash := ss.Metric.Hash()
		if _, ok := l[hash]; ok {
			return true
		}
		l[hash] = struct{}{}
	}
	return false
}

// Result holds the resulting value of an execution or an error
// if any occurred.
type Result struct {
	Err      error
	Value    parser.Value
	Warnings storage.Warnings
}

// Vector returns a Vector if the result value is one. An error is returned if
// the result was an error or the result value is not a Vector.
func (r *Result) Vector() (Vector, error) {
	if r.Err != nil {
		return nil, r.Err
	}
	v, ok := r.Value.(Vector)
	if !ok {
		return nil, errors.New("query result is not a Vector")
	}
	return v, nil
}

// Matrix returns a Matrix. An error is returned if
// the result was an error or the result value is not a Matrix.
func (r *Result) Matrix() (Matrix, error) {
	if r.Err != nil {
		return nil, r.Err
	}
	v, ok := r.Value.(Matrix)
	if !ok {
		return nil, errors.New("query result is not a range Vector")
	}
	return v, nil
}

// Scalar returns a Scalar value. An error is returned if
// the result was an error or the result value is not a Scalar.
func (r *Result) Scalar() (Scalar, error) {
	if r.Err != nil {
		return Scalar{}, r.Err
	}
	v, ok := r.Value.(Scalar)
	if !ok {
		return Scalar{}, errors.New("query result is not a Scalar")
	}
	return v, nil
}

func (r *Result) String() string {
	if r.Err != nil {
		return r.Err.Error()
	}
	if r.Value == nil {
		return ""
	}
	return r.Value.String()
}

// StorageSeries simulates promql.Series as storage.Series.
type StorageSeries struct {
	series Series
}

// NewStorageSeries returns a StorageSeries from a Series.
func NewStorageSeries(series Series) *StorageSeries {
	return &StorageSeries{
		series: series,
	}
}

func (ss *StorageSeries) Labels() labels.Labels {
	return ss.series.Metric
}

// Iterator returns a new iterator of the data of the series.
func (ss *StorageSeries) Iterator() storage.SeriesIterator {
	return newStorageSeriesIterator(ss.series)
}

type storageSeriesIterator struct {
	points []Point
	curr   int
}

func newStorageSeriesIterator(series Series) *storageSeriesIterator {
	return &storageSeriesIterator{
		points: series.Points,
		curr:   -1,
	}
}

func (ssi *storageSeriesIterator) Seek(t int64) bool {
	i := ssi.curr
	if i < 0 {
		i = 0
	}
	for ; i < len(ssi.points); i++ {
		if ssi.points[i].T >= t {
			ssi.curr = i
			return true
		}
	}
	ssi.curr = len(ssi.points) - 1
	return false
}

func (ssi *storageSeriesIterator) At() (t int64, v float64) {
	p := ssi.points[ssi.curr]
	return p.T, p.V
}

func (ssi *storageSeriesIterator) Next() bool {
	ssi.curr++
	return ssi.curr < len(ssi.points)
}

func (ssi *storageSeriesIterator) Err() error {
	return nil
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Contributor: Aaron Meihm ameihm@mozilla.com [:alm]

// scribe module implementation for MIG.
package scribe

import (
	"bytes"
	"encoding/json"
	"fmt"
	scribelib "github.com/mozilla/scribe/src/scribe"
	"io"
	"mig/modules"
	"mig/modules/file"
	"regexp"
	"runtime"
	"strconv"
	"time"
)

var stats statistics

// Counters to populate statistics at end of run.
var counters struct {
	startTime time.Time
}

func startCounters() {
	counters.startTime = time.Now()
}

func endCounters() {
	stats.ExecRuntime = time.Now().Sub(counters.startTime).String()
}

type module struct {
}

func (m *module) NewRun() modules.Runner {
	return new(run)
}

func init() {
	modules.Register("scribe", new(module))
}

type run struct {
	Parameters parameters
	Results    modules.Result
}

func buildResultsScribe(e elements, r *modules.Result) (buf []byte, err error) {
	r.Success = true
	r.Elements = e
	if len(e.Results) > 0 {
		r.FoundAnything = true
	}
	// If any tests resulted in an error, store them as errors in the command.
	for _, x := range e.Results {
		if x.IsError {
			es := fmt.Sprintf("Error: %v in \"%v\"", x.Error, x.Name)
			r.Errors = append(r.Errors, es)
		}
	}
	endCounters()
	r.Statistics = stats
	buf, err = json.Marshal(r)
	return
}

func buildResultsPackage(e elements, r *modules.Result) (buf []byte, err error) {
	r.Success = true
	r.Elements = e
	if len(e.Packages) > 0 {
		r.FoundAnything = true
	}
	endCounters()
	r.Statistics = stats
	buf, err = json.Marshal(r)
	return
}

// This function is used to call the file module from this module. In order to
// avoid exporting types from the file module, we construct parameters for the
// file module using the parameter creation functions (passing command line
// arguments).
//
// We use the file modules file system location functions here to avoid
// duplicating functionality in this module.
func fileModuleLocator(pattern string, regex bool, root string, depth int) ([]string, error) {
	ret := make([]string, 0)

	// Build a pseudo-run struct to let us call the file module.
	run := modules.Available["file"].NewRun()
	args := make([]string, 0)
	args = append(args, "-path", root)
	args = append(args, "-name", pattern)
	args = append(args, "-maxdepth", strconv.Itoa(depth))
	param, err := run.ParamsParser(args)
	if err != nil {
		return ret, err
	}

	buf, err := modules.MakeMessage(modules.MsgClassParameters, param)
	if err != nil {
		return ret, nil
	}
	rdr := bytes.NewReader(buf)

	res := run.Run(rdr)
	var modresult modules.Result
	var sr file.SearchResults
	err = json.Unmarshal([]byte(res), &modresult)
	if err != nil {
		return ret, err
	}
	err = modresult.GetElements(&sr)
	if err != nil {
		return ret, err
	}

	p0, ok := sr["s1"]
	if !ok {
		return ret, fmt.Errorf("result in file module call was missing")
	}
	for _, x := range p0 {
		ret = append(ret, x.File)
	}

	return ret, nil
}

func (r *run) Run(in io.Reader) (resStr string) {
	defer func() {
		if e := recover(); e != nil {
			// return error in json
			r.Results.Errors = append(r.Results.Errors, fmt.Sprintf("%v", e))
			r.Results.Success = false
			endCounters()
			r.Results.Statistics = stats
			err, _ := json.Marshal(r.Results)
			resStr = string(err)
			return
		}
	}()

	// Restrict go runtime processor utilization here, this might be moved
	// into a more generic agent module function at some point.
	runtime.GOMAXPROCS(1)

	// Initialize scribe
	scribelib.Bootstrap()

	// Install the file locator; this allows us to use the file module's
	// search functionality overriding the scribe built-in file system
	// walk function.
	scribelib.InstallFileLocator(fileModuleLocator)

	startCounters()

	// Read module parameters from stdin
	err := modules.ReadInputParameters(in, &r.Parameters)
	if err != nil {
		panic(err)
	}

	err = r.ValidateParameters()
	if err != nil {
		panic(err)
	}

	document := r.Parameters.ScribeDoc
	e := &elements{}

	switch r.Parameters.RunMode {
	case modeScribe:
		e.Results = make([]scribelib.TestResult, 0)
		// Proceed with analysis here. ValidateParameters() will have already
		// validated the document.
		err = scribelib.AnalyzeDocument(document)
		if err != nil {
			panic(err)
		}
		for _, x := range document.GetTestNames() {
			tr, err := scribelib.GetResults(&document, x)
			if err != nil {
				panic(err)
			}
			if !tr.MasterResult && r.Parameters.OnlyTrue {
				continue
			}
			e.Results = append(e.Results, tr)
		}
		buf, err := buildResultsScribe(*e, &r.Results)
		if err != nil {
			panic(err)
		}
		resStr = string(buf)
		return
	case modePackage:
		e.Packages = make([]scribelib.PackageInfo, 0)
		pkglist := scribelib.QueryPackages()
		re, err := regexp.Compile(r.Parameters.PkgMatch)
		if err != nil {
			panic(err)
		}
		for _, x := range pkglist {
			if !re.MatchString(x.Name) {
				continue
			}
			e.Packages = append(e.Packages, x)
		}
		buf, err := buildResultsPackage(*e, &r.Results)
		if err != nil {
			panic(err)
		}
		resStr = string(buf)
		return
	default:
	}
	panic("no operation executed")
	return
}

func (r *run) ValidateParameters() (err error) {
	if r.Parameters.RunMode != modeScribe && r.Parameters.RunMode != modePackage {
		return fmt.Errorf("invalid run mode specified")
	}
	switch r.Parameters.RunMode {
	case modeScribe:
		err = r.Parameters.ScribeDoc.Validate()
	case modePackage:
		if len(r.Parameters.PkgMatch) == 0 {
			return fmt.Errorf("must specify pkgmatch in package mode")
		}
		_, err := regexp.Compile(r.Parameters.PkgMatch)
		if err != nil {
			return err
		}
	default:
		return fmt.Errorf("invalid run mode specified")
	}
	return
}

func (r *run) PrintResults(result modules.Result, foundOnly bool) (prints []string, err error) {
	var (
		elem  elements
		stats statistics
	)

	err = result.GetElements(&elem)
	if err != nil {
		panic(err)
	}
	err = result.GetStatistics(&stats)
	if err != nil {
		panic(err)
	}
	for _, x := range elem.Packages {
		s := fmt.Sprintf("package name:%v version:%v type:%v", x.Name, x.Version, x.Type)
		prints = append(prints, s)
	}
	for _, x := range elem.Results {
		for _, y := range x.SingleLineResults() {
			prints = append(prints, y)
		}
	}
	if !foundOnly {
		for _, we := range result.Errors {
			prints = append(prints, we)
		}
		s := fmt.Sprintf("Statistics: runtime %v", stats.ExecRuntime)
		prints = append(prints, s)
	}
	return
}

type elements struct {
	Results  []scribelib.TestResult  `json:"results"`  // Results of evaluation.
	Packages []scribelib.PackageInfo `json:"packages"` // Results of package query.
}

type statistics struct {
	ExecRuntime string `json:"execruntime"` // Total execution time.
}

// Execution modes
const (
	_ = iota
	modeScribe
	modePackage
)

type parameters struct {
	ScribeDoc scribelib.Document `json:"scribedoc"` // The scribe document for analysis.
	OnlyTrue  bool               `json:"onlytrue"`  // Only return true evaluations
	RunMode   int                `json:"runmode"`   // Execution mode
	PkgMatch  string             `json:"pkgmatch"`  // Match regexp for package mode
}

func newParameters() *parameters {
	return &parameters{}
}
<commit_msg>[minor] update scribe module for recent scribe api changes<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Contributor: Aaron Meihm ameihm@mozilla.com [:alm]

// scribe module implementation for MIG.
package scribe

import (
	"bytes"
	"encoding/json"
	"fmt"
	scribelib "github.com/mozilla/scribe/src/scribe"
	"io"
	"mig/modules"
	"mig/modules/file"
	"regexp"
	"runtime"
	"strconv"
	"time"
)

var stats statistics

// Counters to populate statistics at end of run.
var counters struct {
	startTime time.Time
}

func startCounters() {
	counters.startTime = time.Now()
}

func endCounters() {
	stats.ExecRuntime = time.Now().Sub(counters.startTime).String()
}

type module struct {
}

func (m *module) NewRun() modules.Runner {
	return new(run)
}

func init() {
	modules.Register("scribe", new(module))
}

type run struct {
	Parameters parameters
	Results    modules.Result
}

func buildResultsScribe(e elements, r *modules.Result) (buf []byte, err error) {
	r.Success = true
	r.Elements = e
	if len(e.Results) > 0 {
		r.FoundAnything = true
	}
	// If any tests resulted in an error, store them as errors in the command.
	for _, x := range e.Results {
		if x.IsError {
			es := fmt.Sprintf("Error: %v in \"%v\"", x.Error, x.TestID)
			r.Errors = append(r.Errors, es)
		}
	}
	endCounters()
	r.Statistics = stats
	buf, err = json.Marshal(r)
	return
}

func buildResultsPackage(e elements, r *modules.Result) (buf []byte, err error) {
	r.Success = true
	r.Elements = e
	if len(e.Packages) > 0 {
		r.FoundAnything = true
	}
	endCounters()
	r.Statistics = stats
	buf, err = json.Marshal(r)
	return
}

// This function is used to call the file module from this module. In order to
// avoid exporting types from the file module, we construct parameters for the
// file module using the parameter creation functions (passing command line
// arguments).
//
// We use the file modules file system location functions here to avoid
// duplicating functionality in this module.
func fileModuleLocator(pattern string, regex bool, root string, depth int) ([]string, error) {
	ret := make([]string, 0)

	// Build a pseudo-run struct to let us call the file module.
	run := modules.Available["file"].NewRun()
	args := make([]string, 0)
	args = append(args, "-path", root)
	args = append(args, "-name", pattern)
	args = append(args, "-maxdepth", strconv.Itoa(depth))
	param, err := run.ParamsParser(args)
	if err != nil {
		return ret, err
	}

	buf, err := modules.MakeMessage(modules.MsgClassParameters, param)
	if err != nil {
		return ret, nil
	}
	rdr := bytes.NewReader(buf)

	res := run.Run(rdr)
	var modresult modules.Result
	var sr file.SearchResults
	err = json.Unmarshal([]byte(res), &modresult)
	if err != nil {
		return ret, err
	}
	err = modresult.GetElements(&sr)
	if err != nil {
		return ret, err
	}

	p0, ok := sr["s1"]
	if !ok {
		return ret, fmt.Errorf("result in file module call was missing")
	}
	for _, x := range p0 {
		ret = append(ret, x.File)
	}

	return ret, nil
}

func (r *run) Run(in io.Reader) (resStr string) {
	defer func() {
		if e := recover(); e != nil {
			// return error in json
			r.Results.Errors = append(r.Results.Errors, fmt.Sprintf("%v", e))
			r.Results.Success = false
			endCounters()
			r.Results.Statistics = stats
			err, _ := json.Marshal(r.Results)
			resStr = string(err)
			return
		}
	}()

	// Restrict go runtime processor utilization here, this might be moved
	// into a more generic agent module function at some point.
	runtime.GOMAXPROCS(1)

	// Initialize scribe
	scribelib.Bootstrap()

	// Install the file locator; this allows us to use the file module's
	// search functionality overriding the scribe built-in file system
	// walk function.
	scribelib.InstallFileLocator(fileModuleLocator)

	startCounters()

	// Read module parameters from stdin
	err := modules.ReadInputParameters(in, &r.Parameters)
	if err != nil {
		panic(err)
	}

	err = r.ValidateParameters()
	if err != nil {
		panic(err)
	}

	document := r.Parameters.ScribeDoc
	e := &elements{}

	switch r.Parameters.RunMode {
	case modeScribe:
		e.Results = make([]scribelib.TestResult, 0)
		// Proceed with analysis here. ValidateParameters() will have already
		// validated the document.
		err = scribelib.AnalyzeDocument(document)
		if err != nil {
			panic(err)
		}
		for _, x := range document.GetTestIdentifiers() {
			tr, err := scribelib.GetResults(&document, x)
			if err != nil {
				panic(err)
			}
			if !tr.MasterResult && r.Parameters.OnlyTrue {
				continue
			}
			e.Results = append(e.Results, tr)
		}
		buf, err := buildResultsScribe(*e, &r.Results)
		if err != nil {
			panic(err)
		}
		resStr = string(buf)
		return
	case modePackage:
		e.Packages = make([]scribelib.PackageInfo, 0)
		pkglist := scribelib.QueryPackages()
		re, err := regexp.Compile(r.Parameters.PkgMatch)
		if err != nil {
			panic(err)
		}
		for _, x := range pkglist {
			if !re.MatchString(x.Name) {
				continue
			}
			e.Packages = append(e.Packages, x)
		}
		buf, err := buildResultsPackage(*e, &r.Results)
		if err != nil {
			panic(err)
		}
		resStr = string(buf)
		return
	default:
	}
	panic("no operation executed")
	return
}

func (r *run) ValidateParameters() (err error) {
	if r.Parameters.RunMode != modeScribe && r.Parameters.RunMode != modePackage {
		return fmt.Errorf("invalid run mode specified")
	}
	switch r.Parameters.RunMode {
	case modeScribe:
		err = r.Parameters.ScribeDoc.Validate()
	case modePackage:
		if len(r.Parameters.PkgMatch) == 0 {
			return fmt.Errorf("must specify pkgmatch in package mode")
		}
		_, err := regexp.Compile(r.Parameters.PkgMatch)
		if err != nil {
			return err
		}
	default:
		return fmt.Errorf("invalid run mode specified")
	}
	return
}

func (r *run) PrintResults(result modules.Result, foundOnly bool) (prints []string, err error) {
	var (
		elem  elements
		stats statistics
	)

	err = result.GetElements(&elem)
	if err != nil {
		panic(err)
	}
	err = result.GetStatistics(&stats)
	if err != nil {
		panic(err)
	}
	for _, x := range elem.Packages {
		s := fmt.Sprintf("package name:%v version:%v type:%v", x.Name, x.Version, x.Type)
		prints = append(prints, s)
	}
	for _, x := range elem.Results {
		for _, y := range x.SingleLineResults() {
			prints = append(prints, y)
		}
	}
	if !foundOnly {
		for _, we := range result.Errors {
			prints = append(prints, we)
		}
		s := fmt.Sprintf("Statistics: runtime %v", stats.ExecRuntime)
		prints = append(prints, s)
	}
	return
}

type elements struct {
	Results  []scribelib.TestResult  `json:"results"`  // Results of evaluation.
	Packages []scribelib.PackageInfo `json:"packages"` // Results of package query.
}

type statistics struct {
	ExecRuntime string `json:"execruntime"` // Total execution time.
}

// Execution modes
const (
	_ = iota
	modeScribe
	modePackage
)

type parameters struct {
	ScribeDoc scribelib.Document `json:"scribedoc"` // The scribe document for analysis.
	OnlyTrue  bool               `json:"onlytrue"`  // Only return true evaluations
	RunMode   int                `json:"runmode"`   // Execution mode
	PkgMatch  string             `json:"pkgmatch"`  // Match regexp for package mode
}

func newParameters() *parameters {
	return &parameters{}
}
<|endoftext|>


<commit_before>package request

import (
	"os"
	"fmt"
	"log"
	"bufio"
	"bytes"
	"strings"
	"strconv"
	"io/ioutil"
	"crypto/rand"
	"crypto/tls"
	"net/url"
	"net/http"
	"net/http/httputil"
	"encoding/binary"
	"github.com/toqueteos/webbrowser"
)

func authCodeGrant(request *AurlExecution) (*string, error) {
	state := random()
	authZRequestUrl := authorizationRequestURL("code", request, state)
	webbrowser.Open(authZRequestUrl)
	fmt.Fprintf(os.Stderr, "Open browser and get code from %s\n", authZRequestUrl)

	reader := bufio.NewReader(os.Stdin)
	fmt.Fprint(os.Stderr, "Enter code: ")
	if code, _, err := reader.ReadLine(); err != nil {
		return nil, err
	} else {
		values := url.Values{
			"grant_type":    {"authorization_code"},
			"code":          {string(code)},
			"redirect_uri":  {request.Profile.RedirectURI},
		}
		return tokenRequest(values, request)
	}
}

func implicitGrant(request *AurlExecution) (*string, error) {
	state := random()
	url := authorizationRequestURL("token", request, state)
	webbrowser.Open(url)
	fmt.Fprintf(os.Stderr, "Open browser and get token from %s\n", url)

	reader := bufio.NewReader(os.Stdin)
	fmt.Fprint(os.Stderr, "Enter token: ")
	if token, _, err := reader.ReadLine(); err != nil {
		return nil, err
	} else {
		s := "{\"token_type\": \"bearer\",\"access_token\": \"" + string(token) + "\"}" // TODO
		return &s, nil
	}
}

func resourceOwnerPasswordCredentialsGrant(request *AurlExecution) (*string, error) {
	values := url.Values{
		"grant_type":    {"password"},
		"username":      {request.Profile.Username},
		"password":      {request.Profile.Password},
		"scope":         condVal(strings.Join(strings.Split(request.Profile.Scope, ","), " ")),
	}
	return tokenRequest(values, request)
}

func clientCredentialsGrant(request *AurlExecution) (*string, error) {
	values := url.Values{
		"grant_type":    {"client_credentials"},
		"scope":         condVal(strings.Join(strings.Split(request.Profile.Scope, ","), " ")),
	}
	return tokenRequest(values, request)
}

func refreshGrant(request *AurlExecution, refreshToken string) (*string, error) {
	values := url.Values{
		"grant_type":    {"refresh_token"},
		"refresh_token": {refreshToken},
		"scope":         condVal(strings.Join(strings.Split(request.Profile.Scope, ","), " ")),
	}
	return tokenRequest(values, request)
}

func authorizationRequestURL(responseType string,request *AurlExecution, state string) string {
	var buf bytes.Buffer
	buf.WriteString(request.Profile.AuthorizationEndpoint)
	v := url.Values{
		"response_type": {responseType},
		"client_id":     {request.Profile.ClientId},
		"redirect_uri":  condVal(request.Profile.RedirectURI),
		"scope":         condVal(strings.Join(strings.Split(request.Profile.Scope, ","), " ")),
		"state":         condVal(state),
	}
	if strings.Contains(request.Profile.AuthorizationEndpoint, "?") {
		buf.WriteByte('&')
	} else {
		buf.WriteByte('?')
	}
	buf.WriteString(v.Encode())
	return buf.String()
}

func tokenRequest(v url.Values,request *AurlExecution) (*string, error) {
	req, err := http.NewRequest("POST", request.Profile.TokenEndpoint, strings.NewReader(v.Encode()))
	if err != nil {
		return nil, err
	}
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	req.SetBasicAuth(request.Profile.ClientId, request.Profile.ClientSecret)

	if dumpReq, err := httputil.DumpRequestOut(req, true); err == nil {
		log.Printf("Token request >>>\n%s\n<<<", string(dumpReq))
	} else {
		log.Printf("Token request dump failed: ", err)
	}

	client := &http.Client{
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: *request.Insecure,
			},
		},
	}
	resp, err := client.Do(req)
	defer resp.Body.Close()
	if err != nil {
		log.Printf("Token request failed: %s", err.Error())
		return nil, err
	}

	if dumpResp, err := httputil.DumpResponse(resp, true); err == nil {
		log.Printf("Token response >>>\n%s\n<<<", string(dumpResp))
	} else {
		log.Printf("Token response dump failed: ", err)
	}

	if resp.StatusCode == 200 {
		if b, err := ioutil.ReadAll(resp.Body); err == nil {
			s := string(b)
			return &s, nil
		} else {
			return nil, err
		}
	} else {
		log.Printf("Token request failed: %d", resp.StatusCode)
		return nil, err
	}
}

func condVal(v string) []string {
	if v == "" {
		return nil
	}
	return []string{v}
}

func random() string {
	var n uint64
	binary.Read(rand.Reader, binary.LittleEndian, &n)
	return strconv.FormatUint(n, 36)
}
<commit_msg>fix SEGV (#6)<commit_after>package request

import (
	"os"
	"fmt"
	"log"
	"bufio"
	"bytes"
	"strings"
	"strconv"
	"io/ioutil"
	"crypto/rand"
	"crypto/tls"
	"net/url"
	"net/http"
	"net/http/httputil"
	"encoding/binary"
	"github.com/toqueteos/webbrowser"
)

func authCodeGrant(request *AurlExecution) (*string, error) {
	state := random()
	authZRequestUrl := authorizationRequestURL("code", request, state)
	webbrowser.Open(authZRequestUrl)
	fmt.Fprintf(os.Stderr, "Open browser and get code from %s\n", authZRequestUrl)

	reader := bufio.NewReader(os.Stdin)
	fmt.Fprint(os.Stderr, "Enter code: ")
	if code, _, err := reader.ReadLine(); err != nil {
		return nil, err
	} else {
		values := url.Values{
			"grant_type":    {"authorization_code"},
			"code":          {string(code)},
			"redirect_uri":  {request.Profile.RedirectURI},
		}
		return tokenRequest(values, request)
	}
}

func implicitGrant(request *AurlExecution) (*string, error) {
	state := random()
	url := authorizationRequestURL("token", request, state)
	webbrowser.Open(url)
	fmt.Fprintf(os.Stderr, "Open browser and get token from %s\n", url)

	reader := bufio.NewReader(os.Stdin)
	fmt.Fprint(os.Stderr, "Enter token: ")
	if token, _, err := reader.ReadLine(); err != nil {
		return nil, err
	} else {
		s := "{\"token_type\": \"bearer\",\"access_token\": \"" + string(token) + "\"}" // TODO
		return &s, nil
	}
}

func resourceOwnerPasswordCredentialsGrant(request *AurlExecution) (*string, error) {
	values := url.Values{
		"grant_type":    {"password"},
		"username":      {request.Profile.Username},
		"password":      {request.Profile.Password},
		"scope":         condVal(strings.Join(strings.Split(request.Profile.Scope, ","), " ")),
	}
	return tokenRequest(values, request)
}

func clientCredentialsGrant(request *AurlExecution) (*string, error) {
	values := url.Values{
		"grant_type":    {"client_credentials"},
		"scope":         condVal(strings.Join(strings.Split(request.Profile.Scope, ","), " ")),
	}
	return tokenRequest(values, request)
}

func refreshGrant(request *AurlExecution, refreshToken string) (*string, error) {
	values := url.Values{
		"grant_type":    {"refresh_token"},
		"refresh_token": {refreshToken},
		"scope":         condVal(strings.Join(strings.Split(request.Profile.Scope, ","), " ")),
	}
	return tokenRequest(values, request)
}

func authorizationRequestURL(responseType string,request *AurlExecution, state string) string {
	var buf bytes.Buffer
	buf.WriteString(request.Profile.AuthorizationEndpoint)
	v := url.Values{
		"response_type": {responseType},
		"client_id":     {request.Profile.ClientId},
		"redirect_uri":  condVal(request.Profile.RedirectURI),
		"scope":         condVal(strings.Join(strings.Split(request.Profile.Scope, ","), " ")),
		"state":         condVal(state),
	}
	if strings.Contains(request.Profile.AuthorizationEndpoint, "?") {
		buf.WriteByte('&')
	} else {
		buf.WriteByte('?')
	}
	buf.WriteString(v.Encode())
	return buf.String()
}

func tokenRequest(v url.Values,request *AurlExecution) (*string, error) {
	req, err := http.NewRequest("POST", request.Profile.TokenEndpoint, strings.NewReader(v.Encode()))
	if err != nil {
		return nil, err
	}
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	req.SetBasicAuth(request.Profile.ClientId, request.Profile.ClientSecret)

	if dumpReq, err := httputil.DumpRequestOut(req, true); err == nil {
		log.Printf("Token request >>>\n%s\n<<<", string(dumpReq))
	} else {
		log.Printf("Token request dump failed: %s", err)
	}

	client := &http.Client{
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: *request.Insecure,
			},
		},
	}
	resp, err := client.Do(req)
	if err != nil {
		log.Printf("Token request failed: %s", err.Error())
		return nil, err
	}

	defer resp.Body.Close()

	if dumpResp, err := httputil.DumpResponse(resp, true); err == nil {
		log.Printf("Token response >>>\n%s\n<<<", string(dumpResp))
	} else {
		log.Printf("Token response dump failed: %s", err)
	}

	if resp.StatusCode == 200 {
		if b, err := ioutil.ReadAll(resp.Body); err == nil {
			s := string(b)
			return &s, nil
		} else {
			return nil, err
		}
	} else {
		log.Printf("Token request failed: %d", resp.StatusCode)
		return nil, err
	}
}

func condVal(v string) []string {
	if v == "" {
		return nil
	}
	return []string{v}
}

func random() string {
	var n uint64
	binary.Read(rand.Reader, binary.LittleEndian, &n)
	return strconv.FormatUint(n, 36)
}
<|endoftext|>


<commit_before>// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package firebase is the entry point to the Firebase Admin SDK. It provides functionality for initializing App
// instances, which serve as the central entities that provide access to various other Firebase services exposed
// from the SDK.
package firebase // import "firebase.google.com/go"

import (
	"context"
	"encoding/json"
	"errors"
	"io/ioutil"
	"os"

	"cloud.google.com/go/firestore"
	"firebase.google.com/go/auth"
	"firebase.google.com/go/db"
	"firebase.google.com/go/iid"
	"firebase.google.com/go/internal"
	"firebase.google.com/go/messaging"
	"firebase.google.com/go/storage"
	"golang.org/x/oauth2/google"
	"google.golang.org/api/option"
	"google.golang.org/api/transport"
)

var defaultAuthOverrides = make(map[string]interface{})

// Version of the Firebase Go Admin SDK.
const Version = "3.10.0"

// firebaseEnvName is the name of the environment variable with the Config.
const firebaseEnvName = "FIREBASE_CONFIG"

// An App holds configuration and state common to all Firebase services that are exposed from the SDK.
type App struct {
	authOverride     map[string]interface{}
	creds            *google.DefaultCredentials
	dbURL            string
	projectID        string
	serviceAccountID string
	storageBucket    string
	opts             []option.ClientOption
}

// Config represents the configuration used to initialize an App.
type Config struct {
	AuthOverride     *map[string]interface{} `json:"databaseAuthVariableOverride"`
	DatabaseURL      string                  `json:"databaseURL"`
	ProjectID        string                  `json:"projectId"`
	ServiceAccountID string                  `json:"serviceAccountId"`
	StorageBucket    string                  `json:"storageBucket"`
}

// Auth returns an instance of auth.Client.
func (a *App) Auth(ctx context.Context) (*auth.Client, error) {
	conf := &internal.AuthConfig{
		Creds:            a.creds,
		ProjectID:        a.projectID,
		Opts:             a.opts,
		ServiceAccountID: a.serviceAccountID,
		Version:          Version,
	}
	return auth.NewClient(ctx, conf)
}

// Database returns an instance of db.Client to interact with the default Firebase Database
// configured via Config.DatabaseURL.
func (a *App) Database(ctx context.Context) (*db.Client, error) {
	return a.DatabaseWithURL(ctx, a.dbURL)
}

// DatabaseWithURL returns an instance of db.Client to interact with the Firebase Database
// identified by the given URL.
func (a *App) DatabaseWithURL(ctx context.Context, url string) (*db.Client, error) {
	conf := &internal.DatabaseConfig{
		AuthOverride: a.authOverride,
		URL:          url,
		Opts:         a.opts,
		Version:      Version,
	}
	return db.NewClient(ctx, conf)
}

// Storage returns a new instance of storage.Client.
func (a *App) Storage(ctx context.Context) (*storage.Client, error) {
	conf := &internal.StorageConfig{
		Opts:   a.opts,
		Bucket: a.storageBucket,
	}
	return storage.NewClient(ctx, conf)
}

// Firestore returns a new firestore.Client instance from the https://godoc.org/cloud.google.com/go/firestore
// package.
func (a *App) Firestore(ctx context.Context) (*firestore.Client, error) {
	if a.projectID == "" {
		return nil, errors.New("project id is required to access Firestore")
	}
	return firestore.NewClient(ctx, a.projectID, a.opts...)
}

// InstanceID returns an instance of iid.Client.
func (a *App) InstanceID(ctx context.Context) (*iid.Client, error) {
	conf := &internal.InstanceIDConfig{
		ProjectID: a.projectID,
		Opts:      a.opts,
	}
	return iid.NewClient(ctx, conf)
}

// Messaging returns an instance of messaging.Client.
func (a *App) Messaging(ctx context.Context) (*messaging.Client, error) {
	conf := &internal.MessagingConfig{
		ProjectID: a.projectID,
		Opts:      a.opts,
		Version:   Version,
	}
	return messaging.NewClient(ctx, conf)
}

// NewApp creates a new App from the provided config and client options.
//
// If the client options contain a valid credential (a service account file, a refresh token
// file or an oauth2.TokenSource) the App will be authenticated using that credential. Otherwise,
// NewApp attempts to authenticate the App with Google application default credentials.
// If `config` is nil, the SDK will attempt to load the config options from the
// `FIREBASE_CONFIG` environment variable. If the value in it starts with a `{` it is parsed as a
// JSON object, otherwise it is assumed to be the name of the JSON file containing the options.
func NewApp(ctx context.Context, config *Config, opts ...option.ClientOption) (*App, error) {
	o := []option.ClientOption{option.WithScopes(internal.FirebaseScopes...)}
	o = append(o, opts...)
	creds, err := transport.Creds(ctx, o...)
	if err != nil {
		return nil, err
	}
	if config == nil {
		if config, err = getConfigDefaults(); err != nil {
			return nil, err
		}
	}

	var pid string
	if config.ProjectID != "" {
		pid = config.ProjectID
	} else if creds.ProjectID != "" {
		pid = creds.ProjectID
	} else {
		pid = os.Getenv("GOOGLE_CLOUD_PROJECT")
		if pid == "" {
			pid = os.Getenv("GCLOUD_PROJECT")
		}
	}

	ao := defaultAuthOverrides
	if config.AuthOverride != nil {
		ao = *config.AuthOverride
	}

	return &App{
		authOverride:     ao,
		creds:            creds,
		dbURL:            config.DatabaseURL,
		projectID:        pid,
		serviceAccountID: config.ServiceAccountID,
		storageBucket:    config.StorageBucket,
		opts:             o,
	}, nil
}

// getConfigDefaults reads the default config file, defined by the FIREBASE_CONFIG
// env variable, used only when options are nil.
func getConfigDefaults() (*Config, error) {
	fbc := &Config{}
	confFileName := os.Getenv(firebaseEnvName)
	if confFileName == "" {
		return fbc, nil
	}
	var dat []byte
	if confFileName[0] == byte('{') {
		dat = []byte(confFileName)
	} else {
		var err error
		if dat, err = ioutil.ReadFile(confFileName); err != nil {
			return nil, err
		}
	}
	if err := json.Unmarshal(dat, fbc); err != nil {
		return nil, err
	}

	// Some special handling necessary for db auth overrides
	var m map[string]interface{}
	if err := json.Unmarshal(dat, &m); err != nil {
		return nil, err
	}
	if ao, ok := m["databaseAuthVariableOverride"]; ok && ao == nil {
		// Auth overrides are explicitly set to null
		var nullMap map[string]interface{}
		fbc.AuthOverride = &nullMap
	}
	return fbc, nil
}
<commit_msg>Bumped version to 3.11.0 (#315)<commit_after>// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package firebase is the entry point to the Firebase Admin SDK. It provides functionality for initializing App
// instances, which serve as the central entities that provide access to various other Firebase services exposed
// from the SDK.
package firebase // import "firebase.google.com/go"

import (
	"context"
	"encoding/json"
	"errors"
	"io/ioutil"
	"os"

	"cloud.google.com/go/firestore"
	"firebase.google.com/go/auth"
	"firebase.google.com/go/db"
	"firebase.google.com/go/iid"
	"firebase.google.com/go/internal"
	"firebase.google.com/go/messaging"
	"firebase.google.com/go/storage"
	"golang.org/x/oauth2/google"
	"google.golang.org/api/option"
	"google.golang.org/api/transport"
)

var defaultAuthOverrides = make(map[string]interface{})

// Version of the Firebase Go Admin SDK.
const Version = "3.11.0"

// firebaseEnvName is the name of the environment variable with the Config.
const firebaseEnvName = "FIREBASE_CONFIG"

// An App holds configuration and state common to all Firebase services that are exposed from the SDK.
type App struct {
	authOverride     map[string]interface{}
	creds            *google.DefaultCredentials
	dbURL            string
	projectID        string
	serviceAccountID string
	storageBucket    string
	opts             []option.ClientOption
}

// Config represents the configuration used to initialize an App.
type Config struct {
	AuthOverride     *map[string]interface{} `json:"databaseAuthVariableOverride"`
	DatabaseURL      string                  `json:"databaseURL"`
	ProjectID        string                  `json:"projectId"`
	ServiceAccountID string                  `json:"serviceAccountId"`
	StorageBucket    string                  `json:"storageBucket"`
}

// Auth returns an instance of auth.Client.
func (a *App) Auth(ctx context.Context) (*auth.Client, error) {
	conf := &internal.AuthConfig{
		Creds:            a.creds,
		ProjectID:        a.projectID,
		Opts:             a.opts,
		ServiceAccountID: a.serviceAccountID,
		Version:          Version,
	}
	return auth.NewClient(ctx, conf)
}

// Database returns an instance of db.Client to interact with the default Firebase Database
// configured via Config.DatabaseURL.
func (a *App) Database(ctx context.Context) (*db.Client, error) {
	return a.DatabaseWithURL(ctx, a.dbURL)
}

// DatabaseWithURL returns an instance of db.Client to interact with the Firebase Database
// identified by the given URL.
func (a *App) DatabaseWithURL(ctx context.Context, url string) (*db.Client, error) {
	conf := &internal.DatabaseConfig{
		AuthOverride: a.authOverride,
		URL:          url,
		Opts:         a.opts,
		Version:      Version,
	}
	return db.NewClient(ctx, conf)
}

// Storage returns a new instance of storage.Client.
func (a *App) Storage(ctx context.Context) (*storage.Client, error) {
	conf := &internal.StorageConfig{
		Opts:   a.opts,
		Bucket: a.storageBucket,
	}
	return storage.NewClient(ctx, conf)
}

// Firestore returns a new firestore.Client instance from the https://godoc.org/cloud.google.com/go/firestore
// package.
func (a *App) Firestore(ctx context.Context) (*firestore.Client, error) {
	if a.projectID == "" {
		return nil, errors.New("project id is required to access Firestore")
	}
	return firestore.NewClient(ctx, a.projectID, a.opts...)
}

// InstanceID returns an instance of iid.Client.
func (a *App) InstanceID(ctx context.Context) (*iid.Client, error) {
	conf := &internal.InstanceIDConfig{
		ProjectID: a.projectID,
		Opts:      a.opts,
	}
	return iid.NewClient(ctx, conf)
}

// Messaging returns an instance of messaging.Client.
func (a *App) Messaging(ctx context.Context) (*messaging.Client, error) {
	conf := &internal.MessagingConfig{
		ProjectID: a.projectID,
		Opts:      a.opts,
		Version:   Version,
	}
	return messaging.NewClient(ctx, conf)
}

// NewApp creates a new App from the provided config and client options.
//
// If the client options contain a valid credential (a service account file, a refresh token
// file or an oauth2.TokenSource) the App will be authenticated using that credential. Otherwise,
// NewApp attempts to authenticate the App with Google application default credentials.
// If `config` is nil, the SDK will attempt to load the config options from the
// `FIREBASE_CONFIG` environment variable. If the value in it starts with a `{` it is parsed as a
// JSON object, otherwise it is assumed to be the name of the JSON file containing the options.
func NewApp(ctx context.Context, config *Config, opts ...option.ClientOption) (*App, error) {
	o := []option.ClientOption{option.WithScopes(internal.FirebaseScopes...)}
	o = append(o, opts...)
	creds, err := transport.Creds(ctx, o...)
	if err != nil {
		return nil, err
	}
	if config == nil {
		if config, err = getConfigDefaults(); err != nil {
			return nil, err
		}
	}

	var pid string
	if config.ProjectID != "" {
		pid = config.ProjectID
	} else if creds.ProjectID != "" {
		pid = creds.ProjectID
	} else {
		pid = os.Getenv("GOOGLE_CLOUD_PROJECT")
		if pid == "" {
			pid = os.Getenv("GCLOUD_PROJECT")
		}
	}

	ao := defaultAuthOverrides
	if config.AuthOverride != nil {
		ao = *config.AuthOverride
	}

	return &App{
		authOverride:     ao,
		creds:            creds,
		dbURL:            config.DatabaseURL,
		projectID:        pid,
		serviceAccountID: config.ServiceAccountID,
		storageBucket:    config.StorageBucket,
		opts:             o,
	}, nil
}

// getConfigDefaults reads the default config file, defined by the FIREBASE_CONFIG
// env variable, used only when options are nil.
func getConfigDefaults() (*Config, error) {
	fbc := &Config{}
	confFileName := os.Getenv(firebaseEnvName)
	if confFileName == "" {
		return fbc, nil
	}
	var dat []byte
	if confFileName[0] == byte('{') {
		dat = []byte(confFileName)
	} else {
		var err error
		if dat, err = ioutil.ReadFile(confFileName); err != nil {
			return nil, err
		}
	}
	if err := json.Unmarshal(dat, fbc); err != nil {
		return nil, err
	}

	// Some special handling necessary for db auth overrides
	var m map[string]interface{}
	if err := json.Unmarshal(dat, &m); err != nil {
		return nil, err
	}
	if ao, ok := m["databaseAuthVariableOverride"]; ok && ao == nil {
		// Auth overrides are explicitly set to null
		var nullMap map[string]interface{}
		fbc.AuthOverride = &nullMap
	}
	return fbc, nil
}
<|endoftext|>


<commit_before>// +build linux

package cpu

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

	"github.com/shirou/gopsutil/internal/common"
)

var cpu_tick = float64(100)

func init() {
	getconf, err := exec.LookPath("/usr/bin/getconf")
	if err != nil {
		return
	}
	out, err := invoke.Command(getconf, "CLK_TCK")
	// ignore errors
	if err == nil {
		i, err := strconv.ParseFloat(strings.TrimSpace(string(out)), 64)
		if err == nil {
			cpu_tick = float64(i)
		}
	}
}

func Times(percpu bool) ([]TimesStat, error) {
	filename := common.HostProc("stat")
	var lines = []string{}
	if percpu {
		var startIdx uint = 1
		for {
			linen, _ := common.ReadLinesOffsetN(filename, startIdx, 1)
			line := linen[0]
			if !strings.HasPrefix(line, "cpu") {
				break
			}
			lines = append(lines, line)
			startIdx++
		}
	} else {
		lines, _ = common.ReadLinesOffsetN(filename, 0, 1)
	}

	ret := make([]TimesStat, 0, len(lines))

	for _, line := range lines {
		ct, err := parseStatLine(line)
		if err != nil {
			continue
		}
		ret = append(ret, *ct)

	}
	return ret, nil
}

func sysCPUPath(cpu int32, relPath string) string {
	return common.HostSys(fmt.Sprintf("devices/system/cpu/cpu%d", cpu), relPath)
}

func finishCPUInfo(c *InfoStat) error {
	var lines []string
	var err error
	var value float64

	if len(c.CoreID) == 0 {
		lines, err = common.ReadLines(sysCPUPath(c.CPU, "topology/core_id"))
		if err == nil {
			c.CoreID = lines[0]
		}
	}

	// override the value of c.Mhz with cpufreq/cpuinfo_max_freq regardless
	// of the value from /proc/cpuinfo because we want to report the maximum
	// clock-speed of the CPU for c.Mhz, matching the behaviour of Windows
	lines, err = common.ReadLines(sysCPUPath(c.CPU, "cpufreq/cpuinfo_max_freq"))
	if err != nil {
		return err
	}
	value, err = strconv.ParseFloat(lines[0], 64)
	if err != nil {
		return err
	}
	c.Mhz = value/1000.0  // value is in kHz
	return nil
}

// CPUInfo on linux will return 1 item per physical thread.
//
// CPUs have three levels of counting: sockets, cores, threads.
// Cores with HyperThreading count as having 2 threads per core.
// Sockets often come with many physical CPU cores.
// For example a single socket board with two cores each with HT will
// return 4 CPUInfoStat structs on Linux and the "Cores" field set to 1.
func Info() ([]InfoStat, error) {
	filename := common.HostProc("cpuinfo")
	lines, _ := common.ReadLines(filename)

	var ret []InfoStat

	c := InfoStat{CPU: -1, Cores: 1}
	for _, line := range lines {
		fields := strings.Split(line, ":")
		if len(fields) < 2 {
			continue
		}
		key := strings.TrimSpace(fields[0])
		value := strings.TrimSpace(fields[1])

		switch key {
		case "processor":
			if c.CPU >= 0 {
				err := finishCPUInfo(&c)
				if err != nil {
					return ret, err
				}
				ret = append(ret, c)
			}
			c = InfoStat{Cores: 1}
			t, err := strconv.ParseInt(value, 10, 64)
			if err != nil {
				return ret, err
			}
			c.CPU = int32(t)
		case "vendorId", "vendor_id":
			c.VendorID = value
		case "cpu family":
			c.Family = value
		case "model":
			c.Model = value
		case "model name":
			c.ModelName = value
		case "stepping":
			t, err := strconv.ParseInt(value, 10, 64)
			if err != nil {
				return ret, err
			}
			c.Stepping = int32(t)
		case "cpu MHz":
			// treat this as the fallback value, thus we ignore error
			if t, err := strconv.ParseFloat(value, 64); err == nil {
				c.Mhz = t
			}
		case "cache size":
			t, err := strconv.ParseInt(strings.Replace(value, " KB", "", 1), 10, 64)
			if err != nil {
				return ret, err
			}
			c.CacheSize = int32(t)
		case "physical id":
			c.PhysicalID = value
		case "core id":
			c.CoreID = value
		case "flags", "Features":
			c.Flags = strings.FieldsFunc(value, func(r rune) bool {
				return r == ',' || r == ' '
			})
		}
	}
	if c.CPU >= 0 {
		err := finishCPUInfo(&c)
		if err != nil {
			return ret, err
		}
		ret = append(ret, c)
	}
	return ret, nil
}

func parseStatLine(line string) (*TimesStat, error) {
	fields := strings.Fields(line)

	if strings.HasPrefix(fields[0], "cpu") == false {
		//		return CPUTimesStat{}, e
		return nil, errors.New("not contain cpu")
	}

	cpu := fields[0]
	if cpu == "cpu" {
		cpu = "cpu-total"
	}
	user, err := strconv.ParseFloat(fields[1], 64)
	if err != nil {
		return nil, err
	}
	nice, err := strconv.ParseFloat(fields[2], 64)
	if err != nil {
		return nil, err
	}
	system, err := strconv.ParseFloat(fields[3], 64)
	if err != nil {
		return nil, err
	}
	idle, err := strconv.ParseFloat(fields[4], 64)
	if err != nil {
		return nil, err
	}
	iowait, err := strconv.ParseFloat(fields[5], 64)
	if err != nil {
		return nil, err
	}
	irq, err := strconv.ParseFloat(fields[6], 64)
	if err != nil {
		return nil, err
	}
	softirq, err := strconv.ParseFloat(fields[7], 64)
	if err != nil {
		return nil, err
	}

	ct := &TimesStat{
		CPU:     cpu,
		User:    float64(user) / cpu_tick,
		Nice:    float64(nice) / cpu_tick,
		System:  float64(system) / cpu_tick,
		Idle:    float64(idle) / cpu_tick,
		Iowait:  float64(iowait) / cpu_tick,
		Irq:     float64(irq) / cpu_tick,
		Softirq: float64(softirq) / cpu_tick,
	}
	if len(fields) > 8 { // Linux >= 2.6.11
		steal, err := strconv.ParseFloat(fields[8], 64)
		if err != nil {
			return nil, err
		}
		ct.Steal = float64(steal) / cpu_tick
	}
	if len(fields) > 9 { // Linux >= 2.6.24
		guest, err := strconv.ParseFloat(fields[9], 64)
		if err != nil {
			return nil, err
		}
		ct.Guest = float64(guest) / cpu_tick
	}
	if len(fields) > 10 { // Linux >= 3.2.0
		guestNice, err := strconv.ParseFloat(fields[10], 64)
		if err != nil {
			return nil, err
		}
		ct.GuestNice = float64(guestNice) / cpu_tick
	}

	return ct, nil
}
<commit_msg>Handle the case when the `cpufreq` sysfs does not exist<commit_after>// +build linux

package cpu

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

	"github.com/shirou/gopsutil/internal/common"
)

var cpu_tick = float64(100)

func init() {
	getconf, err := exec.LookPath("/usr/bin/getconf")
	if err != nil {
		return
	}
	out, err := invoke.Command(getconf, "CLK_TCK")
	// ignore errors
	if err == nil {
		i, err := strconv.ParseFloat(strings.TrimSpace(string(out)), 64)
		if err == nil {
			cpu_tick = float64(i)
		}
	}
}

func Times(percpu bool) ([]TimesStat, error) {
	filename := common.HostProc("stat")
	var lines = []string{}
	if percpu {
		var startIdx uint = 1
		for {
			linen, _ := common.ReadLinesOffsetN(filename, startIdx, 1)
			line := linen[0]
			if !strings.HasPrefix(line, "cpu") {
				break
			}
			lines = append(lines, line)
			startIdx++
		}
	} else {
		lines, _ = common.ReadLinesOffsetN(filename, 0, 1)
	}

	ret := make([]TimesStat, 0, len(lines))

	for _, line := range lines {
		ct, err := parseStatLine(line)
		if err != nil {
			continue
		}
		ret = append(ret, *ct)

	}
	return ret, nil
}

func sysCPUPath(cpu int32, relPath string) string {
	return common.HostSys(fmt.Sprintf("devices/system/cpu/cpu%d", cpu), relPath)
}

func finishCPUInfo(c *InfoStat) error {
	var lines []string
	var err error
	var value float64

	if len(c.CoreID) == 0 {
		lines, err = common.ReadLines(sysCPUPath(c.CPU, "topology/core_id"))
		if err == nil {
			c.CoreID = lines[0]
		}
	}

	// override the value of c.Mhz with cpufreq/cpuinfo_max_freq regardless
	// of the value from /proc/cpuinfo because we want to report the maximum
	// clock-speed of the CPU for c.Mhz, matching the behaviour of Windows
	lines, err = common.ReadLines(sysCPUPath(c.CPU, "cpufreq/cpuinfo_max_freq"))
	// if we encounter errors below but has a value from parsing /proc/cpuinfo
	// then we ignore the error
	if err != nil {
		if c.Mhz == 0 {
			return err
		} else {
			return nil
		}
	}
	value, err = strconv.ParseFloat(lines[0], 64)
	if err != nil {
		if c.Mhz == 0 {
			return err
		} else {
			return nil
		}
	}
	c.Mhz = value/1000.0  // value is in kHz
	return nil
}

// CPUInfo on linux will return 1 item per physical thread.
//
// CPUs have three levels of counting: sockets, cores, threads.
// Cores with HyperThreading count as having 2 threads per core.
// Sockets often come with many physical CPU cores.
// For example a single socket board with two cores each with HT will
// return 4 CPUInfoStat structs on Linux and the "Cores" field set to 1.
func Info() ([]InfoStat, error) {
	filename := common.HostProc("cpuinfo")
	lines, _ := common.ReadLines(filename)

	var ret []InfoStat

	c := InfoStat{CPU: -1, Cores: 1}
	for _, line := range lines {
		fields := strings.Split(line, ":")
		if len(fields) < 2 {
			continue
		}
		key := strings.TrimSpace(fields[0])
		value := strings.TrimSpace(fields[1])

		switch key {
		case "processor":
			if c.CPU >= 0 {
				err := finishCPUInfo(&c)
				if err != nil {
					return ret, err
				}
				ret = append(ret, c)
			}
			c = InfoStat{Cores: 1}
			t, err := strconv.ParseInt(value, 10, 64)
			if err != nil {
				return ret, err
			}
			c.CPU = int32(t)
		case "vendorId", "vendor_id":
			c.VendorID = value
		case "cpu family":
			c.Family = value
		case "model":
			c.Model = value
		case "model name":
			c.ModelName = value
		case "stepping":
			t, err := strconv.ParseInt(value, 10, 64)
			if err != nil {
				return ret, err
			}
			c.Stepping = int32(t)
		case "cpu MHz":
			// treat this as the fallback value, thus we ignore error
			if t, err := strconv.ParseFloat(value, 64); err == nil {
				c.Mhz = t
			}
		case "cache size":
			t, err := strconv.ParseInt(strings.Replace(value, " KB", "", 1), 10, 64)
			if err != nil {
				return ret, err
			}
			c.CacheSize = int32(t)
		case "physical id":
			c.PhysicalID = value
		case "core id":
			c.CoreID = value
		case "flags", "Features":
			c.Flags = strings.FieldsFunc(value, func(r rune) bool {
				return r == ',' || r == ' '
			})
		}
	}
	if c.CPU >= 0 {
		err := finishCPUInfo(&c)
		if err != nil {
			return ret, err
		}
		ret = append(ret, c)
	}
	return ret, nil
}

func parseStatLine(line string) (*TimesStat, error) {
	fields := strings.Fields(line)

	if strings.HasPrefix(fields[0], "cpu") == false {
		//		return CPUTimesStat{}, e
		return nil, errors.New("not contain cpu")
	}

	cpu := fields[0]
	if cpu == "cpu" {
		cpu = "cpu-total"
	}
	user, err := strconv.ParseFloat(fields[1], 64)
	if err != nil {
		return nil, err
	}
	nice, err := strconv.ParseFloat(fields[2], 64)
	if err != nil {
		return nil, err
	}
	system, err := strconv.ParseFloat(fields[3], 64)
	if err != nil {
		return nil, err
	}
	idle, err := strconv.ParseFloat(fields[4], 64)
	if err != nil {
		return nil, err
	}
	iowait, err := strconv.ParseFloat(fields[5], 64)
	if err != nil {
		return nil, err
	}
	irq, err := strconv.ParseFloat(fields[6], 64)
	if err != nil {
		return nil, err
	}
	softirq, err := strconv.ParseFloat(fields[7], 64)
	if err != nil {
		return nil, err
	}

	ct := &TimesStat{
		CPU:     cpu,
		User:    float64(user) / cpu_tick,
		Nice:    float64(nice) / cpu_tick,
		System:  float64(system) / cpu_tick,
		Idle:    float64(idle) / cpu_tick,
		Iowait:  float64(iowait) / cpu_tick,
		Irq:     float64(irq) / cpu_tick,
		Softirq: float64(softirq) / cpu_tick,
	}
	if len(fields) > 8 { // Linux >= 2.6.11
		steal, err := strconv.ParseFloat(fields[8], 64)
		if err != nil {
			return nil, err
		}
		ct.Steal = float64(steal) / cpu_tick
	}
	if len(fields) > 9 { // Linux >= 2.6.24
		guest, err := strconv.ParseFloat(fields[9], 64)
		if err != nil {
			return nil, err
		}
		ct.Guest = float64(guest) / cpu_tick
	}
	if len(fields) > 10 { // Linux >= 3.2.0
		guestNice, err := strconv.ParseFloat(fields[10], 64)
		if err != nil {
			return nil, err
		}
		ct.GuestNice = float64(guestNice) / cpu_tick
	}

	return ct, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	t "github.com/bytbox/termbox-go"
	"log"
)

var (
	width  int
	height int

	messageList []Message
)

var chActions = map[rune]func(){
	'u': updateMessages,
}

var keyActions = map[uint16]func(){}

func unknownAction() {
	panic("unrecognized keystroke")
}

func act(a func()) {
	defer func() {
		if er := recover(); er != nil {
			e, ok := er.(string)
			if ok {
				message <- e
			} else {
				message <- "unknown error"
			}
		}
	}()
	a()
}

func updateSize() {
	width = t.Width()
	height = t.Height()
}

// Channels for signaling the main routine
var (
	updates = make(chan interface{}) // updates the screen
	message = make(chan string) // updates the message displayed
)

type Display struct {
	message string
}

func updateMessages() {
	messageList = UpdateAllList()
}

func display(d Display) {
	t.Clear()

	// List all messages
	for i, m := range messageList {
		w := t.Writer(2, i, t.WHITE, t.BLACK)
		fmt.Fprintf(w, "%s", m.Title)
	}

	// Write the error message or otherwise
	messageWriter := t.Writer(0, height-1, t.WHITE, t.BLACK)
	fmt.Fprint(messageWriter, d.message)

	t.Present()
}

func UIMain() {
	t.Init()
	defer func() {
		t.Shutdown()
	}()
	updateSize()

	events := make(chan t.Event)

	go func() {
		for {
			e := t.Event{}
			e.Poll()
			events <- e
		}
	}()

	d := Display{}

	for {
		display(d)
		select {
		case e := <-events:
		switch e.Type {
			case t.EVENT_KEY:
				if e.Ch == 'q' {
					goto Exit
				}
				a, ok := chActions[e.Ch]
				if !ok {
					a, ok = keyActions[e.Key]
				}
				if ok {
					go act(a)
				} else {
					go act(unknownAction)
				}
			case t.EVENT_RESIZE:
				updateSize()
			default:
				log.Print("warning: unknown event type")
			}
		case <-updates:
		case m := <-message:
			d.message = m
		}
	}

Exit:
}
<commit_msg>Messages<commit_after>package main

import (
	"fmt"
	t "github.com/bytbox/termbox-go"
	"log"
)

var (
	width  int
	height int

	messageList []Message
)

var chActions = map[rune]func(){
	'u': updateMessages,
}

var keyActions = map[uint16]func(){}

func unknownAction() {
	panic("unrecognized keystroke")
}

func act(a func()) {
	defer func() {
		if er := recover(); er != nil {
			e, ok := er.(string)
			if ok {
				message <- e
			} else {
				message <- "unknown error"
			}
		}
	}()
	a()
}

func updateSize() {
	width = t.Width()
	height = t.Height()
}

// Channels for signaling the main routine
var (
	updates = make(chan interface{}) // updates the screen
	message = make(chan string) // updates the message displayed
)

type Display struct {
	message string
}

func updateMessages() {
	message <- "updating..."
	messageList = UpdateAllList()
	message <- ""
}

func display(d Display) {
	t.Clear()

	// List all messages
	for i, m := range messageList {
		w := t.Writer(2, i, t.WHITE, t.BLACK)
		fmt.Fprintf(w, "%s", m.Title)
	}

	// Write the error message or otherwise
	messageWriter := t.Writer(0, height-1, t.WHITE, t.BLACK)
	fmt.Fprint(messageWriter, d.message)

	t.Present()
}

func UIMain() {
	t.Init()
	defer func() {
		t.Shutdown()
	}()
	updateSize()

	events := make(chan t.Event)

	go func() {
		for {
			e := t.Event{}
			e.Poll()
			events <- e
		}
	}()

	d := Display{}

	for {
		display(d)
		select {
		case e := <-events:
		switch e.Type {
			case t.EVENT_KEY:
				if e.Ch == 'q' {
					goto Exit
				}
				a, ok := chActions[e.Ch]
				if !ok {
					a, ok = keyActions[e.Key]
				}
				if ok {
					go act(a)
				} else {
					go act(unknownAction)
				}
			case t.EVENT_RESIZE:
				updateSize()
			default:
				log.Print("warning: unknown event type")
			}
		case <-updates:
		case m := <-message:
			d.message = m
		}
	}

Exit:
}
<|endoftext|>


<commit_before>package cqrs

import (
	"errors"
	"fmt"

	"github.com/danielkrainas/tinkersnest/context"
)

var ErrNoHandler = errors.New("no command handler")
var ErrInvalidCommand = errors.New("invalid command for this handler")

type Command interface{}

type CommandHandler interface {
	Handle(ctx context.Context, cmd Command) error
}

type CommandDispatcher struct {
	Handlers []CommandHandler
}

func (d *CommandDispatcher) Dispatch(ctx context.Context, cmd Command) error {
	for _, h := range d.Handlers {
		if err := h.Handle(ctx, cmd); err != nil && err != ErrNoHandler {
			return err
		} else if err == nil {
			return nil
		}
	}

	return ErrNoHandler
}

type CommandRouter map[string]CommandHandler

func getCommandKey(c Command) string {
	return fmt.Sprintf("%T", c)
}

func (r CommandRouter) Register(c Command, handler CommandHandler) {
	r[getCommandKey(c)] = handler
}

func (r CommandRouter) Handle(ctx context.Context, c Command) error {
	h, ok := r[getCommandKey(c)]
	if !ok {
		return ErrNoHandler
	}

	return h.Handle(ctx, c)
}

func WithCommandDispatch(ctx context.Context, d *CommandDispatcher) context.Context {
	return context.WithValue(ctx, "cmd.dispatcher", d)
}

func DispatchCommand(ctx context.Context, c Command) error {
	d, ok := ctx.Value("cmd.dispatcher").(*CommandDispatcher)
	if !ok || d == nil {
		return fmt.Errorf("no valid command dispatchers found in context")
	}

	return d.Dispatch(ctx, c)
}

type RetryHandler struct {
	Retries int
	Inner   CommandHandler
}

func (h *RetryHandler) Handle(ctx context.Context, cmd Command) error {
	var err error
	for i := 0; i < h.Retries; i++ {
		if err = h.Inner.Handle(ctx, cmd); err == nil {
			break
		}
	}

	return err
}
<commit_msg>add delay to retry command handler<commit_after>package cqrs

import (
	"errors"
	"fmt"
	"time"

	"github.com/danielkrainas/tinkersnest/context"
)

var ErrNoHandler = errors.New("no command handler")
var ErrInvalidCommand = errors.New("invalid command for this handler")

type Command interface{}

type CommandHandler interface {
	Handle(ctx context.Context, cmd Command) error
}

type CommandDispatcher struct {
	Handlers []CommandHandler
}

func (d *CommandDispatcher) Dispatch(ctx context.Context, cmd Command) error {
	for _, h := range d.Handlers {
		if err := h.Handle(ctx, cmd); err != nil && err != ErrNoHandler {
			return err
		} else if err == nil {
			return nil
		}
	}

	return ErrNoHandler
}

type CommandRouter map[string]CommandHandler

func getCommandKey(c Command) string {
	return fmt.Sprintf("%T", c)
}

func (r CommandRouter) Register(c Command, handler CommandHandler) {
	r[getCommandKey(c)] = handler
}

func (r CommandRouter) Handle(ctx context.Context, c Command) error {
	h, ok := r[getCommandKey(c)]
	if !ok {
		return ErrNoHandler
	}

	return h.Handle(ctx, c)
}

func WithCommandDispatch(ctx context.Context, d *CommandDispatcher) context.Context {
	return context.WithValue(ctx, "cmd.dispatcher", d)
}

func DispatchCommand(ctx context.Context, c Command) error {
	d, ok := ctx.Value("cmd.dispatcher").(*CommandDispatcher)
	if !ok || d == nil {
		return fmt.Errorf("no valid command dispatchers found in context")
	}

	return d.Dispatch(ctx, c)
}

type RetryHandler struct {
	Retries int
	Delay   time.Duration
	Inner   CommandHandler
}

func (h *RetryHandler) Handle(ctx context.Context, cmd Command) error {
	var err error
	for i := 0; i < h.Retries; i++ {
		if err = h.Inner.Handle(ctx, cmd); err == nil {
			break
		}

		time.Sleep(h.Delay)
	}

	return err
}
<|endoftext|>


<commit_before>package blueprints

import (
	"database/sql"
	"io"

	"github.com/lflux/eve-sdeloader/utils"
)

type ActivityID int

const (
	ManufacturingID    ActivityID = 1
	ResearchTimeID     ActivityID = 3
	ResearchMaterialID ActivityID = 4
	CopyingID          ActivityID = 5
	InventionID        ActivityID = 8
	ReactionID         ActivityID = 11
)

type Activity interface {
	GetTime() int64
	ActivityID() ActivityID
}

type ProductionActivity interface {
	Activity
	GetMaterials() []Material
	GetProducts() []Material
	GetSkills() []Skill
}

type Skill struct {
	Level  int64
	TypeID int64 `yaml:"typeID"`
}

type Material struct {
	Probability *float64
	Quantity    int64
	TypeID      int64 `yaml:"typeID"`
}

type Activities struct {
	Copying          *Copying
	Invention        *Invention
	Manufacturing    *Manufacturing
	ResearchMaterial *ResearchMaterial `yaml:"research_material"`
	ResearchTime     *ResearchTime     `yaml:"research_time"`
}

type Blueprint struct {
	Activities         Activities
	TypeID             int64 `yaml:"blueprintTypeID"`
	MaxProductionLimit int64 `yaml:"maxProductionLimit"`
}

func InsertIndustryBlueprintsStmt(tx *sql.Tx) (*sql.Stmt, error) {
	return tx.Prepare(`INSERT INTO industryblueprints VALUES ($1, $2)`)
}

func InsertIndustryActivitiesStmt(tx *sql.Tx) (*sql.Stmt, error) {
	return tx.Prepare(`INSERT INTO industryactivity VALUES ($1, $2, $3)`)
}

func InsertActivityMaterialsStmt(tx *sql.Tx) (*sql.Stmt, error) {
	return tx.Prepare(`INSERT INTO industryactivityskills VALUES ($1, $2, $3, $4)`)
}

func InsertActivityProbabilitiesStmt(tx *sql.Tx) (*sql.Stmt, error) {
	return tx.Prepare(`INSERT INTO industryactivityprobabilities VALUES ($1, $2, $3, $4)`)
}

func InsertActivityProductsStmt(tx *sql.Tx) (*sql.Stmt, error) {
	return tx.Prepare(`INSERT INTO industryactivityproducts VALUES ($1, $2, $3, $4)`)
}

func InsertActivitySkillsStmt(tx *sql.Tx) (*sql.Stmt, error) {
	return tx.Prepare(`INSERT INTO industryactivityskills VALUES ($1, $2, $3, $4)`)
}

func insertIndustryActivity(entryID string, a Activity) error {
	_, err := insertIndustryActivities.Exec(entryID, a.ActivityID(), a.GetTime())
	return err
}

func insertProductionActivity(entryID string, a ProductionActivity) error {
	var err error
	for _, material := range a.GetMaterials() {
		_, err = insertActivityMaterials.Exec(entryID, a.ActivityID(), material.TypeID, material.Quantity)
		if err != nil {
			return err
		}
	}

	for _, product := range a.GetProducts() {
		_, err = insertActivityProducts.Exec(entryID, a.ActivityID(), product.TypeID, product.Quantity)
		if err != nil {
			return err
		}
		if product.Probability != nil {
			_, err = insertActivityProbabilities.Exec(entryID, a.ActivityID(), product.TypeID, *product.Probability)
		}
	}

	for _, skill := range a.GetSkills() {
		_, err = insertActivitySkills.Exec(entryID, a.ActivityID(), skill.TypeID, skill.Level)
		if err != nil {
			return err
		}
	}

	return nil
}

var (
	insertActivityProducts      *sql.Stmt
	insertIndustryActivities    *sql.Stmt
	insertActivityMaterials     *sql.Stmt
	insertActivityProbabilities *sql.Stmt
	insertActivitySkills        *sql.Stmt
	insertBlueprints            *sql.Stmt
)

func prepareStatements(tx *sql.Tx) error {
	var err error
	insertBlueprints, err = InsertIndustryBlueprintsStmt(tx)
	if err != nil {
		return err
	}

	insertIndustryActivities, err = InsertIndustryActivitiesStmt(tx)
	if err != nil {
		return err
	}

	insertActivityMaterials, err = InsertActivityMaterialsStmt(tx)
	if err != nil {
		return err
	}

	insertActivityProbabilities, err = InsertActivityProbabilitiesStmt(tx)
	if err != nil {
		return err
	}

	insertActivityProducts, err = InsertActivityProductsStmt(tx)
	if err != nil {
		return err
	}

	insertActivitySkills, err = InsertActivitySkillsStmt(tx)

	return err
}

func Import(db *sql.DB, r io.Reader) error {
	entries := make(map[string]*Blueprint)

	err := utils.LoadFromReader(r, entries)
	if err != nil {
		return err
	}

	tx, err := db.Begin()
	if err != nil {
		return err
	}

	err = prepareStatements(tx)
	if err != nil {
		return err
	}

	for entryID, entry := range entries {
		_, err = insertBlueprints.Exec(entryID, entry.MaxProductionLimit)
		if err != nil {
			return err
		}

		a := entry.Activities
		if a.Copying != nil {
			err = insertIndustryActivity(entryID, a.Copying)
			if err != nil {
				return err
			}
		}

		if a.ResearchMaterial != nil {
			err = insertIndustryActivity(entryID, a.ResearchMaterial)
			if err != nil {
				return err
			}
		}

		if a.ResearchTime != nil {
			err = insertIndustryActivity(entryID, a.ResearchTime)
			if err != nil {
				return err
			}
		}

		if a.Invention != nil {
			err = insertIndustryActivity(entryID, a.Invention)
			if err != nil {
				return err
			}

			err = insertProductionActivity(entryID, a.Invention)
			if err != nil {
				return err
			}
		}

		if a.Manufacturing != nil {
			err = insertIndustryActivity(entryID, a.Manufacturing)
			if err != nil {
				return err
			}

			err = insertProductionActivity(entryID, a.Manufacturing)
			if err != nil {
				return err
			}
		}
	}

	return tx.Commit()
}
<commit_msg>Import reactions<commit_after>package blueprints

import (
	"database/sql"
	"io"

	"github.com/lflux/eve-sdeloader/utils"
)

type ActivityID int

const (
	ManufacturingID    ActivityID = 1
	ResearchTimeID     ActivityID = 3
	ResearchMaterialID ActivityID = 4
	CopyingID          ActivityID = 5
	InventionID        ActivityID = 8
	ReactionID         ActivityID = 11
)

type Activity interface {
	GetTime() int64
	ActivityID() ActivityID
}

type ProductionActivity interface {
	Activity
	GetMaterials() []Material
	GetProducts() []Material
	GetSkills() []Skill
}

type Skill struct {
	Level  int64
	TypeID int64 `yaml:"typeID"`
}

type Material struct {
	Probability *float64
	Quantity    int64
	TypeID      int64 `yaml:"typeID"`
}

type Activities struct {
	Copying          *Copying
	Invention        *Invention
	Manufacturing    *Manufacturing
	Reaction         *Reaction
	ResearchMaterial *ResearchMaterial `yaml:"research_material"`
	ResearchTime     *ResearchTime     `yaml:"research_time"`
}

type Blueprint struct {
	Activities         Activities
	TypeID             int64 `yaml:"blueprintTypeID"`
	MaxProductionLimit int64 `yaml:"maxProductionLimit"`
}

func InsertIndustryBlueprintsStmt(tx *sql.Tx) (*sql.Stmt, error) {
	return tx.Prepare(`INSERT INTO industryblueprints VALUES ($1, $2)`)
}

func InsertIndustryActivitiesStmt(tx *sql.Tx) (*sql.Stmt, error) {
	return tx.Prepare(`INSERT INTO industryactivity VALUES ($1, $2, $3)`)
}

func InsertActivityMaterialsStmt(tx *sql.Tx) (*sql.Stmt, error) {
	return tx.Prepare(`INSERT INTO industryactivityskills VALUES ($1, $2, $3, $4)`)
}

func InsertActivityProbabilitiesStmt(tx *sql.Tx) (*sql.Stmt, error) {
	return tx.Prepare(`INSERT INTO industryactivityprobabilities VALUES ($1, $2, $3, $4)`)
}

func InsertActivityProductsStmt(tx *sql.Tx) (*sql.Stmt, error) {
	return tx.Prepare(`INSERT INTO industryactivityproducts VALUES ($1, $2, $3, $4)`)
}

func InsertActivitySkillsStmt(tx *sql.Tx) (*sql.Stmt, error) {
	return tx.Prepare(`INSERT INTO industryactivityskills VALUES ($1, $2, $3, $4)`)
}

func insertIndustryActivity(entryID string, a Activity) error {
	_, err := insertIndustryActivities.Exec(entryID, a.ActivityID(), a.GetTime())
	return err
}

func insertProductionActivity(entryID string, a ProductionActivity) error {
	var err error
	for _, material := range a.GetMaterials() {
		_, err = insertActivityMaterials.Exec(entryID, a.ActivityID(), material.TypeID, material.Quantity)
		if err != nil {
			return err
		}
	}

	for _, product := range a.GetProducts() {
		_, err = insertActivityProducts.Exec(entryID, a.ActivityID(), product.TypeID, product.Quantity)
		if err != nil {
			return err
		}
		if product.Probability != nil {
			_, err = insertActivityProbabilities.Exec(entryID, a.ActivityID(), product.TypeID, *product.Probability)
		}
	}

	for _, skill := range a.GetSkills() {
		_, err = insertActivitySkills.Exec(entryID, a.ActivityID(), skill.TypeID, skill.Level)
		if err != nil {
			return err
		}
	}

	return nil
}

var (
	insertActivityProducts      *sql.Stmt
	insertIndustryActivities    *sql.Stmt
	insertActivityMaterials     *sql.Stmt
	insertActivityProbabilities *sql.Stmt
	insertActivitySkills        *sql.Stmt
	insertBlueprints            *sql.Stmt
)

func prepareStatements(tx *sql.Tx) error {
	var err error
	insertBlueprints, err = InsertIndustryBlueprintsStmt(tx)
	if err != nil {
		return err
	}

	insertIndustryActivities, err = InsertIndustryActivitiesStmt(tx)
	if err != nil {
		return err
	}

	insertActivityMaterials, err = InsertActivityMaterialsStmt(tx)
	if err != nil {
		return err
	}

	insertActivityProbabilities, err = InsertActivityProbabilitiesStmt(tx)
	if err != nil {
		return err
	}

	insertActivityProducts, err = InsertActivityProductsStmt(tx)
	if err != nil {
		return err
	}

	insertActivitySkills, err = InsertActivitySkillsStmt(tx)

	return err
}

func Import(db *sql.DB, r io.Reader) error {
	entries := make(map[string]*Blueprint)

	err := utils.LoadFromReader(r, entries)
	if err != nil {
		return err
	}

	tx, err := db.Begin()
	if err != nil {
		return err
	}

	err = prepareStatements(tx)
	if err != nil {
		return err
	}

	for entryID, entry := range entries {
		_, err = insertBlueprints.Exec(entryID, entry.MaxProductionLimit)
		if err != nil {
			return err
		}

		a := entry.Activities
		if a.Copying != nil {
			err = insertIndustryActivity(entryID, a.Copying)
			if err != nil {
				return err
			}
		}

		if a.ResearchMaterial != nil {
			err = insertIndustryActivity(entryID, a.ResearchMaterial)
			if err != nil {
				return err
			}
		}

		if a.ResearchTime != nil {
			err = insertIndustryActivity(entryID, a.ResearchTime)
			if err != nil {
				return err
			}
		}

		if a.Invention != nil {
			err = insertIndustryActivity(entryID, a.Invention)
			if err != nil {
				return err
			}

			err = insertProductionActivity(entryID, a.Invention)
			if err != nil {
				return err
			}
		}

		if a.Manufacturing != nil {
			err = insertIndustryActivity(entryID, a.Manufacturing)
			if err != nil {
				return err
			}

			err = insertProductionActivity(entryID, a.Manufacturing)
			if err != nil {
				return err
			}
		}

		if a.Reaction != nil {
			err = insertIndustryActivity(entryID, a.Reaction)
			if err != nil {
				return err
			}

			err = insertProductionActivity(entryID, a.Reaction)
			if err != nil {
				return err
			}
		}

	}

	return tx.Commit()
}
<|endoftext|>