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

package gps

import (
	"fmt"
	"sort"

	"github.com/Masterminds/semver"
)

var (
	none = noneConstraint{}
	any  = anyConstraint{}
)

// A Constraint provides structured limitations on the versions that are
// admissible for a given project.
//
// As with Version, it has a private method because the gps's internal
// implementation of the problem is complete, and the system relies on type
// magic to operate.
type Constraint interface {
	fmt.Stringer

	// ImpliedCaretString converts the Constraint to a string in the same manner
	// as String(), but treats the empty operator as equivalent to ^, rather
	// than =.
	//
	// In the same way that String() is the inverse of NewConstraint(), this
	// method is the inverse of to NewSemverConstraintIC().
	ImpliedCaretString() string

	// Matches indicates if the provided Version is allowed by the Constraint.
	Matches(Version) bool

	// MatchesAny indicates if the intersection of the Constraint with the
	// provided Constraint would yield a Constraint that could allow *any*
	// Version.
	MatchesAny(Constraint) bool

	// Intersect computes the intersection of the Constraint with the provided
	// Constraint.
	Intersect(Constraint) Constraint

	// typedString emits the normal stringified representation of the provided
	// constraint, prefixed with a string that uniquely identifies the type of
	// the constraint.
	//
	// It also forces Constraint to be a private/sealed interface, which is a
	// design goal of the system.
	typedString() string
}

// NewSemverConstraint attempts to construct a semver Constraint object from the
// input string.
//
// If the input string cannot be made into a valid semver Constraint, an error
// is returned.
func NewSemverConstraint(body string) (Constraint, error) {
	c, err := semver.NewConstraint(body)
	if err != nil {
		return nil, err
	}
	// If we got a simple semver.Version, simplify by returning our
	// corresponding type
	if sv, ok := c.(semver.Version); ok {
		return semVersion{sv: sv}, nil
	}
	return semverConstraint{c: c}, nil
}

// NewSemverConstraintIC attempts to construct a semver Constraint object from the
// input string, defaulting to a caret, ^, when no constraint is specified.
//
// If the input string cannot be made into a valid semver Constraint, an error
// is returned.
func NewSemverConstraintIC(body string) (Constraint, error) {
	c, err := semver.NewConstraintIC(body)
	if err != nil {
		return nil, err
	}
	// If we got a simple semver.Version, simplify by returning our
	// corresponding type
	if sv, ok := c.(semver.Version); ok {
		return semVersion{sv: sv}, nil
	}
	return semverConstraint{c: c}, nil
}

type semverConstraint struct {
	c semver.Constraint
}

func (c semverConstraint) String() string {
	return c.c.String()
}

// ImpliedCaretString converts the Constraint to a string in the same manner
// as String(), but treats the empty operator as equivalent to ^, rather
// than =.
//
// In the same way that String() is the inverse of NewConstraint(), this
// method is the inverse of to NewSemverConstraintIC().
func (c semverConstraint) ImpliedCaretString() string {
	return c.c.ImpliedCaretString()
}

func (c semverConstraint) typedString() string {
	return fmt.Sprintf("svc-%s", c.c.String())
}

func (c semverConstraint) Matches(v Version) bool {
	switch tv := v.(type) {
	case versionTypeUnion:
		for _, elem := range tv {
			if c.Matches(elem) {
				return true
			}
		}
	case semVersion:
		return c.c.Matches(tv.sv) == nil
	case versionPair:
		if tv2, ok := tv.v.(semVersion); ok {
			return c.c.Matches(tv2.sv) == nil
		}
	}

	return false
}

func (c semverConstraint) MatchesAny(c2 Constraint) bool {
	return c.Intersect(c2) != none
}

func (c semverConstraint) Intersect(c2 Constraint) Constraint {
	switch tc := c2.(type) {
	case anyConstraint:
		return c
	case versionTypeUnion:
		for _, elem := range tc {
			if rc := c.Intersect(elem); rc != none {
				return rc
			}
		}
	case semverConstraint:
		rc := c.c.Intersect(tc.c)
		if !semver.IsNone(rc) {
			return semverConstraint{c: rc}
		}
	case semVersion:
		rc := c.c.Intersect(tc.sv)
		if !semver.IsNone(rc) {
			// If single version intersected with constraint, we know the result
			// must be the single version, so just return it back out
			return c2
		}
	case versionPair:
		if tc2, ok := tc.v.(semVersion); ok {
			rc := c.c.Intersect(tc2.sv)
			if !semver.IsNone(rc) {
				// same reasoning as previous case
				return c2
			}
		}
	}

	return none
}

// IsAny indicates if the provided constraint is the wildcard "Any" constraint.
func IsAny(c Constraint) bool {
	_, ok := c.(anyConstraint)
	return ok
}

// Any returns a constraint that will match anything.
func Any() Constraint {
	return anyConstraint{}
}

// anyConstraint is an unbounded constraint - it matches all other types of
// constraints. It mirrors the behavior of the semver package's any type.
type anyConstraint struct{}

func (anyConstraint) String() string {
	return "*"
}

func (anyConstraint) ImpliedCaretString() string {
	return "*"
}

func (anyConstraint) typedString() string {
	return "any-*"
}

func (anyConstraint) Matches(Version) bool {
	return true
}

func (anyConstraint) MatchesAny(Constraint) bool {
	return true
}

func (anyConstraint) Intersect(c Constraint) Constraint {
	return c
}

// noneConstraint is the empty set - it matches no versions. It mirrors the
// behavior of the semver package's none type.
type noneConstraint struct{}

func (noneConstraint) String() string {
	return ""
}

func (noneConstraint) ImpliedCaretString() string {
	return ""
}

func (noneConstraint) typedString() string {
	return "none-"
}

func (noneConstraint) Matches(Version) bool {
	return false
}

func (noneConstraint) MatchesAny(Constraint) bool {
	return false
}

func (noneConstraint) Intersect(Constraint) Constraint {
	return none
}

// A ProjectConstraint combines a ProjectIdentifier with a Constraint. It
// indicates that, if packages contained in the ProjectIdentifier enter the
// depgraph, they must do so at a version that is allowed by the Constraint.
type ProjectConstraint struct {
	Ident      ProjectIdentifier
	Constraint Constraint
}

// ProjectConstraints is a map of projects, as identified by their import path
// roots (ProjectRoots) to the corresponding ProjectProperties.
//
// They are the standard form in which Manifests declare their required
// dependency properties - constraints and network locations - as well as the
// form in which RootManifests declare their overrides.
type ProjectConstraints map[ProjectRoot]ProjectProperties

type workingConstraint struct {
	Ident                     ProjectIdentifier
	Constraint                Constraint
	overrNet, overrConstraint bool
}

func pcSliceToMap(l []ProjectConstraint, r ...[]ProjectConstraint) ProjectConstraints {
	final := make(ProjectConstraints)

	for _, pc := range l {
		final[pc.Ident.ProjectRoot] = ProjectProperties{
			Source:     pc.Ident.Source,
			Constraint: pc.Constraint,
		}
	}

	for _, pcs := range r {
		for _, pc := range pcs {
			if pp, exists := final[pc.Ident.ProjectRoot]; exists {
				// Technically this should be done through a bridge for
				// cross-version-type matching...but this is a one off for root and
				// that's just ridiculous for this.
				pp.Constraint = pp.Constraint.Intersect(pc.Constraint)
				final[pc.Ident.ProjectRoot] = pp
			} else {
				final[pc.Ident.ProjectRoot] = ProjectProperties{
					Source:     pc.Ident.Source,
					Constraint: pc.Constraint,
				}
			}
		}
	}

	return final
}

func (m ProjectConstraints) asSortedSlice() []ProjectConstraint {
	pcs := make([]ProjectConstraint, len(m))

	k := 0
	for pr, pp := range m {
		pcs[k] = ProjectConstraint{
			Ident: ProjectIdentifier{
				ProjectRoot: pr,
				Source:      pp.Source,
			},
			Constraint: pp.Constraint,
		}
		k++
	}

	sort.Stable(sortedConstraints(pcs))
	return pcs
}

// merge pulls in all the constraints from other ProjectConstraints map(s),
// merging them with the receiver into a new ProjectConstraints map.
//
// If duplicate ProjectRoots are encountered, the constraints are intersected
// together and the latter's NetworkName, if non-empty, is taken.
func (m ProjectConstraints) merge(other ...ProjectConstraints) (out ProjectConstraints) {
	plen := len(m)
	for _, pcm := range other {
		plen += len(pcm)
	}

	out = make(ProjectConstraints, plen)
	for pr, pp := range m {
		out[pr] = pp
	}

	for _, pcm := range other {
		for pr, pp := range pcm {
			if rpp, exists := out[pr]; exists {
				pp.Constraint = pp.Constraint.Intersect(rpp.Constraint)
				if pp.Source == "" {
					pp.Source = rpp.Source
				}
			}
			out[pr] = pp
		}
	}

	return
}

// overrideAll treats the receiver ProjectConstraints map as a set of override
// instructions, and applies overridden values to the ProjectConstraints.
//
// A slice of workingConstraint is returned, allowing differentiation between
// values that were or were not overridden.
func (m ProjectConstraints) overrideAll(pcm ProjectConstraints) (out []workingConstraint) {
	out = make([]workingConstraint, len(pcm))
	k := 0
	for pr, pp := range pcm {
		out[k] = m.override(pr, pp)
		k++
	}

	sort.Stable(sortedWC(out))
	return
}

// override replaces a single ProjectConstraint with a workingConstraint,
// overriding its values if a corresponding entry exists in the
// ProjectConstraints map.
func (m ProjectConstraints) override(pr ProjectRoot, pp ProjectProperties) workingConstraint {
	wc := workingConstraint{
		Ident: ProjectIdentifier{
			ProjectRoot: pr,
			Source:      pp.Source,
		},
		Constraint: pp.Constraint,
	}

	if opp, has := m[pr]; has {
		// The rule for overrides is that *any* non-zero value for the prop
		// should be considered an override, even if it's equal to what's
		// already there.
		if opp.Constraint != nil {
			wc.Constraint = opp.Constraint
			wc.overrConstraint = true
		}

		// This may appear incorrect, because the solver encodes meaning into
		// the empty string for NetworkName (it means that it would use the
		// import path by default, but could be coerced into using an alternate
		// URL). However, that 'coercion' can only happen if there's a
		// disagreement between projects on where a dependency should be sourced
		// from. Such disagreement is exactly what overrides preclude, so
		// there's no need to preserve the meaning of "" here - thus, we can
		// treat it as a zero value and ignore it, rather than applying it.
		if opp.Source != "" {
			wc.Ident.Source = opp.Source
			wc.overrNet = true
		}
	}

	return wc
}

type sortedConstraints []ProjectConstraint

func (s sortedConstraints) Len() int           { return len(s) }
func (s sortedConstraints) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s sortedConstraints) Less(i, j int) bool { return s[i].Ident.less(s[j].Ident) }

type sortedWC []workingConstraint

func (s sortedWC) Len() int           { return len(s) }
func (s sortedWC) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s sortedWC) Less(i, j int) bool { return s[i].Ident.less(s[j].Ident) }
<commit_msg>Tidy up docs a bit<commit_after>// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gps

import (
	"fmt"
	"sort"

	"github.com/Masterminds/semver"
)

var (
	none = noneConstraint{}
	any  = anyConstraint{}
)

// A Constraint provides structured limitations on the versions that are
// admissible for a given project.
//
// As with Version, it has a private method because the gps's internal
// implementation of the problem is complete, and the system relies on type
// magic to operate.
type Constraint interface {
	fmt.Stringer

	// ImpliedCaretString converts the Constraint to a string in the same manner
	// as String(), but treats the empty operator as equivalent to ^, rather
	// than =.
	//
	// In the same way that String() is the inverse of NewConstraint(), this
	// method is the inverse of NewSemverConstraintIC().
	ImpliedCaretString() string

	// Matches indicates if the provided Version is allowed by the Constraint.
	Matches(Version) bool

	// MatchesAny indicates if the intersection of the Constraint with the
	// provided Constraint would yield a Constraint that could allow *any*
	// Version.
	MatchesAny(Constraint) bool

	// Intersect computes the intersection of the Constraint with the provided
	// Constraint.
	Intersect(Constraint) Constraint

	// typedString emits the normal stringified representation of the provided
	// constraint, prefixed with a string that uniquely identifies the type of
	// the constraint.
	//
	// It also forces Constraint to be a private/sealed interface, which is a
	// design goal of the system.
	typedString() string
}

// NewSemverConstraint attempts to construct a semver Constraint object from the
// input string.
//
// If the input string cannot be made into a valid semver Constraint, an error
// is returned.
func NewSemverConstraint(body string) (Constraint, error) {
	c, err := semver.NewConstraint(body)
	if err != nil {
		return nil, err
	}
	// If we got a simple semver.Version, simplify by returning our
	// corresponding type
	if sv, ok := c.(semver.Version); ok {
		return semVersion{sv: sv}, nil
	}
	return semverConstraint{c: c}, nil
}

// NewSemverConstraintIC attempts to construct a semver Constraint object from the
// input string, defaulting to a caret, ^, when no operator is specified. Put
// differently, ^ is the default operator for NewSemverConstraintIC, while =
// is the default operator for NewSemverConstraint.
//
// If the input string cannot be made into a valid semver Constraint, an error
// is returned.
func NewSemverConstraintIC(body string) (Constraint, error) {
	c, err := semver.NewConstraintIC(body)
	if err != nil {
		return nil, err
	}
	// If we got a simple semver.Version, simplify by returning our
	// corresponding type
	if sv, ok := c.(semver.Version); ok {
		return semVersion{sv: sv}, nil
	}
	return semverConstraint{c: c}, nil
}

type semverConstraint struct {
	c semver.Constraint
}

func (c semverConstraint) String() string {
	return c.c.String()
}

// ImpliedCaretString converts the Constraint to a string in the same manner
// as String(), but treats the empty operator as equivalent to ^, rather
// than =.
//
// In the same way that String() is the inverse of NewConstraint(), this
// method is the inverse of NewSemverConstraintIC().
func (c semverConstraint) ImpliedCaretString() string {
	return c.c.ImpliedCaretString()
}

func (c semverConstraint) typedString() string {
	return fmt.Sprintf("svc-%s", c.c.String())
}

func (c semverConstraint) Matches(v Version) bool {
	switch tv := v.(type) {
	case versionTypeUnion:
		for _, elem := range tv {
			if c.Matches(elem) {
				return true
			}
		}
	case semVersion:
		return c.c.Matches(tv.sv) == nil
	case versionPair:
		if tv2, ok := tv.v.(semVersion); ok {
			return c.c.Matches(tv2.sv) == nil
		}
	}

	return false
}

func (c semverConstraint) MatchesAny(c2 Constraint) bool {
	return c.Intersect(c2) != none
}

func (c semverConstraint) Intersect(c2 Constraint) Constraint {
	switch tc := c2.(type) {
	case anyConstraint:
		return c
	case versionTypeUnion:
		for _, elem := range tc {
			if rc := c.Intersect(elem); rc != none {
				return rc
			}
		}
	case semverConstraint:
		rc := c.c.Intersect(tc.c)
		if !semver.IsNone(rc) {
			return semverConstraint{c: rc}
		}
	case semVersion:
		rc := c.c.Intersect(tc.sv)
		if !semver.IsNone(rc) {
			// If single version intersected with constraint, we know the result
			// must be the single version, so just return it back out
			return c2
		}
	case versionPair:
		if tc2, ok := tc.v.(semVersion); ok {
			rc := c.c.Intersect(tc2.sv)
			if !semver.IsNone(rc) {
				// same reasoning as previous case
				return c2
			}
		}
	}

	return none
}

// IsAny indicates if the provided constraint is the wildcard "Any" constraint.
func IsAny(c Constraint) bool {
	_, ok := c.(anyConstraint)
	return ok
}

// Any returns a constraint that will match anything.
func Any() Constraint {
	return anyConstraint{}
}

// anyConstraint is an unbounded constraint - it matches all other types of
// constraints. It mirrors the behavior of the semver package's any type.
type anyConstraint struct{}

func (anyConstraint) String() string {
	return "*"
}

func (anyConstraint) ImpliedCaretString() string {
	return "*"
}

func (anyConstraint) typedString() string {
	return "any-*"
}

func (anyConstraint) Matches(Version) bool {
	return true
}

func (anyConstraint) MatchesAny(Constraint) bool {
	return true
}

func (anyConstraint) Intersect(c Constraint) Constraint {
	return c
}

// noneConstraint is the empty set - it matches no versions. It mirrors the
// behavior of the semver package's none type.
type noneConstraint struct{}

func (noneConstraint) String() string {
	return ""
}

func (noneConstraint) ImpliedCaretString() string {
	return ""
}

func (noneConstraint) typedString() string {
	return "none-"
}

func (noneConstraint) Matches(Version) bool {
	return false
}

func (noneConstraint) MatchesAny(Constraint) bool {
	return false
}

func (noneConstraint) Intersect(Constraint) Constraint {
	return none
}

// A ProjectConstraint combines a ProjectIdentifier with a Constraint. It
// indicates that, if packages contained in the ProjectIdentifier enter the
// depgraph, they must do so at a version that is allowed by the Constraint.
type ProjectConstraint struct {
	Ident      ProjectIdentifier
	Constraint Constraint
}

// ProjectConstraints is a map of projects, as identified by their import path
// roots (ProjectRoots) to the corresponding ProjectProperties.
//
// They are the standard form in which Manifests declare their required
// dependency properties - constraints and network locations - as well as the
// form in which RootManifests declare their overrides.
type ProjectConstraints map[ProjectRoot]ProjectProperties

type workingConstraint struct {
	Ident                     ProjectIdentifier
	Constraint                Constraint
	overrNet, overrConstraint bool
}

func pcSliceToMap(l []ProjectConstraint, r ...[]ProjectConstraint) ProjectConstraints {
	final := make(ProjectConstraints)

	for _, pc := range l {
		final[pc.Ident.ProjectRoot] = ProjectProperties{
			Source:     pc.Ident.Source,
			Constraint: pc.Constraint,
		}
	}

	for _, pcs := range r {
		for _, pc := range pcs {
			if pp, exists := final[pc.Ident.ProjectRoot]; exists {
				// Technically this should be done through a bridge for
				// cross-version-type matching...but this is a one off for root and
				// that's just ridiculous for this.
				pp.Constraint = pp.Constraint.Intersect(pc.Constraint)
				final[pc.Ident.ProjectRoot] = pp
			} else {
				final[pc.Ident.ProjectRoot] = ProjectProperties{
					Source:     pc.Ident.Source,
					Constraint: pc.Constraint,
				}
			}
		}
	}

	return final
}

func (m ProjectConstraints) asSortedSlice() []ProjectConstraint {
	pcs := make([]ProjectConstraint, len(m))

	k := 0
	for pr, pp := range m {
		pcs[k] = ProjectConstraint{
			Ident: ProjectIdentifier{
				ProjectRoot: pr,
				Source:      pp.Source,
			},
			Constraint: pp.Constraint,
		}
		k++
	}

	sort.Stable(sortedConstraints(pcs))
	return pcs
}

// merge pulls in all the constraints from other ProjectConstraints map(s),
// merging them with the receiver into a new ProjectConstraints map.
//
// If duplicate ProjectRoots are encountered, the constraints are intersected
// together and the latter's NetworkName, if non-empty, is taken.
func (m ProjectConstraints) merge(other ...ProjectConstraints) (out ProjectConstraints) {
	plen := len(m)
	for _, pcm := range other {
		plen += len(pcm)
	}

	out = make(ProjectConstraints, plen)
	for pr, pp := range m {
		out[pr] = pp
	}

	for _, pcm := range other {
		for pr, pp := range pcm {
			if rpp, exists := out[pr]; exists {
				pp.Constraint = pp.Constraint.Intersect(rpp.Constraint)
				if pp.Source == "" {
					pp.Source = rpp.Source
				}
			}
			out[pr] = pp
		}
	}

	return
}

// overrideAll treats the receiver ProjectConstraints map as a set of override
// instructions, and applies overridden values to the ProjectConstraints.
//
// A slice of workingConstraint is returned, allowing differentiation between
// values that were or were not overridden.
func (m ProjectConstraints) overrideAll(pcm ProjectConstraints) (out []workingConstraint) {
	out = make([]workingConstraint, len(pcm))
	k := 0
	for pr, pp := range pcm {
		out[k] = m.override(pr, pp)
		k++
	}

	sort.Stable(sortedWC(out))
	return
}

// override replaces a single ProjectConstraint with a workingConstraint,
// overriding its values if a corresponding entry exists in the
// ProjectConstraints map.
func (m ProjectConstraints) override(pr ProjectRoot, pp ProjectProperties) workingConstraint {
	wc := workingConstraint{
		Ident: ProjectIdentifier{
			ProjectRoot: pr,
			Source:      pp.Source,
		},
		Constraint: pp.Constraint,
	}

	if opp, has := m[pr]; has {
		// The rule for overrides is that *any* non-zero value for the prop
		// should be considered an override, even if it's equal to what's
		// already there.
		if opp.Constraint != nil {
			wc.Constraint = opp.Constraint
			wc.overrConstraint = true
		}

		// This may appear incorrect, because the solver encodes meaning into
		// the empty string for NetworkName (it means that it would use the
		// import path by default, but could be coerced into using an alternate
		// URL). However, that 'coercion' can only happen if there's a
		// disagreement between projects on where a dependency should be sourced
		// from. Such disagreement is exactly what overrides preclude, so
		// there's no need to preserve the meaning of "" here - thus, we can
		// treat it as a zero value and ignore it, rather than applying it.
		if opp.Source != "" {
			wc.Ident.Source = opp.Source
			wc.overrNet = true
		}
	}

	return wc
}

type sortedConstraints []ProjectConstraint

func (s sortedConstraints) Len() int           { return len(s) }
func (s sortedConstraints) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s sortedConstraints) Less(i, j int) bool { return s[i].Ident.less(s[j].Ident) }

type sortedWC []workingConstraint

func (s sortedWC) Len() int           { return len(s) }
func (s sortedWC) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s sortedWC) Less(i, j int) bool { return s[i].Ident.less(s[j].Ident) }
<|endoftext|>


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

package license

import "path"

// Metadata holds information extracted from a license file: its license Type
// and FilePath relative to the contents directory.
type Metadata struct {
	// Types is the license type, as determined by the licensecheck package.
	Types []string
	// FilePath is the '/'-separated path to the license file in the module zip,
	// relative to the contents directory.
	FilePath string
}

// A License is a classified license file path and its contents.
type License struct {
	*Metadata
	Contents []byte
}

// redistributableLicenses defines the set of (detectable) licenses that are
// considered permissive of redistribution.
var redistributableLicenses = map[string]bool{
	// Licenses acceptable by OSI
	"AGPL-3.0":             true,
	"Apache-2.0":           true,
	"Artistic-2.0":         true,
	"BSD-2-Clause":         true,
	"BSD-2-Clause-FreeBSD": true,
	"BSD-3-Clause":         true,
	"BSL-1.0":              true,
	"GPL2":                 true,
	"GPL3":                 true,
	"ISC":                  true,
	"LGPL-2.1":             true,
	"LGPL-3.0":             true,
	"MIT":                  true,
	"MPL-2.0":              true,
	"Zlib":                 true,

	"CC-BY-4.0": true,
	"CC0-1.0":   true,
	"JSON":      true,
	"Unlicense": true,
}

// AreRedistributable reports whether content subject to the given licenses
// should be considered redistributable. The current algorithm for this is to
// ensure that:
//   1. Every applicable license is redistributable, and
//   2. There is at least one license in the root directory.
func AreRedistributable(licenses []*Metadata) bool {
	haveRootLicense := false
	for _, lm := range licenses {
		if path.Dir(lm.FilePath) == "." {
			haveRootLicense = true
		}
		if !lm.IsRedistributable() {
			return false
		}
	}
	return haveRootLicense
}

// IsRedistributable reports whether content subject to the given
// license should be considered redistributable. The license
// must have at least one type, and all its types must be redistributable.
func (lm *Metadata) IsRedistributable() bool {
	if len(lm.Types) == 0 {
		return false
	}
	for _, typ := range lm.Types {
		if !redistributableLicenses[typ] {
			return false
		}
	}
	return true
}

// ToMetadatas converts a slice of Licenses to a slice of Metadatas.
func ToMetadatas(lics []*License) []*Metadata {
	var ms []*Metadata
	for _, l := range lics {
		ms = append(ms, l.Metadata)
	}
	return ms
}
<commit_msg>internal/license: remove non-OSI licenses<commit_after>// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package license

import "path"

// Metadata holds information extracted from a license file: its license Type
// and FilePath relative to the contents directory.
type Metadata struct {
	// Types is the license type, as determined by the licensecheck package.
	Types []string
	// FilePath is the '/'-separated path to the license file in the module zip,
	// relative to the contents directory.
	FilePath string
}

// A License is a classified license file path and its contents.
type License struct {
	*Metadata
	Contents []byte
}

// redistributableLicenses defines the set of (detectable) licenses that are
// considered permissive of redistribution.
var redistributableLicenses = map[string]bool{
	// Licenses acceptable by OSI
	"AGPL-3.0":             true,
	"Apache-2.0":           true,
	"Artistic-2.0":         true,
	"BSD-2-Clause":         true,
	"BSD-2-Clause-FreeBSD": true,
	"BSD-3-Clause":         true,
	"BSL-1.0":              true,
	"GPL2":                 true,
	"GPL3":                 true,
	"ISC":                  true,
	"LGPL-2.1":             true,
	"LGPL-3.0":             true,
	"MIT":                  true,
	"MPL-2.0":              true,
	"Zlib":                 true,
}

// AreRedistributable reports whether content subject to the given licenses
// should be considered redistributable. The current algorithm for this is to
// ensure that:
//   1. Every applicable license is redistributable, and
//   2. There is at least one license in the root directory.
func AreRedistributable(licenses []*Metadata) bool {
	haveRootLicense := false
	for _, lm := range licenses {
		if path.Dir(lm.FilePath) == "." {
			haveRootLicense = true
		}
		if !lm.IsRedistributable() {
			return false
		}
	}
	return haveRootLicense
}

// IsRedistributable reports whether content subject to the given
// license should be considered redistributable. The license
// must have at least one type, and all its types must be redistributable.
func (lm *Metadata) IsRedistributable() bool {
	if len(lm.Types) == 0 {
		return false
	}
	for _, typ := range lm.Types {
		if !redistributableLicenses[typ] {
			return false
		}
	}
	return true
}

// ToMetadatas converts a slice of Licenses to a slice of Metadatas.
func ToMetadatas(lics []*License) []*Metadata {
	var ms []*Metadata
	for _, l := range lics {
		ms = append(ms, l.Metadata)
	}
	return ms
}
<|endoftext|>


<commit_before>package mock

import (
	"strconv"

	"golang.org/x/net/context"

	"github.com/docker/docker/api/types"
	dockerAPI "github.com/docker/docker/client"
)

//Docker repo is vendoring x/net/context and it seems that it conflicts
//with whatever version of the same package the vendoring tools retrieve
//A way to fix this is by removing the vendored package from the docker
//directory of the vendor tool of dry, so:
//rm -rf vendor/github.com/docker/docker/vendor/golang.org/x/

//ContainerAPIClientMock mocks docker ContainerAPIClient
type ContainerAPIClientMock struct {
	dockerAPI.ContainerAPIClient
	Containers []types.Container
}

//NetworkAPIClientMock mocks docker NetworkAPIClient
type NetworkAPIClientMock struct {
	dockerAPI.NetworkAPIClient
}

//ImageAPIClientMock mocks docker ImageAPIClient
type ImageAPIClientMock struct {
	dockerAPI.ImageAPIClient
}

//ContainerList returns a list with 10 container with IDs from 0 to 9.
func (m ContainerAPIClientMock) ContainerList(ctx context.Context, options types.ContainerListOptions) ([]types.Container, error) {
	if len(m.Containers) > 0 {
		return m.Containers, nil
	}
	var containers []types.Container

	for i := 0; i < 10; i++ {
		containers = append(containers, types.Container{
			ID: strconv.Itoa(i),
		})
	}

	return containers, nil
}

//ContainerList returns a list with 10 container with IDs from 0 to 9.
func (m ContainerAPIClientMock) ContainerInspect(ctx context.Context, container string) (types.ContainerJSON, error) {
	return types.ContainerJSON{}, nil
}
<commit_msg>Minor<commit_after>package mock

import (
	"strconv"

	"golang.org/x/net/context"

	"github.com/docker/docker/api/types"
	dockerAPI "github.com/docker/docker/client"
)

//Docker repo is vendoring x/net/context and it seems that it conflicts
//with whatever version of the same package the vendoring tools retrieve
//A way to fix this is by removing the vendored package from the docker
//directory of the vendor tool of dry, so:
//rm -rf vendor/github.com/docker/docker/vendor/golang.org/x/

//ContainerAPIClientMock mocks docker ContainerAPIClient
type ContainerAPIClientMock struct {
	dockerAPI.ContainerAPIClient
	Containers []types.Container
}

//NetworkAPIClientMock mocks docker NetworkAPIClient
type NetworkAPIClientMock struct {
	dockerAPI.NetworkAPIClient
}

//ImageAPIClientMock mocks docker ImageAPIClient
type ImageAPIClientMock struct {
	dockerAPI.ImageAPIClient
}

//ContainerList returns a list with 10 container with IDs from 0 to 9.
func (m ContainerAPIClientMock) ContainerList(ctx context.Context, options types.ContainerListOptions) ([]types.Container, error) {
	if len(m.Containers) > 0 {
		return m.Containers, nil
	}
	var containers []types.Container

	for i := 0; i < 10; i++ {
		containers = append(containers, types.Container{
			ID: strconv.Itoa(i),
		})
	}

	return containers, nil
}

//ContainerInspect returns an empty inspection result.
func (m ContainerAPIClientMock) ContainerInspect(ctx context.Context, container string) (types.ContainerJSON, error) {
	return types.ContainerJSON{}, nil
}
<|endoftext|>


<commit_before>package summary

import (
	"github.com/go-task/task/v2/internal/logger"
	"github.com/go-task/task/v2/internal/taskfile"
	"strings"
)

func Print(l *logger.Logger, t *taskfile.Task) {
	printTaskName(l, t)
	if hasSummary(t) {
		printTaskSummary(l, t)
	} else if hasDescription(t) {
		printTaskDescription(l, t)
	} else {
		printNoDescriptionOrSummary(l)
	}
	printTaskDependencies(l, t)
	printTaskCommands(l, t)
}

func hasSummary(t *taskfile.Task) bool {
	return t.Summary != ""
}

func printTaskSummary(l *logger.Logger, t *taskfile.Task) {
	lines := strings.Split(t.Summary, "\n")
	for i, line := range lines {
		notLastLine := i+1 < len(lines)
		if notLastLine || line != "" {
			l.Outf(line)
		}
	}
}

func printTaskName(l *logger.Logger, t *taskfile.Task) {
	l.Outf("task: " + t.Task)
	l.Outf("")
}

func hasDescription(t *taskfile.Task) bool {
	return t.Desc != ""
}

func printTaskDescription(l *logger.Logger, t *taskfile.Task) {
	l.Outf(t.Desc)
}

func printNoDescriptionOrSummary(l *logger.Logger) {
	l.Outf("(task does not have description or summary)")
}

func printTaskDependencies(l *logger.Logger, t *taskfile.Task) {
	hasDependencies := len(t.Deps) > 0
	if hasDependencies {
		l.Outf("")
		l.Outf("dependencies:")

		for _, d := range t.Deps {
			l.Outf(" - %s", d.Task)
		}
	}
}

func printTaskCommands(l *logger.Logger, t *taskfile.Task) {
	hasCommands := len(t.Cmds) > 0
	if hasCommands {
		l.Outf("")
		l.Outf("commands:")
		for _, c := range t.Cmds {
			isCommand := c.Cmd != ""
			if isCommand {
				l.Outf(" - %s", c.Cmd)
			} else {
				l.Outf(" - Task: %s", c.Task)
			}
		}
	}
}
<commit_msg>Update internal/summary/summary.go<commit_after>package summary

import (
	"github.com/go-task/task/v2/internal/logger"
	"github.com/go-task/task/v2/internal/taskfile"
	"strings"
)

func Print(l *logger.Logger, t *taskfile.Task) {
	printTaskName(l, t)
	if hasSummary(t) {
		printTaskSummary(l, t)
	} else if hasDescription(t) {
		printTaskDescription(l, t)
	} else {
		printNoDescriptionOrSummary(l)
	}
	printTaskDependencies(l, t)
	printTaskCommands(l, t)
}

func hasSummary(t *taskfile.Task) bool {
	return t.Summary != ""
}

func printTaskSummary(l *logger.Logger, t *taskfile.Task) {
	lines := strings.Split(t.Summary, "\n")
	for i, line := range lines {
		notLastLine := i+1 < len(lines)
		if notLastLine || line != "" {
			l.Outf(line)
		}
	}
}

func printTaskName(l *logger.Logger, t *taskfile.Task) {
	l.Outf("task: %s", t.Task)
	l.Outf("")
}

func hasDescription(t *taskfile.Task) bool {
	return t.Desc != ""
}

func printTaskDescription(l *logger.Logger, t *taskfile.Task) {
	l.Outf(t.Desc)
}

func printNoDescriptionOrSummary(l *logger.Logger) {
	l.Outf("(task does not have description or summary)")
}

func printTaskDependencies(l *logger.Logger, t *taskfile.Task) {
	hasDependencies := len(t.Deps) > 0
	if hasDependencies {
		l.Outf("")
		l.Outf("dependencies:")

		for _, d := range t.Deps {
			l.Outf(" - %s", d.Task)
		}
	}
}

func printTaskCommands(l *logger.Logger, t *taskfile.Task) {
	hasCommands := len(t.Cmds) > 0
	if hasCommands {
		l.Outf("")
		l.Outf("commands:")
		for _, c := range t.Cmds {
			isCommand := c.Cmd != ""
			if isCommand {
				l.Outf(" - %s", c.Cmd)
			} else {
				l.Outf(" - Task: %s", c.Task)
			}
		}
	}
}
<|endoftext|>


<commit_before>package cli

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/user"

	"github.com/opentable/sous/ext/docker"
	"github.com/opentable/sous/ext/git"
	"github.com/opentable/sous/ext/singularity"
	"github.com/opentable/sous/ext/storage"
	"github.com/opentable/sous/lib"
	"github.com/opentable/sous/util/cmdr"
	"github.com/opentable/sous/util/docker_registry"
	"github.com/opentable/sous/util/shell"
	"github.com/pkg/errors"
	"github.com/samsalisbury/psyringe"
	"github.com/samsalisbury/semv"
)

type (
	// Out is an output used for real data a Command returns. This should only
	// be used when a command needs to write directly to stdout, using the
	// formatting options that come with an output. Usually, you should use a
	// SuccessResult with Data to return data.
	Out struct{ *cmdr.Output }
	// ErrOut is an output used for logging from a Command. This should only be
	// used when a Command needs to write a lot of data to stderr, using the
	// formatting options that come with and Output. Usually you should use and
	// ErrorResult to return error messages.
	ErrOut struct{ *cmdr.Output }
	// SousCLIGraph is a dependency injector used to flesh out Sous commands
	// with their dependencies.
	SousCLIGraph struct{ *psyringe.Psyringe }
	// OutWriter is an alias on io.Writer to disguish "stderr"
	OutWriter io.Writer
	// ErrWriter is an alias on io.Writer to disguish "stderr"
	ErrWriter io.Writer
)

type (
	// StateReader knows how to read state.
	StateReader interface {
		ReadState() (*sous.State, error)
	}
	// StateWriter know how to write state.
	StateWriter interface {
		WriteState(*sous.State) error
	}
)

type (
	// Version represents a version of Sous.
	Version struct{ semv.Version }
	// LocalUser is the currently logged in user.
	LocalUser struct{ *User }
	// LocalSousConfig is the configuration for Sous.
	LocalSousConfig struct{ *Config }
	// LocalWorkDir is the user's current working directory when they invoke Sous.
	LocalWorkDir string
	// LocalWorkDirShell is a shell for working in the user's current working
	// directory.
	LocalWorkDirShell struct{ *shell.Sh }
	// LocalGitClient is a git client rooted in WorkdirShell.Dir.
	LocalGitClient struct{ *git.Client }
	// LocalGitRepo is the git repository containing WorkDir.
	LocalGitRepo struct{ *git.Repo }
	// GitSourceContext is the source context according to the local git repo.
	GitSourceContext struct{ *sous.SourceContext }
	// ScratchDirShell is a shell for working in the scratch area where things
	// like artefacts, and build metadata are stored. It is a new, empty
	// directory, and should be cleaned up eventually.
	ScratchDirShell struct{ *shell.Sh }
	// LocalDockerClient is a docker client object
	LocalDockerClient struct{ docker_registry.Client }
	// LocalStateReader wraps a storage.StateReader, and should be configured
	// to use the current user's local storage.
	LocalStateReader struct{ StateReader }
	// LocalStateWriter wraps a storage.StateWriter, and should be configured to
	// use the current user's local storage.
	LocalStateWriter struct{ StateWriter }
	// CurrentGDM is a snapshot of the GDM at application start. In a CLI
	// context, which this is, that is all we need to simply read the GDM.
	CurrentGDM struct{ sous.Deployments }
	// TargetManifest is a specific manifest for the current SourceLocation.
	// If the named manifest does not exist, it is created.
	TargetManifest struct{ *sous.Manifest }
	// DetectedOTPLDeploySpecs is a set of otpl-deploy configured deployments
	// that have been detected.
	DetectedOTPLDeploySpecs struct{ sous.DeploySpecs }
	// UserSelectedOTPLDeploySpecs is a set of otpl-deploy configured deploy
	// specs that the user has explicitly selected. (May be empty.)
	UserSelectedOTPLDeploySpecs struct{ sous.DeploySpecs }
	// TargetManifestID is the manifest ID being targeted, after resolving all
	// context and flags.
	TargetManifestID sous.ManifestID
)

// BuildGraph builds the dependency injection graph, used to populate commands
// invoked by the user.
func BuildGraph(c *CLI, out, err io.Writer) *SousCLIGraph {
	return &SousCLIGraph{psyringe.New(
		c,
		func() OutWriter { return out },
		func() ErrWriter { return err },
		newOut,
		newErrOut,
		newLogSet,
		newLocalUser,
		newLocalSousConfig,
		newLocalWorkDir,
		newLocalWorkDirShell,
		newScratchDirShell,
		newLocalGitClient,
		newLocalGitRepo,
		newGitSourceContext,
		newSourceContext,
		newBuildContext,
		newBuildConfig,
		newBuildManager,
		newDockerClient,
		newDockerBuilder,
		newSelector,
		newLabeller,
		newRegistrar,
		newDeployer,
		newRegistry,
		newRegistryDumper,
		newLocalDiskStateManager,
		newLocalStateReader,
		newLocalStateWriter,
		newCurrentGDM,
		newCurrentState,
		newTargetManifest,
		newDetectedOTPLConfig,
		newUserSelectedOTPLDeploySpecs,
		newTargetManifestID,
	)}
}

func newOut(c *CLI) Out {
	return Out{c.Out}
}

func newErrOut(c *CLI) ErrOut {
	return ErrOut{c.Err}
}

func newRegistryDumper(r sous.Registry) *sous.RegistryDumper {
	return sous.NewRegistryDumper(r)
}

func newLogSet(s *Sous, err ErrWriter) *sous.LogSet { // XXX temporary until we settle on logging
	if s.flags.Verbosity.Debug {
		if s.flags.Verbosity.Loud {
			sous.Log.Vomit.SetOutput(err)
		}
		sous.Log.Debug.SetOutput(err)
		sous.Log.Info.SetOutput(err)

	}
	if s.flags.Verbosity.Loud {
		sous.Log.Info.SetOutput(err)
	}
	if s.flags.Verbosity.Quiet {
	}
	if s.flags.Verbosity.Silent {
	}

	sous.Log.Vomit.Println("Verbose debugging enabled")
	sous.Log.Debug.Println("Regular debugging enabled")
	return &sous.Log
}

func newGitSourceContext(g LocalGitRepo) (GitSourceContext, error) {
	c, err := g.SourceContext()
	return GitSourceContext{c}, initErr(err, "getting local git context")
}

func newSourceContext(f *DeployFilterFlags, g GitSourceContext) (*sous.SourceContext, error) {
	c := g.SourceContext
	if c == nil {
		c = &sous.SourceContext{}
	}
	mid, err := newTargetManifestID(f, c)
	if err != nil {
		return nil, errors.Wrapf(err, "getting source location")
	}
	sl := sous.ManifestID(mid)
	if sl.Source.Repo != c.SourceLocation().Repo {
		// TODO: Clone the repository, and use the cloned dir as source context.
		return nil, errors.Errorf("source location %q is not the same as the remote %q",
			sl.Source.Repo, c.SourceLocation().Repo)
	}
	return c, nil
}

func newBuildContext(wd LocalWorkDirShell, c *sous.SourceContext) *sous.BuildContext {
	return &sous.BuildContext{Sh: wd.Sh, Source: *c}
}

func newBuildConfig(f *DeployFilterFlags, p *PolicyFlags, bc *sous.BuildContext) *sous.BuildConfig {
	cfg := sous.BuildConfig{
		Repo:       f.Repo,
		Offset:     f.Offset,
		Tag:        f.Tag,
		Revision:   f.Revision,
		Strict:     p.Strict,
		ForceClone: p.ForceClone,
		Context:    bc,
	}

	return &cfg
}

func newBuildManager(bc *sous.BuildConfig, sl sous.Selector, lb sous.Labeller, rg sous.Registrar) *sous.BuildManager {
	mgr := &sous.BuildManager{
		BuildConfig: bc,
		Selector:    sl,
		Labeller:    lb,
		Registrar:   rg,
	}
	return mgr
}

func newLocalUser() (v LocalUser, err error) {
	u, err := user.Current()
	v.User = &User{u}
	return v, initErr(err, "getting current user")
}

func newLocalSousConfig(u LocalUser) (v LocalSousConfig, err error) {
	v.Config, err = newConfig(u.User.ConfigFile(), u.DefaultConfig())
	return v, initErr(err, "getting configuration")
}

// TODO: This should register a cleanup task with the cli, to delete the temp
// dir.
func newScratchDirShell() (v ScratchDirShell, err error) {
	const what = "getting scratch directory"
	dir, err := ioutil.TempDir("", "sous")
	if err != nil {
		return v, initErr(err, what)
	}
	v.Sh, err = shell.DefaultInDir(dir)
	v.TeeOut = os.Stdout
	v.TeeErr = os.Stderr
	return v, initErr(err, what)
}

func newLocalWorkDir() (LocalWorkDir, error) {
	s, err := os.Getwd()
	return LocalWorkDir(s), initErr(err, "determining working directory")
}

func newLocalWorkDirShell(l LocalWorkDir) (v LocalWorkDirShell, err error) {
	v.Sh, err = shell.DefaultInDir(string(l))
	v.TeeEcho = os.Stdout
	//v.TeeOut = os.Stdout
	//v.TeeErr = os.Stderr
	return v, initErr(err, "getting current working directory")
}

func newLocalGitClient(sh LocalWorkDirShell) (v LocalGitClient, err error) {
	v.Client, err = git.NewClient(sh.Sh)
	return v, initErr(err, "initialising git client")
}

func newLocalGitRepo(c LocalGitClient) (v LocalGitRepo, err error) {
	v.Repo, err = c.OpenRepo(".")
	return v, initErr(err, "opening local git repository")
}

func newSelector() sous.Selector {
	return &sous.EchoSelector{
		Factory: func(*sous.BuildContext) (sous.Buildpack, error) {
			return docker.NewDockerfileBuildpack(), nil
		},
	}
}

func newDockerBuilder(cfg LocalSousConfig, cl LocalDockerClient, ctx *sous.SourceContext, source LocalWorkDirShell, scratch ScratchDirShell) (*docker.Builder, error) {
	nc, err := makeDockerRegistry(cfg, cl)
	if err != nil {
		return nil, err
	}
	drh := cfg.Docker.RegistryHost
	return docker.NewBuilder(nc, drh, source.Sh, scratch.Sh)
}

func newLabeller(db *docker.Builder) sous.Labeller {
	return db
}

func newRegistrar(db *docker.Builder) sous.Registrar {
	return db
}

func newRegistry(cfg LocalSousConfig, cl LocalDockerClient) (sous.Registry, error) {
	return makeDockerRegistry(cfg, cl)
}
func newDeployer(r sous.Registry) sous.Deployer {
	// Eventually, based on configuration, we may make different decisions here.
	return singularity.NewDeployer(r, singularity.NewRectiAgent(r))
}

func newDockerClient() LocalDockerClient {
	return LocalDockerClient{docker_registry.NewClient()}
}

func newLocalDiskStateManager(c LocalSousConfig) *storage.DiskStateManager {
	return storage.NewDiskStateManager(c.StateLocation)
}

func newLocalStateReader(sm *storage.DiskStateManager) LocalStateReader {
	return LocalStateReader{sm}
}

func newLocalStateWriter(sm *storage.DiskStateManager) LocalStateWriter {
	return LocalStateWriter{sm}
}

func newCurrentState(sr LocalStateReader) (*sous.State, error) {
	state, err := sr.ReadState()
	if os.IsNotExist(err) {
		log.Println("error reading state:", err)
		log.Println("defaulting to empty state")
		return sous.NewState(), nil
	}
	return state, initErr(err, "reading sous state")
}

func newCurrentGDM(state *sous.State) (CurrentGDM, error) {
	deployments, err := state.Deployments()
	if err != nil {
		return CurrentGDM{}, initErr(err, "expanding state")
	}
	return CurrentGDM{deployments}, initErr(err, "expanding state")
}

// The funcs named makeXXX below are used to create specific implementations of
// sous native types.

// makeDockerRegistry creates a Docker version of sous.Registry
func makeDockerRegistry(cfg LocalSousConfig, cl LocalDockerClient) (*docker.NameCache, error) {
	dbCfg := cfg.Docker.DBConfig()
	db, err := docker.GetDatabase(&dbCfg)
	if err != nil {
		return nil, errors.Wrap(err, "building name cache DB")
	}
	return docker.NewNameCache(cl.Client, db), nil
}

// initErr returns nil if error is nil, otherwise an initialisation error.
// The second argument "what" should be a very short description of the
// initialisation task, e.g. "getting widget" or "reading state" etc.
func initErr(err error, what string) error {
	if err == nil {
		return nil
	}
	message := fmt.Sprintf("error %s:", what)
	if shellErr, ok := err.(shell.Error); ok {
		message += fmt.Sprintf("\ncommand failed:\nshell> %s\n%s",
			shellErr.Command.String(), shellErr.Result.Combined.String())
	} else {
		message += " " + err.Error()
	}
	return fmt.Errorf(message)
}
<commit_msg>Tidy up comments and whitespace.<commit_after>package cli

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/user"

	"github.com/opentable/sous/ext/docker"
	"github.com/opentable/sous/ext/git"
	"github.com/opentable/sous/ext/singularity"
	"github.com/opentable/sous/ext/storage"
	"github.com/opentable/sous/lib"
	"github.com/opentable/sous/util/cmdr"
	"github.com/opentable/sous/util/docker_registry"
	"github.com/opentable/sous/util/shell"
	"github.com/pkg/errors"
	"github.com/samsalisbury/psyringe"
	"github.com/samsalisbury/semv"
)

type (
	// Out is an output used for real data a Command returns. This should only
	// be used when a command needs to write directly to stdout, using the
	// formatting options that come with an output. Usually, you should use a
	// SuccessResult with Data to return data.
	Out struct{ *cmdr.Output }
	// ErrOut is an output used for logging from a Command. This should only be
	// used when a Command needs to write a lot of data to stderr, using the
	// formatting options that come with and Output. Usually you should use and
	// ErrorResult to return error messages.
	ErrOut struct{ *cmdr.Output }
	// SousCLIGraph is a dependency injector used to flesh out Sous commands
	// with their dependencies.
	SousCLIGraph struct{ *psyringe.Psyringe }
	// OutWriter is typically set to os.Stdout.
	OutWriter io.Writer
	// ErrWriter is typically set to os.Stderr.
	ErrWriter io.Writer
	// StateReader knows how to read state.
	StateReader interface {
		ReadState() (*sous.State, error)
	}
	// StateWriter knows how to write state.
	StateWriter interface {
		WriteState(*sous.State) error
	}
	// Version represents a version of Sous.
	Version struct{ semv.Version }
	// LocalUser is the currently logged in user.
	LocalUser struct{ *User }
	// LocalSousConfig is the configuration for Sous.
	LocalSousConfig struct{ *Config }
	// LocalWorkDir is the user's current working directory when they invoke Sous.
	LocalWorkDir string
	// LocalWorkDirShell is a shell for working in the user's current working
	// directory.
	LocalWorkDirShell struct{ *shell.Sh }
	// LocalGitClient is a git client rooted in WorkdirShell.Dir.
	LocalGitClient struct{ *git.Client }
	// LocalGitRepo is the git repository containing WorkDir.
	LocalGitRepo struct{ *git.Repo }
	// GitSourceContext is the source context according to the local git repo.
	GitSourceContext struct{ *sous.SourceContext }
	// ScratchDirShell is a shell for working in the scratch area where things
	// like artefacts, and build metadata are stored. It is a new, empty
	// directory, and should be cleaned up eventually.
	ScratchDirShell struct{ *shell.Sh }
	// LocalDockerClient is a docker client object
	LocalDockerClient struct{ docker_registry.Client }
	// LocalStateReader wraps a storage.StateReader, and should be configured
	// to use the current user's local storage.
	LocalStateReader struct{ StateReader }
	// LocalStateWriter wraps a storage.StateWriter, and should be configured to
	// use the current user's local storage.
	LocalStateWriter struct{ StateWriter }
	// CurrentGDM is a snapshot of the GDM at application start. In a CLI
	// context, which this is, that is all we need to simply read the GDM.
	CurrentGDM struct{ sous.Deployments }
	// TargetManifest is a specific manifest for the current SourceLocation.
	// If the named manifest does not exist, it is created.
	TargetManifest struct{ *sous.Manifest }
	// DetectedOTPLDeploySpecs is a set of otpl-deploy configured deployments
	// that have been detected.
	DetectedOTPLDeploySpecs struct{ sous.DeploySpecs }
	// UserSelectedOTPLDeploySpecs is a set of otpl-deploy configured deploy
	// specs that the user has explicitly selected. (May be empty.)
	UserSelectedOTPLDeploySpecs struct{ sous.DeploySpecs }
	// TargetManifestID is the manifest ID being targeted, after resolving all
	// context and flags.
	TargetManifestID sous.ManifestID
)

// BuildGraph builds the dependency injection graph, used to populate commands
// invoked by the user.
func BuildGraph(c *CLI, out, err io.Writer) *SousCLIGraph {
	return &SousCLIGraph{psyringe.New(
		c,
		func() OutWriter { return out },
		func() ErrWriter { return err },
		newOut,
		newErrOut,
		newLogSet,
		newLocalUser,
		newLocalSousConfig,
		newLocalWorkDir,
		newLocalWorkDirShell,
		newScratchDirShell,
		newLocalGitClient,
		newLocalGitRepo,
		newGitSourceContext,
		newSourceContext,
		newBuildContext,
		newBuildConfig,
		newBuildManager,
		newDockerClient,
		newDockerBuilder,
		newSelector,
		newLabeller,
		newRegistrar,
		newDeployer,
		newRegistry,
		newRegistryDumper,
		newLocalDiskStateManager,
		newLocalStateReader,
		newLocalStateWriter,
		newCurrentGDM,
		newCurrentState,
		newTargetManifest,
		newDetectedOTPLConfig,
		newUserSelectedOTPLDeploySpecs,
		newTargetManifestID,
	)}
}

func newOut(c *CLI) Out {
	return Out{c.Out}
}

func newErrOut(c *CLI) ErrOut {
	return ErrOut{c.Err}
}

func newRegistryDumper(r sous.Registry) *sous.RegistryDumper {
	return sous.NewRegistryDumper(r)
}

func newLogSet(s *Sous, err ErrWriter) *sous.LogSet { // XXX temporary until we settle on logging
	if s.flags.Verbosity.Debug {
		if s.flags.Verbosity.Loud {
			sous.Log.Vomit.SetOutput(err)
		}
		sous.Log.Debug.SetOutput(err)
		sous.Log.Info.SetOutput(err)

	}
	if s.flags.Verbosity.Loud {
		sous.Log.Info.SetOutput(err)
	}
	if s.flags.Verbosity.Quiet {
	}
	if s.flags.Verbosity.Silent {
	}

	sous.Log.Vomit.Println("Verbose debugging enabled")
	sous.Log.Debug.Println("Regular debugging enabled")
	return &sous.Log
}

func newGitSourceContext(g LocalGitRepo) (GitSourceContext, error) {
	c, err := g.SourceContext()
	return GitSourceContext{c}, initErr(err, "getting local git context")
}

func newSourceContext(f *DeployFilterFlags, g GitSourceContext) (*sous.SourceContext, error) {
	c := g.SourceContext
	if c == nil {
		c = &sous.SourceContext{}
	}
	mid, err := newTargetManifestID(f, c)
	if err != nil {
		return nil, errors.Wrapf(err, "getting source location")
	}
	sl := sous.ManifestID(mid)
	if sl.Source.Repo != c.SourceLocation().Repo {
		// TODO: Clone the repository, and use the cloned dir as source context.
		return nil, errors.Errorf("source location %q is not the same as the remote %q",
			sl.Source.Repo, c.SourceLocation().Repo)
	}
	return c, nil
}

func newBuildContext(wd LocalWorkDirShell, c *sous.SourceContext) *sous.BuildContext {
	return &sous.BuildContext{Sh: wd.Sh, Source: *c}
}

func newBuildConfig(f *DeployFilterFlags, p *PolicyFlags, bc *sous.BuildContext) *sous.BuildConfig {
	cfg := sous.BuildConfig{
		Repo:       f.Repo,
		Offset:     f.Offset,
		Tag:        f.Tag,
		Revision:   f.Revision,
		Strict:     p.Strict,
		ForceClone: p.ForceClone,
		Context:    bc,
	}

	return &cfg
}

func newBuildManager(bc *sous.BuildConfig, sl sous.Selector, lb sous.Labeller, rg sous.Registrar) *sous.BuildManager {
	mgr := &sous.BuildManager{
		BuildConfig: bc,
		Selector:    sl,
		Labeller:    lb,
		Registrar:   rg,
	}
	return mgr
}

func newLocalUser() (v LocalUser, err error) {
	u, err := user.Current()
	v.User = &User{u}
	return v, initErr(err, "getting current user")
}

func newLocalSousConfig(u LocalUser) (v LocalSousConfig, err error) {
	v.Config, err = newConfig(u.User.ConfigFile(), u.DefaultConfig())
	return v, initErr(err, "getting configuration")
}

// TODO: This should register a cleanup task with the cli, to delete the temp
// dir.
func newScratchDirShell() (v ScratchDirShell, err error) {
	const what = "getting scratch directory"
	dir, err := ioutil.TempDir("", "sous")
	if err != nil {
		return v, initErr(err, what)
	}
	v.Sh, err = shell.DefaultInDir(dir)
	v.TeeOut = os.Stdout
	v.TeeErr = os.Stderr
	return v, initErr(err, what)
}

func newLocalWorkDir() (LocalWorkDir, error) {
	s, err := os.Getwd()
	return LocalWorkDir(s), initErr(err, "determining working directory")
}

func newLocalWorkDirShell(l LocalWorkDir) (v LocalWorkDirShell, err error) {
	v.Sh, err = shell.DefaultInDir(string(l))
	v.TeeEcho = os.Stdout
	//v.TeeOut = os.Stdout
	//v.TeeErr = os.Stderr
	return v, initErr(err, "getting current working directory")
}

func newLocalGitClient(sh LocalWorkDirShell) (v LocalGitClient, err error) {
	v.Client, err = git.NewClient(sh.Sh)
	return v, initErr(err, "initialising git client")
}

func newLocalGitRepo(c LocalGitClient) (v LocalGitRepo, err error) {
	v.Repo, err = c.OpenRepo(".")
	return v, initErr(err, "opening local git repository")
}

func newSelector() sous.Selector {
	return &sous.EchoSelector{
		Factory: func(*sous.BuildContext) (sous.Buildpack, error) {
			return docker.NewDockerfileBuildpack(), nil
		},
	}
}

func newDockerBuilder(cfg LocalSousConfig, cl LocalDockerClient, ctx *sous.SourceContext, source LocalWorkDirShell, scratch ScratchDirShell) (*docker.Builder, error) {
	nc, err := makeDockerRegistry(cfg, cl)
	if err != nil {
		return nil, err
	}
	drh := cfg.Docker.RegistryHost
	return docker.NewBuilder(nc, drh, source.Sh, scratch.Sh)
}

func newLabeller(db *docker.Builder) sous.Labeller {
	return db
}

func newRegistrar(db *docker.Builder) sous.Registrar {
	return db
}

func newRegistry(cfg LocalSousConfig, cl LocalDockerClient) (sous.Registry, error) {
	return makeDockerRegistry(cfg, cl)
}
func newDeployer(r sous.Registry) sous.Deployer {
	// Eventually, based on configuration, we may make different decisions here.
	return singularity.NewDeployer(r, singularity.NewRectiAgent(r))
}

func newDockerClient() LocalDockerClient {
	return LocalDockerClient{docker_registry.NewClient()}
}

func newLocalDiskStateManager(c LocalSousConfig) *storage.DiskStateManager {
	return storage.NewDiskStateManager(c.StateLocation)
}

func newLocalStateReader(sm *storage.DiskStateManager) LocalStateReader {
	return LocalStateReader{sm}
}

func newLocalStateWriter(sm *storage.DiskStateManager) LocalStateWriter {
	return LocalStateWriter{sm}
}

func newCurrentState(sr LocalStateReader) (*sous.State, error) {
	state, err := sr.ReadState()
	if os.IsNotExist(err) {
		log.Println("error reading state:", err)
		log.Println("defaulting to empty state")
		return sous.NewState(), nil
	}
	return state, initErr(err, "reading sous state")
}

func newCurrentGDM(state *sous.State) (CurrentGDM, error) {
	deployments, err := state.Deployments()
	if err != nil {
		return CurrentGDM{}, initErr(err, "expanding state")
	}
	return CurrentGDM{deployments}, initErr(err, "expanding state")
}

// The funcs named makeXXX below are used to create specific implementations of
// sous native types.

// makeDockerRegistry creates a Docker version of sous.Registry
func makeDockerRegistry(cfg LocalSousConfig, cl LocalDockerClient) (*docker.NameCache, error) {
	dbCfg := cfg.Docker.DBConfig()
	db, err := docker.GetDatabase(&dbCfg)
	if err != nil {
		return nil, errors.Wrap(err, "building name cache DB")
	}
	return docker.NewNameCache(cl.Client, db), nil
}

// initErr returns nil if error is nil, otherwise an initialisation error.
// The second argument "what" should be a very short description of the
// initialisation task, e.g. "getting widget" or "reading state" etc.
func initErr(err error, what string) error {
	if err == nil {
		return nil
	}
	message := fmt.Sprintf("error %s:", what)
	if shellErr, ok := err.(shell.Error); ok {
		message += fmt.Sprintf("\ncommand failed:\nshell> %s\n%s",
			shellErr.Command.String(), shellErr.Result.Combined.String())
	} else {
		message += " " + err.Error()
	}
	return fmt.Errorf(message)
}
<|endoftext|>


<commit_before>// Copyright © 2016 Geoff Holden <geoff@geoffholden.com>

package data

import (
	"database/sql"

	_ "github.com/mattn/go-sqlite3" // Load SQLite DB driver
)

type sqlite_driver struct {
}

func init() {
	RegisterDBDriver("sqlite", sqlite_driver{})
}

func (sqlite sqlite_driver) OpenDatabase(db *sql.DB) error {
	_, err := db.Exec(`
	CREATE TABLE IF NOT EXISTS samples (
		timestamp   integer,
		id          text,
		channel     integer,
		serial      string,
		key         string,
		min         real,
		max         real,
		avg         real
	)`)
	if err != nil {
		db.Close()
		return err
	}

	return nil
}

func (sqlite sqlite_driver) Close(db *sql.DB) {
}

func (sqlite sqlite_driver) InsertRow(db *sql.DB, timestamp int64, id string, channel int, serial string, key string, min float64, max float64, avg float64) error {
	stmt := `INSERT INTO samples (
		timestamp,
		id,
		channel,
		serial,
		key,
		min, max, avg
	) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`

	_, err := db.Exec(stmt, timestamp, id, channel, serial, key, min, max, avg)
	return err
}

func (sqlite sqlite_driver) QueryWind(db *sql.DB, start int64) (*sql.Rows, error) {
	stmt := `SELECT
			(((dir.avg + 5.125 + 360) % 360) / 11.25) % 32 AS dir,
			max(gust.max),
			avg(avg.avg)
		FROM samples dir
		INNER JOIN samples gust
			ON gust.timestamp = dir.timestamp
		INNER JOIN samples avg
			ON avg.timestamp = gust.timestamp
		WHERE dir.key = 'WindDir'
			AND gust.key = 'CurrentWind'
			AND avg.key = 'AverageWind'
			AND dir.timestamp > ?
		GROUP BY dir;`
	return db.Query(stmt, start)
}

func (sqlite sqlite_driver) QueryFirst(db *sql.DB, start int64, key string, id string, channel int) (float64, error) {
	stmt := `SELECT
		avg FROM samples
		WHERE
			key = ? AND
			id LIKE ? AND
			channel = ? AND
			timestamp > ?
		ORDER BY timestamp
		LIMIT 1`
	row := db.QueryRow(stmt, key, id, channel, start)
	var result float64
	err := row.Scan(&result)

	return result, err
}

func (sqlite sqlite_driver) QueryLast(db *sql.DB, start int64, key string, id string, channel int) (float64, error) {
	stmt := `SELECT
		avg FROM samples
		WHERE
			key = ? AND
			id LIKE ? AND
			channel = ? AND
			timestamp > ?
		ORDER BY timestamp DESC
		LIMIT 1`
	row := db.QueryRow(stmt, key, id, channel, start)
	var result float64
	err := row.Scan(&result)

	return result, err
}

func (sqlite sqlite_driver) QueryRows(db *sql.DB, start int64, key string, id string) (*sql.Rows, error) {
	stmt := `SELECT timestamp,min,max,avg FROM samples
		WHERE
			key = ? AND
			id LIKE ? AND
			timestamp > ?
		ORDER BY timestamp`
	return db.Query(stmt, key, id, start)
}

func (sqlite sqlite_driver) QueryRowsInterval(db *sql.DB, start int64, key string, id string, interval int64) (*sql.Rows, error) {
	stmt := `SELECT
			CAST(timestamp/? as INTEGER) * ? as ts,
			MIN(min),
			MAX(max),
			AVG(avg)
		FROM samples
		WHERE
			key = ? AND
			id LIKE ? AND
			timestamp > ?
		ORDER BY timestamp`
	return db.Query(stmt, interval, interval, key, id, start)
}
<commit_msg>Rename driver to sqlite3<commit_after>// Copyright © 2016 Geoff Holden <geoff@geoffholden.com>

package data

import (
	"database/sql"

	_ "github.com/mattn/go-sqlite3" // Load SQLite DB driver
)

type sqlite_driver struct {
}

func init() {
	RegisterDBDriver("sqlite3", sqlite_driver{})
}

func (sqlite sqlite_driver) OpenDatabase(db *sql.DB) error {
	_, err := db.Exec(`
	CREATE TABLE IF NOT EXISTS samples (
		timestamp   integer,
		id          text,
		channel     integer,
		serial      string,
		key         string,
		min         real,
		max         real,
		avg         real
	)`)
	if err != nil {
		db.Close()
		return err
	}

	return nil
}

func (sqlite sqlite_driver) Close(db *sql.DB) {
}

func (sqlite sqlite_driver) InsertRow(db *sql.DB, timestamp int64, id string, channel int, serial string, key string, min float64, max float64, avg float64) error {
	stmt := `INSERT INTO samples (
		timestamp,
		id,
		channel,
		serial,
		key,
		min, max, avg
	) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`

	_, err := db.Exec(stmt, timestamp, id, channel, serial, key, min, max, avg)
	return err
}

func (sqlite sqlite_driver) QueryWind(db *sql.DB, start int64) (*sql.Rows, error) {
	stmt := `SELECT
			(((dir.avg + 5.125 + 360) % 360) / 11.25) % 32 AS dir,
			max(gust.max),
			avg(avg.avg)
		FROM samples dir
		INNER JOIN samples gust
			ON gust.timestamp = dir.timestamp
		INNER JOIN samples avg
			ON avg.timestamp = gust.timestamp
		WHERE dir.key = 'WindDir'
			AND gust.key = 'CurrentWind'
			AND avg.key = 'AverageWind'
			AND dir.timestamp > ?
		GROUP BY dir;`
	return db.Query(stmt, start)
}

func (sqlite sqlite_driver) QueryFirst(db *sql.DB, start int64, key string, id string, channel int) (float64, error) {
	stmt := `SELECT
		avg FROM samples
		WHERE
			key = ? AND
			id LIKE ? AND
			channel = ? AND
			timestamp > ?
		ORDER BY timestamp
		LIMIT 1`
	row := db.QueryRow(stmt, key, id, channel, start)
	var result float64
	err := row.Scan(&result)

	return result, err
}

func (sqlite sqlite_driver) QueryLast(db *sql.DB, start int64, key string, id string, channel int) (float64, error) {
	stmt := `SELECT
		avg FROM samples
		WHERE
			key = ? AND
			id LIKE ? AND
			channel = ? AND
			timestamp > ?
		ORDER BY timestamp DESC
		LIMIT 1`
	row := db.QueryRow(stmt, key, id, channel, start)
	var result float64
	err := row.Scan(&result)

	return result, err
}

func (sqlite sqlite_driver) QueryRows(db *sql.DB, start int64, key string, id string) (*sql.Rows, error) {
	stmt := `SELECT timestamp,min,max,avg FROM samples
		WHERE
			key = ? AND
			id LIKE ? AND
			timestamp > ?
		ORDER BY timestamp`
	return db.Query(stmt, key, id, start)
}

func (sqlite sqlite_driver) QueryRowsInterval(db *sql.DB, start int64, key string, id string, interval int64) (*sql.Rows, error) {
	stmt := `SELECT
			CAST(timestamp/? as INTEGER) * ? as ts,
			MIN(min),
			MAX(max),
			AVG(avg)
		FROM samples
		WHERE
			key = ? AND
			id LIKE ? AND
			timestamp > ?
		ORDER BY timestamp`
	return db.Query(stmt, interval, interval, key, id, start)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"log"
	"sort"
	"strings"

	"github.com/couchbaselabs/go-couchbase"
)

var ddocs = map[string]string{
	"jenkins": `{
		"views": {
			"by_build": {
				"map": "function (doc, meta) {emit([doc.build, doc.priority, doc.os], [doc.failCount, doc.totalCount]);}"
			}
		}
	}`,
}

type DataSource struct {
	CouchbaseAddress string
}

func (ds *DataSource) GetBucket(bucket string) *couchbase.Bucket {
	client, _ := couchbase.Connect(ds.CouchbaseAddress)
	pool, _ := client.GetPool("default")

	b, err := pool.GetBucket(bucket)
	if err != nil {
		log.Fatalf("Error reading bucket:  %v", err)
	}
	return b
}

func (ds *DataSource) QueryView(b *couchbase.Bucket, ddoc, view string,
	params map[string]interface{}) []couchbase.ViewRow {
	params["stale"] = "false"
	vr, err := b.View(ddoc, view, params)
	if err != nil {
		ds.installDDoc(ddoc)
	}
	return vr.Rows
}

func (ds *DataSource) installDDoc(ddoc string) {
	b := ds.GetBucket(ddoc) // bucket name == ddoc name
	err := b.PutDDoc(ddoc, ddocs[ddoc])
	if err != nil {
		log.Fatalf("%v", err)
	}
}

func (ds *DataSource) GetTimeline(abs bool) []byte {
	b := ds.GetBucket("jenkins")
	rows := ds.QueryView(b, "jenkins", "by_build", map[string]interface{}{})

	failed := map[string]float64{}
	total := map[string]float64{}
	builds := []string{}
	for i := range rows {
		build := rows[i].Key.([]interface{})[0].(string)
		failCount := rows[i].Value.([]interface{})[0].(float64)
		totalCount := rows[i].Value.([]interface{})[1].(float64)
		if _, ok := failed[build]; ok {
			failed[build] += failCount
		} else {
			failed[build] = failCount
		}
		if _, ok := total[build]; ok {
			total[build] += totalCount
		} else {
			total[build] = totalCount
		}
		builds = append(builds, build)
	}

	passedValues := []interface{}{}
	failedValues := []interface{}{}
	sort.Strings(builds)
	if abs {
		for _, build := range builds {
			passedValues = append(passedValues, []interface{}{
				build,
				total[build] - failed[build],
			})
			failedValues = append(failedValues, []interface{}{
				build,
				-failed[build],
			})
		}
	} else {
		for _, build := range builds {
			passedValues = append(passedValues, []interface{}{
				build,
				100.0 * (total[build] - failed[build]) / total[build],
			})
			failedValues = append(failedValues, []interface{}{
				build,
				100.0 * failed[build] / total[build],
			})
		}
	}

	timeline := []map[string]interface{}{
		map[string]interface{}{"key": "Passed", "values": passedValues},
		map[string]interface{}{"key": "Failed", "values": failedValues},
	}
	j, _ := json.Marshal(timeline)
	return j
}

func appendIfUnique(slice []string, s string) []string {
	for i := range slice {
		if slice[i] == s {
			return slice
		}
	}
	return append(slice, s)
}

func (ds *DataSource) GetBreakdown(build string, by_platform bool) []byte {
	b := ds.GetBucket("jenkins")
	params := map[string]interface{}{"startkey": []string{build}}
	rows := ds.QueryView(b, "jenkins", "by_build", params)

	keys := []string{}
	failed := map[string]float64{}
	total := map[string]float64{}
	for i := range rows {
		var key string
		if by_platform {
			key = rows[i].Key.([]interface{})[2].(string)
		} else {
			key = rows[i].Key.([]interface{})[1].(string)
		}
		if key == "N/A" {
			continue
		}

		failCount := rows[i].Value.([]interface{})[0].(float64)
		totalCount := rows[i].Value.([]interface{})[1].(float64)
		if _, ok := failed[key]; ok {
			failed[key] += failCount
		} else {
			failed[key] = failCount
		}
		if _, ok := total[key]; ok {
			total[key] += totalCount
		} else {
			total[key] = totalCount
		}
		keys = appendIfUnique(keys, key)
	}

	sort.Strings(keys)
	data := map[string]interface{}{}
	for _, key := range keys {
		title := strings.Title(strings.ToLower(key))
		data[title] = []map[string]interface{}{
			{"key": "Passed", "value": total[key] - failed[key]},
			{"key": "Failed", "value": failed[key]},
		}
	}

	j, _ := json.Marshal(data)
	return j
}
<commit_msg>custom timeline legend<commit_after>package main

import (
	"encoding/json"
	"log"
	"sort"
	"strings"

	"github.com/couchbaselabs/go-couchbase"
)

var ddocs = map[string]string{
	"jenkins": `{
		"views": {
			"by_build": {
				"map": "function (doc, meta) {emit([doc.build, doc.priority, doc.os], [doc.failCount, doc.totalCount]);}"
			}
		}
	}`,
}

type DataSource struct {
	CouchbaseAddress string
}

func (ds *DataSource) GetBucket(bucket string) *couchbase.Bucket {
	client, _ := couchbase.Connect(ds.CouchbaseAddress)
	pool, _ := client.GetPool("default")

	b, err := pool.GetBucket(bucket)
	if err != nil {
		log.Fatalf("Error reading bucket:  %v", err)
	}
	return b
}

func (ds *DataSource) QueryView(b *couchbase.Bucket, ddoc, view string,
	params map[string]interface{}) []couchbase.ViewRow {
	params["stale"] = "false"
	vr, err := b.View(ddoc, view, params)
	if err != nil {
		ds.installDDoc(ddoc)
	}
	return vr.Rows
}

func (ds *DataSource) installDDoc(ddoc string) {
	b := ds.GetBucket(ddoc) // bucket name == ddoc name
	err := b.PutDDoc(ddoc, ddocs[ddoc])
	if err != nil {
		log.Fatalf("%v", err)
	}
}

func (ds *DataSource) GetTimeline(abs bool) []byte {
	b := ds.GetBucket("jenkins")
	rows := ds.QueryView(b, "jenkins", "by_build", map[string]interface{}{})

	failed := map[string]float64{}
	total := map[string]float64{}
	builds := []string{}
	for i := range rows {
		build := rows[i].Key.([]interface{})[0].(string)
		failCount := rows[i].Value.([]interface{})[0].(float64)
		totalCount := rows[i].Value.([]interface{})[1].(float64)
		if _, ok := failed[build]; ok {
			failed[build] += failCount
		} else {
			failed[build] = failCount
		}
		if _, ok := total[build]; ok {
			total[build] += totalCount
		} else {
			total[build] = totalCount
		}
		builds = append(builds, build)
	}

	timeline := []map[string]interface{}{}
	passedValues := []interface{}{}
	failedValues := []interface{}{}
	sort.Strings(builds)
	if abs {
		for _, build := range builds {
			passedValues = append(passedValues, []interface{}{
				build,
				total[build] - failed[build],
			})
			failedValues = append(failedValues, []interface{}{
				build,
				-failed[build],
			})
		}
		timeline = append(timeline,
			map[string]interface{}{"key": "Passed", "values": passedValues})
		timeline = append(timeline,
			map[string]interface{}{"key": "Failed", "values": failedValues})
	} else {
		for _, build := range builds {
			passedValues = append(passedValues, []interface{}{
				build,
				100.0 * (total[build] - failed[build]) / total[build],
			})
			failedValues = append(failedValues, []interface{}{
				build,
				100.0 * failed[build] / total[build],
			})
		}
		timeline = append(timeline,
			map[string]interface{}{"key": "Passed, %", "values": passedValues})
		timeline = append(timeline,
			map[string]interface{}{"key": "Failed, %", "values": failedValues})
	}

	j, _ := json.Marshal(timeline)
	return j
}

func appendIfUnique(slice []string, s string) []string {
	for i := range slice {
		if slice[i] == s {
			return slice
		}
	}
	return append(slice, s)
}

func (ds *DataSource) GetBreakdown(build string, by_platform bool) []byte {
	b := ds.GetBucket("jenkins")
	params := map[string]interface{}{"startkey": []string{build}}
	rows := ds.QueryView(b, "jenkins", "by_build", params)

	keys := []string{}
	failed := map[string]float64{}
	total := map[string]float64{}
	for i := range rows {
		var key string
		if by_platform {
			key = rows[i].Key.([]interface{})[2].(string)
		} else {
			key = rows[i].Key.([]interface{})[1].(string)
		}
		if key == "N/A" {
			continue
		}

		failCount := rows[i].Value.([]interface{})[0].(float64)
		totalCount := rows[i].Value.([]interface{})[1].(float64)
		if _, ok := failed[key]; ok {
			failed[key] += failCount
		} else {
			failed[key] = failCount
		}
		if _, ok := total[key]; ok {
			total[key] += totalCount
		} else {
			total[key] = totalCount
		}
		keys = appendIfUnique(keys, key)
	}

	sort.Strings(keys)
	data := map[string]interface{}{}
	for _, key := range keys {
		title := strings.Title(strings.ToLower(key))
		data[title] = []map[string]interface{}{
			{"key": "Passed", "value": total[key] - failed[key]},
			{"key": "Failed", "value": failed[key]},
		}
	}

	j, _ := json.Marshal(data)
	return j
}
<|endoftext|>


<commit_before>package builtin

import (
	"github.com/oleiade/lane"
	"log"
	"math/rand"
	"strconv"
	"sync"
	"time"

	flow "github.com/wanliu/goflow"
)

func NewFinal() interface{} {
	return new(Final)
}

type Final struct {
	sync.RWMutex

	flow.Component

	ReplyQueue *lane.Queue

	delayMin int
	delayMax int

	In       <-chan ReplyData
	DelayMin <-chan float64
	DelayMax <-chan float64
}

func (s *Final) Init() {
	s.ReplyQueue = lane.NewQueue()
}

func (s *Final) OnIn(data ReplyData) {
	s.Lock()
	s.ReplyQueue.Enqueue(data)
	s.Unlock()

	s.SendReply()
}

func (s *Final) OnDelayMin(min float64) {
	s.delayMin = int(min)
}

func (s *Final) OnDelayMax(max float64) {
	s.delayMax = int(max)
}

func (s Final) DelayRange() int {
	rand.Seed(time.Now().UnixNano())

	if s.delayMin == 0 {
		return 3 + rand.Intn(2)
	} else {
		if s.delayMax > s.delayMin {
			return s.delayMin + rand.Intn(s.delayMax-s.delayMin)
		} else {
			return s.delayMin + rand.Intn(3)
		}
	}
}

func (s *Final) SendReply() {
	// secs := s.DelayRange()
	secs := 3

	s.RLock()
	for s.ReplyQueue.Head() != nil {
		data := s.ReplyQueue.Dequeue().(ReplyData)

		log.Printf("[Delay]Delay reply for " + strconv.Itoa(secs) + " seconds.")
		time.Sleep(time.Second * time.Duration(secs))

		data.Ctx.Post(data.Reply)
	}
	s.RUnlock()
}
<commit_msg>remove 3 ses delay<commit_after>package builtin

import (
	"github.com/oleiade/lane"
	// "log"
	"math/rand"
	// "strconv"
	"sync"
	"time"

	flow "github.com/wanliu/goflow"
)

func NewFinal() interface{} {
	return new(Final)
}

type Final struct {
	sync.RWMutex

	flow.Component

	ReplyQueue *lane.Queue

	delayMin int
	delayMax int

	In       <-chan ReplyData
	DelayMin <-chan float64
	DelayMax <-chan float64
}

func (s *Final) Init() {
	s.ReplyQueue = lane.NewQueue()
}

func (s *Final) OnIn(data ReplyData) {
	s.Lock()
	s.ReplyQueue.Enqueue(data)
	s.Unlock()

	s.SendReply()
}

func (s *Final) OnDelayMin(min float64) {
	s.delayMin = int(min)
}

func (s *Final) OnDelayMax(max float64) {
	s.delayMax = int(max)
}

func (s Final) DelayRange() int {
	rand.Seed(time.Now().UnixNano())

	if s.delayMin == 0 {
		return 3 + rand.Intn(2)
	} else {
		if s.delayMax > s.delayMin {
			return s.delayMin + rand.Intn(s.delayMax-s.delayMin)
		} else {
			return s.delayMin + rand.Intn(3)
		}
	}
}

func (s *Final) SendReply() {
	// secs := s.DelayRange()
	// secs := 3

	s.RLock()
	for s.ReplyQueue.Head() != nil {
		data := s.ReplyQueue.Dequeue().(ReplyData)

		// log.Printf("[Delay]Delay reply for " + strconv.Itoa(secs) + " seconds.")
		// time.Sleep(time.Second * time.Duration(secs))

		data.Ctx.Post(data.Reply)
	}
	s.RUnlock()
}
<|endoftext|>


<commit_before>package builtin

import (
	// "log"

	"github.com/wanliu/flow/builtin/config"
	"github.com/wanliu/flow/builtin/resolves"
	"github.com/wanliu/flow/context"
)

type Order struct {
	TryGetEntities

	expMins        float64
	OrderSyncQueue string

	Ctx           <-chan context.Context
	ExpireMinutes <-chan float64
	New           chan<- context.Context
	Patch         chan<- context.Context
	Out           chan<- ReplyData
	SyncQueue     <-chan string
}

func GetOrder() interface{} {
	return new(Order)
}

func (c *Order) OnSyncQueue(queue string) {
	c.OrderSyncQueue = queue
}

func (c *Order) OnCtx(ctx context.Context) {
	if GroupChat(ctx) {
		c.New <- ctx
		return
	}

	currentOrder := ctx.Value(config.CtxKeyOrder)

	if c.expMins != 0 {
		ctx.SetValue(config.CtxKeyExpiredMinutes, int(c.expMins))
	}

	if c.OrderSyncQueue != "" {
		ctx.SetValue(config.CtxKeySyncQueue, c.OrderSyncQueue)
	}

	if nil != currentOrder {
		cOrder := currentOrder.(resolves.OrderResolve)

		exMin := config.SesssionExpiredMinutes

		if c.expMins != 0 {
			exMin = int(c.expMins)
		}

		if cOrder.Modifable(exMin) {
			c.Patch <- ctx
		} else {
			c.New <- ctx
		}
	} else {
		c.New <- ctx
	}
}

func (c *Order) OnExpireMinutes(minutes float64) {
	c.expMins = minutes
}
<commit_msg>fix order sync queue<commit_after>package builtin

import (
	// "log"

	"github.com/wanliu/flow/builtin/config"
	"github.com/wanliu/flow/builtin/resolves"
	"github.com/wanliu/flow/context"
)

type Order struct {
	TryGetEntities

	expMins        float64
	OrderSyncQueue string

	Ctx           <-chan context.Context
	ExpireMinutes <-chan float64
	New           chan<- context.Context
	Patch         chan<- context.Context
	Out           chan<- ReplyData
	SyncQueue     <-chan string
}

func GetOrder() interface{} {
	return new(Order)
}

func (c *Order) OnSyncQueue(queue string) {
	c.OrderSyncQueue = queue
}

func (c *Order) OnCtx(ctx context.Context) {
	if c.OrderSyncQueue != "" {
		ctx.SetValue(config.CtxKeySyncQueue, c.OrderSyncQueue)
	}

	if c.expMins != 0 {
		ctx.SetValue(config.CtxKeyExpiredMinutes, int(c.expMins))
	}

	if GroupChat(ctx) {
		c.New <- ctx
		return
	}

	currentOrder := ctx.Value(config.CtxKeyOrder)

	if nil != currentOrder {
		cOrder := currentOrder.(resolves.OrderResolve)

		exMin := config.SesssionExpiredMinutes

		if c.expMins != 0 {
			exMin = int(c.expMins)
		}

		if cOrder.Modifable(exMin) {
			c.Patch <- ctx
		} else {
			c.New <- ctx
		}
	} else {
		c.New <- ctx
	}
}

func (c *Order) OnExpireMinutes(minutes float64) {
	c.expMins = minutes
}
<|endoftext|>


<commit_before>package execute

import (
	"fmt"

	"github.com/influxdata/platform/query"
	"github.com/influxdata/platform/query/interpreter"
	"github.com/influxdata/platform/query/semantic"
	"github.com/pkg/errors"
)

type aggregateTransformation struct {
	d     Dataset
	cache TableBuilderCache
	agg   Aggregate

	config AggregateConfig
}

type AggregateConfig struct {
	Columns []string `json:"columns"`
	TimeSrc string   `json:"time_src"`
	TimeDst string   `json:"time_dst"`
}

var DefaultAggregateConfig = AggregateConfig{
	Columns: []string{DefaultValueColLabel},
	TimeSrc: DefaultStopColLabel,
	TimeDst: DefaultTimeColLabel,
}

func (c AggregateConfig) Copy() AggregateConfig {
	nc := c
	if c.Columns != nil {
		nc.Columns = make([]string, len(c.Columns))
		copy(nc.Columns, c.Columns)
	}
	return nc
}

func (c *AggregateConfig) ReadArgs(args query.Arguments) error {
	if label, ok, err := args.GetString("timeDst"); err != nil {
		return err
	} else if ok {
		c.TimeDst = label
	} else {
		c.TimeDst = DefaultAggregateConfig.TimeDst
	}

	if timeValue, ok, err := args.GetString("timeSrc"); err != nil {
		return err
	} else if ok {
		c.TimeSrc = timeValue
	} else {
		c.TimeSrc = DefaultAggregateConfig.TimeSrc
	}

	if cols, ok, err := args.GetArray("columns", semantic.String); err != nil {
		return err
	} else if ok {
		columns, err := interpreter.ToStringArray(cols)
		if err != nil {
			return err
		}
		c.Columns = columns
	} else {
		c.Columns = DefaultAggregateConfig.Columns
	}
	return nil
}

func NewAggregateTransformation(d Dataset, c TableBuilderCache, agg Aggregate, config AggregateConfig) *aggregateTransformation {
	return &aggregateTransformation{
		d:      d,
		cache:  c,
		agg:    agg,
		config: config,
	}
}

func NewAggregateTransformationAndDataset(id DatasetID, mode AccumulationMode, agg Aggregate, config AggregateConfig, a *Allocator) (*aggregateTransformation, Dataset) {
	cache := NewTableBuilderCache(a)
	d := NewDataset(id, mode, cache)
	return NewAggregateTransformation(d, cache, agg, config), d
}

func (t *aggregateTransformation) RetractTable(id DatasetID, key query.GroupKey) error {
	//TODO(nathanielc): Store intermediate state for retractions
	return t.d.RetractTable(key)
}

func (t *aggregateTransformation) Process(id DatasetID, tbl query.Table) error {
	builder, new := t.cache.TableBuilder(tbl.Key())
	if !new {
		return fmt.Errorf("aggregate found duplicate table with key: %v", tbl.Key())
	}

	AddTableKeyCols(tbl.Key(), builder)
	builder.AddCol(query.ColMeta{
		Label: t.config.TimeDst,
		Type:  query.TTime,
	})

	builderColMap := make([]int, len(t.config.Columns))
	tableColMap := make([]int, len(t.config.Columns))
	aggregates := make([]ValueFunc, len(t.config.Columns))

	cols := tbl.Cols()
	for j, label := range t.config.Columns {
		idx := -1
		for bj, bc := range cols {
			if bc.Label == label {
				idx = bj
				break
			}
		}
		if idx < 0 {
			return fmt.Errorf("column %q does not exist", label)
		}
		c := cols[idx]
		if tbl.Key().HasCol(c.Label) {
			return errors.New("cannot aggregate columns that are part of the group key")
		}
		var vf ValueFunc
		switch c.Type {
		case query.TBool:
			vf = t.agg.NewBoolAgg()
		case query.TInt:
			vf = t.agg.NewIntAgg()
		case query.TUInt:
			vf = t.agg.NewUIntAgg()
		case query.TFloat:
			vf = t.agg.NewFloatAgg()
		case query.TString:
			vf = t.agg.NewStringAgg()
		default:
			return fmt.Errorf("unsupported aggregate column type %v", c.Type)
		}
		aggregates[j] = vf
		builderColMap[j] = builder.AddCol(query.ColMeta{
			Label: c.Label,
			Type:  vf.Type(),
		})
		tableColMap[j] = idx
	}
	if err := AppendAggregateTime(t.config.TimeSrc, t.config.TimeDst, tbl.Key(), builder); err != nil {
		return err
	}

	tbl.Do(func(cr query.ColReader) error {
		for j := range t.config.Columns {
			vf := aggregates[j]

			tj := tableColMap[j]
			c := tbl.Cols()[tj]

			switch c.Type {
			case query.TBool:
				vf.(DoBoolAgg).DoBool(cr.Bools(tj))
			case query.TInt:
				vf.(DoIntAgg).DoInt(cr.Ints(tj))
			case query.TUInt:
				vf.(DoUIntAgg).DoUInt(cr.UInts(tj))
			case query.TFloat:
				vf.(DoFloatAgg).DoFloat(cr.Floats(tj))
			case query.TString:
				vf.(DoStringAgg).DoString(cr.Strings(tj))
			default:
				return fmt.Errorf("unsupport aggregate type %v", c.Type)
			}
		}
		return nil
	})
	for j, vf := range aggregates {
		bj := builderColMap[j]
		// Append aggregated value
		switch vf.Type() {
		case query.TBool:
			builder.AppendBool(bj, vf.(BoolValueFunc).ValueBool())
		case query.TInt:
			builder.AppendInt(bj, vf.(IntValueFunc).ValueInt())
		case query.TUInt:
			builder.AppendUInt(bj, vf.(UIntValueFunc).ValueUInt())
		case query.TFloat:
			builder.AppendFloat(bj, vf.(FloatValueFunc).ValueFloat())
		case query.TString:
			builder.AppendString(bj, vf.(StringValueFunc).ValueString())
		}
	}

	AppendKeyValues(tbl.Key(), builder)

	return nil
}

func (t *aggregateTransformation) UpdateWatermark(id DatasetID, mark Time) error {
	return t.d.UpdateWatermark(mark)
}
func (t *aggregateTransformation) UpdateProcessingTime(id DatasetID, pt Time) error {
	return t.d.UpdateProcessingTime(pt)
}
func (t *aggregateTransformation) Finish(id DatasetID, err error) {
	t.d.Finish(err)
}

func AppendAggregateTime(srcTime, dstTime string, key query.GroupKey, builder TableBuilder) error {
	srcTimeIdx := ColIdx(srcTime, key.Cols())
	if srcTimeIdx < 0 {
		return fmt.Errorf("timeValue column %q does not exist", srcTime)
	}
	srcTimeCol := key.Cols()[srcTimeIdx]
	if srcTimeCol.Type != query.TTime {
		return fmt.Errorf("timeValue column %q does not have type time", srcTime)
	}

	dstTimeIdx := ColIdx(dstTime, builder.Cols())
	if dstTimeIdx < 0 {
		return fmt.Errorf("timeValue column %q does not exist", dstTime)
	}
	dstTimeCol := builder.Cols()[dstTimeIdx]
	if dstTimeCol.Type != query.TTime {
		return fmt.Errorf("timeValue column %q does not have type time", dstTime)
	}

	builder.AppendTime(dstTimeIdx, key.ValueTime(srcTimeIdx))
	return nil
}

type Aggregate interface {
	NewBoolAgg() DoBoolAgg
	NewIntAgg() DoIntAgg
	NewUIntAgg() DoUIntAgg
	NewFloatAgg() DoFloatAgg
	NewStringAgg() DoStringAgg
}

type ValueFunc interface {
	Type() query.DataType
}
type DoBoolAgg interface {
	ValueFunc
	DoBool([]bool)
}
type DoFloatAgg interface {
	ValueFunc
	DoFloat([]float64)
}
type DoIntAgg interface {
	ValueFunc
	DoInt([]int64)
}
type DoUIntAgg interface {
	ValueFunc
	DoUInt([]uint64)
}
type DoStringAgg interface {
	ValueFunc
	DoString([]string)
}

type BoolValueFunc interface {
	ValueBool() bool
}
type FloatValueFunc interface {
	ValueFloat() float64
}
type IntValueFunc interface {
	ValueInt() int64
}
type UIntValueFunc interface {
	ValueUInt() uint64
}
type StringValueFunc interface {
	ValueString() string
}
<commit_msg>fix: Properly check aggregate type<commit_after>package execute

import (
	"fmt"

	"github.com/influxdata/platform/query"
	"github.com/influxdata/platform/query/interpreter"
	"github.com/influxdata/platform/query/semantic"
	"github.com/pkg/errors"
)

type aggregateTransformation struct {
	d     Dataset
	cache TableBuilderCache
	agg   Aggregate

	config AggregateConfig
}

type AggregateConfig struct {
	Columns []string `json:"columns"`
	TimeSrc string   `json:"time_src"`
	TimeDst string   `json:"time_dst"`
}

var DefaultAggregateConfig = AggregateConfig{
	Columns: []string{DefaultValueColLabel},
	TimeSrc: DefaultStopColLabel,
	TimeDst: DefaultTimeColLabel,
}

func (c AggregateConfig) Copy() AggregateConfig {
	nc := c
	if c.Columns != nil {
		nc.Columns = make([]string, len(c.Columns))
		copy(nc.Columns, c.Columns)
	}
	return nc
}

func (c *AggregateConfig) ReadArgs(args query.Arguments) error {
	if label, ok, err := args.GetString("timeDst"); err != nil {
		return err
	} else if ok {
		c.TimeDst = label
	} else {
		c.TimeDst = DefaultAggregateConfig.TimeDst
	}

	if timeValue, ok, err := args.GetString("timeSrc"); err != nil {
		return err
	} else if ok {
		c.TimeSrc = timeValue
	} else {
		c.TimeSrc = DefaultAggregateConfig.TimeSrc
	}

	if cols, ok, err := args.GetArray("columns", semantic.String); err != nil {
		return err
	} else if ok {
		columns, err := interpreter.ToStringArray(cols)
		if err != nil {
			return err
		}
		c.Columns = columns
	} else {
		c.Columns = DefaultAggregateConfig.Columns
	}
	return nil
}

func NewAggregateTransformation(d Dataset, c TableBuilderCache, agg Aggregate, config AggregateConfig) *aggregateTransformation {
	return &aggregateTransformation{
		d:      d,
		cache:  c,
		agg:    agg,
		config: config,
	}
}

func NewAggregateTransformationAndDataset(id DatasetID, mode AccumulationMode, agg Aggregate, config AggregateConfig, a *Allocator) (*aggregateTransformation, Dataset) {
	cache := NewTableBuilderCache(a)
	d := NewDataset(id, mode, cache)
	return NewAggregateTransformation(d, cache, agg, config), d
}

func (t *aggregateTransformation) RetractTable(id DatasetID, key query.GroupKey) error {
	//TODO(nathanielc): Store intermediate state for retractions
	return t.d.RetractTable(key)
}

func (t *aggregateTransformation) Process(id DatasetID, tbl query.Table) error {
	builder, new := t.cache.TableBuilder(tbl.Key())
	if !new {
		return fmt.Errorf("aggregate found duplicate table with key: %v", tbl.Key())
	}

	AddTableKeyCols(tbl.Key(), builder)
	builder.AddCol(query.ColMeta{
		Label: t.config.TimeDst,
		Type:  query.TTime,
	})

	builderColMap := make([]int, len(t.config.Columns))
	tableColMap := make([]int, len(t.config.Columns))
	aggregates := make([]ValueFunc, len(t.config.Columns))

	cols := tbl.Cols()
	for j, label := range t.config.Columns {
		idx := -1
		for bj, bc := range cols {
			if bc.Label == label {
				idx = bj
				break
			}
		}
		if idx < 0 {
			return fmt.Errorf("column %q does not exist", label)
		}
		c := cols[idx]
		if tbl.Key().HasCol(c.Label) {
			return errors.New("cannot aggregate columns that are part of the group key")
		}
		var vf ValueFunc
		switch c.Type {
		case query.TBool:
			vf = t.agg.NewBoolAgg()
		case query.TInt:
			vf = t.agg.NewIntAgg()
		case query.TUInt:
			vf = t.agg.NewUIntAgg()
		case query.TFloat:
			vf = t.agg.NewFloatAgg()
		case query.TString:
			vf = t.agg.NewStringAgg()
		}
		if vf == nil {
			return fmt.Errorf("unsupported aggregate column type %v", c.Type)
		}
		aggregates[j] = vf
		builderColMap[j] = builder.AddCol(query.ColMeta{
			Label: c.Label,
			Type:  vf.Type(),
		})
		tableColMap[j] = idx
	}
	if err := AppendAggregateTime(t.config.TimeSrc, t.config.TimeDst, tbl.Key(), builder); err != nil {
		return err
	}

	tbl.Do(func(cr query.ColReader) error {
		for j := range t.config.Columns {
			vf := aggregates[j]

			tj := tableColMap[j]
			c := tbl.Cols()[tj]

			switch c.Type {
			case query.TBool:
				vf.(DoBoolAgg).DoBool(cr.Bools(tj))
			case query.TInt:
				vf.(DoIntAgg).DoInt(cr.Ints(tj))
			case query.TUInt:
				vf.(DoUIntAgg).DoUInt(cr.UInts(tj))
			case query.TFloat:
				vf.(DoFloatAgg).DoFloat(cr.Floats(tj))
			case query.TString:
				vf.(DoStringAgg).DoString(cr.Strings(tj))
			default:
				return fmt.Errorf("unsupport aggregate type %v", c.Type)
			}
		}
		return nil
	})
	for j, vf := range aggregates {
		bj := builderColMap[j]
		// Append aggregated value
		switch vf.Type() {
		case query.TBool:
			builder.AppendBool(bj, vf.(BoolValueFunc).ValueBool())
		case query.TInt:
			builder.AppendInt(bj, vf.(IntValueFunc).ValueInt())
		case query.TUInt:
			builder.AppendUInt(bj, vf.(UIntValueFunc).ValueUInt())
		case query.TFloat:
			builder.AppendFloat(bj, vf.(FloatValueFunc).ValueFloat())
		case query.TString:
			builder.AppendString(bj, vf.(StringValueFunc).ValueString())
		}
	}

	AppendKeyValues(tbl.Key(), builder)

	return nil
}

func (t *aggregateTransformation) UpdateWatermark(id DatasetID, mark Time) error {
	return t.d.UpdateWatermark(mark)
}
func (t *aggregateTransformation) UpdateProcessingTime(id DatasetID, pt Time) error {
	return t.d.UpdateProcessingTime(pt)
}
func (t *aggregateTransformation) Finish(id DatasetID, err error) {
	t.d.Finish(err)
}

func AppendAggregateTime(srcTime, dstTime string, key query.GroupKey, builder TableBuilder) error {
	srcTimeIdx := ColIdx(srcTime, key.Cols())
	if srcTimeIdx < 0 {
		return fmt.Errorf("timeValue column %q does not exist", srcTime)
	}
	srcTimeCol := key.Cols()[srcTimeIdx]
	if srcTimeCol.Type != query.TTime {
		return fmt.Errorf("timeValue column %q does not have type time", srcTime)
	}

	dstTimeIdx := ColIdx(dstTime, builder.Cols())
	if dstTimeIdx < 0 {
		return fmt.Errorf("timeValue column %q does not exist", dstTime)
	}
	dstTimeCol := builder.Cols()[dstTimeIdx]
	if dstTimeCol.Type != query.TTime {
		return fmt.Errorf("timeValue column %q does not have type time", dstTime)
	}

	builder.AppendTime(dstTimeIdx, key.ValueTime(srcTimeIdx))
	return nil
}

type Aggregate interface {
	NewBoolAgg() DoBoolAgg
	NewIntAgg() DoIntAgg
	NewUIntAgg() DoUIntAgg
	NewFloatAgg() DoFloatAgg
	NewStringAgg() DoStringAgg
}

type ValueFunc interface {
	Type() query.DataType
}
type DoBoolAgg interface {
	ValueFunc
	DoBool([]bool)
}
type DoFloatAgg interface {
	ValueFunc
	DoFloat([]float64)
}
type DoIntAgg interface {
	ValueFunc
	DoInt([]int64)
}
type DoUIntAgg interface {
	ValueFunc
	DoUInt([]uint64)
}
type DoStringAgg interface {
	ValueFunc
	DoString([]string)
}

type BoolValueFunc interface {
	ValueBool() bool
}
type FloatValueFunc interface {
	ValueFloat() float64
}
type IntValueFunc interface {
	ValueInt() int64
}
type UIntValueFunc interface {
	ValueUInt() uint64
}
type StringValueFunc interface {
	ValueString() string
}
<|endoftext|>


<commit_before>// +build linux

package journald

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

	"github.com/coreos/go-systemd/sdjournal"
	"github.com/segmentio/ecs-logs/lib"
)

func NewReader() (r ecslogs.Reader, err error) {
	var j *sdjournal.Journal

	if j, err = sdjournal.NewJournal(); err != nil {
		return
	}

	if err = j.SeekTail(); err != nil {
		j.Close()
		return
	}

	r = reader{j}
	return
}

type reader struct {
	*sdjournal.Journal
}

func (r reader) ReadMessage() (msg ecslogs.Message, err error) {
	for {
		var cur int
		var ok bool

		if cur, err = r.Next(); err != nil {
			return
		}

		if cur == 0 {
			r.Wait(sdjournal.IndefiniteWait)
			continue
		}

		if msg, ok, err = r.getMessage(); ok || err != nil {
			return
		}
	}
}

func (r reader) getMessage() (msg ecslogs.Message, ok bool, err error) {
	if msg.Group, err = r.GetDataValue("CONTAINER_TAG"); len(msg.Group) == 0 {
		// No CONTAINER_TAG, this must be a journal message from a process that
		// isn't running in a docker container.
		err = nil
		return
	}

	if msg.Stream, err = r.GetDataValue("CONTAINER_NAME"); err != nil {
		// There's a CONTAINER_TAG but no CONTAINER_NAME, something is seriously
		// wrong here, the log docker log driver is misbehaving.
		err = fmt.Errorf("missing CONTAINER_NAME in message with CONTAINER_TAG=%s", msg.Group)
		return
	}

	if s := r.getString("MESSAGE"); len(s) != 0 {
		d := json.NewDecoder(strings.NewReader(s))
		d.UseNumber()

		if d.Decode(&msg.Event) != nil {
			msg.Event.Message = s
		}
	}

	if msg.Event.Level == ecslogs.NONE {
		msg.Event.Level = r.getPriority()
	}

	if len(msg.Event.Info.Host) == 0 {
		msg.Event.Info.Host = r.getString("_HOSTNAME")
	}

	if len(msg.Event.Info.Source) == 0 {
		msg.Event.Info.Source = ecslogs.MessageSource(
			r.getString("CODE_FILE"),
			r.getInt("CODE_LINE"),
			r.getString("CODE_FUNC"),
		)
	}

	if len(msg.Event.Info.ID) == 0 {
		msg.Event.Info.ID = r.getString("MESSAGE_ID")
	}

	if msg.Event.Info.PID == 0 {
		msg.Event.Info.PID = r.getInt("_PID")
	}

	if msg.Event.Info.GID == 0 {
		msg.Event.Info.GID = r.getInt("_GID")
	}

	if msg.Event.Info.UID == 0 {
		msg.Event.Info.UID = r.getInt("_UID")
	}

	if msg.Event.Time == (time.Time{}) {
		msg.Event.Time = r.getTime()
	}

	ok = true
	return
}

func (r reader) getInt(k string) (v int) {
	v, _ = strconv.Atoi(r.getString(k))
	return
}

func (r reader) getTime() (t time.Time) {
	if u, e := r.GetRealtimeUsec(); e == nil {
		t = time.Unix(int64(u/1000000), int64((u%1000000)*1000))
	}
	return
}

func (r reader) getPriority() (p ecslogs.Level) {
	if v, e := strconv.Atoi(r.getString("PRIORITY")); e != nil {
		p = ecslogs.INFO
	} else {
		p = ecslogs.Level(v + 1)
	}
	return
}

func (r reader) getString(k string) (s string) {
	s, _ = r.GetDataValue(k)
	return
}
<commit_msg>fix journal reader<commit_after>// +build linux

package journald

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

	"github.com/coreos/go-systemd/sdjournal"
	"github.com/segmentio/ecs-logs/lib"
)

func NewReader() (r ecslogs.Reader, err error) {
	var j *sdjournal.Journal

	if j, err = sdjournal.NewJournal(); err != nil {
		return
	}

	if err = j.SeekTail(); err != nil {
		j.Close()
		return
	}

	r = reader{j}
	return
}

type reader struct {
	*sdjournal.Journal
}

func (r reader) ReadMessage() (msg ecslogs.Message, err error) {
	for {
		var cur int
		var ok bool

		if cur, err = r.Next(); err != nil {
			return
		}

		if cur == 0 {
			r.Wait(sdjournal.IndefiniteWait)
			continue
		}

		if msg, ok, err = r.getMessage(); ok || err != nil {
			return
		}
	}
}

func (r reader) getMessage() (msg ecslogs.Message, ok bool, err error) {
	if msg.Group, err = r.GetDataValue("CONTAINER_TAG"); len(msg.Group) == 0 {
		// No CONTAINER_TAG, this must be a journal message from a process that
		// isn't running in a docker container.
		err = nil
		return
	}

	if msg.Stream, err = r.GetDataValue("CONTAINER_NAME"); err != nil {
		// There's a CONTAINER_TAG but no CONTAINER_NAME, something is seriously
		// wrong here, the log docker log driver is misbehaving.
		err = fmt.Errorf("missing CONTAINER_NAME in message with CONTAINER_TAG=%s", msg.Group)
		return
	}

	if s := r.getString("MESSAGE"); len(s) != 0 {
		d := json.NewDecoder(strings.NewReader(s))
		d.UseNumber()

		if d.Decode(&msg.Event) != nil {
			msg.Event.Message = s
		}
	}

	if msg.Event.Level == ecslogs.NONE {
		msg.Event.Level = r.getPriority()
	}

	if len(msg.Event.Info.Host) == 0 {
		msg.Event.Info.Host = r.getString("_HOSTNAME")
	}

	if len(msg.Event.Info.Source) == 0 {
		msg.Event.Info.Source = (ecslogs.FuncInfo{
			File: r.getString("CODE_FILE"),
			Func: r.getString("CODE_FUNC"),
			Line: r.getInt("CODE_LINE"),
		}).String()
	}

	if len(msg.Event.Info.ID) == 0 {
		msg.Event.Info.ID = r.getString("MESSAGE_ID")
	}

	if msg.Event.Info.PID == 0 {
		msg.Event.Info.PID = r.getInt("_PID")
	}

	if msg.Event.Info.GID == 0 {
		msg.Event.Info.GID = r.getInt("_GID")
	}

	if msg.Event.Info.UID == 0 {
		msg.Event.Info.UID = r.getInt("_UID")
	}

	if msg.Event.Time == (time.Time{}) {
		msg.Event.Time = r.getTime()
	}

	ok = true
	return
}

func (r reader) getInt(k string) (v int) {
	v, _ = strconv.Atoi(r.getString(k))
	return
}

func (r reader) getTime() (t time.Time) {
	if u, e := r.GetRealtimeUsec(); e == nil {
		t = time.Unix(int64(u/1000000), int64((u%1000000)*1000))
	}
	return
}

func (r reader) getPriority() (p ecslogs.Level) {
	if v, e := strconv.Atoi(r.getString("PRIORITY")); e != nil {
		p = ecslogs.INFO
	} else {
		p = ecslogs.Level(v + 1)
	}
	return
}

func (r reader) getString(k string) (s string) {
	s, _ = r.GetDataValue(k)
	return
}
<|endoftext|>


<commit_before>package google

func canonicalizeServiceScope(scope string) string {
	// This is a convenience map of short names used by the gcloud tool
	// to the GCE auth endpoints they alias to.
	scopeMap := map[string]string{
		"bigquery":        "https://www.googleapis.com/auth/bigquery",
		"cloud-platform":  "https://www.googleapis.com/auth/cloud-platform",
		"compute-ro":      "https://www.googleapis.com/auth/compute.readonly",
		"compute-rw":      "https://www.googleapis.com/auth/compute",
		"datastore":       "https://www.googleapis.com/auth/datastore",
		"logging-write":   "https://www.googleapis.com/auth/logging.write",
		"monitoring":      "https://www.googleapis.com/auth/monitoring",
		"pubsub":          "https://www.googleapis.com/auth/pubsub",
		"sql":             "https://www.googleapis.com/auth/sqlservice",
		"sql-admin":       "https://www.googleapis.com/auth/sqlservice.admin",
		"storage-full":    "https://www.googleapis.com/auth/devstorage.full_control",
		"storage-ro":      "https://www.googleapis.com/auth/devstorage.read_only",
		"storage-rw":      "https://www.googleapis.com/auth/devstorage.read_write",
		"taskqueue":       "https://www.googleapis.com/auth/taskqueue",
		"useraccounts-ro": "https://www.googleapis.com/auth/cloud.useraccounts.readonly",
		"useraccounts-rw": "https://www.googleapis.com/auth/cloud.useraccounts",
		"userinfo-email":  "https://www.googleapis.com/auth/userinfo.email",
	}

	if matchedURL, ok := scopeMap[scope]; ok {
		return matchedURL
	}

	return scope
}
<commit_msg>provider/google: add scope aliases<commit_after>package google

func canonicalizeServiceScope(scope string) string {
	// This is a convenience map of short names used by the gcloud tool
	// to the GCE auth endpoints they alias to.
	scopeMap := map[string]string{
		"bigquery":              "https://www.googleapis.com/auth/bigquery",
		"cloud-platform":        "https://www.googleapis.com/auth/cloud-platform",
		"cloud-source-repos":    "https://www.googleapis.com/auth/source.full_control",
		"cloud-source-repos-ro": "https://www.googleapis.com/auth/source.read_only",
		"compute-ro":            "https://www.googleapis.com/auth/compute.readonly",
		"compute-rw":            "https://www.googleapis.com/auth/compute",
		"datastore":             "https://www.googleapis.com/auth/datastore",
		"logging-write":         "https://www.googleapis.com/auth/logging.write",
		"monitoring":            "https://www.googleapis.com/auth/monitoring",
		"monitoring-write":      "https://www.googleapis.com/auth/monitoring.write",
		"pubsub":                "https://www.googleapis.com/auth/pubsub",
		"service-control":       "https://www.googleapis.com/auth/servicecontrol",
		"service-management":    "https://www.googleapis.com/auth/service.management.readonly",
		"sql":                   "https://www.googleapis.com/auth/sqlservice",
		"sql-admin":             "https://www.googleapis.com/auth/sqlservice.admin",
		"storage-full":          "https://www.googleapis.com/auth/devstorage.full_control",
		"storage-ro":            "https://www.googleapis.com/auth/devstorage.read_only",
		"storage-rw":            "https://www.googleapis.com/auth/devstorage.read_write",
		"taskqueue":             "https://www.googleapis.com/auth/taskqueue",
		"useraccounts-ro":       "https://www.googleapis.com/auth/cloud.useraccounts.readonly",
		"useraccounts-rw":       "https://www.googleapis.com/auth/cloud.useraccounts",
		"userinfo-email":        "https://www.googleapis.com/auth/userinfo.email",
	}

	if matchedURL, ok := scopeMap[scope]; ok {
		return matchedURL
	}

	return scope
}
<|endoftext|>