<commit_before>/*
Copyright 2021 The Vitess Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package evalengine

import (
	"fmt"

	"vitess.io/vitess/go/mysql/collations"
	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
	"vitess.io/vitess/go/vt/sqlparser"
	"vitess.io/vitess/go/vt/vterrors"
)

type (
	ConverterLookup interface {
		ColumnLookup(col *sqlparser.ColName) (int, error)
		CollationIDLookup(expr sqlparser.Expr) collations.ID
	}
)

var ErrConvertExprNotSupported = "expr cannot be converted, not supported"

func convertComparisonExpr(op sqlparser.ComparisonExprOperator, left, right sqlparser.Expr, lookup ConverterLookup) (Expr, error) {
	l, err := convertExpr(left, lookup)
	if err != nil {
		return nil, err
	}
	r, err := convertExpr(right, lookup)
	if err != nil {
		return nil, err
	}
	return convertComparisonExpr2(op, l, r)
}

func convertComparisonExpr2(op sqlparser.ComparisonExprOperator, left, right Expr) (Expr, error) {
	binaryExpr := BinaryExpr{
		Left:  left,
		Right: right,
	}

	if op == sqlparser.InOp || op == sqlparser.NotInOp {
		return &InExpr{
			BinaryExpr: binaryExpr,
			Negate:     op == sqlparser.NotInOp,
			Hashed:     nil,
		}, nil
	}

	coercedExpr := BinaryCoercedExpr{
		BinaryExpr: binaryExpr,
	}
	if err := coercedExpr.coerce(); err != nil {
		return nil, err
	}

	switch op {
	case sqlparser.EqualOp:
		return &ComparisonExpr{coercedExpr, compareEQ{}}, nil
	case sqlparser.NotEqualOp:
		return &ComparisonExpr{coercedExpr, compareNE{}}, nil
	case sqlparser.LessThanOp:
		return &ComparisonExpr{coercedExpr, compareLT{}}, nil
	case sqlparser.LessEqualOp:
		return &ComparisonExpr{coercedExpr, compareLE{}}, nil
	case sqlparser.GreaterThanOp:
		return &ComparisonExpr{coercedExpr, compareGT{}}, nil
	case sqlparser.GreaterEqualOp:
		return &ComparisonExpr{coercedExpr, compareGE{}}, nil
	case sqlparser.NullSafeEqualOp:
		return &ComparisonExpr{coercedExpr, compareNullSafeEQ{}}, nil
	case sqlparser.LikeOp:
		return &LikeExpr{BinaryCoercedExpr: coercedExpr}, nil
	case sqlparser.NotLikeOp:
		return &LikeExpr{BinaryCoercedExpr: coercedExpr, Negate: true}, nil
	default:
		return nil, vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "%s: %s", ErrConvertExprNotSupported, op.ToString())
	}
}

func convertLogicalExpr(opname string, left, right sqlparser.Expr, lookup ConverterLookup) (Expr, error) {
	l, err := convertExpr(left, lookup)
	if err != nil {
		return nil, err
	}
	r, err := convertExpr(right, lookup)
	if err != nil {
		return nil, err
	}

	var logic func(l, r boolean) boolean
	switch opname {
	case "AND":
		logic = func(l, r boolean) boolean { return l.and(r) }
	case "OR":
		logic = func(l, r boolean) boolean { return l.or(r) }
	case "XOR":
		logic = func(l, r boolean) boolean { return l.xor(r) }
	default:
		panic("unexpected logical operator")
	}

	return &LogicalExpr{
		BinaryExpr: BinaryExpr{
			Left:  l,
			Right: r,
		},
		op:     logic,
		opname: opname,
	}, nil
}

func getCollation(expr sqlparser.Expr, lookup ConverterLookup) collations.TypedCollation {
	collation := collations.TypedCollation{
		Coercibility: collations.CoerceCoercible,
		Repertoire:   collations.RepertoireUnicode,
	}
	if lookup != nil {
		collation.Collation = lookup.CollationIDLookup(expr)
	} else {
		sysdefault, _ := collations.Local().ResolveCollation("", "")
		collation.Collation = sysdefault.ID()
	}
	return collation
}

func ConvertEx(e sqlparser.Expr, lookup ConverterLookup, simplify bool) (Expr, error) {
	expr, err := convertExpr(e, lookup)
	if err != nil {
		return nil, err
	}
	if simplify {
		expr, err = simplifyExpr(expr)
	}
	return expr, err
}

// Convert converts between AST expressions and executable expressions
func Convert(e sqlparser.Expr, lookup ConverterLookup) (Expr, error) {
	return ConvertEx(e, lookup, true)
}

func convertExpr(e sqlparser.Expr, lookup ConverterLookup) (Expr, error) {
	switch node := e.(type) {
	case *sqlparser.ColName:
		if lookup == nil {
			return nil, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "%s: cannot lookup column", ErrConvertExprNotSupported)
		}
		idx, err := lookup.ColumnLookup(node)
		if err != nil {
			return nil, err
		}
		collation := getCollation(node, lookup)
		return NewColumn(idx, collation), nil
	case *sqlparser.ComparisonExpr:
		return convertComparisonExpr(node.Operator, node.Left, node.Right, lookup)
	case sqlparser.Argument:
		collation := getCollation(e, lookup)
		return NewBindVar(string(node), collation), nil
	case sqlparser.ListArg:
		collation := getCollation(e, lookup)
		return NewBindVar(string(node), collation), nil
	case *sqlparser.Literal:
		switch node.Type {
		case sqlparser.IntVal:
			return NewLiteralIntegralFromBytes(node.Bytes())
		case sqlparser.FloatVal:
			return NewLiteralRealFromBytes(node.Bytes())
		case sqlparser.StrVal:
			collation := getCollation(e, lookup)
			return NewLiteralString(node.Bytes(), collation), nil
		case sqlparser.HexNum:
			return nil, vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "%s: hexadecimal value: %s", ErrConvertExprNotSupported, node.Val)
		}
	case sqlparser.BoolVal:
		if node {
			return NewLiteralInt(1), nil
		}
		return NewLiteralInt(0), nil
	case *sqlparser.AndExpr:
		return convertLogicalExpr("AND", node.Left, node.Right, lookup)
	case *sqlparser.OrExpr:
		return convertLogicalExpr("OR", node.Left, node.Right, lookup)
	case *sqlparser.XorExpr:
		return convertLogicalExpr("XOR", node.Left, node.Right, lookup)
	case *sqlparser.NotExpr:
		inner, err := convertExpr(node.Expr, lookup)
		if err != nil {
			return nil, err
		}
		return &NotExpr{UnaryExpr{inner}}, nil
	case *sqlparser.BinaryExpr:
		var op ArithmeticOp
		switch node.Operator {
		case sqlparser.PlusOp:
			op = &OpAddition{}
		case sqlparser.MinusOp:
			op = &OpSubstraction{}
		case sqlparser.MultOp:
			op = &OpMultiplication{}
		case sqlparser.DivOp:
			op = &OpDivision{}
		default:
			return nil, vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "%s: %T", ErrConvertExprNotSupported, e)
		}
		left, err := convertExpr(node.Left, lookup)
		if err != nil {
			return nil, err
		}
		right, err := convertExpr(node.Right, lookup)
		if err != nil {
			return nil, err
		}
		return &ArithmeticExpr{
			BinaryExpr: BinaryExpr{
				Left:  left,
				Right: right,
			},
			Op: op,
		}, nil
	case sqlparser.ValTuple:
		var exprs TupleExpr
		for _, expr := range node {
			convertedExpr, err := convertExpr(expr, lookup)
			if err != nil {
				return nil, err
			}
			exprs = append(exprs, convertedExpr)
		}
		return exprs, nil
	case *sqlparser.NullVal:
		return NullExpr, nil
	case *sqlparser.CollateExpr:
		expr, err := convertExpr(node.Expr, lookup)
		if err != nil {
			return nil, err
		}
		coll := collations.Local().LookupByName(node.Collation)
		if coll == nil {
			return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "Unknown collation: '%s'", node.Collation)
		}
		return &CollateExpr{
			UnaryExpr: UnaryExpr{expr},
			TypedCollation: collations.TypedCollation{
				Collation:    coll.ID(),
				Coercibility: collations.CoerceExplicit,
				Repertoire:   collations.RepertoireUnicode,
			},
		}, nil
	case *sqlparser.IntroducerExpr:
		expr, err := convertExpr(node.Expr, lookup)
		if err != nil {
			return nil, err
		}
		coll := collations.Local().DefaultCollationForCharset(node.CharacterSet[1:])
		if coll == nil {
			panic(fmt.Sprintf("unknown character set: %s", node.CharacterSet))
		}
		switch lit := expr.(type) {
		case *Literal:
			lit.Val.collation.Collation = coll.ID()
		case *BindVariable:
			lit.coll.Collation = coll.ID()
		default:
			panic(fmt.Sprintf("character set introducers are only supported for literals and arguments"))
		}
		return expr, nil
	}
	return nil, vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "%s: %T", ErrConvertExprNotSupported, e)
}
<commit_msg>evalengine: lint<commit_after>/*
Copyright 2021 The Vitess Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package evalengine

import (
	"fmt"

	"vitess.io/vitess/go/mysql/collations"
	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
	"vitess.io/vitess/go/vt/sqlparser"
	"vitess.io/vitess/go/vt/vterrors"
)

type (
	ConverterLookup interface {
		ColumnLookup(col *sqlparser.ColName) (int, error)
		CollationIDLookup(expr sqlparser.Expr) collations.ID
	}
)

var ErrConvertExprNotSupported = "expr cannot be converted, not supported"

func convertComparisonExpr(op sqlparser.ComparisonExprOperator, left, right sqlparser.Expr, lookup ConverterLookup) (Expr, error) {
	l, err := convertExpr(left, lookup)
	if err != nil {
		return nil, err
	}
	r, err := convertExpr(right, lookup)
	if err != nil {
		return nil, err
	}
	return convertComparisonExpr2(op, l, r)
}

func convertComparisonExpr2(op sqlparser.ComparisonExprOperator, left, right Expr) (Expr, error) {
	binaryExpr := BinaryExpr{
		Left:  left,
		Right: right,
	}

	if op == sqlparser.InOp || op == sqlparser.NotInOp {
		return &InExpr{
			BinaryExpr: binaryExpr,
			Negate:     op == sqlparser.NotInOp,
			Hashed:     nil,
		}, nil
	}

	coercedExpr := BinaryCoercedExpr{
		BinaryExpr: binaryExpr,
	}
	if err := coercedExpr.coerce(); err != nil {
		return nil, err
	}

	switch op {
	case sqlparser.EqualOp:
		return &ComparisonExpr{coercedExpr, compareEQ{}}, nil
	case sqlparser.NotEqualOp:
		return &ComparisonExpr{coercedExpr, compareNE{}}, nil
	case sqlparser.LessThanOp:
		return &ComparisonExpr{coercedExpr, compareLT{}}, nil
	case sqlparser.LessEqualOp:
		return &ComparisonExpr{coercedExpr, compareLE{}}, nil
	case sqlparser.GreaterThanOp:
		return &ComparisonExpr{coercedExpr, compareGT{}}, nil
	case sqlparser.GreaterEqualOp:
		return &ComparisonExpr{coercedExpr, compareGE{}}, nil
	case sqlparser.NullSafeEqualOp:
		return &ComparisonExpr{coercedExpr, compareNullSafeEQ{}}, nil
	case sqlparser.LikeOp:
		return &LikeExpr{BinaryCoercedExpr: coercedExpr}, nil
	case sqlparser.NotLikeOp:
		return &LikeExpr{BinaryCoercedExpr: coercedExpr, Negate: true}, nil
	default:
		return nil, vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "%s: %s", ErrConvertExprNotSupported, op.ToString())
	}
}

func convertLogicalExpr(opname string, left, right sqlparser.Expr, lookup ConverterLookup) (Expr, error) {
	l, err := convertExpr(left, lookup)
	if err != nil {
		return nil, err
	}
	r, err := convertExpr(right, lookup)
	if err != nil {
		return nil, err
	}

	var logic func(l, r boolean) boolean
	switch opname {
	case "AND":
		logic = func(l, r boolean) boolean { return l.and(r) }
	case "OR":
		logic = func(l, r boolean) boolean { return l.or(r) }
	case "XOR":
		logic = func(l, r boolean) boolean { return l.xor(r) }
	default:
		panic("unexpected logical operator")
	}

	return &LogicalExpr{
		BinaryExpr: BinaryExpr{
			Left:  l,
			Right: r,
		},
		op:     logic,
		opname: opname,
	}, nil
}

func getCollation(expr sqlparser.Expr, lookup ConverterLookup) collations.TypedCollation {
	collation := collations.TypedCollation{
		Coercibility: collations.CoerceCoercible,
		Repertoire:   collations.RepertoireUnicode,
	}
	if lookup != nil {
		collation.Collation = lookup.CollationIDLookup(expr)
	} else {
		sysdefault, _ := collations.Local().ResolveCollation("", "")
		collation.Collation = sysdefault.ID()
	}
	return collation
}

func ConvertEx(e sqlparser.Expr, lookup ConverterLookup, simplify bool) (Expr, error) {
	expr, err := convertExpr(e, lookup)
	if err != nil {
		return nil, err
	}
	if simplify {
		expr, err = simplifyExpr(expr)
	}
	return expr, err
}

// Convert converts between AST expressions and executable expressions
func Convert(e sqlparser.Expr, lookup ConverterLookup) (Expr, error) {
	return ConvertEx(e, lookup, true)
}

func convertExpr(e sqlparser.Expr, lookup ConverterLookup) (Expr, error) {
	switch node := e.(type) {
	case *sqlparser.ColName:
		if lookup == nil {
			return nil, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "%s: cannot lookup column", ErrConvertExprNotSupported)
		}
		idx, err := lookup.ColumnLookup(node)
		if err != nil {
			return nil, err
		}
		collation := getCollation(node, lookup)
		return NewColumn(idx, collation), nil
	case *sqlparser.ComparisonExpr:
		return convertComparisonExpr(node.Operator, node.Left, node.Right, lookup)
	case sqlparser.Argument:
		collation := getCollation(e, lookup)
		return NewBindVar(string(node), collation), nil
	case sqlparser.ListArg:
		collation := getCollation(e, lookup)
		return NewBindVar(string(node), collation), nil
	case *sqlparser.Literal:
		switch node.Type {
		case sqlparser.IntVal:
			return NewLiteralIntegralFromBytes(node.Bytes())
		case sqlparser.FloatVal:
			return NewLiteralRealFromBytes(node.Bytes())
		case sqlparser.StrVal:
			collation := getCollation(e, lookup)
			return NewLiteralString(node.Bytes(), collation), nil
		case sqlparser.HexNum:
			return nil, vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "%s: hexadecimal value: %s", ErrConvertExprNotSupported, node.Val)
		}
	case sqlparser.BoolVal:
		if node {
			return NewLiteralInt(1), nil
		}
		return NewLiteralInt(0), nil
	case *sqlparser.AndExpr:
		return convertLogicalExpr("AND", node.Left, node.Right, lookup)
	case *sqlparser.OrExpr:
		return convertLogicalExpr("OR", node.Left, node.Right, lookup)
	case *sqlparser.XorExpr:
		return convertLogicalExpr("XOR", node.Left, node.Right, lookup)
	case *sqlparser.NotExpr:
		inner, err := convertExpr(node.Expr, lookup)
		if err != nil {
			return nil, err
		}
		return &NotExpr{UnaryExpr{inner}}, nil
	case *sqlparser.BinaryExpr:
		var op ArithmeticOp
		switch node.Operator {
		case sqlparser.PlusOp:
			op = &OpAddition{}
		case sqlparser.MinusOp:
			op = &OpSubstraction{}
		case sqlparser.MultOp:
			op = &OpMultiplication{}
		case sqlparser.DivOp:
			op = &OpDivision{}
		default:
			return nil, vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "%s: %T", ErrConvertExprNotSupported, e)
		}
		left, err := convertExpr(node.Left, lookup)
		if err != nil {
			return nil, err
		}
		right, err := convertExpr(node.Right, lookup)
		if err != nil {
			return nil, err
		}
		return &ArithmeticExpr{
			BinaryExpr: BinaryExpr{
				Left:  left,
				Right: right,
			},
			Op: op,
		}, nil
	case sqlparser.ValTuple:
		var exprs TupleExpr
		for _, expr := range node {
			convertedExpr, err := convertExpr(expr, lookup)
			if err != nil {
				return nil, err
			}
			exprs = append(exprs, convertedExpr)
		}
		return exprs, nil
	case *sqlparser.NullVal:
		return NullExpr, nil
	case *sqlparser.CollateExpr:
		expr, err := convertExpr(node.Expr, lookup)
		if err != nil {
			return nil, err
		}
		coll := collations.Local().LookupByName(node.Collation)
		if coll == nil {
			return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "Unknown collation: '%s'", node.Collation)
		}
		return &CollateExpr{
			UnaryExpr: UnaryExpr{expr},
			TypedCollation: collations.TypedCollation{
				Collation:    coll.ID(),
				Coercibility: collations.CoerceExplicit,
				Repertoire:   collations.RepertoireUnicode,
			},
		}, nil
	case *sqlparser.IntroducerExpr:
		expr, err := convertExpr(node.Expr, lookup)
		if err != nil {
			return nil, err
		}
		coll := collations.Local().DefaultCollationForCharset(node.CharacterSet[1:])
		if coll == nil {
			panic(fmt.Sprintf("unknown character set: %s", node.CharacterSet))
		}
		switch lit := expr.(type) {
		case *Literal:
			lit.Val.collation.Collation = coll.ID()
		case *BindVariable:
			lit.coll.Collation = coll.ID()
		default:
			panic("character set introducers are only supported for literals and arguments")
		}
		return expr, nil
	}
	return nil, vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "%s: %T", ErrConvertExprNotSupported, e)
}
<|endoftext|>


<commit_before>package integration_test

import (
	"encoding/json"
	"fmt"
	"github.com/APTrust/exchange/constants"
	"github.com/APTrust/exchange/context"
	"github.com/APTrust/exchange/dpn/models"
	apt_models "github.com/APTrust/exchange/models"
	apt_testutil "github.com/APTrust/exchange/util/testutil"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"net/url"
	"strings"
	"testing"
)

func packageGetWorkItems(t *testing.T) (*context.Context, []*apt_models.WorkItem) {
	_context, err := apt_testutil.GetContext("integration.json")
	require.Nil(t, err, "Could not create context")
	params := url.Values{}
	params.Set("item_action", "DPN")
	params.Set("page", "1")
	params.Set("per_page", "100")
	resp := _context.PharosClient.WorkItemList(params)
	require.Nil(t, resp.Error)
	return _context, resp.WorkItems()
}

// TestPackageWorkItems checks to see if Pharos WorkItems
// were updated correctly.
func TestPackageWorkItems(t *testing.T) {
	if !apt_testutil.ShouldRunIntegrationTests() {
		t.Skip("Skipping integration test. Set ENV var RUN_EXCHANGE_INTEGRATION=true if you want to run them.")
	}
	_, workItems := packageGetWorkItems(t)
	for _, item := range workItems {
		assert.Equal(t, constants.StageStore, item.Stage)
		assert.Equal(t, constants.StatusPending, item.Status)
		assert.Equal(t, "Packaging completed, awaiting storage", item.Note)
		assert.Equal(t, "", item.Node)
		assert.Equal(t, 0, item.Pid)
		assert.True(t, item.Retry)
	}
}

// TestPackageWorkItemState checks to see if Pharos WorkItemState
// records were updated correctly.
func TestPackageWorkItemState(t *testing.T) {
	if !apt_testutil.ShouldRunIntegrationTests() {
		t.Skip("Skipping integration test. Set ENV var RUN_EXCHANGE_INTEGRATION=true if you want to run them.")
	}
	_context, workItems := packageGetWorkItems(t)
	for _, item := range workItems {
		require.NotNil(t, item.WorkItemStateId)
		resp := _context.PharosClient.WorkItemStateGet(*item.WorkItemStateId)
		require.Nil(t, resp.Error)
		workItemState := resp.WorkItemState()
		require.NotNil(t, workItemState)
		assert.Equal(t, constants.ActionDPN, workItemState.Action)
		assert.False(t, workItemState.CreatedAt.IsZero())
		assert.False(t, workItemState.UpdatedAt.IsZero())

		detail := fmt.Sprintf("%s from Pharos", item.ObjectIdentifier)
		testPackageWorkItemState(t, _context, workItemState.State, detail)
	}

}

// TestPackageJsonLog checks that all expected entries are present
// in the dpn_package.json log.
func TestPackageJsonLog(t *testing.T) {

}

// TestPackageTarFilesPresent tests whether all expected DPN bags
// (tar files) are present in the staging area.
func TestPackageTarFilesPresent(t *testing.T) {

}

// TestPackageCleanup checks to see whether dpn_package cleaned up
// all of the intermediate files created during the bag building
// process. Those are directories containing untarred bags.
func TestPackageCleanup(t *testing.T) {

}

// TestPackageItemsQueued checks to see if dpn_package pushed items
// into the dpn_store NSQ topic.
func TestPackageItemsQueued(t *testing.T) {

}

// Test the JSON serialized WorkItemState. Param WorkItemState is a
// string of JSON data. Param detail describes which object we're
// testing and where the JSON came from, so failure messages can be
// more informative.
func testPackageWorkItemState(t *testing.T, _context *context.Context, workItemState, detail string) {
	dpnIngestManifest := models.NewDPNIngestManifest(nil)
	err := json.Unmarshal([]byte(workItemState), dpnIngestManifest)
	require.Nil(t, err, "Could not unmarshal state")

	require.NotNil(t, dpnIngestManifest.PackageSummary, detail)
	require.NotNil(t, dpnIngestManifest.ValidateSummary, detail)
	assert.False(t, dpnIngestManifest.PackageSummary.StartedAt.IsZero(), detail)
	assert.False(t, dpnIngestManifest.PackageSummary.FinishedAt.IsZero(), detail)
	assert.False(t, dpnIngestManifest.ValidateSummary.StartedAt.IsZero(), detail)
	assert.False(t, dpnIngestManifest.ValidateSummary.FinishedAt.IsZero(), detail)

	assert.NotNil(t, dpnIngestManifest.WorkItem, detail)
	require.NotNil(t, dpnIngestManifest.DPNBag, detail)
	assert.NotEmpty(t, dpnIngestManifest.DPNBag.UUID, detail)
	assert.NotEmpty(t, dpnIngestManifest.DPNBag.LocalId, detail)
	assert.NotEmpty(t, dpnIngestManifest.DPNBag.Member, detail)
	assert.Equal(t, dpnIngestManifest.DPNBag.UUID, dpnIngestManifest.DPNBag.FirstVersionUUID, detail)
	assert.EqualValues(t, 1, dpnIngestManifest.DPNBag.Version, detail)
	assert.Equal(t, _context.Config.DPN.LocalNode, dpnIngestManifest.DPNBag.IngestNode, detail)
	assert.Equal(t, _context.Config.DPN.LocalNode, dpnIngestManifest.DPNBag.AdminNode, detail)
	assert.Equal(t, "D", dpnIngestManifest.DPNBag.BagType, detail)
	assert.NotEqual(t, 0, dpnIngestManifest.DPNBag.Size, detail)
	assert.False(t, dpnIngestManifest.DPNBag.CreatedAt.IsZero(), detail)
	assert.False(t, dpnIngestManifest.DPNBag.UpdatedAt.IsZero(), detail)

	require.NotEmpty(t, dpnIngestManifest.DPNBag.MessageDigests, detail)
	messageDigest := dpnIngestManifest.DPNBag.MessageDigests[0]
	assert.Equal(t, dpnIngestManifest.DPNBag.UUID, messageDigest.Bag, detail)
	assert.Equal(t, constants.AlgSha256, messageDigest.Algorithm, detail)
	assert.Equal(t, _context.Config.DPN.LocalNode, messageDigest.Node, detail)
	assert.Equal(t, 64, len(messageDigest.Value), detail)
	assert.False(t, messageDigest.CreatedAt.IsZero(), detail)

	assert.NotEmpty(t, dpnIngestManifest.LocalDir, detail)
	assert.NotEmpty(t, dpnIngestManifest.LocalTarFile, detail)
	assert.True(t, strings.HasSuffix(dpnIngestManifest.LocalTarFile, ".tar"), detail)

	// Bag has not yet been stored in Glacier, so this should be empty.
	assert.Empty(t, dpnIngestManifest.StorageURL, detail)
}
<commit_msg>Post-test dpn_package json<commit_after>package integration_test

import (
	"encoding/json"
	"fmt"
	"github.com/APTrust/exchange/constants"
	"github.com/APTrust/exchange/context"
	"github.com/APTrust/exchange/dpn/models"
	apt_models "github.com/APTrust/exchange/models"
	apt_testutil "github.com/APTrust/exchange/util/testutil"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"net/url"
	"path/filepath"
	"strings"
	"testing"
)

func packageGetWorkItems(t *testing.T) (*context.Context, []*apt_models.WorkItem) {
	_context, err := apt_testutil.GetContext("integration.json")
	require.Nil(t, err, "Could not create context")
	params := url.Values{}
	params.Set("item_action", "DPN")
	params.Set("page", "1")
	params.Set("per_page", "100")
	resp := _context.PharosClient.WorkItemList(params)
	require.Nil(t, resp.Error)
	return _context, resp.WorkItems()
}

// TestPackageWorkItems checks to see if Pharos WorkItems
// were updated correctly.
func TestPackageWorkItems(t *testing.T) {
	if !apt_testutil.ShouldRunIntegrationTests() {
		t.Skip("Skipping integration test. Set ENV var RUN_EXCHANGE_INTEGRATION=true if you want to run them.")
	}
	_, workItems := packageGetWorkItems(t)
	for _, item := range workItems {
		assert.Equal(t, constants.StageStore, item.Stage)
		assert.Equal(t, constants.StatusPending, item.Status)
		assert.Equal(t, "Packaging completed, awaiting storage", item.Note)
		assert.Equal(t, "", item.Node)
		assert.Equal(t, 0, item.Pid)
		assert.True(t, item.Retry)
	}
}

// TestPackageWorkItemState checks to see if Pharos WorkItemState
// records were updated correctly.
func TestPackageWorkItemState(t *testing.T) {
	if !apt_testutil.ShouldRunIntegrationTests() {
		t.Skip("Skipping integration test. Set ENV var RUN_EXCHANGE_INTEGRATION=true if you want to run them.")
	}
	_context, workItems := packageGetWorkItems(t)
	for _, item := range workItems {
		require.NotNil(t, item.WorkItemStateId)
		resp := _context.PharosClient.WorkItemStateGet(*item.WorkItemStateId)
		require.Nil(t, resp.Error)
		workItemState := resp.WorkItemState()
		require.NotNil(t, workItemState)
		assert.Equal(t, constants.ActionDPN, workItemState.Action)
		assert.False(t, workItemState.CreatedAt.IsZero())
		assert.False(t, workItemState.UpdatedAt.IsZero())

		detail := fmt.Sprintf("%s from Pharos", item.ObjectIdentifier)
		testPackageWorkItemState(t, _context, workItemState.State, detail)
	}

}

// TestPackageJsonLog checks that all expected entries are present
// in the dpn_package.json log.
func TestPackageJsonLog(t *testing.T) {
	if !apt_testutil.ShouldRunIntegrationTests() {
		t.Skip("Skipping integration test. Set ENV var RUN_EXCHANGE_INTEGRATION=true if you want to run them.")
	}
	_context, err := apt_testutil.GetContext("integration.json")
	require.Nil(t, err)
	pathToLogFile := filepath.Join(_context.Config.LogDirectory, "dpn_package.json")
	for _, s3Key := range apt_testutil.INTEGRATION_GOOD_BAGS[0:7] {
		parts := strings.Split(s3Key, "/")
		tarFileName := parts[1]
		manifest, err := apt_testutil.FindDPNIngestManifestInLog(pathToLogFile, tarFileName)
		require.Nil(t, err)
		require.NotNil(t, manifest)

		detail := fmt.Sprintf("%s from JSON log", tarFileName)
		testPackageManifest(t, _context, manifest, detail)
	}
}

// TestPackageTarFilesPresent tests whether all expected DPN bags
// (tar files) are present in the staging area.
func TestPackageTarFilesPresent(t *testing.T) {

}

// TestPackageCleanup checks to see whether dpn_package cleaned up
// all of the intermediate files created during the bag building
// process. Those are directories containing untarred bags.
func TestPackageCleanup(t *testing.T) {

}

// TestPackageItemsQueued checks to see if dpn_package pushed items
// into the dpn_store NSQ topic.
func TestPackageItemsQueued(t *testing.T) {

}

// Test the JSON serialized WorkItemState. Param WorkItemState is a
// string of JSON data. Param detail describes which object we're
// testing and where the JSON came from, so failure messages can be
// more informative.
func testPackageWorkItemState(t *testing.T, _context *context.Context, workItemState, detail string) {
	dpnIngestManifest := models.NewDPNIngestManifest(nil)
	err := json.Unmarshal([]byte(workItemState), dpnIngestManifest)
	require.Nil(t, err, "Could not unmarshal state")
	testPackageManifest(t, _context, dpnIngestManifest, detail)
}

func testPackageManifest(t *testing.T, _context *context.Context, dpnIngestManifest *models.DPNIngestManifest, detail string) {
	require.NotNil(t, dpnIngestManifest.PackageSummary, detail)
	require.NotNil(t, dpnIngestManifest.ValidateSummary, detail)
	assert.False(t, dpnIngestManifest.PackageSummary.StartedAt.IsZero(), detail)
	assert.False(t, dpnIngestManifest.PackageSummary.FinishedAt.IsZero(), detail)
	assert.False(t, dpnIngestManifest.ValidateSummary.StartedAt.IsZero(), detail)
	assert.False(t, dpnIngestManifest.ValidateSummary.FinishedAt.IsZero(), detail)

	assert.NotNil(t, dpnIngestManifest.WorkItem, detail)
	require.NotNil(t, dpnIngestManifest.DPNBag, detail)
	assert.NotEmpty(t, dpnIngestManifest.DPNBag.UUID, detail)
	assert.NotEmpty(t, dpnIngestManifest.DPNBag.LocalId, detail)
	assert.NotEmpty(t, dpnIngestManifest.DPNBag.Member, detail)
	assert.Equal(t, dpnIngestManifest.DPNBag.UUID, dpnIngestManifest.DPNBag.FirstVersionUUID, detail)
	assert.EqualValues(t, 1, dpnIngestManifest.DPNBag.Version, detail)
	assert.Equal(t, _context.Config.DPN.LocalNode, dpnIngestManifest.DPNBag.IngestNode, detail)
	assert.Equal(t, _context.Config.DPN.LocalNode, dpnIngestManifest.DPNBag.AdminNode, detail)
	assert.Equal(t, "D", dpnIngestManifest.DPNBag.BagType, detail)
	assert.NotEqual(t, 0, dpnIngestManifest.DPNBag.Size, detail)
	assert.False(t, dpnIngestManifest.DPNBag.CreatedAt.IsZero(), detail)
	assert.False(t, dpnIngestManifest.DPNBag.UpdatedAt.IsZero(), detail)

	require.NotEmpty(t, dpnIngestManifest.DPNBag.MessageDigests, detail)
	messageDigest := dpnIngestManifest.DPNBag.MessageDigests[0]
	assert.Equal(t, dpnIngestManifest.DPNBag.UUID, messageDigest.Bag, detail)
	assert.Equal(t, constants.AlgSha256, messageDigest.Algorithm, detail)
	assert.Equal(t, _context.Config.DPN.LocalNode, messageDigest.Node, detail)
	assert.Equal(t, 64, len(messageDigest.Value), detail)
	assert.False(t, messageDigest.CreatedAt.IsZero(), detail)

	assert.NotEmpty(t, dpnIngestManifest.LocalDir, detail)
	assert.NotEmpty(t, dpnIngestManifest.LocalTarFile, detail)
	assert.True(t, strings.HasSuffix(dpnIngestManifest.LocalTarFile, ".tar"), detail)

	// Bag has not yet been stored in Glacier, so this should be empty.
	assert.Empty(t, dpnIngestManifest.StorageURL, detail)
}
<|endoftext|>


<commit_before>package boss

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/pajlada/pajbot2/common"
)

type parse struct {
	m *common.Msg
}

/*
Parse parses an IRC message into a more readable bot.Msg
*/
func Parse(line string) common.Msg {
	p := &parse{}
	p.m = &common.Msg{
		User: common.User{},
	}
	parseTags := true

	var splitline []string
	if strings.HasPrefix(line, ":") {
		parseTags = false
		splitline = strings.SplitN(line, ":", 2)
	} else {
		splitline = strings.SplitN(line, " :", 2)
	}
	tagsRaw := splitline[0]
	msg := splitline[1]
	tags := make(map[string]string)

	p.GetMessage(msg)
	if p.m.User.Name == "twitchnotify" {
		if !strings.Contains(p.m.Message, " to ") && !strings.Contains(p.m.Message, " while ") {
			p.m.Type = "sub"
			p.Sub()
		} else {
			p.m.Type = "hostSub" // useless xD
		}

	} else {
		if strings.Contains(msg, "PRIVMSG") {
			p.m.Type = "privmsg"
		} else {
			p.m.Type = "whisper"
		}

		// Should user properties stay at their zero value when there are no tags? Do we even care about this scenario?
		if parseTags {
			for _, tagValue := range strings.Split(tagsRaw, ";") {
				spl := strings.Split(tagValue, "=")
				k := spl[0]
				v := spl[1]
				tags[k] = v
			}
			p.GetTwitchEmotes(tags["emotes"])
			p.GetTags(tags)
		}
	}

	return *p.m
}

func (p *parse) GetTwitchEmotes(emotetag string) {
	// TODO: Parse more emote information (bttv (and ffz?), name, size, isGif)
	// will we done by a module in the bot itself
	p.m.Emotes = make([]common.Emote, 0)
	if emotetag == "" {
		return
	}
	emoteSlice := strings.Split(emotetag, "/")
	for i := range emoteSlice {
		id := strings.Split(emoteSlice[i], ":")[0]
		e := &common.Emote{}
		e.Type = "twitch"
		e.Name = ""
		e.ID = id
		// 28 px should be fine for twitch emotes
		e.SizeX = 28
		e.SizeY = 28
		e.Count = strings.Count(emoteSlice[i], "-")
		p.m.Emotes = append(p.m.Emotes, *e)
	}
}

func (p *parse) GetTags(tags map[string]string) {
	// TODO: Parse id and color
	// color and id is pretty useless imo
	if tags["display-name"] == "" {
		p.m.User.DisplayName = p.m.User.Name
	} else {
		p.m.User.DisplayName = tags["display-name"]
	}
	p.m.User.Type = tags["user-type"]
	if tags["turbo"] == "1" {
		p.m.User.Turbo = true
	}
	if tags["mod"] == "1" {
		p.m.User.Mod = true
	}
	if tags["subscriber"] == "1" {
		p.m.User.Mod = true
	}

}

func (p *parse) GetMessage(msg string) {
	if strings.HasPrefix(msg, ":") {
		msg = strings.Replace(msg, ":", "", 1)
	}
	p.m.Message = strings.SplitN(msg, " :", 2)[1]
	p.m.User.Name = strings.SplitN(msg, "!", 2)[0]
	c := strings.SplitN(msg, "#", 3)[1]
	p.m.Channel = strings.SplitN(c, " ", 2)[0]
	p.getAction()
}

// regex in 2016 LUL
func (p *parse) getAction() {
	fmt.Println(":" + p.m.Message + ":")
	if strings.HasPrefix(p.m.Message, "\u0001ACTION ") && strings.HasSuffix(p.m.Message, "\u0001") {
		p.m.Me = true
		m := p.m.Message
		m = strings.Replace(m, "\u0001ACTION ", "", 1)
		m = strings.Replace(m, "\u0001", "", 1)
		p.m.Message = m
	}
}

func (p *parse) Sub() {
	m := p.m.Message
	if strings.Contains(m, "just ") {
		p.m.Length = 1
	} else {
		temp := strings.Split(m, " for ")[1]
		l := strings.Split(temp, " ")[0]
		length, err := strconv.Atoi(l)
		if err == nil {
			p.m.Length = length
		} else {
			panic(err)
		}
	}
	p.m.User.DisplayName = strings.Split(m, " ")[0]
	p.m.User.Name = strings.ToLower(p.m.User.DisplayName)
}
<commit_msg>now parsing /me correctly<commit_after>package boss

import (
	"strconv"
	"strings"

	"github.com/pajlada/pajbot2/common"
)

type parse struct {
	m *common.Msg
}

/*
Parse parses an IRC message into a more readable bot.Msg
*/
func Parse(line string) common.Msg {
	p := &parse{}
	p.m = &common.Msg{
		User: common.User{},
	}
	parseTags := true

	var splitline []string
	if strings.HasPrefix(line, ":") {
		parseTags = false
		splitline = strings.SplitN(line, ":", 2)
	} else {
		splitline = strings.SplitN(line, " :", 2)
	}
	tagsRaw := splitline[0]
	msg := splitline[1]
	tags := make(map[string]string)

	p.GetMessage(msg)
	if p.m.User.Name == "twitchnotify" {
		if !strings.Contains(p.m.Message, " to ") && !strings.Contains(p.m.Message, " while ") {
			p.m.Type = "sub"
			p.Sub()
		} else {
			p.m.Type = "hostSub" // useless xD
		}

	} else {
		if strings.Contains(msg, "PRIVMSG") {
			p.m.Type = "privmsg"
		} else {
			p.m.Type = "whisper"
		}

		// Should user properties stay at their zero value when there are no tags? Do we even care about this scenario?
		if parseTags {
			for _, tagValue := range strings.Split(tagsRaw, ";") {
				spl := strings.Split(tagValue, "=")
				k := spl[0]
				v := spl[1]
				tags[k] = v
			}
			p.GetTwitchEmotes(tags["emotes"])
			p.GetTags(tags)
		}
	}

	return *p.m
}

func (p *parse) GetTwitchEmotes(emotetag string) {
	// TODO: Parse more emote information (bttv (and ffz?), name, size, isGif)
	// will we done by a module in the bot itself
	p.m.Emotes = make([]common.Emote, 0)
	if emotetag == "" {
		return
	}
	emoteSlice := strings.Split(emotetag, "/")
	for i := range emoteSlice {
		id := strings.Split(emoteSlice[i], ":")[0]
		e := &common.Emote{}
		e.Type = "twitch"
		e.Name = ""
		e.ID = id
		// 28 px should be fine for twitch emotes
		e.SizeX = 28
		e.SizeY = 28
		e.Count = strings.Count(emoteSlice[i], "-")
		p.m.Emotes = append(p.m.Emotes, *e)
	}
}

func (p *parse) GetTags(tags map[string]string) {
	// TODO: Parse id and color
	// color and id is pretty useless imo
	if tags["display-name"] == "" {
		p.m.User.DisplayName = p.m.User.Name
	} else {
		p.m.User.DisplayName = tags["display-name"]
	}
	p.m.User.Type = tags["user-type"]
	if tags["turbo"] == "1" {
		p.m.User.Turbo = true
	}
	if tags["mod"] == "1" {
		p.m.User.Mod = true
	}
	if tags["subscriber"] == "1" {
		p.m.User.Mod = true
	}

}

func (p *parse) GetMessage(msg string) {
	if strings.HasPrefix(msg, ":") {
		msg = strings.Replace(msg, ":", "", 1)
	}
	p.m.Message = strings.SplitN(msg, " :", 2)[1]
	p.m.User.Name = strings.SplitN(msg, "!", 2)[0]
	c := strings.SplitN(msg, "#", 3)[1]
	p.m.Channel = strings.SplitN(c, " ", 2)[0]
	p.getAction()
}

// regex in 2016 LUL
func (p *parse) getAction() {
	if strings.HasPrefix(p.m.Message, "\u0001ACTION ") && strings.HasSuffix(p.m.Message, "\u0001") {
		p.m.Me = true
		m := p.m.Message
		m = strings.Replace(m, "\u0001ACTION ", "", 1)
		m = strings.Replace(m, "\u0001", "", 1)
		p.m.Message = m
	}
}

func (p *parse) Sub() {
	m := p.m.Message
	if strings.Contains(m, "just ") {
		p.m.Length = 1
	} else {
		temp := strings.Split(m, " for ")[1]
		l := strings.Split(temp, " ")[0]
		length, err := strconv.Atoi(l)
		if err == nil {
			p.m.Length = length
		} else {
			panic(err)
		}
	}
	p.m.User.DisplayName = strings.Split(m, " ")[0]
	p.m.User.Name = strings.ToLower(p.m.User.DisplayName)
}
<|endoftext|>


<commit_before>/*
 * This is the main core of the yaag package
 */
package yaag

import (
	"encoding/json"
	"html/template"
	"io"
	"log"
	"os"
	"path/filepath"

	"github.com/betacraft/yaag/yaag/models"
)

var count int
var config *Config

// Initial empty spec
var spec *models.Spec = &models.Spec{}

func IsOn() bool {
	return config.On
}

func Init(conf *Config) {
	config = conf
	// load the config file
	if conf.DocPath == "" {
		conf.DocPath = "apidoc.html"
	}

	filePath, err := filepath.Abs(conf.DocPath + ".json")
	dataFile, err := os.Open(filePath)
	defer dataFile.Close()
	if err == nil {
		json.NewDecoder(io.Reader(dataFile)).Decode(spec)
		generateHtml()
	}
}

func add(x, y int) int {
	return x + y
}

func mult(x, y int) int {
	return (x + 1) * y
}

func GenerateHtml(apiCall *models.ApiCall) {
	shouldAddPathSpec := true
	for k, apiSpec := range spec.ApiSpecs {
		if apiSpec.Path == apiCall.CurrentPath && apiSpec.HttpVerb == apiCall.MethodType {
			shouldAddPathSpec = false
			apiCall.Id = count
			count += 1
			deleteCommonHeaders(apiCall)
			avoid := false
			for _, currentApiCall := range spec.ApiSpecs[k].Calls {
				if apiCall.RequestBody == currentApiCall.RequestBody &&
					apiCall.ResponseCode == currentApiCall.ResponseCode &&
					apiCall.ResponseBody == currentApiCall.ResponseBody {
					avoid = true
				}
			}
			if !avoid {
				spec.ApiSpecs[k].Calls = append(apiSpec.Calls, *apiCall)
			}
		}
	}

	if shouldAddPathSpec {
		apiSpec := models.ApiSpec{
			HttpVerb: apiCall.MethodType,
			Path:     apiCall.CurrentPath,
		}
		apiCall.Id = count
		count += 1
		deleteCommonHeaders(apiCall)
		apiSpec.Calls = append(apiSpec.Calls, *apiCall)
		spec.ApiSpecs = append(spec.ApiSpecs, apiSpec)
	}
	filePath, err := filepath.Abs(config.DocPath)
	dataFile, err := os.Create(filePath + ".json")
	if err != nil {
		log.Println(err)
		return
	}
	defer dataFile.Close()
	data, err := json.Marshal(spec)
	if err != nil {
		log.Println(err)
		return
	}
	_, err = dataFile.Write(data)
	if err != nil {
		log.Println(err)
		return
	}
	generateHtml()
}

func generateHtml() {
	funcs := template.FuncMap{"add": add, "mult": mult}
	t := template.New("API Documentation").Funcs(funcs)
	htmlString := Template
	t, err := t.Parse(htmlString)
	if err != nil {
		log.Println(err)
		return
	}
	filePath, err := filepath.Abs(config.DocPath)
	if err != nil {
		panic("Error while creating file path : " + err.Error())
	}
	homeHtmlFile, err := os.Create(filePath)
	defer homeHtmlFile.Close()
	if err != nil {
		panic("Error while creating documentation file : " + err.Error())
	}
	homeWriter := io.Writer(homeHtmlFile)
	t.Execute(homeWriter, map[string]interface{}{"array": spec.ApiSpecs,
		"baseUrls": config.BaseUrls, "Title": config.DocTitle})
}

func deleteCommonHeaders(call *models.ApiCall) {
	delete(call.RequestHeader, "Accept")
	delete(call.RequestHeader, "Accept-Encoding")
	delete(call.RequestHeader, "Accept-Language")
	delete(call.RequestHeader, "Cache-Control")
	delete(call.RequestHeader, "Connection")
	delete(call.RequestHeader, "Cookie")
	delete(call.RequestHeader, "Origin")
	delete(call.RequestHeader, "User-Agent")
}

func IsStatusCodeValid(code int) bool  {
	if code > 200 && code < 300 {
		return true
	} else {
		return false
	}
}
<commit_msg>bugfix: statuscode check. fixes #44<commit_after>/*
 * This is the main core of the yaag package
 */
package yaag

import (
	"encoding/json"
	"html/template"
	"io"
	"log"
	"os"
	"path/filepath"

	"github.com/betacraft/yaag/yaag/models"
)

var count int
var config *Config

// Initial empty spec
var spec *models.Spec = &models.Spec{}

func IsOn() bool {
	return config.On
}

func Init(conf *Config) {
	config = conf
	// load the config file
	if conf.DocPath == "" {
		conf.DocPath = "apidoc.html"
	}

	filePath, err := filepath.Abs(conf.DocPath + ".json")
	dataFile, err := os.Open(filePath)
	defer dataFile.Close()
	if err == nil {
		json.NewDecoder(io.Reader(dataFile)).Decode(spec)
		generateHtml()
	}
}

func add(x, y int) int {
	return x + y
}

func mult(x, y int) int {
	return (x + 1) * y
}

func GenerateHtml(apiCall *models.ApiCall) {
	shouldAddPathSpec := true
	for k, apiSpec := range spec.ApiSpecs {
		if apiSpec.Path == apiCall.CurrentPath && apiSpec.HttpVerb == apiCall.MethodType {
			shouldAddPathSpec = false
			apiCall.Id = count
			count += 1
			deleteCommonHeaders(apiCall)
			avoid := false
			for _, currentApiCall := range spec.ApiSpecs[k].Calls {
				if apiCall.RequestBody == currentApiCall.RequestBody &&
					apiCall.ResponseCode == currentApiCall.ResponseCode &&
					apiCall.ResponseBody == currentApiCall.ResponseBody {
					avoid = true
				}
			}
			if !avoid {
				spec.ApiSpecs[k].Calls = append(apiSpec.Calls, *apiCall)
			}
		}
	}

	if shouldAddPathSpec {
		apiSpec := models.ApiSpec{
			HttpVerb: apiCall.MethodType,
			Path:     apiCall.CurrentPath,
		}
		apiCall.Id = count
		count += 1
		deleteCommonHeaders(apiCall)
		apiSpec.Calls = append(apiSpec.Calls, *apiCall)
		spec.ApiSpecs = append(spec.ApiSpecs, apiSpec)
	}
	filePath, err := filepath.Abs(config.DocPath)
	dataFile, err := os.Create(filePath + ".json")
	if err != nil {
		log.Println(err)
		return
	}
	defer dataFile.Close()
	data, err := json.Marshal(spec)
	if err != nil {
		log.Println(err)
		return
	}
	_, err = dataFile.Write(data)
	if err != nil {
		log.Println(err)
		return
	}
	generateHtml()
}

func generateHtml() {
	funcs := template.FuncMap{"add": add, "mult": mult}
	t := template.New("API Documentation").Funcs(funcs)
	htmlString := Template
	t, err := t.Parse(htmlString)
	if err != nil {
		log.Println(err)
		return
	}
	filePath, err := filepath.Abs(config.DocPath)
	if err != nil {
		panic("Error while creating file path : " + err.Error())
	}
	homeHtmlFile, err := os.Create(filePath)
	defer homeHtmlFile.Close()
	if err != nil {
		panic("Error while creating documentation file : " + err.Error())
	}
	homeWriter := io.Writer(homeHtmlFile)
	t.Execute(homeWriter, map[string]interface{}{"array": spec.ApiSpecs,
		"baseUrls": config.BaseUrls, "Title": config.DocTitle})
}

func deleteCommonHeaders(call *models.ApiCall) {
	delete(call.RequestHeader, "Accept")
	delete(call.RequestHeader, "Accept-Encoding")
	delete(call.RequestHeader, "Accept-Language")
	delete(call.RequestHeader, "Cache-Control")
	delete(call.RequestHeader, "Connection")
	delete(call.RequestHeader, "Cookie")
	delete(call.RequestHeader, "Origin")
	delete(call.RequestHeader, "User-Agent")
}

func IsStatusCodeValid(code int) bool  {
	if code >= 200 && code < 300 {
		return true
	} else {
		return false
	}
}
<|endoftext|>


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

package filepath

import (
	"runtime"
	"strings"

	"github.com/juju/errors"
	"github.com/juju/utils"
)

// Renderer provides methods for the different functions in
// the stdlib path/filepath package that don't relate to a concrete
// filesystem. So Abs, EvalSymlinks, Glob, Rel, and Walk are not
// included. Also, while the functions in path/filepath relate to the
// current host, the PathRenderer methods relate to the renderer's
// target platform. So for example, a windows-oriented implementation
// will give windows-specific results even when used on linux.
type Renderer interface {
	// Base mimics path/filepath.
	Base(path string) string

	// Clean mimics path/filepath.
	Clean(path string) string

	// Dir mimics path/filepath.
	Dir(path string) string

	// Ext mimics path/filepath.
	Ext(path string) string

	// FromSlash mimics path/filepath.
	FromSlash(path string) string

	// IsAbs mimics path/filepath.
	IsAbs(path string) bool

	// Join mimics path/filepath.
	Join(path ...string) string

	// Match mimics path/filepath.
	Match(pattern, name string) (matched bool, err error)

	// Split mimics path/filepath.
	Split(path string) (dir, file string)

	// SplitList mimics path/filepath.
	SplitList(path string) []string

	// ToSlash mimics path/filepath.
	ToSlash(path string) string

	// VolumeName mimics path/filepath.
	VolumeName(path string) string
}

// NewRenderer returns a Renderer for the given os.
func NewRenderer(os string) (Renderer, error) {
	if os == "" {
		os = runtime.GOOS
	}

	os = strings.ToLower(os)
	switch {
	case os == utils.OSWindows:
		return &WindowsRenderer{}, nil
	case utils.OSIsUnix(os):
		return &UnixRenderer{}, nil
	case os == "ubuntu":
		return &UnixRenderer{}, nil
	default:
		return nil, errors.NotFoundf("renderer for %q", os)
	}
}
<commit_msg>Add 3 methods to Renderer (borrowed from Python's os.path).<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package filepath

import (
	"runtime"
	"strings"

	"github.com/juju/errors"
	"github.com/juju/utils"
)

// Renderer provides methods for the different functions in
// the stdlib path/filepath package that don't relate to a concrete
// filesystem. So Abs, EvalSymlinks, Glob, Rel, and Walk are not
// included. Also, while the functions in path/filepath relate to the
// current host, the PathRenderer methods relate to the renderer's
// target platform. So for example, a windows-oriented implementation
// will give windows-specific results even when used on linux.
type Renderer interface {
	// Base mimics path/filepath.
	Base(path string) string

	// Clean mimics path/filepath.
	Clean(path string) string

	// Dir mimics path/filepath.
	Dir(path string) string

	// Ext mimics path/filepath.
	Ext(path string) string

	// FromSlash mimics path/filepath.
	FromSlash(path string) string

	// IsAbs mimics path/filepath.
	IsAbs(path string) bool

	// Join mimics path/filepath.
	Join(path ...string) string

	// Match mimics path/filepath.
	Match(pattern, name string) (matched bool, err error)

	// NormCase normalizes the case of a pathname. On Unix and Mac OS X,
	// this returns the path unchanged; on case-insensitive filesystems,
	// it converts the path to lowercase. On Windows, it also converts
	// forward slashes to backward slashes.
	NormCase(path string) string

	// Split mimics path/filepath.
	Split(path string) (dir, file string)

	// SplitDrive splits the pathname into a pair (drive, tail) where
	// drive is either a mount point or the empty string. On systems
	// which do not use drive specifications, drive will always be the
	// empty string. In all cases, drive + tail will be the same as path.
	//
	// On Windows, splits a pathname into drive/UNC sharepoint and
	// relative path.
	//
	// If the path contains a drive letter, drive will contain
	// everything up to and including the colon. e.g.
	// splitdrive("c:/dir") returns ("c:", "/dir")
	//
	// If the path contains a UNC path, drive will contain the host name
	// and share, up to but not including the fourth separator. e.g.
	// SplitDrive("//host/computer/dir") returns ("//host/computer", "/dir").
	SplitDrive(path string) string

	// SplitList mimics path/filepath.
	SplitList(path string) []string

	// SplitSuffix splits the pathname into a pair (root, suffix) such
	// that root + suffix == path, and ext is empty or begins with a
	// period and contains at most one period. Leading periods on the
	// basename are ignored; SplitSuffix('.cshrc') returns ('.cshrc', '').
	SplitSuffix(path string) (string, string)

	// ToSlash mimics path/filepath.
	ToSlash(path string) string

	// VolumeName mimics path/filepath.
	VolumeName(path string) string
}

// NewRenderer returns a Renderer for the given os.
func NewRenderer(os string) (Renderer, error) {
	if os == "" {
		os = runtime.GOOS
	}

	os = strings.ToLower(os)
	switch {
	case os == utils.OSWindows:
		return &WindowsRenderer{}, nil
	case utils.OSIsUnix(os):
		return &UnixRenderer{}, nil
	case os == "ubuntu":
		return &UnixRenderer{}, nil
	default:
		return nil, errors.NotFoundf("renderer for %q", os)
	}
}
<|endoftext|>


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

// +build !js

package devicescale

import (
	"fmt"
	"syscall"
	"unsafe"
)

const (
	logPixelsX              = 88
	monitorDefaultToNearest = 2
	mdtEffectiveDpi         = 0
)

var (
	user32 = syscall.NewLazyDLL("user32")
	gdi32  = syscall.NewLazyDLL("gdi32")
	shcore = syscall.NewLazyDLL("shcore")
)

var (
	procSetProcessDPIAware = user32.NewProc("SetProcessDPIAware")
	procGetActiveWindow    = user32.NewProc("GetActiveWindow")
	procGetWindowDC        = user32.NewProc("GetWindowDC")
	procReleaseDC          = user32.NewProc("ReleaseDC")
	procMonitorFromWindow  = user32.NewProc("MonitorFromWindow")
	procGetMonitorInfo     = user32.NewProc("GetMonitorInfoW")

	procGetDeviceCaps = gdi32.NewProc("GetDeviceCaps")

	// GetScaleFactorForMonitor function can return unrelaiavle value (e.g. returning 180
	// for 200% scale). Use GetDpiForMonitor instead.
	procGetDpiForMonitor = shcore.NewProc("GetDpiForMonitor")
)

var shcoreAvailable = false

func init() {
	if shcore.Load() == nil {
		shcoreAvailable = true
	}
}

func setProcessDPIAware() error {
	r, _, e := syscall.Syscall(procSetProcessDPIAware.Addr(), 0, 0, 0, 0)
	if e != 0 {
		return fmt.Errorf("devicescale: SetProcessDPIAware failed: error code: %d", e)
	}
	if r == 0 {
		return fmt.Errorf("devicescale: SetProcessDPIAware failed: returned value: %d", r)
	}
	return nil
}

func getActiveWindow() (uintptr, error) {
	r, _, e := syscall.Syscall(procGetActiveWindow.Addr(), 0, 0, 0, 0)
	if e != 0 {
		return 0, fmt.Errorf("devicescale: GetActiveWindow failed: error code: %d", e)
	}
	return r, nil
}

func getWindowDC(hwnd uintptr) (uintptr, error) {
	r, _, e := syscall.Syscall(procGetWindowDC.Addr(), 1, hwnd, 0, 0)
	if e != 0 {
		return 0, fmt.Errorf("devicescale: GetWindowDC failed: error code: %d", e)
	}
	if r == 0 {
		return 0, fmt.Errorf("devicescale: GetWindowDC failed: returned value: %d", r)
	}
	return r, nil
}

func releaseDC(hwnd, hdc uintptr) error {
	r, _, e := syscall.Syscall(procReleaseDC.Addr(), 2, hwnd, hdc, 0)
	if e != 0 {
		return fmt.Errorf("devicescale: ReleaseDC failed: error code: %d", e)
	}
	if r == 0 {
		return fmt.Errorf("devicescale: ReleaseDC failed: returned value: %d", r)
	}
	return nil
}

func getDeviceCaps(hdc uintptr, nindex int) (int, error) {
	r, _, e := syscall.Syscall(procGetDeviceCaps.Addr(), 2, hdc, uintptr(nindex), 0)
	if e != 0 {
		return 0, fmt.Errorf("devicescale: GetDeviceCaps failed: error code: %d", e)
	}
	return int(r), nil
}

func monitorFromWindow(hwnd uintptr, dwFlags int) (uintptr, error) {
	r, _, e := syscall.Syscall(procMonitorFromWindow.Addr(), 2, hwnd, uintptr(dwFlags), 0)
	if e != 0 {
		return 0, fmt.Errorf("devicescale: MonitorFromWindow failed: error code: %d", e)
	}
	if r == 0 {
		return 0, fmt.Errorf("devicescale: MonitorFromWindow failed: returned value: %d", r)
	}
	return r, nil
}

func getMonitorInfo(hMonitor uintptr, lpMonitorInfo uintptr) error {
	r, _, e := syscall.Syscall(procGetMonitorInfo.Addr(), 2, hMonitor, lpMonitorInfo, 0)
	if e != 0 {
		return fmt.Errorf("devicescale: GetMonitorInfo failed: error code: %d", e)
	}
	if r == 0 {
		return fmt.Errorf("devicescale: GetMonitorInfo failed: returned value: %d", r)
	}
	return nil
}

func getDpiForMonitor(hMonitor uintptr, dpiType uintptr, dpiX, dpiY uintptr) error {
	r, _, e := syscall.Syscall6(procGetDpiForMonitor.Addr(), 4,
		hMonitor, dpiType, dpiX, dpiY, 0, 0)
	if e != 0 {
		return fmt.Errorf("devicescale: GetDpiForMonitor failed: error code: %d", e)
	}
	if r != 0 {
		return fmt.Errorf("devicescale: GetDpiForMonitor failed: returned value: %d", r)
	}
	return nil
}

func getFromLogPixelSx() float64 {
	dc, err := getWindowDC(0)
	if err != nil {
		panic(err)
	}
	defer releaseDC(0, dc)

	// Note that GetDeviceCaps with LOGPIXELSX always returns a same value for any monitors
	// even if multiple monitors are used.
	dpi, err := getDeviceCaps(dc, logPixelsX)
	if err != nil {
		panic(err)
	}

	return float64(dpi) / 96
}

func impl() float64 {
	if err := setProcessDPIAware(); err != nil {
		panic(err)
	}

	// On Windows 7 or older, shcore.dll is not available.
	if !shcoreAvailable {
		return getFromLogPixelSx()
	}

	w, err := getActiveWindow()
	if err != nil {
		panic(err)
	}
	// The window is not initialized yet when w == 0.
	if w == 0 {
		return getFromLogPixelSx()
	}
	defer releaseDC(0, w)

	m, err := monitorFromWindow(w, monitorDefaultToNearest)
	if err != nil {
		panic(err)
	}

	dpiX := uint32(0)
	dpiY := uint32(0) // Passing dpiY is needed even though this is not used.
	if err := getDpiForMonitor(m, mdtEffectiveDpi, uintptr(unsafe.Pointer(&dpiX)), uintptr(unsafe.Pointer(&dpiY))); err != nil {
		panic(err)
	}
	return float64(dpiX) / 96
}
<commit_msg>gofmt -s -w<commit_after>// Copyright 2018 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build !js

package devicescale

import (
	"fmt"
	"syscall"
	"unsafe"
)

const (
	logPixelsX              = 88
	monitorDefaultToNearest = 2
	mdtEffectiveDpi         = 0
)

var (
	user32 = syscall.NewLazyDLL("user32")
	gdi32  = syscall.NewLazyDLL("gdi32")
	shcore = syscall.NewLazyDLL("shcore")
)

var (
	procSetProcessDPIAware = user32.NewProc("SetProcessDPIAware")
	procGetActiveWindow    = user32.NewProc("GetActiveWindow")
	procGetWindowDC        = user32.NewProc("GetWindowDC")
	procReleaseDC          = user32.NewProc("ReleaseDC")
	procMonitorFromWindow  = user32.NewProc("MonitorFromWindow")
	procGetMonitorInfo     = user32.NewProc("GetMonitorInfoW")

	procGetDeviceCaps = gdi32.NewProc("GetDeviceCaps")

	// GetScaleFactorForMonitor function can return unrelaiavle value (e.g. returning 180
	// for 200% scale). Use GetDpiForMonitor instead.
	procGetDpiForMonitor = shcore.NewProc("GetDpiForMonitor")
)

var shcoreAvailable = false

func init() {
	if shcore.Load() == nil {
		shcoreAvailable = true
	}
}

func setProcessDPIAware() error {
	r, _, e := syscall.Syscall(procSetProcessDPIAware.Addr(), 0, 0, 0, 0)
	if e != 0 {
		return fmt.Errorf("devicescale: SetProcessDPIAware failed: error code: %d", e)
	}
	if r == 0 {
		return fmt.Errorf("devicescale: SetProcessDPIAware failed: returned value: %d", r)
	}
	return nil
}

func getActiveWindow() (uintptr, error) {
	r, _, e := syscall.Syscall(procGetActiveWindow.Addr(), 0, 0, 0, 0)
	if e != 0 {
		return 0, fmt.Errorf("devicescale: GetActiveWindow failed: error code: %d", e)
	}
	return r, nil
}

func getWindowDC(hwnd uintptr) (uintptr, error) {
	r, _, e := syscall.Syscall(procGetWindowDC.Addr(), 1, hwnd, 0, 0)
	if e != 0 {
		return 0, fmt.Errorf("devicescale: GetWindowDC failed: error code: %d", e)
	}
	if r == 0 {
		return 0, fmt.Errorf("devicescale: GetWindowDC failed: returned value: %d", r)
	}
	return r, nil
}

func releaseDC(hwnd, hdc uintptr) error {
	r, _, e := syscall.Syscall(procReleaseDC.Addr(), 2, hwnd, hdc, 0)
	if e != 0 {
		return fmt.Errorf("devicescale: ReleaseDC failed: error code: %d", e)
	}
	if r == 0 {
		return fmt.Errorf("devicescale: ReleaseDC failed: returned value: %d", r)
	}
	return nil
}

func getDeviceCaps(hdc uintptr, nindex int) (int, error) {
	r, _, e := syscall.Syscall(procGetDeviceCaps.Addr(), 2, hdc, uintptr(nindex), 0)
	if e != 0 {
		return 0, fmt.Errorf("devicescale: GetDeviceCaps failed: error code: %d", e)
	}
	return int(r), nil
}

func monitorFromWindow(hwnd uintptr, dwFlags int) (uintptr, error) {
	r, _, e := syscall.Syscall(procMonitorFromWindow.Addr(), 2, hwnd, uintptr(dwFlags), 0)
	if e != 0 {
		return 0, fmt.Errorf("devicescale: MonitorFromWindow failed: error code: %d", e)
	}
	if r == 0 {
		return 0, fmt.Errorf("devicescale: MonitorFromWindow failed: returned value: %d", r)
	}
	return r, nil
}

func getMonitorInfo(hMonitor uintptr, lpMonitorInfo uintptr) error {
	r, _, e := syscall.Syscall(procGetMonitorInfo.Addr(), 2, hMonitor, lpMonitorInfo, 0)
	if e != 0 {
		return fmt.Errorf("devicescale: GetMonitorInfo failed: error code: %d", e)
	}
	if r == 0 {
		return fmt.Errorf("devicescale: GetMonitorInfo failed: returned value: %d", r)
	}
	return nil
}

func getDpiForMonitor(hMonitor uintptr, dpiType uintptr, dpiX, dpiY uintptr) error {
	r, _, e := syscall.Syscall6(procGetDpiForMonitor.Addr(), 4,
		hMonitor, dpiType, dpiX, dpiY, 0, 0)
	if e != 0 {
		return fmt.Errorf("devicescale: GetDpiForMonitor failed: error code: %d", e)
	}
	if r != 0 {
		return fmt.Errorf("devicescale: GetDpiForMonitor failed: returned value: %d", r)
	}
	return nil
}

func getFromLogPixelSx() float64 {
	dc, err := getWindowDC(0)
	if err != nil {
		panic(err)
	}
	defer releaseDC(0, dc)

	// Note that GetDeviceCaps with LOGPIXELSX always returns a same value for any monitors
	// even if multiple monitors are used.
	dpi, err := getDeviceCaps(dc, logPixelsX)
	if err != nil {
		panic(err)
	}

	return float64(dpi) / 96
}

func impl() float64 {
	if err := setProcessDPIAware(); err != nil {
		panic(err)
	}

	// On Windows 7 or older, shcore.dll is not available.
	if !shcoreAvailable {
		return getFromLogPixelSx()
	}

	w, err := getActiveWindow()
	if err != nil {
		panic(err)
	}
	// The window is not initialized yet when w == 0.
	if w == 0 {
		return getFromLogPixelSx()
	}
	defer releaseDC(0, w)

	m, err := monitorFromWindow(w, monitorDefaultToNearest)
	if err != nil {
		panic(err)
	}

	dpiX := uint32(0)
	dpiY := uint32(0) // Passing dpiY is needed even though this is not used.
	if err := getDpiForMonitor(m, mdtEffectiveDpi, uintptr(unsafe.Pointer(&dpiX)), uintptr(unsafe.Pointer(&dpiY))); err != nil {
		panic(err)
	}
	return float64(dpiX) / 96
}
<|endoftext|>


<commit_before>package gcsx

import (
	"context"
	"testing"

	"golang.org/x/oauth2"
)

func TestNewStorageHandleHttp2Disabled(t *testing.T) {
	sc := storageClientConfig{disableHttp2: true,
		maxConnsPerHost:     10,
		maxIdleConnsPerHost: 100,
		tokenSrc:            oauth2.StaticTokenSource(&oauth2.Token{})}

	handleCreated, err := GetStorageClientHandle(context.Background(), sc)

	if err != nil {
		t.Errorf("Handle creation failure")
	}
	if handleCreated == nil {
		t.Errorf("Storage handle is null")
	}
	if handleCreated.client == nil {
		t.Errorf("Storage client handle is null")
	}
}

func TestNewStorageHandleHttp2Enabled(t *testing.T) {
	sc := storageClientConfig{disableHttp2: false,
		maxConnsPerHost:     10,
		maxIdleConnsPerHost: 100,
		tokenSrc:            oauth2.StaticTokenSource(&oauth2.Token{})}

	handleCreated, err := GetStorageClientHandle(context.Background(), sc)

	if err != nil {
		t.Errorf("Handle creation failure")
	}
	if handleCreated == nil {
		t.Errorf("Storage handle is null")
	}
	if handleCreated.client == nil {
		t.Errorf("Storage client handle is null")
	}
}

func TestNewStorageHandleWithZeroMaxConnsPerHost(t *testing.T) {
	sc := storageClientConfig{disableHttp2: true,
		maxConnsPerHost:     0,
		maxIdleConnsPerHost: 100,
		tokenSrc:            oauth2.StaticTokenSource(&oauth2.Token{})}

	handleCreated, err := GetStorageClientHandle(context.Background(), sc)

	if err != nil {
		t.Errorf("Handle creation failure")
	}
	if handleCreated == nil {
		t.Errorf("Storage handle is null")
	}
	if handleCreated.client == nil {
		t.Errorf("Storage client handle is null")
	}
}
<commit_msg>Fixing linting issue in storage client test<commit_after>package gcsx

import (
	"context"
	"testing"

	"golang.org/x/oauth2"
)

func TestNewStorageHandleHttp2Disabled(t *testing.T) {
	sc := storageClientConfig{disableHttp2: true,
		maxConnsPerHost:     10,
		maxIdleConnsPerHost: 100,
		tokenSrc:            oauth2.StaticTokenSource(&oauth2.Token{})}

	handleCreated, err := GetStorageClientHandle(context.Background(), sc)

	if err != nil {
		t.Errorf("Handle creation failure")
	}
	if nil == handleCreated {
		t.Fatalf("Storage handle is null")
	}
	if nil == handleCreated.client {
		t.Fatalf("Storage client handle is null")
	}
}

func TestNewStorageHandleHttp2Enabled(t *testing.T) {
	sc := storageClientConfig{disableHttp2: false,
		maxConnsPerHost:     10,
		maxIdleConnsPerHost: 100,
		tokenSrc:            oauth2.StaticTokenSource(&oauth2.Token{})}

	handleCreated, err := GetStorageClientHandle(context.Background(), sc)

	if err != nil {
		t.Errorf("Handle creation failure")
	}
	if nil == handleCreated {
		t.Fatalf("Storage handle is null")
	}
	if nil == handleCreated.client {
		t.Fatalf("Storage client handle is null")
	}
}

func TestNewStorageHandleWithZeroMaxConnsPerHost(t *testing.T) {
	sc := storageClientConfig{disableHttp2: true,
		maxConnsPerHost:     0,
		maxIdleConnsPerHost: 100,
		tokenSrc:            oauth2.StaticTokenSource(&oauth2.Token{})}

	handleCreated, err := GetStorageClientHandle(context.Background(), sc)

	if err != nil {
		t.Errorf("Handle creation failure")
	}
	if nil == handleCreated {
		t.Fatalf("Storage handle is null")
	}
	if nil == handleCreated.client {
		t.Fatalf("Storage client handle is null")
	}
}
<|endoftext|>


<commit_before>package partners

import (
	"fmt"
	"log"
	"net/url"
	"time"

	"github.com/brnstz/bus/internal/conf"
	"github.com/brnstz/bus/internal/etc"
	"github.com/brnstz/bus/internal/models"

	"github.com/brnstz/bus/internal/partners/nyct_subway"
	"github.com/brnstz/bus/internal/partners/transit_realtime"

	"github.com/golang/protobuf/proto"
)

var (
	esiURL = "http://datamine.mta.info/mta_esi.php"

	routeToFeed = map[string]string{
		"1":  "1",
		"2":  "1",
		"3":  "1",
		"4":  "1",
		"5":  "1",
		"6":  "1",
		"6X": "1",
		"S":  "1",
		"GS": "1",
		"L":  "2",
		"SI": "11",
	}
)

type mtaNYCSubway struct{}

func (_ mtaNYCSubway) Live(route models.Route, stop models.Stop) (d models.Departures, v []models.Vehicle, err error) {
	//now := time.Now()

	feed, exists := routeToFeed[stop.RouteID]
	if !exists {
		return
	}

	q := url.Values{}
	q.Set("key", conf.API.DatamineAPIKey)
	q.Set("feed_id", feed)
	u := fmt.Sprint(esiURL, "?", q.Encode())

	b, err := etc.RedisCache(u)
	if err != nil {
		log.Println("can't get live subways", err)
		return
	}

	tr := &transit_realtime.FeedMessage{}
	err = proto.Unmarshal(b, tr)
	if err != nil {
		log.Println("can't unmarshal", err)
		return
	}

	for _, e := range tr.Entity {
		var event interface{}

		var vehicle models.Vehicle

		tripUpdate := e.GetTripUpdate()
		trip := tripUpdate.GetTrip()
		if trip == nil {
			log.Println("skipping nil trip", e)
			continue
		}

		event, err = proto.GetExtension(trip, nyct_subway.E_NyctTripDescriptor)
		if err != nil {
			log.Println("can't get extension", err)
			continue
		}

		nycTrip, ok := event.(*nyct_subway.NyctTripDescriptor)
		if !ok {
			log.Println("can't coerce to nyct_subway.NyctTripDescriptor")
			continue
		}

		updates := tripUpdate.GetStopTimeUpdate()

		first := true
		for _, u := range updates {

			stopID := u.GetStopId()
			departureTime := time.Unix(u.GetDeparture().GetTime(), 0)

			// The first update in an entity is the stop where the train will
			// next be. Include only "assigned" trips, which are those that
			// are about to start.
			if first && nycTrip.GetIsAssigned() {
				first = false

				vehicle, err = models.GetVehicle(route.AgencyID, route.ID, stop.ID)
				vehicle.Live = true
				if err != nil {
					log.Println("can't get vehicle", err)
					return
				}
				v = append(v, vehicle)
			} else {
				first = false
			}

			// If this is our stop, then get the departure time.
			if stopID == stop.ID {
				d = append(d,
					&models.Departure{
						Time:   departureTime,
						TripID: trip.GetTripId(),
						Live:   true,
					},
				)
			}
		}
	}

	return
}
<commit_msg>refactored stop update stuff<commit_after>package partners

import (
	"fmt"
	"log"
	"net/url"
	"time"

	"github.com/brnstz/bus/internal/conf"
	"github.com/brnstz/bus/internal/etc"
	"github.com/brnstz/bus/internal/models"

	"github.com/brnstz/bus/internal/partners/nyct_subway"
	"github.com/brnstz/bus/internal/partners/transit_realtime"

	"github.com/golang/protobuf/proto"
)

var (
	esiURL = "http://datamine.mta.info/mta_esi.php"

	routeToFeed = map[string]string{
		"1":  "1",
		"2":  "1",
		"3":  "1",
		"4":  "1",
		"5":  "1",
		"6":  "1",
		"6X": "1",
		"S":  "1",
		"GS": "1",
		"L":  "2",
		"SI": "11",
	}
)

type mtaNYCSubway struct{}

func (_ mtaNYCSubway) Live(route models.Route, stop models.Stop) (d models.Departures, v []models.Vehicle, err error) {

	// Get the feed for this route, if there is one. Otherwise, nothing
	// to return.
	feed, exists := routeToFeed[stop.RouteID]
	if !exists {
		return
	}

	// Construct URL and call external API, possibly getting cached
	// value.
	q := url.Values{}
	q.Set("key", conf.API.DatamineAPIKey)
	q.Set("feed_id", feed)
	u := fmt.Sprint(esiURL, "?", q.Encode())

	b, err := etc.RedisCache(u)
	if err != nil {
		log.Println("can't get live subways", err)
		return
	}

	// Load the protobuf struct
	tr := &transit_realtime.FeedMessage{}
	err = proto.Unmarshal(b, tr)
	if err != nil {
		log.Println("can't unmarshal", err)
		return
	}

	// Look at each message in the feed
	for _, e := range tr.Entity {

		// Get some updates
		tripUpdate := e.GetTripUpdate()
		trip := tripUpdate.GetTrip()
		stopTimeUpdates := tripUpdate.GetStopTimeUpdate()

		// If we have at least one stopTimeUpdate and the trip is non-nil,
		// we can get the NYCT extensions.
		if len(stopTimeUpdates) > 0 && trip != nil {
			var event interface{}

			// Get the NYC extension so we can see if the Trip is "assigned"
			// yet If it's assigned, we'll put the vehicle on the map.
			event, err = proto.GetExtension(
				trip, nyct_subway.E_NyctTripDescriptor,
			)
			if err != nil {
				log.Println("can't get extension", err)
				return
			}
			nycTrip, ok := event.(*nyct_subway.NyctTripDescriptor)
			if !ok {
				log.Println("can't coerce to nyct_subway.NyctTripDescriptor")
				return
			}

			// The first update in an entity is the stop where the train will
			// next be. Include only "assigned" trips, which are those that
			// are about to start.
			if nycTrip.GetIsAssigned() {
				var vehicle models.Vehicle

				// Get a "vehicle" with the lat/lon of the update's stop
				// (*not* the stop of our request)
				vehicle, err = models.GetVehicle(
					route.AgencyID, route.ID, stopTimeUpdates[0].GetStopId(),
				)
				vehicle.Live = true
				if err != nil {
					log.Println("can't get vehicle", err)
					return
				}
				v = append(v, vehicle)
			}
		}

		// Go through all updates to check for our stop ID's departure
		// time.
		for _, u := range stopTimeUpdates {
			// If this is our stop, then get the departure time.
			if u.GetStopId() == stop.ID {
				d = append(d,
					&models.Departure{
						Time:   time.Unix(u.GetDeparture().GetTime(), 0),
						TripID: trip.GetTripId(),
						Live:   true,
					},
				)
			}
		}
	}

	return
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package visualization

import (
	"errors"
	"io/ioutil"
	"os"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
)

func TestCreateFile(t *testing.T) {
	new(defaultExecutor).createFile(".text.svg", []byte("the contents"))

	// teardown
	defer os.Remove(".text.svg")

	actualContents, err := ioutil.ReadFile(".text.svg")
	assert.NoError(t, err)
	assert.Equal(t, "the contents", string(actualContents))
}

func TestCreateFileOverwriteExisting(t *testing.T) {
	new(defaultExecutor).createFile(".text.svg", []byte("delete me"))
	new(defaultExecutor).createFile(".text.svg", []byte("correct answer"))

	// teardown
	defer os.Remove(".text.svg")

	actualContents, err := ioutil.ReadFile(".text.svg")
	assert.NoError(t, err)
	assert.Equal(t, "correct answer", string(actualContents))
}

func TestGenerateFlameGraph(t *testing.T) {
	mockExecutor := new(mockExecutor)
	visualizer := defaultVisualizer{
		executor: mockExecutor,
	}

	graphInput := "N4;N5 1\nN4;N6;N5 8\n"

	mockExecutor.On("runPerlScript", graphInput).Return([]byte("<svg></svg>"), nil).Once()
	mockExecutor.On("createFile", ".text.svg", mock.AnythingOfType("[]uint8")).Return(nil).Once()

	visualizer.GenerateFlameGraph(graphInput, ".text.svg", false)

	mockExecutor.AssertExpectations(t)
}

func TestGenerateFlameGraphPrintsToStdout(t *testing.T) {
	mockExecutor := new(mockExecutor)
	visualizer := defaultVisualizer{
		executor: mockExecutor,
	}
	graphInput := "N4;N5 1\nN4;N6;N5 8\n"
	mockExecutor.On("runPerlScript", graphInput).Return([]byte("<svg></svg>"), nil).Once()
	visualizer.GenerateFlameGraph(graphInput, ".text.svg", true)

	mockExecutor.AssertNotCalled(t, "createFile")
	mockExecutor.AssertExpectations(t)
}

// Underlying errors can occur in runPerlScript(). This test ensures that errors
// like a missing flamegraph.pl script or malformed input are propagated.
func TestGenerateFlameGraphExecError(t *testing.T) {
	mockExecutor := new(mockExecutor)
	visualizer := defaultVisualizer{
		executor: mockExecutor,
	}
	mockExecutor.On("runPerlScript", "").Return(nil, errors.New("bad input")).Once()

	err := visualizer.GenerateFlameGraph("", ".text.svg", false)
	assert.Error(t, err)
	mockExecutor.AssertNotCalled(t, "createFile")
	mockExecutor.AssertExpectations(t)
}

func TestRunPerlScriptDoesExist(t *testing.T) {
	mockOSWrapper := new(mockOSWrapper)
	executor := defaultExecutor{
		osWrapper: mockOSWrapper,
	}
	cwd, _ := os.Getwd()
	mockOSWrapper.On("execLookPath", "flamegraph.pl").Return("", errors.New("DNE")).Once()
	mockOSWrapper.On("execLookPath", cwd+"/flamegraph.pl").Return("", errors.New("DNE")).Once()
	mockOSWrapper.On("execLookPath", "flame-graph-gen").Return("/somepath/flame-graph-gen", nil).Once()

	mockOSWrapper.On("cmdOutput", mock.AnythingOfType("*exec.Cmd")).Return([]byte("output"), nil).Once()

	out, err := executor.runPerlScript("some graph input")

	assert.Equal(t, []byte("output"), out)
	assert.NoError(t, err)
	mockOSWrapper.AssertExpectations(t)
}

func TestRunPerlScriptDoesNotExist(t *testing.T) {
	mockOSWrapper := new(mockOSWrapper)
	executor := defaultExecutor{
		osWrapper: mockOSWrapper,
	}
	cwd, _ := os.Getwd()
	mockOSWrapper.On("execLookPath", "flamegraph.pl").Return("", errors.New("DNE")).Once()
	mockOSWrapper.On("execLookPath", cwd+"/flamegraph.pl").Return("", errors.New("DNE")).Once()
	mockOSWrapper.On("execLookPath", "flame-graph-gen").Return("", errors.New("DNE")).Once()

	out, err := executor.runPerlScript("some graph input")

	assert.Equal(t, 0, len(out))
	assert.Error(t, err)
	mockOSWrapper.AssertExpectations(t)
}

// Smoke test the NewVisualizer method
func TestNewVisualizer(t *testing.T) {
	assert.NotNil(t, NewVisualizer())
}
<commit_msg>Fail immediately if os.Getwd returns an error in tests<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package visualization

import (
	"errors"
	"io/ioutil"
	"os"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
)

func TestCreateFile(t *testing.T) {
	new(defaultExecutor).createFile(".text.svg", []byte("the contents"))

	// teardown
	defer os.Remove(".text.svg")

	actualContents, err := ioutil.ReadFile(".text.svg")
	assert.NoError(t, err)
	assert.Equal(t, "the contents", string(actualContents))
}

func TestCreateFileOverwriteExisting(t *testing.T) {
	new(defaultExecutor).createFile(".text.svg", []byte("delete me"))
	new(defaultExecutor).createFile(".text.svg", []byte("correct answer"))

	// teardown
	defer os.Remove(".text.svg")

	actualContents, err := ioutil.ReadFile(".text.svg")
	assert.NoError(t, err)
	assert.Equal(t, "correct answer", string(actualContents))
}

func TestGenerateFlameGraph(t *testing.T) {
	mockExecutor := new(mockExecutor)
	visualizer := defaultVisualizer{
		executor: mockExecutor,
	}

	graphInput := "N4;N5 1\nN4;N6;N5 8\n"

	mockExecutor.On("runPerlScript", graphInput).Return([]byte("<svg></svg>"), nil).Once()
	mockExecutor.On("createFile", ".text.svg", mock.AnythingOfType("[]uint8")).Return(nil).Once()

	visualizer.GenerateFlameGraph(graphInput, ".text.svg", false)

	mockExecutor.AssertExpectations(t)
}

func TestGenerateFlameGraphPrintsToStdout(t *testing.T) {
	mockExecutor := new(mockExecutor)
	visualizer := defaultVisualizer{
		executor: mockExecutor,
	}
	graphInput := "N4;N5 1\nN4;N6;N5 8\n"
	mockExecutor.On("runPerlScript", graphInput).Return([]byte("<svg></svg>"), nil).Once()
	visualizer.GenerateFlameGraph(graphInput, ".text.svg", true)

	mockExecutor.AssertNotCalled(t, "createFile")
	mockExecutor.AssertExpectations(t)
}

// Underlying errors can occur in runPerlScript(). This test ensures that errors
// like a missing flamegraph.pl script or malformed input are propagated.
func TestGenerateFlameGraphExecError(t *testing.T) {
	mockExecutor := new(mockExecutor)
	visualizer := defaultVisualizer{
		executor: mockExecutor,
	}
	mockExecutor.On("runPerlScript", "").Return(nil, errors.New("bad input")).Once()

	err := visualizer.GenerateFlameGraph("", ".text.svg", false)
	assert.Error(t, err)
	mockExecutor.AssertNotCalled(t, "createFile")
	mockExecutor.AssertExpectations(t)
}

func TestRunPerlScriptDoesExist(t *testing.T) {
	mockOSWrapper := new(mockOSWrapper)
	executor := defaultExecutor{
		osWrapper: mockOSWrapper,
	}
	cwd, err := os.Getwd()
	if err != nil {
		t.Fatal(err.Error())
	}
	mockOSWrapper.On("execLookPath", "flamegraph.pl").Return("", errors.New("DNE")).Once()
	mockOSWrapper.On("execLookPath", cwd+"/flamegraph.pl").Return("", errors.New("DNE")).Once()
	mockOSWrapper.On("execLookPath", "flame-graph-gen").Return("/somepath/flame-graph-gen", nil).Once()

	mockOSWrapper.On("cmdOutput", mock.AnythingOfType("*exec.Cmd")).Return([]byte("output"), nil).Once()

	out, err := executor.runPerlScript("some graph input")

	assert.Equal(t, []byte("output"), out)
	assert.NoError(t, err)
	mockOSWrapper.AssertExpectations(t)
}

func TestRunPerlScriptDoesNotExist(t *testing.T) {
	mockOSWrapper := new(mockOSWrapper)
	executor := defaultExecutor{
		osWrapper: mockOSWrapper,
	}
	cwd, err := os.Getwd()
	if err != nil {
		t.Fatal(err.Error())
	}
	mockOSWrapper.On("execLookPath", "flamegraph.pl").Return("", errors.New("DNE")).Once()
	mockOSWrapper.On("execLookPath", cwd+"/flamegraph.pl").Return("", errors.New("DNE")).Once()
	mockOSWrapper.On("execLookPath", "flame-graph-gen").Return("", errors.New("DNE")).Once()

	out, err := executor.runPerlScript("some graph input")

	assert.Equal(t, 0, len(out))
	assert.Error(t, err)
	mockOSWrapper.AssertExpectations(t)
}

// Smoke test the NewVisualizer method
func TestNewVisualizer(t *testing.T) {
	assert.NotNil(t, NewVisualizer())
}
<|endoftext|>


<commit_before>// Dnode protocol for net/rpc
package kite

import (
	"encoding/json"
	"fmt"
	"io"
	"net/rpc"
)

func NewDnodeClient(conn io.ReadWriteCloser) rpc.ClientCodec {
	return &DnodeClientCodec{
		rwc: conn,
		dec: json.NewDecoder(conn),
		enc: json.NewEncoder(conn),
	}
}

type DnodeClientCodec struct {
	dec *json.Decoder
	enc *json.Encoder
	rwc io.ReadWriteCloser
}

func (c *DnodeClientCodec) WriteRequest(r *rpc.Request, body interface{}) error {
	fmt.Println("Dnode WriteRequest")

	return nil
}

func (c *DnodeClientCodec) ReadResponseHeader(r *rpc.Response) error {
	fmt.Println("Dnode ReadResponseHeader")
	return nil
}

func (c *DnodeClientCodec) ReadResponseBody(x interface{}) error {
	fmt.Println("Dnode ReadResponseBody")
	return nil
}

func (c *DnodeClientCodec) Close() error {
	fmt.Println("Dnode ClientClose")
	return nil
}

type DnodeServerCodec struct{}

func (c *DnodeServerCodec) ReadRequestHeader(r *rpc.Request) error {
	fmt.Println("Dnode ReadRequestHeader")
	return nil
}

func (c *DnodeServerCodec) ReadRequestBody(body interface{}) error {
	fmt.Println("Dnode ReadRequestBody")
	return nil
}

func (c *DnodeServerCodec) WriteResponse(r *rpc.Response, body interface{}) error {
	fmt.Println("Dnode WriteResponse")
	return nil
}

func (c *DnodeServerCodec) Close() error {
	fmt.Println("Dnode ServerClose")
	return nil
}
<commit_msg>more improvements to dnode<commit_after>// Dnode protocol for net/rpc
package kite

import (
	"encoding/json"
	"fmt"
	"io"
	"koding/tools/dnode"
	"log"
	"net/rpc"
)

func NewDnodeClient(conn io.ReadWriteCloser) rpc.ClientCodec {
	return &DnodeClientCodec{
		rwc: conn,
		dec: json.NewDecoder(conn),
		enc: json.NewEncoder(conn),
	}
}

type DnodeClientCodec struct {
	dec *json.Decoder
	enc *json.Encoder
	rwc io.ReadWriteCloser
}

func (c *DnodeClientCodec) WriteRequest(r *rpc.Request, body interface{}) error {
	fmt.Println("Dnode WriteRequest")

	return nil
}

func (c *DnodeClientCodec) ReadResponseHeader(r *rpc.Response) error {
	fmt.Println("Dnode ReadResponseHeader")
	return nil
}

func (c *DnodeClientCodec) ReadResponseBody(x interface{}) error {
	fmt.Println("Dnode ReadResponseBody")
	return nil
}

func (c *DnodeClientCodec) Close() error {
	fmt.Println("Dnode ClientClose")
	return c.rwc.Close()
}

//

type DnodeMessage struct {
	Method    interface{}           `json:"method"`
	Arguments *dnode.Partial        `json:"arguments"`
	Callbacks map[string]([]string) `json:"callbacks"`
}

func (d *DnodeMessage) reset() {
	d.Method = nil
	d.Arguments = nil
	d.Callbacks = nil
}

type DnodeServerCodec struct {
	dec *json.Decoder // for reading JSON values
	enc *json.Encoder // for writing JSON values
	rwc io.ReadWriteCloser

	// temporary work space
	req  DnodeMessage
	resp DnodeMessage
}

func NewDnodeServerCodec(conn io.ReadWriteCloser) rpc.ServerCodec {
	return &DnodeServerCodec{
		rwc: conn,
		dec: json.NewDecoder(conn),
		enc: json.NewEncoder(conn),
	}
}

func (c *DnodeServerCodec) ReadRequestHeader(r *rpc.Request) error {
	err := c.dec.Decode(&c.req)
	if err != nil {
		log.Println(err)
	}
	fmt.Printf("Dnode Message arguments %+v\n", c.req.Arguments)
	fmt.Printf("Dnode Message arguments %+v\n", string(c.req.Arguments.Raw))

	return nil
}

func (c *DnodeServerCodec) ReadRequestBody(body interface{}) error {
	return nil
}

func (c *DnodeServerCodec) WriteResponse(r *rpc.Response, body interface{}) error {
	// fmt.Printf("Dnode WriteResponse r: %+v body: %+v\n", r, body)
	return nil
}

func (c *DnodeServerCodec) Close() error {
	return c.rwc.Close()
}
<|endoftext|>


<commit_before>package template

// Functions available to gondola templates

import (
	"encoding/json"
	"fmt"
	"gnd.la/assets"
	"gnd.la/types"
	"html/template"
	"reflect"
	"strconv"
	"strings"
	"time"
)

func eq(args ...interface{}) bool {
	if len(args) == 0 {
		return false
	}
	x := args[0]
	switch x := x.(type) {
	case string, int, int64, byte, float32, float64:
		for _, y := range args[1:] {
			if x == y {
				return true
			}
		}
		return false
	}

	for _, y := range args[1:] {
		if reflect.DeepEqual(x, y) {
			return true
		}
	}
	return false
}

func neq(args ...interface{}) bool {
	return !eq(args...)
}

func _json(arg interface{}) string {
	if arg == nil {
		return ""
	}
	b, err := json.Marshal(arg)
	if err == nil {
		return string(b)
	}
	return ""
}

func nz(x interface{}) bool {
	switch x := x.(type) {
	case int, uint, int64, uint64, byte, float32, float64:
		return x != 0
	case string:
		return len(x) > 0
	}
	return false
}

func lower(x string) string {
	return strings.ToLower(x)
}

func join(x []string, sep string) string {
	return strings.Join(x, sep)
}

func _map(args ...interface{}) (map[string]interface{}, error) {
	var key string
	m := make(map[string]interface{})
	for ii, v := range args {
		if ii%2 == 0 {
			if s, ok := v.(string); ok {
				key = s
			} else {
				return nil, fmt.Errorf("Invalid argument to map at index %d, %t instead of string", ii, v)
			}
		} else {
			m[key] = v
		}
	}
	return m, nil
}

func mult(args ...interface{}) (float64, error) {
	val := 1.0
	for ii, v := range args {
		value := reflect.ValueOf(v)
		switch value.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			val *= float64(value.Int())
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			val *= float64(value.Uint())
		case reflect.Float32, reflect.Float64:
			val *= value.Float()
		case reflect.String:
			v, err := strconv.ParseFloat(value.String(), 64)
			if err != nil {
				return 0, fmt.Errorf("Error parsing string passed to mult at index %d: %s", ii, err)
			}
			val *= v
		default:
			return 0, fmt.Errorf("Invalid argument of type %T passed to mult at index %d", v, ii)
		}
	}
	return val, nil

}

func concat(args ...interface{}) string {
	s := make([]string, len(args))
	for ii, v := range args {
		s[ii] = types.ToString(v)
	}
	return strings.Join(s, "")
}

func and(args ...interface{}) bool {
	for _, v := range args {
		t, _ := types.IsTrue(v)
		if !t {
			return false
		}
	}
	return true
}

func or(args ...interface{}) interface{} {
	for _, v := range args {
		t, _ := types.IsTrue(v)
		if t {
			return v
		}
	}
	return nil
}

func not(arg interface{}) bool {
	t, _ := types.IsTrue(arg)
	return !t
}

func now() time.Time {
	return time.Now()
}

var templateFuncs template.FuncMap = template.FuncMap{
	"eq":     eq,
	"neq":    neq,
	"json":   _json,
	"nz":     nz,
	"lower":  lower,
	"join":   join,
	"map":    _map,
	"mult":   mult,
	"render": assets.Render,
	"concat": concat,
	"and":    and,
	"or":     or,
	"not":    not,
	"now":    now,
}
<commit_msg>Add add() function to templates<commit_after>package template

// Functions available to gondola templates

import (
	"encoding/json"
	"fmt"
	"gnd.la/assets"
	"gnd.la/types"
	"html/template"
	"reflect"
	"strconv"
	"strings"
	"time"
)

func eq(args ...interface{}) bool {
	if len(args) == 0 {
		return false
	}
	x := args[0]
	switch x := x.(type) {
	case string, int, int64, byte, float32, float64:
		for _, y := range args[1:] {
			if x == y {
				return true
			}
		}
		return false
	}

	for _, y := range args[1:] {
		if reflect.DeepEqual(x, y) {
			return true
		}
	}
	return false
}

func neq(args ...interface{}) bool {
	return !eq(args...)
}

func _json(arg interface{}) string {
	if arg == nil {
		return ""
	}
	b, err := json.Marshal(arg)
	if err == nil {
		return string(b)
	}
	return ""
}

func nz(x interface{}) bool {
	switch x := x.(type) {
	case int, uint, int64, uint64, byte, float32, float64:
		return x != 0
	case string:
		return len(x) > 0
	}
	return false
}

func lower(x string) string {
	return strings.ToLower(x)
}

func join(x []string, sep string) string {
	return strings.Join(x, sep)
}

func _map(args ...interface{}) (map[string]interface{}, error) {
	var key string
	m := make(map[string]interface{})
	for ii, v := range args {
		if ii%2 == 0 {
			if s, ok := v.(string); ok {
				key = s
			} else {
				return nil, fmt.Errorf("Invalid argument to map at index %d, %t instead of string", ii, v)
			}
		} else {
			m[key] = v
		}
	}
	return m, nil
}

func mult(args ...interface{}) (float64, error) {
	val := 1.0
	for ii, v := range args {
		value := reflect.ValueOf(v)
		switch value.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			val *= float64(value.Int())
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			val *= float64(value.Uint())
		case reflect.Float32, reflect.Float64:
			val *= value.Float()
		case reflect.String:
			v, err := strconv.ParseFloat(value.String(), 64)
			if err != nil {
				return 0, fmt.Errorf("Error parsing string passed to mult at index %d: %s", ii, err)
			}
			val *= v
		default:
			return 0, fmt.Errorf("Invalid argument of type %T passed to mult at index %d", v, ii)
		}
	}
	return val, nil

}

func add(args ...interface{}) (float64, error) {
	val := 0.0
	for ii, v := range args {
		value := reflect.ValueOf(v)
		switch value.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			val += float64(value.Int())
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			val += float64(value.Uint())
		case reflect.Float32, reflect.Float64:
			val += value.Float()
		case reflect.String:
			v, err := strconv.ParseFloat(value.String(), 64)
			if err != nil {
				return 0, fmt.Errorf("error parsing string passed to add() at index %d: %s", ii, err)
			}
			val += v
		default:
			return 0, fmt.Errorf("invalid argument of type %T passed to add() at index %d", v, ii)
		}
	}
	return val, nil

}

func concat(args ...interface{}) string {
	s := make([]string, len(args))
	for ii, v := range args {
		s[ii] = types.ToString(v)
	}
	return strings.Join(s, "")
}

func and(args ...interface{}) bool {
	for _, v := range args {
		t, _ := types.IsTrue(v)
		if !t {
			return false
		}
	}
	return true
}

func or(args ...interface{}) interface{} {
	for _, v := range args {
		t, _ := types.IsTrue(v)
		if t {
			return v
		}
	}
	return nil
}

func not(arg interface{}) bool {
	t, _ := types.IsTrue(arg)
	return !t
}

func now() time.Time {
	return time.Now()
}

var templateFuncs template.FuncMap = template.FuncMap{
	"eq":     eq,
	"neq":    neq,
	"json":   _json,
	"nz":     nz,
	"lower":  lower,
	"join":   join,
	"map":    _map,
	"mult":   mult,
	"add":    add,
	"render": assets.Render,
	"concat": concat,
	"and":    and,
	"or":     or,
	"not":    not,
	"now":    now,
}
<|endoftext|>


<commit_before>package stage

import (
	"fmt"

	"github.com/flant/werf/pkg/image"
	"github.com/flant/werf/pkg/util"
)

func NewGitLatestPatchStage(gitPatchStageOptions *NewGitPatchStageOptions, baseStageOptions *NewBaseStageOptions) *GitLatestPatchStage {
	s := &GitLatestPatchStage{}
	s.GitPatchStage = newGitPatchStage(GitLatestPatch, gitPatchStageOptions, baseStageOptions)
	return s
}

type GitLatestPatchStage struct {
	*GitPatchStage
}

func (s *GitLatestPatchStage) IsEmpty(c Conveyor, prevBuiltImage image.ImageInterface) (bool, error) {
	if empty, err := s.GitPatchStage.IsEmpty(c, prevBuiltImage); err != nil {
		return false, err
	} else if empty {
		return true, nil
	}

	isEmpty := true
	for _, gitMapping := range s.gitMappings {
		commit := gitMapping.GetGitCommitFromImageLabels(prevBuiltImage.Labels())
		if exist, err := gitMapping.GitRepo().IsCommitExists(commit); err != nil {
			return false, err
		} else if !exist {
			return true, nil
		}

		if empty, err := gitMapping.IsPatchEmpty(prevBuiltImage); err != nil {
			return false, err
		} else if !empty {
			isEmpty = false
			break
		}
	}

	return isEmpty, nil
}

func (s *GitLatestPatchStage) GetDependencies(_ Conveyor, _, prevBuiltImage image.ImageInterface) (string, error) {
	var args []string

	for _, gitMapping := range s.gitMappings {
		patchContent, err := gitMapping.GetPatchContent(prevBuiltImage)
		if err != nil {
			return "", fmt.Errorf("error getting patch between previous built image %s and current commit for git mapping %s: %s", prevBuiltImage.Name(), gitMapping.Name, err)
		}

		args = append(args, patchContent)
	}

	return util.Sha256Hash(args...), nil
}
<commit_msg>**INCOMPATIBLE CHANGE** Fix stages and images isolation problem for git-latest-patch and stages-signature<commit_after>package stage

import (
	"fmt"

	"github.com/flant/werf/pkg/storage"

	"github.com/flant/werf/pkg/image"
	"github.com/flant/werf/pkg/util"
)

func NewGitLatestPatchStage(gitPatchStageOptions *NewGitPatchStageOptions, baseStageOptions *NewBaseStageOptions) *GitLatestPatchStage {
	s := &GitLatestPatchStage{}
	s.GitPatchStage = newGitPatchStage(GitLatestPatch, gitPatchStageOptions, baseStageOptions)
	return s
}

type GitLatestPatchStage struct {
	*GitPatchStage
}

func (s *GitLatestPatchStage) IsEmpty(c Conveyor, prevBuiltImage image.ImageInterface) (bool, error) {
	if empty, err := s.GitPatchStage.IsEmpty(c, prevBuiltImage); err != nil {
		return false, err
	} else if empty {
		return true, nil
	}

	isEmpty := true
	for _, gitMapping := range s.gitMappings {
		commit := gitMapping.GetGitCommitFromImageLabels(prevBuiltImage.Labels())
		if exist, err := gitMapping.GitRepo().IsCommitExists(commit); err != nil {
			return false, err
		} else if !exist {
			return true, nil
		}

		if empty, err := gitMapping.IsPatchEmpty(prevBuiltImage); err != nil {
			return false, err
		} else if !empty {
			isEmpty = false
			break
		}
	}

	return isEmpty, nil
}

func (s *GitLatestPatchStage) GetDependencies(_ Conveyor, _, prevBuiltImage image.ImageInterface) (string, error) {
	var args []string

	for _, gitMapping := range s.gitMappings {
		patchContent, err := gitMapping.GetPatchContent(prevBuiltImage)
		if err != nil {
			return "", fmt.Errorf("error getting patch between previous built image %s and current commit for git mapping %s: %s", prevBuiltImage.Name(), gitMapping.Name, err)
		}

		args = append(args, patchContent)
	}

	return util.Sha256Hash(args...), nil
}

func (s *GitLatestPatchStage) SelectCacheImage(images []*storage.ImageInfo) (*storage.ImageInfo, error) {
	ancestorsImages, err := s.selectCacheImagesAncestorsByGitMappings(images)
	if err != nil {
		return nil, fmt.Errorf("unable to select cache images ancestors by git mappings: %s", err)
	}
	return s.selectCacheImageByOldestCreationTimestamp(ancestorsImages)
}

func (s *GitLatestPatchStage) GetNextStageDependencies(c Conveyor) (string, error) {
	return s.BaseStage.getNextStageGitDependencies(c)
}
<|endoftext|>