<commit_before>package main

import (
	"flag"
	"fmt"
	"net/http"

	"github.com/watchly/ngbuild/integrations/slack"
)

var (
	hostname     = flag.String("hostname", "", "domain name of the build server")
	clientID     = flag.String("clientID", "", "slack oauth client ID")
	clientSecret = flag.String("clientSecret", "", "slack oauth client secret")
)

func main() {
	flag.Parse()

	if *hostname == "" || *clientID == "" || *clientSecret == "" {
		fmt.Println("Slack OAuth credentials and hostname required")
	}

	// FIXME: Uncomment when fixed
	// app := core.NewApp("ngbuild-slack")
	// token, _ := app.NewBuild("pulls/24", nil)
	// build, _ := app.GetBuild(token)

	slack.NewSlack()

	// s.BuildFailed(app, build)

	if err := http.ListenAndServe(":http", nil); err != nil {
		fmt.Println(err.Error())
	}
}
<commit_msg>Remove useless cmd<commit_after><|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/format"
	"log"
	"os"
	"strconv"
)

var (
	packageName = flag.String("package", "schemalex", "name of package")
	fileName    = flag.String("file", "tokens_gen.go", "name of file")
)

func main() {
	flag.Parse()
	if err := _main(); err != nil {
		log.Fatal(err)
	}
}

func _main() error {
	var buf bytes.Buffer

	buf.WriteString(`// Code generated by internal/cmd/gentokens/main.go; DO NOT EDIT.`)
	buf.WriteString("\n\npackage " + *packageName)
	buf.WriteString("\n\n// TokenType describes the possible types of tokens that schemalex understands")
	buf.WriteString("\ntype TokenType int")

	buf.WriteString("\n\n// Token represents a token")
	buf.WriteString("\ntype Token struct {")
	buf.WriteString("\nType TokenType")
	buf.WriteString("\nValue string")
	buf.WriteString("\nPos int")
	buf.WriteString("\nLine int")
	buf.WriteString("\nCol int")
	buf.WriteString("\nEOF bool")
	buf.WriteString("\n}")

	buf.WriteString("\n\n// NewToken creates a new token of type `t`, with value `v`")
	buf.WriteString("\nfunc NewToken(t TokenType, v string) *Token {")
	buf.WriteString("\nreturn &Token{Type: t, Value: v}")
	buf.WriteString("\n}")

	buf.WriteString("\n\n// List of possible tokens")
	buf.WriteString("\nconst (")
	buf.WriteString("\nILLEGAL TokenType = iota")

	tokens := []struct {
		Comment string
		Ident   string
	}{
		{Ident: "EOF"},
		{Ident: "SPACE"},
		{Ident: "IDENT"},
		{Ident: "BACKTICK_IDENT"},
		{Ident: "DOUBLE_QUOTE_IDENT"},
		{Ident: "SINGLE_QUOTE_IDENT"},
		{Ident: "NUMBER"},
		{Ident: "LPAREN", Comment: "("},
		{Ident: "RPAREN", Comment: ")"},
		{Ident: "COMMA", Comment: ","},
		{Ident: "SEMICOLON", Comment: ";"},
		{Ident: "DOT", Comment: "."},
		{Ident: "SLASH", Comment: "/"},
		{Ident: "ASTERISK", Comment: "*"},
		{Ident: "DASH", Comment: "-"},
		{Ident: "PLUS", Comment: "+"},
		{Ident: "SINGLE_QUOTE", Comment: "'"},
		{Ident: "DOUBLE_QUOTE", Comment: "\""},
		{Ident: "EQUAL", Comment: "="},
		{Ident: "COMMENT_IDENT", Comment: `// /*   */, --, #`},
		{Ident: "ACTION"},
		{Ident: "AUTO_INCREMENT"},
		{Ident: "AVG_ROW_LENGTH"},
		{Ident: "BIGINT"},
		{Ident: "BINARY"},
		{Ident: "BIT"},
		{Ident: "BLOB"},
		{Ident: "BOOL"},
		{Ident: "BOOLEAN"},
		{Ident: "BTREE"},
		{Ident: "CASCADE"},
		{Ident: "CHAR"},
		{Ident: "CHARACTER"},
		{Ident: "CHARSET"},
		{Ident: "CHECK"},
		{Ident: "CHECKSUM"},
		{Ident: "COLLATE"},
		{Ident: "COMMENT"},
		{Ident: "COMPACT"},
		{Ident: "COMPRESSED"},
		{Ident: "CONNECTION"},
		{Ident: "CONSTRAINT"},
		{Ident: "CREATE"},
		{Ident: "CURRENT_TIMESTAMP"},
		{Ident: "DATA"},
		{Ident: "DATABASE"},
		{Ident: "DATE"},
		{Ident: "DATETIME"},
		{Ident: "DECIMAL"},
		{Ident: "DEFAULT"},
		{Ident: "DELAY_KEY_WRITE"},
		{Ident: "DELETE"},
		{Ident: "DIRECTORY"},
		{Ident: "DISK"},
		{Ident: "DOUBLE"},
		{Ident: "DROP"},
		{Ident: "DYNAMIC"},
		{Ident: "ENGINE"},
		{Ident: "ENUM"},
		{Ident: "EXISTS"},
		{Ident: "FALSE"},
		{Ident: "FIRST"},
		{Ident: "FIXED"},
		{Ident: "FLOAT"},
		{Ident: "FOREIGN"},
		{Ident: "FULL"},
		{Ident: "FULLTEXT"},
		{Ident: "HASH"},
		{Ident: "IF"},
		{Ident: "INDEX"},
		{Ident: "INSERT_METHOD"},
		{Ident: "INT"},
		{Ident: "INTEGER"},
		{Ident: "JSON"},
		{Ident: "KEY"},
		{Ident: "KEY_BLOCK_SIZE"},
		{Ident: "LAST"},
		{Ident: "LIKE"},
		{Ident: "LONGBLOB"},
		{Ident: "LONGTEXT"},
		{Ident: "MATCH"},
		{Ident: "MAX_ROWS"},
		{Ident: "MEDIUMBLOB"},
		{Ident: "MEDIUMINT"},
		{Ident: "MEDIUMTEXT"},
		{Ident: "MEMORY"},
		{Ident: "MIN_ROWS"},
		{Ident: "NO"},
		{Ident: "NOT"},
		{Ident: "NULL"},
		{Ident: "NUMERIC"},
		{Ident: "ON"},
		{Ident: "PACK_KEYS"},
		{Ident: "PARTIAL"},
		{Ident: "PARSER"},
		{Ident: "PASSWORD"},
		{Ident: "PRIMARY"},
		{Ident: "REAL"},
		{Ident: "REDUNDANT"},
		{Ident: "REFERENCES"},
		{Ident: "RESTRICT"},
		{Ident: "ROW_FORMAT"},
		{Ident: "SET"},
		{Ident: "SIMPLE"},
		{Ident: "SMALLINT"},
		{Ident: "SPATIAL"},
		{Ident: "STATS_AUTO_RECALC"},
		{Ident: "STATS_PERSISTENT"},
		{Ident: "STATS_SAMPLE_PAGES"},
		{Ident: "STORAGE"},
		{Ident: "TABLE"},
		{Ident: "TABLESPACE"},
		{Ident: "TEMPORARY"},
		{Ident: "TEXT"},
		{Ident: "TIME"},
		{Ident: "TIMESTAMP"},
		{Ident: "TINYBLOB"},
		{Ident: "TINYINT"},
		{Ident: "TINYTEXT"},
		{Ident: "TRUE"},
		{Ident: "UNION"},
		{Ident: "UNIQUE"},
		{Ident: "UNSIGNED"},
		{Ident: "UPDATE"},
		{Ident: "USE"},
		{Ident: "USING"},
		{Ident: "VARBINARY"},
		{Ident: "VARCHAR"},
		{Ident: "YEAR"},
		{Ident: "WITH"},
		{Ident: "ZEROFILL"},
		{Ident: "ASC"},
		{Ident: "DESC"},
		{Ident: "NOW"},
	}

	for _, tok := range tokens {
		buf.WriteString("\n" + tok.Ident)
		if c := tok.Comment; c != "" {
			buf.WriteString("// " + c)
		}
	}
	buf.WriteString("\n)") // end const (

	buf.WriteString("\n\nvar keywordIdentMap = map[string]TokenType{")
	for _, tok := range tokens[20:] {
		buf.WriteString("\n" + strconv.Quote(tok.Ident) + ": " + tok.Ident + ",")
	}
	buf.WriteString("\n}")

	buf.WriteString("\n\nfunc (t TokenType) String() string {")
	buf.WriteString("\nswitch t {")
	buf.WriteString("\ncase ILLEGAL:")
	buf.WriteString("\nreturn \"ILLEGAL\"")
	for _, tok := range tokens {
		buf.WriteString("\ncase ")
		buf.WriteString(tok.Ident)
		buf.WriteByte(':')
		buf.WriteString("\nreturn ")
		buf.WriteString(strconv.Quote(tok.Ident))
	}
	buf.WriteString("\n}")
	buf.WriteString("\nreturn \"(invalid)\"")
	buf.WriteString("\n}")

	formatted, err := format.Source(buf.Bytes())
	if err != nil {
		fmt.Printf("%s", buf.Bytes())
		return err
	}

	f, err := os.Create(*fileName)
	if err != nil {
		return err
	}
	defer f.Close()

	f.Write(formatted)
	return nil
}
<commit_msg>Add Ident GEOMETRY<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/format"
	"log"
	"os"
	"strconv"
)

var (
	packageName = flag.String("package", "schemalex", "name of package")
	fileName    = flag.String("file", "tokens_gen.go", "name of file")
)

func main() {
	flag.Parse()
	if err := _main(); err != nil {
		log.Fatal(err)
	}
}

func _main() error {
	var buf bytes.Buffer

	buf.WriteString(`// Code generated by internal/cmd/gentokens/main.go; DO NOT EDIT.`)
	buf.WriteString("\n\npackage " + *packageName)
	buf.WriteString("\n\n// TokenType describes the possible types of tokens that schemalex understands")
	buf.WriteString("\ntype TokenType int")

	buf.WriteString("\n\n// Token represents a token")
	buf.WriteString("\ntype Token struct {")
	buf.WriteString("\nType TokenType")
	buf.WriteString("\nValue string")
	buf.WriteString("\nPos int")
	buf.WriteString("\nLine int")
	buf.WriteString("\nCol int")
	buf.WriteString("\nEOF bool")
	buf.WriteString("\n}")

	buf.WriteString("\n\n// NewToken creates a new token of type `t`, with value `v`")
	buf.WriteString("\nfunc NewToken(t TokenType, v string) *Token {")
	buf.WriteString("\nreturn &Token{Type: t, Value: v}")
	buf.WriteString("\n}")

	buf.WriteString("\n\n// List of possible tokens")
	buf.WriteString("\nconst (")
	buf.WriteString("\nILLEGAL TokenType = iota")

	tokens := []struct {
		Comment string
		Ident   string
	}{
		{Ident: "EOF"},
		{Ident: "SPACE"},
		{Ident: "IDENT"},
		{Ident: "BACKTICK_IDENT"},
		{Ident: "DOUBLE_QUOTE_IDENT"},
		{Ident: "SINGLE_QUOTE_IDENT"},
		{Ident: "NUMBER"},
		{Ident: "LPAREN", Comment: "("},
		{Ident: "RPAREN", Comment: ")"},
		{Ident: "COMMA", Comment: ","},
		{Ident: "SEMICOLON", Comment: ";"},
		{Ident: "DOT", Comment: "."},
		{Ident: "SLASH", Comment: "/"},
		{Ident: "ASTERISK", Comment: "*"},
		{Ident: "DASH", Comment: "-"},
		{Ident: "PLUS", Comment: "+"},
		{Ident: "SINGLE_QUOTE", Comment: "'"},
		{Ident: "DOUBLE_QUOTE", Comment: "\""},
		{Ident: "EQUAL", Comment: "="},
		{Ident: "COMMENT_IDENT", Comment: `// /*   */, --, #`},
		{Ident: "ACTION"},
		{Ident: "AUTO_INCREMENT"},
		{Ident: "AVG_ROW_LENGTH"},
		{Ident: "BIGINT"},
		{Ident: "BINARY"},
		{Ident: "BIT"},
		{Ident: "BLOB"},
		{Ident: "BOOL"},
		{Ident: "BOOLEAN"},
		{Ident: "BTREE"},
		{Ident: "CASCADE"},
		{Ident: "CHAR"},
		{Ident: "CHARACTER"},
		{Ident: "CHARSET"},
		{Ident: "CHECK"},
		{Ident: "CHECKSUM"},
		{Ident: "COLLATE"},
		{Ident: "COMMENT"},
		{Ident: "COMPACT"},
		{Ident: "COMPRESSED"},
		{Ident: "CONNECTION"},
		{Ident: "CONSTRAINT"},
		{Ident: "CREATE"},
		{Ident: "CURRENT_TIMESTAMP"},
		{Ident: "DATA"},
		{Ident: "DATABASE"},
		{Ident: "DATE"},
		{Ident: "DATETIME"},
		{Ident: "DECIMAL"},
		{Ident: "DEFAULT"},
		{Ident: "DELAY_KEY_WRITE"},
		{Ident: "DELETE"},
		{Ident: "DIRECTORY"},
		{Ident: "DISK"},
		{Ident: "DOUBLE"},
		{Ident: "DROP"},
		{Ident: "DYNAMIC"},
		{Ident: "ENGINE"},
		{Ident: "ENUM"},
		{Ident: "EXISTS"},
		{Ident: "FALSE"},
		{Ident: "FIRST"},
		{Ident: "FIXED"},
		{Ident: "FLOAT"},
		{Ident: "FOREIGN"},
		{Ident: "FULL"},
		{Ident: "FULLTEXT"},
		{Ident: "GEOMETRY"},
		{Ident: "HASH"},
		{Ident: "IF"},
		{Ident: "INDEX"},
		{Ident: "INSERT_METHOD"},
		{Ident: "INT"},
		{Ident: "INTEGER"},
		{Ident: "JSON"},
		{Ident: "KEY"},
		{Ident: "KEY_BLOCK_SIZE"},
		{Ident: "LAST"},
		{Ident: "LIKE"},
		{Ident: "LONGBLOB"},
		{Ident: "LONGTEXT"},
		{Ident: "MATCH"},
		{Ident: "MAX_ROWS"},
		{Ident: "MEDIUMBLOB"},
		{Ident: "MEDIUMINT"},
		{Ident: "MEDIUMTEXT"},
		{Ident: "MEMORY"},
		{Ident: "MIN_ROWS"},
		{Ident: "NO"},
		{Ident: "NOT"},
		{Ident: "NULL"},
		{Ident: "NUMERIC"},
		{Ident: "ON"},
		{Ident: "PACK_KEYS"},
		{Ident: "PARTIAL"},
		{Ident: "PARSER"},
		{Ident: "PASSWORD"},
		{Ident: "PRIMARY"},
		{Ident: "REAL"},
		{Ident: "REDUNDANT"},
		{Ident: "REFERENCES"},
		{Ident: "RESTRICT"},
		{Ident: "ROW_FORMAT"},
		{Ident: "SET"},
		{Ident: "SIMPLE"},
		{Ident: "SMALLINT"},
		{Ident: "SPATIAL"},
		{Ident: "STATS_AUTO_RECALC"},
		{Ident: "STATS_PERSISTENT"},
		{Ident: "STATS_SAMPLE_PAGES"},
		{Ident: "STORAGE"},
		{Ident: "TABLE"},
		{Ident: "TABLESPACE"},
		{Ident: "TEMPORARY"},
		{Ident: "TEXT"},
		{Ident: "TIME"},
		{Ident: "TIMESTAMP"},
		{Ident: "TINYBLOB"},
		{Ident: "TINYINT"},
		{Ident: "TINYTEXT"},
		{Ident: "TRUE"},
		{Ident: "UNION"},
		{Ident: "UNIQUE"},
		{Ident: "UNSIGNED"},
		{Ident: "UPDATE"},
		{Ident: "USE"},
		{Ident: "USING"},
		{Ident: "VARBINARY"},
		{Ident: "VARCHAR"},
		{Ident: "YEAR"},
		{Ident: "WITH"},
		{Ident: "ZEROFILL"},
		{Ident: "ASC"},
		{Ident: "DESC"},
		{Ident: "NOW"},
	}

	for _, tok := range tokens {
		buf.WriteString("\n" + tok.Ident)
		if c := tok.Comment; c != "" {
			buf.WriteString("// " + c)
		}
	}
	buf.WriteString("\n)") // end const (

	buf.WriteString("\n\nvar keywordIdentMap = map[string]TokenType{")
	for _, tok := range tokens[20:] {
		buf.WriteString("\n" + strconv.Quote(tok.Ident) + ": " + tok.Ident + ",")
	}
	buf.WriteString("\n}")

	buf.WriteString("\n\nfunc (t TokenType) String() string {")
	buf.WriteString("\nswitch t {")
	buf.WriteString("\ncase ILLEGAL:")
	buf.WriteString("\nreturn \"ILLEGAL\"")
	for _, tok := range tokens {
		buf.WriteString("\ncase ")
		buf.WriteString(tok.Ident)
		buf.WriteByte(':')
		buf.WriteString("\nreturn ")
		buf.WriteString(strconv.Quote(tok.Ident))
	}
	buf.WriteString("\n}")
	buf.WriteString("\nreturn \"(invalid)\"")
	buf.WriteString("\n}")

	formatted, err := format.Source(buf.Bytes())
	if err != nil {
		fmt.Printf("%s", buf.Bytes())
		return err
	}

	f, err := os.Create(*fileName)
	if err != nil {
		return err
	}
	defer f.Close()

	f.Write(formatted)
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2017 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package entry

import stdregexp "regexp"

type regexp struct {
	*items
	expr      *stdregexp.Regexp
	hasParams bool
}

// Entry.Type
func (r *regexp) Type() int {
	return TypeRegexp
}

// Entry.Match
func (r *regexp) Match(url string) int {
	loc := r.expr.FindStringIndex(url)

	if loc != nil &&
		loc[0] == 0 &&
		loc[1] == len(url) {
		return 0
	}
	return -1
}

// Entry.Params
func (r *regexp) Params(url string) map[string]string {
	if !r.hasParams {
		return nil
	}

	// 正确匹配正则表达式，则获相关的正则表达式命名变量。
	mapped := make(map[string]string, 3)
	subexps := r.expr.SubexpNames()
	args := r.expr.FindStringSubmatch(url)
	for index, name := range subexps {
		if len(name) > 0 && index < len(args) {
			mapped[name] = args[index]
		}
	}
	return mapped
}
<commit_msg>[internal/entry] 更新文档<commit_after>// Copyright 2017 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package entry

import stdregexp "regexp"

type regexp struct {
	*items
	hasParams bool // 仅在正则中只包含未命名正则时，才为 true
	expr      *stdregexp.Regexp
}

// Entry.Type
func (r *regexp) Type() int {
	return TypeRegexp
}

// Entry.Match
func (r *regexp) Match(url string) int {
	loc := r.expr.FindStringIndex(url)

	if loc != nil &&
		loc[0] == 0 &&
		loc[1] == len(url) {
		return 0
	}
	return -1
}

// Entry.Params
func (r *regexp) Params(url string) map[string]string {
	if !r.hasParams {
		return nil
	}

	// 正确匹配正则表达式，则获相关的正则表达式命名变量。
	mapped := make(map[string]string, 3)
	subexps := r.expr.SubexpNames()
	args := r.expr.FindStringSubmatch(url)
	for index, name := range subexps {
		if len(name) > 0 && index < len(args) {
			mapped[name] = args[index]
		}
	}
	return mapped
}
<|endoftext|>


<commit_before>/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package common

import (
	"context"
	"crypto/tls"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
	"time"

	pcommon "github.com/hyperledger/fabric-protos-go/common"
	pb "github.com/hyperledger/fabric-protos-go/peer"
	"github.com/hyperledger/fabric/bccsp"
	"github.com/hyperledger/fabric/bccsp/factory"
	"github.com/hyperledger/fabric/common/channelconfig"
	"github.com/hyperledger/fabric/common/flogging"
	"github.com/hyperledger/fabric/core/comm"
	"github.com/hyperledger/fabric/core/config"
	"github.com/hyperledger/fabric/core/scc/cscc"
	"github.com/hyperledger/fabric/msp"
	mspmgmt "github.com/hyperledger/fabric/msp/mgmt"
	"github.com/hyperledger/fabric/protoutil"
	"github.com/mitchellh/mapstructure"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

// UndefinedParamValue defines what undefined parameters in the command line will initialise to
const UndefinedParamValue = ""
const CmdRoot = "core"

var mainLogger = flogging.MustGetLogger("main")
var logOutput = os.Stderr

var (
	defaultConnTimeout = 3 * time.Second
	// These function variables (xyzFnc) can be used to invoke corresponding xyz function
	// this will allow the invoking packages to mock these functions in their unit test cases

	// GetEndorserClientFnc is a function that returns a new endorser client connection
	// to the provided peer address using the TLS root cert file,
	// by default it is set to GetEndorserClient function
	GetEndorserClientFnc func(address, tlsRootCertFile string) (pb.EndorserClient, error)

	// GetPeerDeliverClientFnc is a function that returns a new deliver client connection
	// to the provided peer address using the TLS root cert file,
	// by default it is set to GetDeliverClient function
	GetPeerDeliverClientFnc func(address, tlsRootCertFile string) (pb.DeliverClient, error)

	// GetDeliverClientFnc is a function that returns a new deliver client connection
	// to the provided peer address using the TLS root cert file,
	// by default it is set to GetDeliverClient function
	GetDeliverClientFnc func(address, tlsRootCertFile string) (pb.Deliver_DeliverClient, error)

	// GetDefaultSignerFnc is a function that returns a default Signer(Default/PERR)
	// by default it is set to GetDefaultSigner function
	GetDefaultSignerFnc func() (msp.SigningIdentity, error)

	// GetBroadcastClientFnc returns an instance of the BroadcastClient interface
	// by default it is set to GetBroadcastClient function
	GetBroadcastClientFnc func() (BroadcastClient, error)

	// GetOrdererEndpointOfChainFnc returns orderer endpoints of given chain
	// by default it is set to GetOrdererEndpointOfChain function
	GetOrdererEndpointOfChainFnc func(chainID string, signer Signer,
		endorserClient pb.EndorserClient, cryptoProvider bccsp.BCCSP) ([]string, error)

	// GetCertificateFnc is a function that returns the client TLS certificate
	GetCertificateFnc func() (tls.Certificate, error)
)

type CommonClient struct {
	*comm.GRPCClient
	Address string
	sn      string
}

func init() {
	GetEndorserClientFnc = GetEndorserClient
	GetDefaultSignerFnc = GetDefaultSigner
	GetBroadcastClientFnc = GetBroadcastClient
	GetOrdererEndpointOfChainFnc = GetOrdererEndpointOfChain
	GetDeliverClientFnc = GetDeliverClient
	GetPeerDeliverClientFnc = GetPeerDeliverClient
	GetCertificateFnc = GetCertificate
}

// InitConfig initializes viper config
func InitConfig(cmdRoot string) error {

	err := config.InitViper(nil, cmdRoot)
	if err != nil {
		return err
	}

	err = viper.ReadInConfig() // Find and read the config file
	if err != nil {            // Handle errors reading the config file
		// The version of Viper we use claims the config type isn't supported when in fact the file hasn't been found
		// Display a more helpful message to avoid confusing the user.
		if strings.Contains(fmt.Sprint(err), "Unsupported Config Type") {
			return errors.New(fmt.Sprintf("Could not find config file. "+
				"Please make sure that FABRIC_CFG_PATH is set to a path "+
				"which contains %s.yaml", cmdRoot))
		} else {
			return errors.WithMessagef(err, "error when reading %s config file", cmdRoot)
		}
	}

	return nil
}

// InitCrypto initializes crypto for this peer
func InitCrypto(mspMgrConfigDir, localMSPID, localMSPType string) error {
	// Check whether msp folder exists
	fi, err := os.Stat(mspMgrConfigDir)
	if os.IsNotExist(err) || !fi.IsDir() {
		// No need to try to load MSP from folder which is not available
		return errors.Errorf("cannot init crypto, folder \"%s\" does not exist", mspMgrConfigDir)
	}
	// Check whether localMSPID exists
	if localMSPID == "" {
		return errors.New("the local MSP must have an ID")
	}

	// Init the BCCSP
	SetBCCSPKeystorePath()
	bccspConfig := factory.GetDefaultOpts()
	if config := viper.Get("peer.BCCSP"); config != nil {
		err = mapstructure.Decode(config, bccspConfig)
		if err != nil {
			return errors.WithMessage(err, "could not decode peer BCCSP configuration")
		}
	}

	err = mspmgmt.LoadLocalMspWithType(mspMgrConfigDir, bccspConfig, localMSPID, localMSPType)
	if err != nil {
		return errors.WithMessagef(err, "error when setting up MSP of type %s from directory %s", localMSPType, mspMgrConfigDir)
	}

	return nil
}

// SetBCCSPKeystorePath sets the file keystore path for the SW BCCSP provider
// to an absolute path relative to the config file
func SetBCCSPKeystorePath() {
	viper.Set("peer.BCCSP.SW.FileKeyStore.KeyStore",
		config.GetPath("peer.BCCSP.SW.FileKeyStore.KeyStore"))
}

// GetDefaultSigner return a default Signer(Default/PERR) for cli
func GetDefaultSigner() (msp.SigningIdentity, error) {
	signer, err := mspmgmt.GetLocalMSP(factory.GetDefault()).GetDefaultSigningIdentity()
	if err != nil {
		return nil, errors.WithMessage(err, "error obtaining the default signing identity")
	}

	return signer, err
}

// Signer defines the interface needed for signing messages
type Signer interface {
	Sign(msg []byte) ([]byte, error)
	Serialize() ([]byte, error)
}

// GetOrdererEndpointOfChain returns orderer endpoints of given chain
func GetOrdererEndpointOfChain(chainID string, signer Signer, endorserClient pb.EndorserClient, cryptoProvider bccsp.BCCSP) ([]string, error) {
	// query cscc for chain config block
	invocation := &pb.ChaincodeInvocationSpec{
		ChaincodeSpec: &pb.ChaincodeSpec{
			Type:        pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]),
			ChaincodeId: &pb.ChaincodeID{Name: "cscc"},
			Input:       &pb.ChaincodeInput{Args: [][]byte{[]byte(cscc.GetConfigBlock), []byte(chainID)}},
		},
	}

	creator, err := signer.Serialize()
	if err != nil {
		return nil, errors.WithMessage(err, "error serializing identity for signer")
	}

	prop, _, err := protoutil.CreateProposalFromCIS(pcommon.HeaderType_CONFIG, "", invocation, creator)
	if err != nil {
		return nil, errors.WithMessage(err, "error creating GetConfigBlock proposal")
	}

	signedProp, err := protoutil.GetSignedProposal(prop, signer)
	if err != nil {
		return nil, errors.WithMessage(err, "error creating signed GetConfigBlock proposal")
	}

	proposalResp, err := endorserClient.ProcessProposal(context.Background(), signedProp)
	if err != nil {
		return nil, errors.WithMessage(err, "error endorsing GetConfigBlock")
	}

	if proposalResp == nil {
		return nil, errors.WithMessage(err, "error nil proposal response")
	}

	if proposalResp.Response.Status != 0 && proposalResp.Response.Status != 200 {
		return nil, errors.Errorf("error bad proposal response %d: %s", proposalResp.Response.Status, proposalResp.Response.Message)
	}

	// parse config block
	block, err := protoutil.UnmarshalBlock(proposalResp.Response.Payload)
	if err != nil {
		return nil, errors.WithMessage(err, "error unmarshaling config block")
	}

	envelopeConfig, err := protoutil.ExtractEnvelope(block, 0)
	if err != nil {
		return nil, errors.WithMessage(err, "error extracting config block envelope")
	}
	bundle, err := channelconfig.NewBundleFromEnvelope(envelopeConfig, cryptoProvider)
	if err != nil {
		return nil, errors.WithMessage(err, "error loading config block")
	}

	return bundle.ChannelConfig().OrdererAddresses(), nil
}

// CheckLogLevel checks that a given log level string is valid
func CheckLogLevel(level string) error {
	if !flogging.IsValidLevel(level) {
		return errors.Errorf("invalid log level provided - %s", level)
	}
	return nil
}

func configFromEnv(prefix string) (address, override string, clientConfig comm.ClientConfig, err error) {
	address = viper.GetString(prefix + ".address")
	override = viper.GetString(prefix + ".tls.serverhostoverride")
	clientConfig = comm.ClientConfig{}
	connTimeout := viper.GetDuration(prefix + ".client.connTimeout")
	if connTimeout == time.Duration(0) {
		connTimeout = defaultConnTimeout
	}
	clientConfig.Timeout = connTimeout
	secOpts := comm.SecureOptions{
		UseTLS:            viper.GetBool(prefix + ".tls.enabled"),
		RequireClientCert: viper.GetBool(prefix + ".tls.clientAuthRequired")}
	if secOpts.UseTLS {
		caPEM, res := ioutil.ReadFile(config.GetPath(prefix + ".tls.rootcert.file"))
		if res != nil {
			err = errors.WithMessage(res,
				fmt.Sprintf("unable to load %s.tls.rootcert.file", prefix))
			return
		}
		secOpts.ServerRootCAs = [][]byte{caPEM}
	}
	if secOpts.RequireClientCert {
		keyPEM, res := ioutil.ReadFile(config.GetPath(prefix + ".tls.clientKey.file"))
		if res != nil {
			err = errors.WithMessage(res,
				fmt.Sprintf("unable to load %s.tls.clientKey.file", prefix))
			return
		}
		secOpts.Key = keyPEM
		certPEM, res := ioutil.ReadFile(config.GetPath(prefix + ".tls.clientCert.file"))
		if res != nil {
			err = errors.WithMessage(res,
				fmt.Sprintf("unable to load %s.tls.clientCert.file", prefix))
			return
		}
		secOpts.Certificate = certPEM
	}
	clientConfig.SecOpts = secOpts
	return
}

func InitCmd(cmd *cobra.Command, args []string) {
	err := InitConfig(CmdRoot)
	if err != nil { // Handle errors reading the config file
		mainLogger.Errorf("Fatal error when initializing %s config : %s", CmdRoot, err)
		os.Exit(1)
	}

	// read in the legacy logging level settings and, if set,
	// notify users of the FABRIC_LOGGING_SPEC env variable
	var loggingLevel string
	if viper.GetString("logging_level") != "" {
		loggingLevel = viper.GetString("logging_level")
	} else {
		loggingLevel = viper.GetString("logging.level")
	}
	if loggingLevel != "" {
		mainLogger.Warning("CORE_LOGGING_LEVEL is no longer supported, please use the FABRIC_LOGGING_SPEC environment variable")
	}

	loggingSpec := os.Getenv("FABRIC_LOGGING_SPEC")
	loggingFormat := os.Getenv("FABRIC_LOGGING_FORMAT")

	flogging.Init(flogging.Config{
		Format:  loggingFormat,
		Writer:  logOutput,
		LogSpec: loggingSpec,
	})

	// Init the MSP
	var mspMgrConfigDir = config.GetPath("peer.mspConfigPath")
	var mspID = viper.GetString("peer.localMspId")
	var mspType = viper.GetString("peer.localMspType")
	if mspType == "" {
		mspType = msp.ProviderTypeToString(msp.FABRIC)
	}
	err = InitCrypto(mspMgrConfigDir, mspID, mspType)
	if err != nil { // Handle errors reading the config file
		mainLogger.Errorf("Cannot run peer because %s", err.Error())
		os.Exit(1)
	}
}
<commit_msg>Fix spelling error<commit_after>/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package common

import (
	"context"
	"crypto/tls"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
	"time"

	pcommon "github.com/hyperledger/fabric-protos-go/common"
	pb "github.com/hyperledger/fabric-protos-go/peer"
	"github.com/hyperledger/fabric/bccsp"
	"github.com/hyperledger/fabric/bccsp/factory"
	"github.com/hyperledger/fabric/common/channelconfig"
	"github.com/hyperledger/fabric/common/flogging"
	"github.com/hyperledger/fabric/core/comm"
	"github.com/hyperledger/fabric/core/config"
	"github.com/hyperledger/fabric/core/scc/cscc"
	"github.com/hyperledger/fabric/msp"
	mspmgmt "github.com/hyperledger/fabric/msp/mgmt"
	"github.com/hyperledger/fabric/protoutil"
	"github.com/mitchellh/mapstructure"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

// UndefinedParamValue defines what undefined parameters in the command line will initialise to
const UndefinedParamValue = ""
const CmdRoot = "core"

var mainLogger = flogging.MustGetLogger("main")
var logOutput = os.Stderr

var (
	defaultConnTimeout = 3 * time.Second
	// These function variables (xyzFnc) can be used to invoke corresponding xyz function
	// this will allow the invoking packages to mock these functions in their unit test cases

	// GetEndorserClientFnc is a function that returns a new endorser client connection
	// to the provided peer address using the TLS root cert file,
	// by default it is set to GetEndorserClient function
	GetEndorserClientFnc func(address, tlsRootCertFile string) (pb.EndorserClient, error)

	// GetPeerDeliverClientFnc is a function that returns a new deliver client connection
	// to the provided peer address using the TLS root cert file,
	// by default it is set to GetDeliverClient function
	GetPeerDeliverClientFnc func(address, tlsRootCertFile string) (pb.DeliverClient, error)

	// GetDeliverClientFnc is a function that returns a new deliver client connection
	// to the provided peer address using the TLS root cert file,
	// by default it is set to GetDeliverClient function
	GetDeliverClientFnc func(address, tlsRootCertFile string) (pb.Deliver_DeliverClient, error)

	// GetDefaultSignerFnc is a function that returns a default Signer(Default/PERR)
	// by default it is set to GetDefaultSigner function
	GetDefaultSignerFnc func() (msp.SigningIdentity, error)

	// GetBroadcastClientFnc returns an instance of the BroadcastClient interface
	// by default it is set to GetBroadcastClient function
	GetBroadcastClientFnc func() (BroadcastClient, error)

	// GetOrdererEndpointOfChainFnc returns orderer endpoints of given chain
	// by default it is set to GetOrdererEndpointOfChain function
	GetOrdererEndpointOfChainFnc func(chainID string, signer Signer,
		endorserClient pb.EndorserClient, cryptoProvider bccsp.BCCSP) ([]string, error)

	// GetCertificateFnc is a function that returns the client TLS certificate
	GetCertificateFnc func() (tls.Certificate, error)
)

type CommonClient struct {
	*comm.GRPCClient
	Address string
	sn      string
}

func init() {
	GetEndorserClientFnc = GetEndorserClient
	GetDefaultSignerFnc = GetDefaultSigner
	GetBroadcastClientFnc = GetBroadcastClient
	GetOrdererEndpointOfChainFnc = GetOrdererEndpointOfChain
	GetDeliverClientFnc = GetDeliverClient
	GetPeerDeliverClientFnc = GetPeerDeliverClient
	GetCertificateFnc = GetCertificate
}

// InitConfig initializes viper config
func InitConfig(cmdRoot string) error {

	err := config.InitViper(nil, cmdRoot)
	if err != nil {
		return err
	}

	err = viper.ReadInConfig() // Find and read the config file
	if err != nil {            // Handle errors reading the config file
		// The version of Viper we use claims the config type isn't supported when in fact the file hasn't been found
		// Display a more helpful message to avoid confusing the user.
		if strings.Contains(fmt.Sprint(err), "Unsupported Config Type") {
			return errors.New(fmt.Sprintf("Could not find config file. "+
				"Please make sure that FABRIC_CFG_PATH is set to a path "+
				"which contains %s.yaml", cmdRoot))
		} else {
			return errors.WithMessagef(err, "error when reading %s config file", cmdRoot)
		}
	}

	return nil
}

// InitCrypto initializes crypto for this peer
func InitCrypto(mspMgrConfigDir, localMSPID, localMSPType string) error {
	// Check whether msp folder exists
	fi, err := os.Stat(mspMgrConfigDir)
	if os.IsNotExist(err) || !fi.IsDir() {
		// No need to try to load MSP from folder which is not available
		return errors.Errorf("cannot init crypto, folder \"%s\" does not exist", mspMgrConfigDir)
	}
	// Check whether localMSPID exists
	if localMSPID == "" {
		return errors.New("the local MSP must have an ID")
	}

	// Init the BCCSP
	SetBCCSPKeystorePath()
	bccspConfig := factory.GetDefaultOpts()
	if config := viper.Get("peer.BCCSP"); config != nil {
		err = mapstructure.Decode(config, bccspConfig)
		if err != nil {
			return errors.WithMessage(err, "could not decode peer BCCSP configuration")
		}
	}

	err = mspmgmt.LoadLocalMspWithType(mspMgrConfigDir, bccspConfig, localMSPID, localMSPType)
	if err != nil {
		return errors.WithMessagef(err, "error when setting up MSP of type %s from directory %s", localMSPType, mspMgrConfigDir)
	}

	return nil
}

// SetBCCSPKeystorePath sets the file keystore path for the SW BCCSP provider
// to an absolute path relative to the config file
func SetBCCSPKeystorePath() {
	viper.Set("peer.BCCSP.SW.FileKeyStore.KeyStore",
		config.GetPath("peer.BCCSP.SW.FileKeyStore.KeyStore"))
}

// GetDefaultSigner return a default Signer(Default/PEER) for cli
func GetDefaultSigner() (msp.SigningIdentity, error) {
	signer, err := mspmgmt.GetLocalMSP(factory.GetDefault()).GetDefaultSigningIdentity()
	if err != nil {
		return nil, errors.WithMessage(err, "error obtaining the default signing identity")
	}

	return signer, err
}

// Signer defines the interface needed for signing messages
type Signer interface {
	Sign(msg []byte) ([]byte, error)
	Serialize() ([]byte, error)
}

// GetOrdererEndpointOfChain returns orderer endpoints of given chain
func GetOrdererEndpointOfChain(chainID string, signer Signer, endorserClient pb.EndorserClient, cryptoProvider bccsp.BCCSP) ([]string, error) {
	// query cscc for chain config block
	invocation := &pb.ChaincodeInvocationSpec{
		ChaincodeSpec: &pb.ChaincodeSpec{
			Type:        pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]),
			ChaincodeId: &pb.ChaincodeID{Name: "cscc"},
			Input:       &pb.ChaincodeInput{Args: [][]byte{[]byte(cscc.GetConfigBlock), []byte(chainID)}},
		},
	}

	creator, err := signer.Serialize()
	if err != nil {
		return nil, errors.WithMessage(err, "error serializing identity for signer")
	}

	prop, _, err := protoutil.CreateProposalFromCIS(pcommon.HeaderType_CONFIG, "", invocation, creator)
	if err != nil {
		return nil, errors.WithMessage(err, "error creating GetConfigBlock proposal")
	}

	signedProp, err := protoutil.GetSignedProposal(prop, signer)
	if err != nil {
		return nil, errors.WithMessage(err, "error creating signed GetConfigBlock proposal")
	}

	proposalResp, err := endorserClient.ProcessProposal(context.Background(), signedProp)
	if err != nil {
		return nil, errors.WithMessage(err, "error endorsing GetConfigBlock")
	}

	if proposalResp == nil {
		return nil, errors.WithMessage(err, "error nil proposal response")
	}

	if proposalResp.Response.Status != 0 && proposalResp.Response.Status != 200 {
		return nil, errors.Errorf("error bad proposal response %d: %s", proposalResp.Response.Status, proposalResp.Response.Message)
	}

	// parse config block
	block, err := protoutil.UnmarshalBlock(proposalResp.Response.Payload)
	if err != nil {
		return nil, errors.WithMessage(err, "error unmarshaling config block")
	}

	envelopeConfig, err := protoutil.ExtractEnvelope(block, 0)
	if err != nil {
		return nil, errors.WithMessage(err, "error extracting config block envelope")
	}
	bundle, err := channelconfig.NewBundleFromEnvelope(envelopeConfig, cryptoProvider)
	if err != nil {
		return nil, errors.WithMessage(err, "error loading config block")
	}

	return bundle.ChannelConfig().OrdererAddresses(), nil
}

// CheckLogLevel checks that a given log level string is valid
func CheckLogLevel(level string) error {
	if !flogging.IsValidLevel(level) {
		return errors.Errorf("invalid log level provided - %s", level)
	}
	return nil
}

func configFromEnv(prefix string) (address, override string, clientConfig comm.ClientConfig, err error) {
	address = viper.GetString(prefix + ".address")
	override = viper.GetString(prefix + ".tls.serverhostoverride")
	clientConfig = comm.ClientConfig{}
	connTimeout := viper.GetDuration(prefix + ".client.connTimeout")
	if connTimeout == time.Duration(0) {
		connTimeout = defaultConnTimeout
	}
	clientConfig.Timeout = connTimeout
	secOpts := comm.SecureOptions{
		UseTLS:            viper.GetBool(prefix + ".tls.enabled"),
		RequireClientCert: viper.GetBool(prefix + ".tls.clientAuthRequired")}
	if secOpts.UseTLS {
		caPEM, res := ioutil.ReadFile(config.GetPath(prefix + ".tls.rootcert.file"))
		if res != nil {
			err = errors.WithMessage(res,
				fmt.Sprintf("unable to load %s.tls.rootcert.file", prefix))
			return
		}
		secOpts.ServerRootCAs = [][]byte{caPEM}
	}
	if secOpts.RequireClientCert {
		keyPEM, res := ioutil.ReadFile(config.GetPath(prefix + ".tls.clientKey.file"))
		if res != nil {
			err = errors.WithMessage(res,
				fmt.Sprintf("unable to load %s.tls.clientKey.file", prefix))
			return
		}
		secOpts.Key = keyPEM
		certPEM, res := ioutil.ReadFile(config.GetPath(prefix + ".tls.clientCert.file"))
		if res != nil {
			err = errors.WithMessage(res,
				fmt.Sprintf("unable to load %s.tls.clientCert.file", prefix))
			return
		}
		secOpts.Certificate = certPEM
	}
	clientConfig.SecOpts = secOpts
	return
}

func InitCmd(cmd *cobra.Command, args []string) {
	err := InitConfig(CmdRoot)
	if err != nil { // Handle errors reading the config file
		mainLogger.Errorf("Fatal error when initializing %s config : %s", CmdRoot, err)
		os.Exit(1)
	}

	// read in the legacy logging level settings and, if set,
	// notify users of the FABRIC_LOGGING_SPEC env variable
	var loggingLevel string
	if viper.GetString("logging_level") != "" {
		loggingLevel = viper.GetString("logging_level")
	} else {
		loggingLevel = viper.GetString("logging.level")
	}
	if loggingLevel != "" {
		mainLogger.Warning("CORE_LOGGING_LEVEL is no longer supported, please use the FABRIC_LOGGING_SPEC environment variable")
	}

	loggingSpec := os.Getenv("FABRIC_LOGGING_SPEC")
	loggingFormat := os.Getenv("FABRIC_LOGGING_FORMAT")

	flogging.Init(flogging.Config{
		Format:  loggingFormat,
		Writer:  logOutput,
		LogSpec: loggingSpec,
	})

	// Init the MSP
	var mspMgrConfigDir = config.GetPath("peer.mspConfigPath")
	var mspID = viper.GetString("peer.localMspId")
	var mspType = viper.GetString("peer.localMspType")
	if mspType == "" {
		mspType = msp.ProviderTypeToString(msp.FABRIC)
	}
	err = InitCrypto(mspMgrConfigDir, mspID, mspType)
	if err != nil { // Handle errors reading the config file
		mainLogger.Errorf("Cannot run peer because %s", err.Error())
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package schema_test

import (
	"testing"

	"github.com/graph-gophers/graphql-go/internal/schema"
)

type parseTestCase struct {
	description string
	sdl         string
	expected    *schema.Schema
	err         error
}

var parseTests = []parseTestCase{{
	description: "Parses interface definition",
	sdl:         "interface Greeting { message: String! }",
	expected: &schema.Schema{
		Types: map[string]schema.NamedType{
			"Greeting": &schema.Interface{
				Name:   "Greeting",
				Fields: []*schema.Field{{Name: "message"}},
			}},
	}}, {
	description: "Parses type with description string",
	sdl: `
	"Single line description."
	type Type {
		field: String
	}`,
	expected: &schema.Schema{
		Types: map[string]schema.NamedType{
			"Type": &schema.Object{
				Name: "Type",
				Desc: "Single line description.",
			}},
	}}, {
	description: "Parses type with multi-line description string",
	sdl: `
	"""
	Multi-line description.
	"""
	type Type {
		field: String
	}`,
	expected: &schema.Schema{
		Types: map[string]schema.NamedType{
			"Type": &schema.Object{
				Name: "Type",
				Desc: "Multi-line description.",
			}},
	}}, {
	description: "Parses type with multi-line description and ignores comments",
	sdl: `
	"""
	Multi-line description with ignored comments.
	"""
	# This comment should be ignored.
	type Type {
		field: String
	}`,
	expected: &schema.Schema{
		Types: map[string]schema.NamedType{
			"Type": &schema.Object{
				Name: "Type",
				Desc: "Multi-line description with ignored comments.",
			}},
	}},
}

func TestParse(t *testing.T) {
	setup := func(t *testing.T) *schema.Schema {
		t.Helper()
		return schema.New()
	}

	for _, test := range parseTests {
		t.Run(test.description, func(t *testing.T) {
			t.Skip("TODO: add support for descriptions")
			schema := setup(t)

			err := schema.Parse(test.sdl, false)
			if err != nil {
				t.Fatal(err)
			}

			// TODO: verify schema is the same as expected.
		})
	}
}
<commit_msg>Update schema_test.go<commit_after>package schema_test

import (
	"testing"

	"github.com/graph-gophers/graphql-go/internal/schema"
)

type parseTestCase struct {
	description string
	sdl         string
	expected    *schema.Schema
	err         error
}

var parseTests = []parseTestCase{{
	description: "Parses interface definition",
	sdl:         "interface Greeting { message: String! }",
	expected: &schema.Schema{
		Types: map[string]schema.NamedType{
			"Greeting": &schema.Interface{
				Name:   "Greeting",
				Fields: []*schema.Field{{Name: "message"}},
			}},
	}}, {
	description: "Parses type with description string",
	sdl: `
	"Single line description."
	type Type {
		field: String
	}`,
	expected: &schema.Schema{
		Types: map[string]schema.NamedType{
			"Type": &schema.Object{
				Name: "Type",
				Desc: "Single line description.",
			}},
	}}, {
	description: "Parses type with multi-line description string",
	sdl: `
	"""
	Multi-line description.
	"""
	type Type {
		field: String
	}`,
	expected: &schema.Schema{
		Types: map[string]schema.NamedType{
			"Type": &schema.Object{
				Name: "Type",
				Desc: "Multi-line description.",
			}},
	}}, {
	description: "Parses type with multi-line description and ignores comments",
	sdl: `
	"""
	Multi-line description with ignored comments.
	"""
	# This comment should be ignored.
	type Type {
		field: String
	}`,
	expected: &schema.Schema{
		Types: map[string]schema.NamedType{
			"Type": &schema.Object{
				Name: "Type",
				Desc: "Multi-line description with ignored comments.",
			}},
	}},
}

func TestParse(t *testing.T) {
	setup := func(t *testing.T) *schema.Schema {
		t.Helper()
		return schema.New()
	}

	for _, test := range parseTests {
		t.Run(test.description, func(t *testing.T) {
			t.Skip("TODO: add support for descriptions")
			schema := setup(t)

			err := schema.Parse(test.sdl, false)
			if err != nil {
				t.Fatal(err)
			}

			// TODO: verify schema is the same as expected.
		})
	}
}

func TestInvalidInterfaceImpl(t *testing.T) {
	var tests = []parseTestCase{{
		description: "Parses type Welcome that implements interface Greeting without providing required fields",
		sdl:         "interface Greeting { message: String! } type Welcome implements Greeting {}",
		err:         errors.Errorf(`interface "Greeting" expects field "message" but "Welcome" does not provide it`),
	}}

	setup := func(t *testing.T) *schema.Schema {
		t.Helper()
		return schema.New()
	}
	for _, test := range tests {
		t.Run(test.description, func(t *testing.T) {
			schema := setup(t)
			err := schema.Parse(test.sdl, false)
			if err == nil || err.Error() != test.err.Error() {
				t.Fatal(err)
			}
		})
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Hajime Hoshi
//
// 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 android ios

package mobile

import (
	"context"
	"fmt"
	"image"
	"runtime/debug"
	"sync"
	"time"

	"golang.org/x/mobile/app"
	"golang.org/x/mobile/event/lifecycle"
	"golang.org/x/mobile/event/paint"
	"golang.org/x/mobile/event/size"
	"golang.org/x/mobile/event/touch"
	"golang.org/x/mobile/gl"

	"github.com/hajimehoshi/ebiten/internal/devicescale"
	"github.com/hajimehoshi/ebiten/internal/driver"
	"github.com/hajimehoshi/ebiten/internal/graphicsdriver/opengl"
	"github.com/hajimehoshi/ebiten/internal/hooks"
	"github.com/hajimehoshi/ebiten/internal/thread"
)

var (
	glContextCh = make(chan gl.Context)

	// renderCh receives when updating starts.
	renderCh = make(chan struct{})

	// renderEndCh receives when updating finishes.
	renderEndCh = make(chan struct{})

	theUI = &UserInterface{}
)

func init() {
	theUI.input.ui = theUI
}

func Get() *UserInterface {
	return theUI
}

func (u *UserInterface) Update() {
	renderCh <- struct{}{}
	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		<-renderEndCh
		if u.t != nil {
			u.t.Call(func() error {
				cancel()
				return nil
			})
		} else {
			cancel()
		}
	}()

	if u.graphics.IsGL() {
		if u.glWorker == nil {
			panic("mobile: glWorker must be initialized but not")
		}
		workAvailable := u.glWorker.WorkAvailable()
	loop:
		for {
			select {
			case <-workAvailable:
				u.glWorker.DoWork()
			case <-ctx.Done():
				break loop
			}
		}
		return
	} else {
		u.t.Loop(ctx)
	}
}

type UserInterface struct {
	width       int
	height      int
	scale       float64
	sizeChanged bool

	// Used for gomobile-build
	fullscreenScale    float64
	fullscreenWidthPx  int
	fullscreenHeightPx int

	graphics driver.Graphics

	input Input

	t        *thread.Thread
	glWorker gl.Worker

	m sync.RWMutex
}

func deviceScale() float64 {
	return devicescale.GetAt(0, 0)
}

// appMain is the main routine for gomobile-build mode.
func (u *UserInterface) appMain(a app.App) {
	var glctx gl.Context
	touches := map[touch.Sequence]*Touch{}
	for e := range a.Events() {
		switch e := a.Filter(e).(type) {
		case lifecycle.Event:
			switch e.Crosses(lifecycle.StageVisible) {
			case lifecycle.CrossOn:
				glctx, _ = e.DrawContext.(gl.Context)
				// Assume that glctx is always a same instance.
				// Then, only once initializing should be enough.
				if glContextCh != nil {
					glContextCh <- glctx
					glContextCh = nil
				}
				a.Send(paint.Event{})
			case lifecycle.CrossOff:
				glctx = nil
			}
		case size.Event:
			u.setFullscreenImpl(e.WidthPx, e.HeightPx)
		case paint.Event:
			if glctx == nil || e.External {
				continue
			}
			renderCh <- struct{}{}
			<-renderEndCh
			a.Publish()
			a.Send(paint.Event{})
		case touch.Event:
			switch e.Type {
			case touch.TypeBegin, touch.TypeMove:
				s := deviceScale()
				x, y := float64(e.X)/s, float64(e.Y)/s
				// TODO: Is it ok to cast from int64 to int here?
				touches[e.Sequence] = &Touch{
					ID: int(e.Sequence),
					X:  int(x),
					Y:  int(y),
				}
			case touch.TypeEnd:
				delete(touches, e.Sequence)
			}
			ts := []*Touch{}
			for _, t := range touches {
				ts = append(ts, t)
			}
			u.input.update(ts)
		}
	}
}

func (u *UserInterface) Run(width, height int, scale float64, title string, context driver.UIContext, graphics driver.Graphics) error {
	go func() {
		if err := u.run(width, height, scale, title, context, graphics, true); err != nil {
			// As mobile apps never ends, Loop can't return. Just panic here.
			panic(err)
		}
	}()
	app.Main(u.appMain)
	return nil
}

func (u *UserInterface) RunWithoutMainLoop(width, height int, scale float64, title string, context driver.UIContext, graphics driver.Graphics) <-chan error {
	ch := make(chan error)
	go func() {
		defer close(ch)
		if err := u.run(width, height, scale, title, context, graphics, false); err != nil {
			ch <- err
		}
	}()
	return ch
}

func (u *UserInterface) run(width, height int, scale float64, title string, context driver.UIContext, graphics driver.Graphics, mainloop bool) (err error) {
	// Convert the panic to a regular error so that Java/Objective-C layer can treat this easily e.g., for
	// Crashlytics. A panic is treated as SIGABRT, and there is no way to handle this on Java/Objective-C layer
	// unfortunately.
	// TODO: Panic on other goroutines cannot be handled here.
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("%v\n%q", r, string(debug.Stack()))
		}
	}()

	u.m.Lock()
	u.width = width
	u.height = height
	u.scale = scale
	u.sizeChanged = true
	u.graphics = graphics
	u.m.Unlock()
	// title is ignored?

	if graphics.IsGL() {
		var ctx gl.Context
		if mainloop {
			ctx = <-glContextCh
		} else {
			ctx, u.glWorker = gl.NewContext()
		}
		graphics.(*opengl.Driver).SetMobileGLContext(ctx)
	} else {
		u.t = thread.New()
		graphics.SetThread(u.t)
	}

	// Force to set the screen size
	u.updateSize(context)
	for {
		if err := u.update(context); err != nil {
			return err
		}
	}
}

func (u *UserInterface) updateSize(context driver.UIContext) {
	width, height := 0, 0
	actualScale := 0.0

	u.m.Lock()
	sizeChanged := u.sizeChanged
	if sizeChanged {
		width = u.width
		height = u.height
		actualScale = u.scaleImpl() * deviceScale()
	}
	u.sizeChanged = false
	u.m.Unlock()

	if sizeChanged {
		// Sizing also calls GL functions
		context.SetSize(width, height, actualScale)
	}
}

func (u *UserInterface) ActualScale() float64 {
	u.m.Lock()
	s := u.scaleImpl() * deviceScale()
	u.m.Unlock()
	return s
}

func (u *UserInterface) scaleImpl() float64 {
	scale := u.scale
	if u.fullscreenScale != 0 {
		scale = u.fullscreenScale
	}
	return scale
}

func (u *UserInterface) update(context driver.UIContext) error {
	t := time.NewTimer(500 * time.Millisecond)
	defer t.Stop()

	select {
	case <-renderCh:
	case <-t.C:
		hooks.SuspendAudio()
		<-renderCh
	}

	hooks.ResumeAudio()

	defer func() {
		renderEndCh <- struct{}{}
	}()

	if err := context.Update(func() {
		u.updateSize(context)
	}); err != nil {
		return err
	}
	return nil
}

func (u *UserInterface) ScreenSize() (int, int) {
	u.m.Lock()
	w, h := u.width, u.height
	u.m.Unlock()
	return w, h
}

func (u *UserInterface) ScreenSizeInFullscreen() (int, int) {
	// TODO: This function should return fullscreenWidthPx, fullscreenHeightPx,
	// but these values are not initialized until the main loop starts.
	return 0, 0
}

func (u *UserInterface) SetScreenSize(width, height int) {
	u.m.Lock()
	if u.width != width || u.height != height {
		u.width = width
		u.height = height
		u.updateFullscreenScaleIfNeeded()
		u.sizeChanged = true
	}
	u.m.Unlock()
}

func (u *UserInterface) SetScreenScale(scale float64) {
	u.m.Lock()
	if u.scale != scale {
		u.scale = scale
		u.sizeChanged = true
	}
	u.m.Unlock()
}

func (u *UserInterface) ScreenScale() float64 {
	u.m.RLock()
	s := u.scale
	u.m.RUnlock()
	return s
}

func (u *UserInterface) setFullscreenImpl(widthPx, heightPx int) {
	// This implementation is only for gomobile-build so far.
	u.m.Lock()
	u.fullscreenWidthPx = widthPx
	u.fullscreenHeightPx = heightPx
	u.updateFullscreenScaleIfNeeded()
	u.sizeChanged = true
	u.m.Unlock()
}

func (u *UserInterface) updateFullscreenScaleIfNeeded() {
	if u.fullscreenWidthPx == 0 || u.fullscreenHeightPx == 0 {
		return
	}
	w, h := u.width, u.height
	scaleX := float64(u.fullscreenWidthPx) / float64(w)
	scaleY := float64(u.fullscreenHeightPx) / float64(h)
	scale := scaleX
	if scale > scaleY {
		scale = scaleY
	}
	u.fullscreenScale = scale / deviceScale()
	u.sizeChanged = true
}

func (u *UserInterface) ScreenPadding() (x0, y0, x1, y1 float64) {
	u.m.Lock()
	x0, y0, x1, y1 = u.screenPaddingImpl()
	u.m.Unlock()
	return
}

func (u *UserInterface) screenPaddingImpl() (x0, y0, x1, y1 float64) {
	if u.fullscreenScale == 0 {
		return 0, 0, 0, 0
	}
	s := u.fullscreenScale * deviceScale()
	ox := (float64(u.fullscreenWidthPx) - float64(u.width)*s) / 2
	oy := (float64(u.fullscreenHeightPx) - float64(u.height)*s) / 2
	return ox, oy, ox, oy
}

func (u *UserInterface) adjustPosition(x, y int) (int, int) {
	ox, oy, _, _ := u.screenPaddingImpl()
	s := u.scaleImpl()
	as := s * deviceScale()
	return int(float64(x)/s - ox/as), int(float64(y)/s - oy/as)
}

func (u *UserInterface) IsCursorVisible() bool {
	return false
}

func (u *UserInterface) SetCursorVisible(visible bool) {
	// Do nothing
}

func (u *UserInterface) IsFullscreen() bool {
	return false
}

func (u *UserInterface) SetFullscreen(fullscreen bool) {
	// Do nothing
}

func (u *UserInterface) IsRunnableInBackground() bool {
	return false
}

func (u *UserInterface) SetRunnableInBackground(runnableInBackground bool) {
	// Do nothing
}

func (u *UserInterface) SetWindowTitle(title string) {
	// Do nothing
}

func (u *UserInterface) SetWindowIcon(iconImages []image.Image) {
	// Do nothing
}

func (u *UserInterface) IsWindowDecorated() bool {
	return false
}

func (u *UserInterface) SetWindowDecorated(decorated bool) {
	// Do nothing
}

func (u *UserInterface) IsWindowResizable() bool {
	return false
}

func (u *UserInterface) SetWindowResizable(decorated bool) {
	// Do nothing
}

func (u *UserInterface) IsVsyncEnabled() bool {
	return true
}

func (u *UserInterface) SetVsyncEnabled(enabled bool) {
	// Do nothing
}

func (u *UserInterface) DeviceScaleFactor() float64 {
	return deviceScale()
}

func (u *UserInterface) SetWindowPosition(x, y int) {
	// Do nothing
}

func (u *UserInterface) WindowPosition() (int, int) {
	return 0, 0
}

func (u *UserInterface) SetScreenTransparent(transparent bool) {
	// Do nothing
}

func (u *UserInterface) IsScreenTransparent() bool {
	return false
}

func (u *UserInterface) Input() driver.Input {
	return &u.input
}

type Touch struct {
	ID int
	X  int
	Y  int
}

func (u *UserInterface) UpdateInput(touches []*Touch) {
	u.input.update(touches)
}
<commit_msg>uidriver/mobile: Refactoring: Rename variables<commit_after>// Copyright 2016 Hajime Hoshi
//
// 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 android ios

package mobile

import (
	"context"
	"fmt"
	"image"
	"runtime/debug"
	"sync"
	"time"

	"golang.org/x/mobile/app"
	"golang.org/x/mobile/event/lifecycle"
	"golang.org/x/mobile/event/paint"
	"golang.org/x/mobile/event/size"
	"golang.org/x/mobile/event/touch"
	"golang.org/x/mobile/gl"

	"github.com/hajimehoshi/ebiten/internal/devicescale"
	"github.com/hajimehoshi/ebiten/internal/driver"
	"github.com/hajimehoshi/ebiten/internal/graphicsdriver/opengl"
	"github.com/hajimehoshi/ebiten/internal/hooks"
	"github.com/hajimehoshi/ebiten/internal/thread"
)

var (
	glContextCh = make(chan gl.Context)

	// renderCh receives when updating starts.
	renderCh = make(chan struct{})

	// renderEndCh receives when updating finishes.
	renderEndCh = make(chan struct{})

	theUI = &UserInterface{}
)

func init() {
	theUI.input.ui = theUI
}

func Get() *UserInterface {
	return theUI
}

func (u *UserInterface) Update() {
	renderCh <- struct{}{}
	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		<-renderEndCh
		if u.t != nil {
			u.t.Call(func() error {
				cancel()
				return nil
			})
		} else {
			cancel()
		}
	}()

	if u.graphics.IsGL() {
		if u.glWorker == nil {
			panic("mobile: glWorker must be initialized but not")
		}
		workAvailable := u.glWorker.WorkAvailable()
	loop:
		for {
			select {
			case <-workAvailable:
				u.glWorker.DoWork()
			case <-ctx.Done():
				break loop
			}
		}
		return
	} else {
		u.t.Loop(ctx)
	}
}

type UserInterface struct {
	width       int
	height      int
	scale       float64
	sizeChanged bool

	// Used for gomobile-build
	gbuildScale    float64
	gbuildWidthPx  int
	gbuildHeightPx int

	graphics driver.Graphics

	input Input

	t        *thread.Thread
	glWorker gl.Worker

	m sync.RWMutex
}

func deviceScale() float64 {
	return devicescale.GetAt(0, 0)
}

// appMain is the main routine for gomobile-build mode.
func (u *UserInterface) appMain(a app.App) {
	var glctx gl.Context
	touches := map[touch.Sequence]*Touch{}
	for e := range a.Events() {
		switch e := a.Filter(e).(type) {
		case lifecycle.Event:
			switch e.Crosses(lifecycle.StageVisible) {
			case lifecycle.CrossOn:
				glctx, _ = e.DrawContext.(gl.Context)
				// Assume that glctx is always a same instance.
				// Then, only once initializing should be enough.
				if glContextCh != nil {
					glContextCh <- glctx
					glContextCh = nil
				}
				a.Send(paint.Event{})
			case lifecycle.CrossOff:
				glctx = nil
			}
		case size.Event:
			u.setGBuildImpl(e.WidthPx, e.HeightPx)
		case paint.Event:
			if glctx == nil || e.External {
				continue
			}
			renderCh <- struct{}{}
			<-renderEndCh
			a.Publish()
			a.Send(paint.Event{})
		case touch.Event:
			switch e.Type {
			case touch.TypeBegin, touch.TypeMove:
				s := deviceScale()
				x, y := float64(e.X)/s, float64(e.Y)/s
				// TODO: Is it ok to cast from int64 to int here?
				touches[e.Sequence] = &Touch{
					ID: int(e.Sequence),
					X:  int(x),
					Y:  int(y),
				}
			case touch.TypeEnd:
				delete(touches, e.Sequence)
			}
			ts := []*Touch{}
			for _, t := range touches {
				ts = append(ts, t)
			}
			u.input.update(ts)
		}
	}
}

func (u *UserInterface) Run(width, height int, scale float64, title string, context driver.UIContext, graphics driver.Graphics) error {
	go func() {
		if err := u.run(width, height, scale, title, context, graphics, true); err != nil {
			// As mobile apps never ends, Loop can't return. Just panic here.
			panic(err)
		}
	}()
	app.Main(u.appMain)
	return nil
}

func (u *UserInterface) RunWithoutMainLoop(width, height int, scale float64, title string, context driver.UIContext, graphics driver.Graphics) <-chan error {
	ch := make(chan error)
	go func() {
		defer close(ch)
		if err := u.run(width, height, scale, title, context, graphics, false); err != nil {
			ch <- err
		}
	}()
	return ch
}

func (u *UserInterface) run(width, height int, scale float64, title string, context driver.UIContext, graphics driver.Graphics, mainloop bool) (err error) {
	// Convert the panic to a regular error so that Java/Objective-C layer can treat this easily e.g., for
	// Crashlytics. A panic is treated as SIGABRT, and there is no way to handle this on Java/Objective-C layer
	// unfortunately.
	// TODO: Panic on other goroutines cannot be handled here.
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("%v\n%q", r, string(debug.Stack()))
		}
	}()

	u.m.Lock()
	u.width = width
	u.height = height
	u.scale = scale
	u.sizeChanged = true
	u.graphics = graphics
	u.m.Unlock()
	// title is ignored?

	if graphics.IsGL() {
		var ctx gl.Context
		if mainloop {
			ctx = <-glContextCh
		} else {
			ctx, u.glWorker = gl.NewContext()
		}
		graphics.(*opengl.Driver).SetMobileGLContext(ctx)
	} else {
		u.t = thread.New()
		graphics.SetThread(u.t)
	}

	// Force to set the screen size
	u.updateSize(context)
	for {
		if err := u.update(context); err != nil {
			return err
		}
	}
}

func (u *UserInterface) updateSize(context driver.UIContext) {
	width, height := 0, 0
	actualScale := 0.0

	u.m.Lock()
	sizeChanged := u.sizeChanged
	if sizeChanged {
		width = u.width
		height = u.height
		actualScale = u.scaleImpl() * deviceScale()
	}
	u.sizeChanged = false
	u.m.Unlock()

	if sizeChanged {
		// Sizing also calls GL functions
		context.SetSize(width, height, actualScale)
	}
}

func (u *UserInterface) ActualScale() float64 {
	u.m.Lock()
	s := u.scaleImpl() * deviceScale()
	u.m.Unlock()
	return s
}

func (u *UserInterface) scaleImpl() float64 {
	scale := u.scale
	if u.gbuildScale != 0 {
		scale = u.gbuildScale
	}
	return scale
}

func (u *UserInterface) update(context driver.UIContext) error {
	t := time.NewTimer(500 * time.Millisecond)
	defer t.Stop()

	select {
	case <-renderCh:
	case <-t.C:
		hooks.SuspendAudio()
		<-renderCh
	}

	hooks.ResumeAudio()

	defer func() {
		renderEndCh <- struct{}{}
	}()

	if err := context.Update(func() {
		u.updateSize(context)
	}); err != nil {
		return err
	}
	return nil
}

func (u *UserInterface) ScreenSize() (int, int) {
	u.m.Lock()
	w, h := u.width, u.height
	u.m.Unlock()
	return w, h
}

func (u *UserInterface) ScreenSizeInFullscreen() (int, int) {
	// TODO: This function should return gbuildWidthPx, gbuildHeightPx,
	// but these values are not initialized until the main loop starts.
	return 0, 0
}

func (u *UserInterface) SetScreenSize(width, height int) {
	u.m.Lock()
	if u.width != width || u.height != height {
		u.width = width
		u.height = height
		u.updateGBuildScaleIfNeeded()
		u.sizeChanged = true
	}
	u.m.Unlock()
}

func (u *UserInterface) SetScreenScale(scale float64) {
	u.m.Lock()
	if u.scale != scale {
		u.scale = scale
		u.sizeChanged = true
	}
	u.m.Unlock()
}

func (u *UserInterface) ScreenScale() float64 {
	u.m.RLock()
	s := u.scale
	u.m.RUnlock()
	return s
}

func (u *UserInterface) setGBuildImpl(widthPx, heightPx int) {
	u.m.Lock()
	u.gbuildWidthPx = widthPx
	u.gbuildHeightPx = heightPx
	u.updateGBuildScaleIfNeeded()
	u.sizeChanged = true
	u.m.Unlock()
}

func (u *UserInterface) updateGBuildScaleIfNeeded() {
	if u.gbuildWidthPx == 0 || u.gbuildHeightPx == 0 {
		return
	}
	w, h := u.width, u.height
	scaleX := float64(u.gbuildWidthPx) / float64(w)
	scaleY := float64(u.gbuildHeightPx) / float64(h)
	scale := scaleX
	if scale > scaleY {
		scale = scaleY
	}
	u.gbuildScale = scale / deviceScale()
	u.sizeChanged = true
}

func (u *UserInterface) ScreenPadding() (x0, y0, x1, y1 float64) {
	u.m.Lock()
	x0, y0, x1, y1 = u.screenPaddingImpl()
	u.m.Unlock()
	return
}

func (u *UserInterface) screenPaddingImpl() (x0, y0, x1, y1 float64) {
	if u.gbuildScale == 0 {
		return 0, 0, 0, 0
	}
	s := u.gbuildScale * deviceScale()
	ox := (float64(u.gbuildWidthPx) - float64(u.width)*s) / 2
	oy := (float64(u.gbuildHeightPx) - float64(u.height)*s) / 2
	return ox, oy, ox, oy
}

func (u *UserInterface) adjustPosition(x, y int) (int, int) {
	ox, oy, _, _ := u.screenPaddingImpl()
	s := u.scaleImpl()
	as := s * deviceScale()
	return int(float64(x)/s - ox/as), int(float64(y)/s - oy/as)
}

func (u *UserInterface) IsCursorVisible() bool {
	return false
}

func (u *UserInterface) SetCursorVisible(visible bool) {
	// Do nothing
}

func (u *UserInterface) IsFullscreen() bool {
	return false
}

func (u *UserInterface) SetFullscreen(fullscreen bool) {
	// Do nothing
}

func (u *UserInterface) IsRunnableInBackground() bool {
	return false
}

func (u *UserInterface) SetRunnableInBackground(runnableInBackground bool) {
	// Do nothing
}

func (u *UserInterface) SetWindowTitle(title string) {
	// Do nothing
}

func (u *UserInterface) SetWindowIcon(iconImages []image.Image) {
	// Do nothing
}

func (u *UserInterface) IsWindowDecorated() bool {
	return false
}

func (u *UserInterface) SetWindowDecorated(decorated bool) {
	// Do nothing
}

func (u *UserInterface) IsWindowResizable() bool {
	return false
}

func (u *UserInterface) SetWindowResizable(decorated bool) {
	// Do nothing
}

func (u *UserInterface) IsVsyncEnabled() bool {
	return true
}

func (u *UserInterface) SetVsyncEnabled(enabled bool) {
	// Do nothing
}

func (u *UserInterface) DeviceScaleFactor() float64 {
	return deviceScale()
}

func (u *UserInterface) SetWindowPosition(x, y int) {
	// Do nothing
}

func (u *UserInterface) WindowPosition() (int, int) {
	return 0, 0
}

func (u *UserInterface) SetScreenTransparent(transparent bool) {
	// Do nothing
}

func (u *UserInterface) IsScreenTransparent() bool {
	return false
}

func (u *UserInterface) Input() driver.Input {
	return &u.input
}

type Touch struct {
	ID int
	X  int
	Y  int
}

func (u *UserInterface) UpdateInput(touches []*Touch) {
	u.input.update(touches)
}
<|endoftext|>


<commit_before>package vault

import (
	"crypto/md5"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/aws/aws-sdk-go/aws/awserr"
	ini "github.com/go-ini/ini"
	"github.com/mitchellh/go-homedir"
)

func init() {
	ini.PrettyFormat = false
}

// Config is an abstraction over what is in ~/.aws/config
type Config struct {
	Path    string
	iniFile *ini.File
}

// ConfigPath returns either $AWS_CONFIG_FILE or ~/.aws/config
func ConfigPath() (string, error) {
	file := os.Getenv("AWS_CONFIG_FILE")
	if file == "" {
		home, err := homedir.Dir()
		if err != nil {
			return "", err
		}
		file = filepath.Join(home, "/.aws/config")
	}
	return file, nil
}

// LoadConfig loads and parses a config. No error is returned if the file doesn't exist
func LoadConfig(path string) (*Config, error) {
	config := &Config{
		Path: path,
	}
	if _, err := os.Stat(path); err == nil {
		if parseErr := config.parseFile(); parseErr != nil {
			return nil, parseErr
		}
	} else {
		log.Printf("Config file %s doesn't exist", path)
	}
	return config, nil
}

// LoadConfigFromEnv finds the config file from the environment
func LoadConfigFromEnv() (*Config, error) {
	file, err := ConfigPath()
	if err != nil {
		return nil, err
	}

	log.Printf("Loading config file %s", file)
	return LoadConfig(file)
}

func (c *Config) parseFile() error {
	log.Printf("Parsing config file %s", c.Path)
	f, err := ini.LoadSources(ini.LoadOptions{
		AllowNestedValues: true,
	}, c.Path)
	if err != nil {
		return fmt.Errorf("Error parsing config file %q: %v", c.Path, err)
	}
	c.iniFile = f
	return nil
}

type Profile struct {
	Name            string `ini:"-"`
	MFASerial       string `ini:"mfa_serial,omitempty"`
	RoleARN         string `ini:"role_arn,omitempty"`
	Region          string `ini:"region,omitempty"`
	SourceProfile   string `ini:"source_profile,omitempty"`
	RoleSessionName string `ini:"role_session_name,omitempty"`
}

func (p Profile) Hash() ([]byte, error) {
	hasher := md5.New()
	if err := json.NewEncoder(hasher).Encode(p); err != nil {
		return nil, err
	}
	b := hasher.Sum(nil)
	return b, nil
}

func readProfileFromIni(f *ini.File, sectionName string, profile *Profile) error {
	if f == nil {
		return errors.New("No ini file available")
	}
	section, err := f.GetSection(sectionName)
	if err != nil {
		return err
	}
	if err = section.MapTo(&profile); err != nil {
		return err
	}
	return nil
}

// Profiles returns all the profiles in the config
func (c *Config) Profiles() []Profile {
	var result []Profile

	if c.iniFile == nil {
		return result
	}

	for _, section := range c.iniFile.SectionStrings() {
		if section != "DEFAULT" {
			profile, _ := c.Profile(strings.TrimPrefix(section, "profile "))
			result = append(result, profile)
		}
	}

	return result
}

// Profile returns the  profile with the matching name. If there isn't any,
// an empty profile with the provided name is returned, along with false.
func (c *Config) Profile(name string) (Profile, bool) {
	profile := Profile{
		Name: name,
	}
	if c.iniFile == nil {
		return profile, false
	}
	// default profile name has a slightly different section format
	sectionName := "profile " + name
	if name == "default" {
		sectionName = "default"
	}
	section, err := c.iniFile.GetSection(sectionName)
	if err != nil {
		return profile, false
	}
	if err = section.MapTo(&profile); err != nil {
		panic(err)
	}
	return profile, true
}

// Add the profile to the configuration file
func (c *Config) Add(profile Profile) error {
	if c.iniFile == nil {
		return errors.New("No iniFile to add to")
	}
	// default profile name has a slightly different section format
	sectionName := "profile " + profile.Name
	if profile.Name == "default" {
		sectionName = "default"
	}
	section, err := c.iniFile.NewSection(sectionName)
	if err != nil {
		return fmt.Errorf("Error creating section %q: %v", profile.Name, err)
	}
	if err = section.ReflectFrom(&profile); err != nil {
		return fmt.Errorf("Error mapping profile to ini file: %v", err)
	}
	return c.iniFile.SaveTo(c.Path)
}

// SourceProfile returns the source profile of the given profile. If there isn't any,
// the named profile, a new profile is returned. False is only returned if no profile by the name exists.
func (c *Config) SourceProfile(name string) (Profile, bool) {
	profile, ok := c.Profile(name)
	if profile.SourceProfile != "" {
		return c.Profile(profile.SourceProfile)
	}
	return profile, ok
}

// FormatCredentialError formats errors with some user friendly context
func (c *Config) FormatCredentialError(err error, profileName string) string {
	source, _ := c.SourceProfile(profileName)
	sourceDescr := profileName

	// add custom formatting for source_profile
	if source.Name != profileName {
		sourceDescr = fmt.Sprintf("%s (source profile for %s)", source.Name, profileName)
	}

	if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "NoCredentialProviders" {
		return fmt.Sprintf(
			"No credentials found for profile %s.\n"+
				"Use 'aws-vault add %s' to set up credentials or 'aws-vault list' to see what credentials exist",
			sourceDescr, source.Name)
	}

	return fmt.Sprintf("Failed to get credentials for %s: %v", sourceDescr, err)
}
<commit_msg>Refactor to create config file if one does not exist already.<commit_after>package vault

import (
	"crypto/md5"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/aws/aws-sdk-go/aws/awserr"
	ini "github.com/go-ini/ini"
	"github.com/mitchellh/go-homedir"
)

func init() {
	ini.PrettyFormat = false
}

// Config is an abstraction over what is in ~/.aws/config
type Config struct {
	Path    string
	iniFile *ini.File
}

// ConfigPath returns either $AWS_CONFIG_FILE or ~/.aws/config
func ConfigPath() (string, error) {
	file := os.Getenv("AWS_CONFIG_FILE")
	if file == "" {
		home, err := homedir.Dir()
		if err != nil {
			return "", err
		}
		file = filepath.Join(home, "/.aws/config")
	}
	return file, nil
}

// CreateConfig will create the config directory and file if they do not exist
func CreateConfig() (error) {
	file, err := ConfigPath()
	if err != nil {
		return err
	}
	dir := filepath.Dir(file)
	if _, err := os.Stat(dir); os.IsNotExist(err) {
		os.Mkdir(dir, 0755)
		log.Printf("Config directory %s created", dir)
	}
	if _, err := os.Stat(file); os.IsNotExist(err) {
		newFile, err := os.Create(file)
		if err != nil {
			log.Printf("Config file %s not created", file)
			return err
		}
		newFile.Close()
		log.Printf("Config file %s created", file)
        }
	return nil
}

// LoadConfig loads and parses a config. No error is returned if the file doesn't exist
func LoadConfig(path string) (*Config, error) {
	config := &Config{
		Path: path,
	}
	if _, err := os.Stat(path); err == nil {
		if parseErr := config.parseFile(); parseErr != nil {
			return nil, parseErr
		}
	} else {
		log.Printf("Config file %s doesn't exist so lets create it", path)
		err := CreateConfig()
		if err != nil {
			return nil, err
		}
		if parseErr := config.parseFile(); parseErr != nil {
			return nil, parseErr
		}
	}
	return config, nil
}

// LoadConfigFromEnv finds the config file from the environment
func LoadConfigFromEnv() (*Config, error) {
	file, err := ConfigPath()
	if err != nil {
		return nil, err
	}

	log.Printf("Loading config file %s", file)
	return LoadConfig(file)
}

func (c *Config) parseFile() error {
	log.Printf("Parsing config file %s", c.Path)
	f, err := ini.LoadSources(ini.LoadOptions{
		AllowNestedValues: true,
	}, c.Path)
	if err != nil {
		return fmt.Errorf("Error parsing config file %q: %v", c.Path, err)
	}
	c.iniFile = f
	return nil
}

type Profile struct {
	Name            string `ini:"-"`
	MFASerial       string `ini:"mfa_serial,omitempty"`
	RoleARN         string `ini:"role_arn,omitempty"`
	Region          string `ini:"region,omitempty"`
	SourceProfile   string `ini:"source_profile,omitempty"`
	RoleSessionName string `ini:"role_session_name,omitempty"`
}

func (p Profile) Hash() ([]byte, error) {
	hasher := md5.New()
	if err := json.NewEncoder(hasher).Encode(p); err != nil {
		return nil, err
	}
	b := hasher.Sum(nil)
	return b, nil
}

func readProfileFromIni(f *ini.File, sectionName string, profile *Profile) error {
	if f == nil {
		return errors.New("No ini file available")
	}
	section, err := f.GetSection(sectionName)
	if err != nil {
		return err
	}
	if err = section.MapTo(&profile); err != nil {
		return err
	}
	return nil
}

// Profiles returns all the profiles in the config
func (c *Config) Profiles() []Profile {
	var result []Profile

	if c.iniFile == nil {
		return result
	}

	for _, section := range c.iniFile.SectionStrings() {
		if section != "DEFAULT" {
			profile, _ := c.Profile(strings.TrimPrefix(section, "profile "))
			result = append(result, profile)
		}
	}

	return result
}

// Profile returns the  profile with the matching name. If there isn't any,
// an empty profile with the provided name is returned, along with false.
func (c *Config) Profile(name string) (Profile, bool) {
	profile := Profile{
		Name: name,
	}
	if c.iniFile == nil {
		return profile, false
	}
	// default profile name has a slightly different section format
	sectionName := "profile " + name
	if name == "default" {
		sectionName = "default"
	}
	section, err := c.iniFile.GetSection(sectionName)
	if err != nil {
		return profile, false
	}
	if err = section.MapTo(&profile); err != nil {
		panic(err)
	}
	return profile, true
}

// Add the profile to the configuration file
func (c *Config) Add(profile Profile) error {
	if c.iniFile == nil {
		return errors.New("No iniFile to add to")
	}
	// default profile name has a slightly different section format
	sectionName := "profile " + profile.Name
	if profile.Name == "default" {
		sectionName = "default"
	}
	section, err := c.iniFile.NewSection(sectionName)
	if err != nil {
		return fmt.Errorf("Error creating section %q: %v", profile.Name, err)
	}
	if err = section.ReflectFrom(&profile); err != nil {
		return fmt.Errorf("Error mapping profile to ini file: %v", err)
	}
	return c.iniFile.SaveTo(c.Path)
}

// SourceProfile returns the source profile of the given profile. If there isn't any,
// the named profile, a new profile is returned. False is only returned if no profile by the name exists.
func (c *Config) SourceProfile(name string) (Profile, bool) {
	profile, ok := c.Profile(name)
	if profile.SourceProfile != "" {
		return c.Profile(profile.SourceProfile)
	}
	return profile, ok
}

// FormatCredentialError formats errors with some user friendly context
func (c *Config) FormatCredentialError(err error, profileName string) string {
	source, _ := c.SourceProfile(profileName)
	sourceDescr := profileName

	// add custom formatting for source_profile
	if source.Name != profileName {
		sourceDescr = fmt.Sprintf("%s (source profile for %s)", source.Name, profileName)
	}

	if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "NoCredentialProviders" {
		return fmt.Sprintf(
			"No credentials found for profile %s.\n"+
				"Use 'aws-vault add %s' to set up credentials or 'aws-vault list' to see what credentials exist",
			sourceDescr, source.Name)
	}

	return fmt.Sprintf("Failed to get credentials for %s: %v", sourceDescr, err)
}
<|endoftext|>


<commit_before>package app

import (
	"fmt"

	"github.com/moncho/dry/version"
)

//ShortHelp is a short description of dry
const ShortHelp = `
dry

A tool to interact with a Docker Daemon from the terminal.
`

var help = `
<white>dry ` + fmt.Sprintf("version %s, build %s", version.VERSION, version.GITCOMMIT) + `</>` +
	`
A tool to interact with a Docker Daemon from the terminal.

Visit <blue>http://moncho.github.io/dry/</> for more information.

<yellow>Global keybinds</>
	<white>F8</>        Shows Docker disk usage
	<white>F9</>        Shows the last 10 events reported by Docker
	<white>F10</>       Inspects Docker
	<white>1</>         To container list
	<white>2</>         To image list
	<white>3</>         To network list
	<white>4</>         To node list (in Swarm mode)
	<white>5</>         To service list (in Swarm mode)
	<white>m</>         Show container monitor mode
	<white>h</>         Shows this help screen
	<white>Ctrl+c</>    Quits <white>dry</> immediately
	<white>q</>         Quits <white>dry</>
	<white>esc</>       Goes back to the main screen

<yellow>Global list keybinds</>
	<white>F1</>        Cycles through sort modes
	<white>F5</>        Refreshes the list
	<white>/</>         Defines Filter

<yellow>Container list keybinds</>
	<white>F2</>        Toggles showing all containers (default shows just running)
	<white>e</>         Removes the selected container
	<white>Ctrl+e</>    Removes all stopped containers
	<white>Ctrl+k</>    Kills the selected container
	<white>l</>         Displays the logs of the selected container
	<white>Ctrl+r</>    Restarts selected container
	<white>s</>         Displays a live stream of the selected container resource usage statistics
	<white>Ctrl+t</>    Stops selected container (noop if it is not running)
	<white>Enter</>     Returns low-level information of the selected container

<yellow>Image list keybinds</>
	<white>Ctrl+e</>    Removes the selected image
	<white>Ctrl+f</>    Forces removal of the selected image
	<white>i</>         Shows image history
	<white>Enter</>     Returns low-level information of the selected image

<yellow>Network list keybinds</>
	<white>Enter</>     Returns low-level information of the selected network

<yellow>Node list keybinds</>
	<white>Enter</>     Shows the list of taks running on the selected node

<yellow>Service list keybinds</>
	<white>Enter</>     Shows the list of taks that are part of the selected service
	<white>l</>         Displays the logs of the selected service
	<white>Ctrl+R</>    Removes the selected service

<yellow>Move around in lists</>
	<white>ArrowUp</>   Moves the cursor one line up
	<white>ArrowDown</> Moves the cursor one line down
	<white>g</>         Moves the cursor to the beginning of the list
	<white>G</>         Moves the cursor to the end of the list

<yellow>Move around in logs/inspect buffers</>
	<white>/</>         Searches for a pattern
	<white>F</>         Only show lines that matches a pattern
	<white>g</>         Moves the cursor to the beginning
	<white>G</>         Moves the cursor until the end
	<white>n</>         After a search, it moves forwards to the next search hit
	<white>N</>         After a search, it moves backwards to the previous search hit
	<white>pg up</>     Moves the cursor "screen size" lines up
	<white>pg down</>   Moves the cursor "screen size" lines down

<r> Press ESC to exit help. </r>
`

const (
	commonMappings = "<b>[H]:<darkgrey>Help</> <b>[Q]:<darkgrey>Quit</> <blue>|</> "
	keyMappings    = commonMappings +
		"<b>[F1]:<darkgrey>Sort</> <b>[F2]:<darkgrey>Toggle Show Containers</> <b>[F5]:<darkgrey>Refresh</> <b>[/]:<darkgrey>Filter</> <blue>|</> " +
		"<b>[m]:<darkgrey>Monitor mode</> <b>[2]:<darkgrey>Images</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <blue>|</> <b>[Enter]:<darkgrey>Commands</></>"

	monitorMapping = commonMappings +
		"<b>[m]:<darkgrey>Monitor mode</> <b>[1]:<darkgrey>Containers</> <b>[2]:<darkgrey>Images</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</>"

	swarmMapping = commonMappings +
		"<b>[m]:<darkgrey>Monitor mode</> <b>[1]:<darkgrey>Containers</> <b>[2]:<darkgrey>Images</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</>"

	imagesKeyMappings = commonMappings +
		"<b>[F1]:<darkgrey>Sort</> <b>[F5]:<darkgrey>Refresh</> <blue>|</> " +
		"<b>[1]:<darkgrey>Containers</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <blue>|</>" +
		"<b>[Ctrl+D]:<darkgrey>Remove Dangling</> <b>[Ctrl+E]:<darkgrey>Remove</> <b>[Ctrl+F]:<darkgrey>Force Remove</> <b>[I]:<darkgrey>History</>"

	networkKeyMappings = commonMappings +
		"<b>[F1]:<darkgrey>Sort</> <b>[F5]:<darkgrey>Refresh</> <blue>|</> " +
		"<b>[1]:<darkgrey>Containers</> <b>[2]:<darkgrey>Images</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <blue>|</>" +
		"<b>[Ctrl+E]:<darkgrey>Remove</> <b>[Enter]:<darkgrey>Inspect</>"

	diskUsageKeyMappings = commonMappings +
		"<b>[1]:<darkgrey>Containers</> <b>[2]:<darkgrey>Images</><blue>|</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <blue>|</>" +
		"<b>[p]:<darkgrey>Prune</>"

	serviceKeyMappings = swarmMapping + "<blue>|</> <b>[F1]:<darkgrey>Sort</> <b>[F5]:<darkgrey>Refresh</> <b>[/]:<darkgrey>Filter</> <blue>|</> <b>[l]:<darkgrey>Service logs</> <b>[Ctrl+R]:<darkgrey>Remove Service</> <b>[Ctrl+S]:<darkgrey>Scale service</>"

	nodeKeyMappings = swarmMapping + " <blue>|</> <b>[F1]:<darkgrey>Sort</> <b>[F5]:<darkgrey>Refresh</> <blue>|</>  <b>[Enter]:<darkgrey>Show Node Tasks</> <b>[Ctrl+A]:<darkgrey>Set Availability</>"

	commandsMenuBar = "<b>[Esc]:<darkgrey>Back</> <b>[Up]:<darkgrey>Cursor Up</> <b>[Down]:<darkgrey>Cursor Down</> <b>[Enter]:<darkgrey>Execute Command</>"
)
<commit_msg>minor<commit_after>package app

import (
	"fmt"

	"github.com/moncho/dry/version"
)

//ShortHelp is a short description of dry
const ShortHelp = `
dry

A tool to interact with a Docker Daemon from the terminal.
`

var help = `
<white>dry ` + fmt.Sprintf("version %s, build %s", version.VERSION, version.GITCOMMIT) + `</>` +
	`
A tool to interact with a Docker Daemon from the terminal.

Visit <blue>http://moncho.github.io/dry/</> for more information.

<yellow>Global keybinds</>
	<white>F8</>        Shows Docker disk usage
	<white>F9</>        Shows the last 10 events reported by Docker
	<white>F10</>       Inspects Docker
	<white>1</>         To container list
	<white>2</>         To image list
	<white>3</>         To network list
	<white>4</>         To node list (in Swarm mode)
	<white>5</>         To service list (in Swarm mode)
	<white>m</>         Show container monitor mode
	<white>h</>         Shows this help screen
	<white>Ctrl+c</>    Quits <white>dry</> immediately
	<white>q</>         Quits <white>dry</>
	<white>esc</>       Goes back to the main screen

<yellow>Global list keybinds</>
	<white>F1</>        Cycles through sort modes
	<white>F5</>        Refreshes the list
	<white>%</>         Filter

<yellow>Container list keybinds</>
	<white>F2</>        Toggles showing all containers (default shows just running)
	<white>e</>         Removes the selected container
	<white>Ctrl+e</>    Removes all stopped containers
	<white>Ctrl+k</>    Kills the selected container
	<white>l</>         Displays the logs of the selected container
	<white>Ctrl+r</>    Restarts selected container
	<white>s</>         Displays a live stream of the selected container resource usage statistics
	<white>Ctrl+t</>    Stops selected container (noop if it is not running)
	<white>Enter</>     Returns low-level information of the selected container

<yellow>Image list keybinds</>
	<white>Ctrl+e</>    Removes the selected image
	<white>Ctrl+f</>    Forces removal of the selected image
	<white>i</>         Shows image history
	<white>Enter</>     Returns low-level information of the selected image

<yellow>Network list keybinds</>
	<white>Enter</>     Returns low-level information of the selected network

<yellow>Node list keybinds</>
	<white>Enter</>     Shows the list of taks running on the selected node

<yellow>Service list keybinds</>
	<white>Enter</>     Shows the list of taks that are part of the selected service
	<white>l</>         Displays the logs of the selected service
	<white>Ctrl+R</>    Removes the selected service

<yellow>Move around in lists</>
	<white>ArrowUp</>   Moves the cursor one line up
	<white>ArrowDown</> Moves the cursor one line down
	<white>g</>         Moves the cursor to the beginning of the list
	<white>G</>         Moves the cursor to the end of the list

<yellow>Move around in logs/inspect buffers</>
	<white>/</>         Searches for a pattern
	<white>F</>         Only show lines that matches a pattern
	<white>g</>         Moves the cursor to the beginning
	<white>G</>         Moves the cursor until the end
	<white>n</>         After a search, it moves forwards to the next search hit
	<white>N</>         After a search, it moves backwards to the previous search hit
	<white>pg up</>     Moves the cursor "screen size" lines up
	<white>pg down</>   Moves the cursor "screen size" lines down

<r> Press ESC to exit help. </r>
`

const (
	commonMappings = "<b>[H]:<darkgrey>Help</> <b>[Q]:<darkgrey>Quit</> <blue>|</> "
	keyMappings    = commonMappings +
		"<b>[F1]:<darkgrey>Sort</> <b>[F2]:<darkgrey>Toggle Show Containers</> <b>[F5]:<darkgrey>Refresh</> <b>[%]:<darkgrey>Filter</> <blue>|</> " +
		"<b>[m]:<darkgrey>Monitor mode</> <b>[2]:<darkgrey>Images</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <blue>|</> <b>[Enter]:<darkgrey>Commands</></>"

	monitorMapping = commonMappings +
		"<b>[m]:<darkgrey>Monitor mode</> <b>[1]:<darkgrey>Containers</> <b>[2]:<darkgrey>Images</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</>"

	swarmMapping = commonMappings +
		"<b>[m]:<darkgrey>Monitor mode</> <b>[1]:<darkgrey>Containers</> <b>[2]:<darkgrey>Images</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</>"

	imagesKeyMappings = commonMappings +
		"<b>[F1]:<darkgrey>Sort</> <b>[F5]:<darkgrey>Refresh</> <blue>|</> " +
		"<b>[1]:<darkgrey>Containers</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <blue>|</>" +
		"<b>[Ctrl+D]:<darkgrey>Remove Dangling</> <b>[Ctrl+E]:<darkgrey>Remove</> <b>[Ctrl+F]:<darkgrey>Force Remove</> <b>[I]:<darkgrey>History</>"

	networkKeyMappings = commonMappings +
		"<b>[F1]:<darkgrey>Sort</> <b>[F5]:<darkgrey>Refresh</> <blue>|</> " +
		"<b>[1]:<darkgrey>Containers</> <b>[2]:<darkgrey>Images</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <blue>|</>" +
		"<b>[Ctrl+E]:<darkgrey>Remove</> <b>[Enter]:<darkgrey>Inspect</>"

	diskUsageKeyMappings = commonMappings +
		"<b>[1]:<darkgrey>Containers</> <b>[2]:<darkgrey>Images</><blue>|</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <blue>|</>" +
		"<b>[p]:<darkgrey>Prune</>"

	serviceKeyMappings = swarmMapping + "<blue>|</> <b>[F1]:<darkgrey>Sort</> <b>[F5]:<darkgrey>Refresh</> <b>[%]:<darkgrey>Filter</> <blue>|</> <b>[l]:<darkgrey>Service logs</> <b>[Ctrl+R]:<darkgrey>Remove Service</> <b>[Ctrl+S]:<darkgrey>Scale service</>"

	nodeKeyMappings = swarmMapping + " <blue>|</> <b>[F1]:<darkgrey>Sort</> <b>[F5]:<darkgrey>Refresh</> <blue>|</>  <b>[Enter]:<darkgrey>Show Node Tasks</> <b>[Ctrl+A]:<darkgrey>Set Availability</>"

	commandsMenuBar = "<b>[Esc]:<darkgrey>Back</> <b>[Up]:<darkgrey>Cursor Up</> <b>[Down]:<darkgrey>Cursor Down</> <b>[Enter]:<darkgrey>Execute Command</>"
)
<|endoftext|>


<commit_before>package def

import (
	"time"
)

type InputGroup map[string]*Input

type OutputGroup map[string]*Output

/*
	Input specifies a data source to feed into the beginning of a computation.

	Inputs can be one of many different `Type`s of data source.
	Examples may include "tar", "git", "hadoop", "ipfs", etc.

	Inputs must specify both a `Hash` and a `URI`.
	`Input.Hash` is the content identity descriptor and will always be verified for all types of data source.
	`Input.Hash` is both identifies the data and provides integrity (in other words,
	all repeatr's input types will use a cryptographically strong hash here,
	so given a hash even an untrusted datastore is safe to use).
	Repeatr requires this to be accurate because if the inputs change, output
	consistency is impossible -- so even for plain http downloads, this is enforced.

	`Input.URI` is a secondary content lookup descriptor, like where on
	the filesystem or network information can be fetched from.
	`Input.URI` might contain extra description to answer questions like
	"which git remote url should i fetch from" or
	"which ipfs swarm do i coordinate with".

	Use can use `Formula.SetupHash` to get a hash covering the all the pieces
	of the formula used to set up and launch the action: that includes
	all of the type, hash, and mountpath options of every Input.
	The `URI` is *not* included in that hash, because repeatr understands
	that your data will be mobile -- that's why we have the `Input.Hash` take the leading role
	and why the `Input.Hash` should be sufficient to identify the information.
	Changes in the `Input.URI` field may make or break whether the data is accessible,
	but should never actually change the content of the data -- it's just supposed to talk about
	transport details; and content itself is still checked by `Input.Hash`.
*/
type Input struct {
	Type       string          `json:"type"`           // implementation name (repeatr-internal).  included in Formula.SetupHash.
	Hash       string          `json:"hash"`           // identifying hash of input data.  included in Formula.SetupHash.
	Warehouses WarehouseCoords `json:"silo,omitempty"` // secondary content lookup descriptor.  *not* included in Formula.SetupHash.
	MountPath  string          `json:"mount"`          // filepath where this input should be mounted in the execution context.  included in Formula.SetupHash.
	Tag        string          `json:"tag"`            // human readable name tag for this input.  ONLY USED FOR DOWNSTREAM APIs; do not reference this.
}

/*
	Output describes where we intend to pick up data after a task completes.

	Outputs can be one of many different `Type`s of data sink.
	Examples may include "tar", "git", "hadoop", "ipfs", etc.

	`Output.MountPath` states where we should collect information from the
	task execution environment.
	After the task completes, repeatr will pick up this data, ship it off
	to storage, and also calculate a checksum of the data so we can see
	whether it matches any prior (or future) runs of this `Formula`.

	Outputs must specify a `URI`; repeatr will ship your data to this address.
	`Output.URI` has similar properties to `Input.URI` (and also similarly,
	is not included in the Formula.SetupHash, because repeatr understands that
	your data can be mobile; if you change storage locations, that
	shouldn't bust any caches of known computations).

	The `Output.Hash` field will be filled in with a value computed
	from the data present in `Output.MountPath` after the task has completed.
	As with `Input.Hash`, the `Output.Hash` in repeatr will always be a
	cryptographically strong hash, which means it precisely describes your
	data, and makes it virtually impossible to accidentally get the same
	`Hash` as other data -- any changes to your output will always result
	in a very different `Hash` value.

	(In a content-addressable data store, repeatr may just lift the data store's
	address to use as `Output.Hash`, which is super efficient for everyone involved.
	For other more legacy-oriented systems, this may be a hash of the
	of the working filesystem right before before export.)

	`Output.Filters` may also be used to do a clean up pass on output files
	before committing them to storage or doing repeatr's consistency checks.
	One typical example, which is engaged by default, is setting all file
	modification times to a standard value, because this metadata is
	typically both very noisy and very useless.
*/
type Output struct {
	Type       string          `json:"type"`            // implementation name (repeatr-internal).
	Hash       string          `json:"hash"`            // identifying hash of output data.  generated by the output handling implementation during data export when a task is complete.
	Warehouses WarehouseCoords `json:"silo,omitempty"`  // where to ship the output data.
	MountPath  string          `json:"mount,omitempty"` // filepath where this output will be yanked from the job when it reaches completion.
	Filters    *Filters        `json:"filters,omitempty"`
	Tag        string          `json:"tag"` // human readable name tag for this ouput.  ONLY USED FOR DOWNSTREAM APIs; do not reference this.
}

/*
	Filters are transformations that can be applied to data, either to
	normalize it for storage or to apply attributes to it before feeding
	the data into an action's inputs.

	The following filters are available:

		- uid   -- the posix user ownership number
		- gid   -- the posix group ownership number
		- mtime -- the posix file modification timestamp

	'uid', 'gid', and 'mtime' are all filtered by default on formula outputs --
	most use cases do not need these attributes, and they are a source of nondeterminism.
	If you want to keep them, you may specify	`uid keep`, `gid keep`, `mtime keep`,
	etc; if you want the filters to flatten to different values than the defaults,
	you may specify `uid 12000`, etc.
	(Note that the default mtime filter flattens the time to Jan 1, 2010 --
	*not* epoch.  Some contemporary software has been known to regard zero/epoch
	timestamps as errors or empty values, so we've choosen a different value in
	the interest of practicality.)

	Filters on inputs will be applied after the data is fetched and before your
	job starts.
	Filters on outputs will be applied after your job process exits, but before
	the output hash is computed and the data committed to any warehouses for storage.

	Note that these filters are built-ins (and there are no extensions possible).
	If you need more complex data transformations, incorporate it into your job
	itself!  These filters are built-in because they cover the most common sources
	of nondeterminism, and because they are efficient to implement as special
	cases in the IO engines (and in some cases, e.g. ownership filters, are also
	necessary for security properties an dusing repeatr IO with minimal host
	system priviledges).
*/
type Filters struct {
	UidMode   FilterMode
	Uid       int
	GidMode   FilterMode
	Gid       int
	MtimeMode FilterMode
	Mtime     time.Time
}

type FilterMode int

const (
	FilterUninitialized FilterMode = iota
	FilterUse
	FilterKeep
	FilterHost
)

var (
	FilterDefaultUid   = 1000
	FilterDefaultGid   = 1000
	FilterDefaultMtime = time.Date(2010, time.January, 1, 0, 0, 0, 0, time.UTC)
)
<commit_msg>Fix formula.SetupHash fixture regression.<commit_after>package def

import (
	"time"
)

type InputGroup map[string]*Input

type OutputGroup map[string]*Output

/*
	Input specifies a data source to feed into the beginning of a computation.

	Inputs can be one of many different `Type`s of data source.
	Examples may include "tar", "git", "hadoop", "ipfs", etc.

	Inputs must specify both a `Hash` and a `URI`.
	`Input.Hash` is the content identity descriptor and will always be verified for all types of data source.
	`Input.Hash` is both identifies the data and provides integrity (in other words,
	all repeatr's input types will use a cryptographically strong hash here,
	so given a hash even an untrusted datastore is safe to use).
	Repeatr requires this to be accurate because if the inputs change, output
	consistency is impossible -- so even for plain http downloads, this is enforced.

	`Input.URI` is a secondary content lookup descriptor, like where on
	the filesystem or network information can be fetched from.
	`Input.URI` might contain extra description to answer questions like
	"which git remote url should i fetch from" or
	"which ipfs swarm do i coordinate with".

	Use can use `Formula.SetupHash` to get a hash covering the all the pieces
	of the formula used to set up and launch the action: that includes
	all of the type, hash, and mountpath options of every Input.
	The `URI` is *not* included in that hash, because repeatr understands
	that your data will be mobile -- that's why we have the `Input.Hash` take the leading role
	and why the `Input.Hash` should be sufficient to identify the information.
	Changes in the `Input.URI` field may make or break whether the data is accessible,
	but should never actually change the content of the data -- it's just supposed to talk about
	transport details; and content itself is still checked by `Input.Hash`.
*/
type Input struct {
	Type       string          `json:"type"`           // implementation name (repeatr-internal).  included in Formula.SetupHash.
	Hash       string          `json:"hash"`           // identifying hash of input data.  included in Formula.SetupHash.
	Warehouses WarehouseCoords `json:"silo,omitempty"` // secondary content lookup descriptor.  *not* included in Formula.SetupHash.
	MountPath  string          `json:"mount"`          // filepath where this input should be mounted in the execution context.  included in Formula.SetupHash.
	Tag        string          `json:"tag,omitempty"`  // human readable name tag for this input.  ONLY USED FOR DOWNSTREAM APIs; do not reference this.
}

/*
	Output describes where we intend to pick up data after a task completes.

	Outputs can be one of many different `Type`s of data sink.
	Examples may include "tar", "git", "hadoop", "ipfs", etc.

	`Output.MountPath` states where we should collect information from the
	task execution environment.
	After the task completes, repeatr will pick up this data, ship it off
	to storage, and also calculate a checksum of the data so we can see
	whether it matches any prior (or future) runs of this `Formula`.

	Outputs must specify a `URI`; repeatr will ship your data to this address.
	`Output.URI` has similar properties to `Input.URI` (and also similarly,
	is not included in the Formula.SetupHash, because repeatr understands that
	your data can be mobile; if you change storage locations, that
	shouldn't bust any caches of known computations).

	The `Output.Hash` field will be filled in with a value computed
	from the data present in `Output.MountPath` after the task has completed.
	As with `Input.Hash`, the `Output.Hash` in repeatr will always be a
	cryptographically strong hash, which means it precisely describes your
	data, and makes it virtually impossible to accidentally get the same
	`Hash` as other data -- any changes to your output will always result
	in a very different `Hash` value.

	(In a content-addressable data store, repeatr may just lift the data store's
	address to use as `Output.Hash`, which is super efficient for everyone involved.
	For other more legacy-oriented systems, this may be a hash of the
	of the working filesystem right before before export.)

	`Output.Filters` may also be used to do a clean up pass on output files
	before committing them to storage or doing repeatr's consistency checks.
	One typical example, which is engaged by default, is setting all file
	modification times to a standard value, because this metadata is
	typically both very noisy and very useless.
*/
type Output struct {
	Type       string          `json:"type"`            // implementation name (repeatr-internal).
	Hash       string          `json:"hash"`            // identifying hash of output data.  generated by the output handling implementation during data export when a task is complete.
	Warehouses WarehouseCoords `json:"silo,omitempty"`  // where to ship the output data.
	MountPath  string          `json:"mount,omitempty"` // filepath where this output will be yanked from the job when it reaches completion.
	Filters    *Filters        `json:"filters,omitempty"`
	Tag        string          `json:"tag,omitempty"` // human readable name tag for this ouput.  ONLY USED FOR DOWNSTREAM APIs; do not reference this.
}

/*
	Filters are transformations that can be applied to data, either to
	normalize it for storage or to apply attributes to it before feeding
	the data into an action's inputs.

	The following filters are available:

		- uid   -- the posix user ownership number
		- gid   -- the posix group ownership number
		- mtime -- the posix file modification timestamp

	'uid', 'gid', and 'mtime' are all filtered by default on formula outputs --
	most use cases do not need these attributes, and they are a source of nondeterminism.
	If you want to keep them, you may specify	`uid keep`, `gid keep`, `mtime keep`,
	etc; if you want the filters to flatten to different values than the defaults,
	you may specify `uid 12000`, etc.
	(Note that the default mtime filter flattens the time to Jan 1, 2010 --
	*not* epoch.  Some contemporary software has been known to regard zero/epoch
	timestamps as errors or empty values, so we've choosen a different value in
	the interest of practicality.)

	Filters on inputs will be applied after the data is fetched and before your
	job starts.
	Filters on outputs will be applied after your job process exits, but before
	the output hash is computed and the data committed to any warehouses for storage.

	Note that these filters are built-ins (and there are no extensions possible).
	If you need more complex data transformations, incorporate it into your job
	itself!  These filters are built-in because they cover the most common sources
	of nondeterminism, and because they are efficient to implement as special
	cases in the IO engines (and in some cases, e.g. ownership filters, are also
	necessary for security properties an dusing repeatr IO with minimal host
	system priviledges).
*/
type Filters struct {
	UidMode   FilterMode
	Uid       int
	GidMode   FilterMode
	Gid       int
	MtimeMode FilterMode
	Mtime     time.Time
}

type FilterMode int

const (
	FilterUninitialized FilterMode = iota
	FilterUse
	FilterKeep
	FilterHost
)

var (
	FilterDefaultUid   = 1000
	FilterDefaultGid   = 1000
	FilterDefaultMtime = time.Date(2010, time.January, 1, 0, 0, 0, 0, time.UTC)
)
<|endoftext|>