<commit_before>package utils

import (
	"bitbucket.org/kardianos/osext"
	"fmt"
	"github.com/ethereum/eth-go"
	"github.com/ethereum/eth-go/ethcrypto"
	"github.com/ethereum/eth-go/ethdb"
	"github.com/ethereum/eth-go/ethlog"
	"github.com/ethereum/eth-go/ethminer"
	"github.com/ethereum/eth-go/ethpub"
	"github.com/ethereum/eth-go/ethrpc"
	"github.com/ethereum/eth-go/ethutil"
	"github.com/ethereum/eth-go/ethwire"
	"io"
	"log"
	"os"
	"os/signal"
	"path"
	"path/filepath"
	"runtime"
	"time"
)

var logger = ethlog.NewLogger("CLI")
var interruptCallbacks = []func(os.Signal){}

// Register interrupt handlers callbacks
func RegisterInterrupt(cb func(os.Signal)) {
	interruptCallbacks = append(interruptCallbacks, cb)
}

// go routine that call interrupt handlers in order of registering
func HandleInterrupt() {
	c := make(chan os.Signal, 1)
	go func() {
		signal.Notify(c, os.Interrupt)
		for sig := range c {
			logger.Errorf("Shutting down (%v) ... \n", sig)
			RunInterruptCallbacks(sig)
		}
	}()
}

func RunInterruptCallbacks(sig os.Signal) {
	for _, cb := range interruptCallbacks {
		cb(sig)
	}
}

func AbsolutePath(Datadir string, filename string) string {
	if path.IsAbs(filename) {
		return filename
	}
	return path.Join(Datadir, filename)
}

func openLogFile(Datadir string, filename string) *os.File {
	path := AbsolutePath(Datadir, filename)
	file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		panic(fmt.Sprintf("error opening log file '%s': %v", filename, err))
	}
	return file
}

func confirm(message string) bool {
	fmt.Println(message, "Are you sure? (y/n)")
	var r string
	fmt.Scanln(&r)
	for ; ; fmt.Scanln(&r) {
		if r == "n" || r == "y" {
			break
		} else {
			fmt.Printf("Yes or no?", r)
		}
	}
	return r == "y"
}

func InitDataDir(Datadir string) {
	_, err := os.Stat(Datadir)
	if err != nil {
		if os.IsNotExist(err) {
			fmt.Printf("Data directory '%s' doesn't exist, creating it\n", Datadir)
			os.Mkdir(Datadir, 0777)
		}
	}
}

func InitLogging(Datadir string, LogFile string, LogLevel int, DebugFile string) {
	var writer io.Writer
	if LogFile == "" {
		writer = os.Stdout
	} else {
		writer = openLogFile(Datadir, LogFile)
	}
	ethlog.AddLogSystem(ethlog.NewStdLogSystem(writer, log.LstdFlags, ethlog.LogLevel(LogLevel)))
	if DebugFile != "" {
		writer = openLogFile(Datadir, DebugFile)
		ethlog.AddLogSystem(ethlog.NewStdLogSystem(writer, log.LstdFlags, ethlog.DebugLevel))
	}
}

func InitConfig(ConfigFile string, Datadir string, EnvPrefix string) *ethutil.ConfigManager {
	InitDataDir(Datadir)
	return ethutil.ReadConfig(ConfigFile, Datadir, EnvPrefix)
}

func exit(err error) {
	status := 0
	if err != nil {
		fmt.Println(err)
		logger.Errorln("Fatal: ", err)
		status = 1
	}
	ethlog.Flush()
	os.Exit(status)
}

func NewDatabase() ethutil.Database {
	db, err := ethdb.NewLDBDatabase("database")
	if err != nil {
		exit(err)
	}
	return db
}

func NewClientIdentity(clientIdentifier, version, customIdentifier string) *ethwire.SimpleClientIdentity {
	return ethwire.NewSimpleClientIdentity(clientIdentifier, version, customIdentifier)
}

func NewEthereum(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager *ethcrypto.KeyManager, usePnp bool, OutboundPort string, MaxPeer int) *eth.Ethereum {
	ethereum, err := eth.New(db, clientIdentity, keyManager, eth.CapDefault, usePnp)
	if err != nil {
		logger.Fatalln("eth start err:", err)
	}
	ethereum.Port = OutboundPort
	ethereum.MaxPeers = MaxPeer
	return ethereum
}

func StartEthereum(ethereum *eth.Ethereum, UseSeed bool) {
	logger.Infof("Starting %s", ethereum.ClientIdentity())
	ethereum.Start(UseSeed)
	RegisterInterrupt(func(sig os.Signal) {
		ethereum.Stop()
		ethlog.Flush()
	})
}

func ShowGenesis(ethereum *eth.Ethereum) {
	logger.Infoln(ethereum.BlockChain().Genesis())
	exit(nil)
}

func NewKeyManager(KeyStore string, Datadir string, db ethutil.Database) *ethcrypto.KeyManager {
	var keyManager *ethcrypto.KeyManager
	switch {
	case KeyStore == "db":
		keyManager = ethcrypto.NewDBKeyManager(db)
	case KeyStore == "file":
		keyManager = ethcrypto.NewFileKeyManager(Datadir)
	default:
		exit(fmt.Errorf("unknown keystore type: %s", KeyStore))
	}
	return keyManager
}

func DefaultAssetPath() string {
	var assetPath string
	// If the current working directory is the go-ethereum dir
	// assume a debug build and use the source directory as
	// asset directory.
	pwd, _ := os.Getwd()
	if pwd == path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "ethereal") {
		assetPath = path.Join(pwd, "assets")
	} else {
		switch runtime.GOOS {
		case "darwin":
			// Get Binary Directory
			exedir, _ := osext.ExecutableFolder()
			assetPath = filepath.Join(exedir, "../Resources")
		case "linux":
			assetPath = "/usr/share/ethereal"
		case "windows":
			assetPath = "./assets"
		default:
			assetPath = "."
		}
	}
	return assetPath
}

func KeyTasks(keyManager *ethcrypto.KeyManager, KeyRing string, GenAddr bool, SecretFile string, ExportDir string, NonInteractive bool) {
	ethcrypto.InitWords(DefaultAssetPath()) // Init mnemonic word list

	var err error
	switch {
	case GenAddr:
		if NonInteractive || confirm("This action overwrites your old private key.") {
			err = keyManager.Init(KeyRing, 0, true)
		}
		exit(err)
	case len(SecretFile) > 0:
		SecretFile = ethutil.ExpandHomePath(SecretFile)

		if NonInteractive || confirm("This action overwrites your old private key.") {
			err = keyManager.InitFromSecretsFile(KeyRing, 0, SecretFile)
		}
		exit(err)
	case len(ExportDir) > 0:
		err = keyManager.Init(KeyRing, 0, false)
		if err == nil {
			err = keyManager.Export(ExportDir)
		}
		exit(err)
	default:
		// Creates a keypair if none exists
		err = keyManager.Init(KeyRing, 0, false)
		if err != nil {
			exit(err)
		}
	}
}

func StartRpc(ethereum *eth.Ethereum, RpcPort int) {
	var err error
	ethereum.RpcServer, err = ethrpc.NewJsonRpcServer(ethpub.NewPEthereum(ethereum), RpcPort)
	if err != nil {
		logger.Errorf("Could not start RPC interface (port %v): %v", RpcPort, err)
	} else {
		go ethereum.RpcServer.Start()
	}
}

var miner *ethminer.Miner

func GetMiner() *ethminer.Miner {
	return miner
}

func StartMining(ethereum *eth.Ethereum) bool {
	if !ethereum.Mining {
		ethereum.Mining = true

		addr := ethereum.KeyManager().Address()

		go func() {
			miner = ethminer.NewDefaultMiner(addr, ethereum)
			// Give it some time to connect with peers
			time.Sleep(3 * time.Second)
			for !ethereum.IsUpToDate() {
				time.Sleep(5 * time.Second)
			}

			logger.Infoln("Miner started")
			miner := ethminer.NewDefaultMiner(addr, ethereum)
			miner.Start()
		}()
		RegisterInterrupt(func(os.Signal) {
			StopMining(ethereum)
		})
		return true
	}
	return false
}

func StopMining(ethereum *eth.Ethereum) bool {
	if ethereum.Mining && miner != nil {
		miner.Stop()
		logger.Infoln("Miner stopped")
		ethereum.Mining = false
		return true
	}
	return false
}

// Replay block
func BlockDo(ethereum *eth.Ethereum, hash []byte) error {
	block := ethereum.BlockChain().GetBlock(hash)
	if block == nil {
		return fmt.Errorf("unknown block %x", hash)
	}

	parent := ethereum.BlockChain().GetBlock(block.PrevHash)

	_, err := ethereum.StateManager().ApplyDiff(parent.State(), parent, block)
	if err != nil {
		return err
	}

	return nil

}
<commit_msg>Fixed miner stopping / starting:wq<commit_after>package utils

import (
	"bitbucket.org/kardianos/osext"
	"fmt"
	"github.com/ethereum/eth-go"
	"github.com/ethereum/eth-go/ethcrypto"
	"github.com/ethereum/eth-go/ethdb"
	"github.com/ethereum/eth-go/ethlog"
	"github.com/ethereum/eth-go/ethminer"
	"github.com/ethereum/eth-go/ethpub"
	"github.com/ethereum/eth-go/ethrpc"
	"github.com/ethereum/eth-go/ethutil"
	"github.com/ethereum/eth-go/ethwire"
	"io"
	"log"
	"os"
	"os/signal"
	"path"
	"path/filepath"
	"runtime"
	"time"
)

var logger = ethlog.NewLogger("CLI")
var interruptCallbacks = []func(os.Signal){}

// Register interrupt handlers callbacks
func RegisterInterrupt(cb func(os.Signal)) {
	interruptCallbacks = append(interruptCallbacks, cb)
}

// go routine that call interrupt handlers in order of registering
func HandleInterrupt() {
	c := make(chan os.Signal, 1)
	go func() {
		signal.Notify(c, os.Interrupt)
		for sig := range c {
			logger.Errorf("Shutting down (%v) ... \n", sig)
			RunInterruptCallbacks(sig)
		}
	}()
}

func RunInterruptCallbacks(sig os.Signal) {
	for _, cb := range interruptCallbacks {
		cb(sig)
	}
}

func AbsolutePath(Datadir string, filename string) string {
	if path.IsAbs(filename) {
		return filename
	}
	return path.Join(Datadir, filename)
}

func openLogFile(Datadir string, filename string) *os.File {
	path := AbsolutePath(Datadir, filename)
	file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		panic(fmt.Sprintf("error opening log file '%s': %v", filename, err))
	}
	return file
}

func confirm(message string) bool {
	fmt.Println(message, "Are you sure? (y/n)")
	var r string
	fmt.Scanln(&r)
	for ; ; fmt.Scanln(&r) {
		if r == "n" || r == "y" {
			break
		} else {
			fmt.Printf("Yes or no?", r)
		}
	}
	return r == "y"
}

func InitDataDir(Datadir string) {
	_, err := os.Stat(Datadir)
	if err != nil {
		if os.IsNotExist(err) {
			fmt.Printf("Data directory '%s' doesn't exist, creating it\n", Datadir)
			os.Mkdir(Datadir, 0777)
		}
	}
}

func InitLogging(Datadir string, LogFile string, LogLevel int, DebugFile string) {
	var writer io.Writer
	if LogFile == "" {
		writer = os.Stdout
	} else {
		writer = openLogFile(Datadir, LogFile)
	}
	ethlog.AddLogSystem(ethlog.NewStdLogSystem(writer, log.LstdFlags, ethlog.LogLevel(LogLevel)))
	if DebugFile != "" {
		writer = openLogFile(Datadir, DebugFile)
		ethlog.AddLogSystem(ethlog.NewStdLogSystem(writer, log.LstdFlags, ethlog.DebugLevel))
	}
}

func InitConfig(ConfigFile string, Datadir string, EnvPrefix string) *ethutil.ConfigManager {
	InitDataDir(Datadir)
	return ethutil.ReadConfig(ConfigFile, Datadir, EnvPrefix)
}

func exit(err error) {
	status := 0
	if err != nil {
		fmt.Println(err)
		logger.Errorln("Fatal: ", err)
		status = 1
	}
	ethlog.Flush()
	os.Exit(status)
}

func NewDatabase() ethutil.Database {
	db, err := ethdb.NewLDBDatabase("database")
	if err != nil {
		exit(err)
	}
	return db
}

func NewClientIdentity(clientIdentifier, version, customIdentifier string) *ethwire.SimpleClientIdentity {
	return ethwire.NewSimpleClientIdentity(clientIdentifier, version, customIdentifier)
}

func NewEthereum(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager *ethcrypto.KeyManager, usePnp bool, OutboundPort string, MaxPeer int) *eth.Ethereum {
	ethereum, err := eth.New(db, clientIdentity, keyManager, eth.CapDefault, usePnp)
	if err != nil {
		logger.Fatalln("eth start err:", err)
	}
	ethereum.Port = OutboundPort
	ethereum.MaxPeers = MaxPeer
	return ethereum
}

func StartEthereum(ethereum *eth.Ethereum, UseSeed bool) {
	logger.Infof("Starting %s", ethereum.ClientIdentity())
	ethereum.Start(UseSeed)
	RegisterInterrupt(func(sig os.Signal) {
		ethereum.Stop()
		ethlog.Flush()
	})
}

func ShowGenesis(ethereum *eth.Ethereum) {
	logger.Infoln(ethereum.BlockChain().Genesis())
	exit(nil)
}

func NewKeyManager(KeyStore string, Datadir string, db ethutil.Database) *ethcrypto.KeyManager {
	var keyManager *ethcrypto.KeyManager
	switch {
	case KeyStore == "db":
		keyManager = ethcrypto.NewDBKeyManager(db)
	case KeyStore == "file":
		keyManager = ethcrypto.NewFileKeyManager(Datadir)
	default:
		exit(fmt.Errorf("unknown keystore type: %s", KeyStore))
	}
	return keyManager
}

func DefaultAssetPath() string {
	var assetPath string
	// If the current working directory is the go-ethereum dir
	// assume a debug build and use the source directory as
	// asset directory.
	pwd, _ := os.Getwd()
	if pwd == path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "ethereal") {
		assetPath = path.Join(pwd, "assets")
	} else {
		switch runtime.GOOS {
		case "darwin":
			// Get Binary Directory
			exedir, _ := osext.ExecutableFolder()
			assetPath = filepath.Join(exedir, "../Resources")
		case "linux":
			assetPath = "/usr/share/ethereal"
		case "windows":
			assetPath = "./assets"
		default:
			assetPath = "."
		}
	}
	return assetPath
}

func KeyTasks(keyManager *ethcrypto.KeyManager, KeyRing string, GenAddr bool, SecretFile string, ExportDir string, NonInteractive bool) {
	ethcrypto.InitWords(DefaultAssetPath()) // Init mnemonic word list

	var err error
	switch {
	case GenAddr:
		if NonInteractive || confirm("This action overwrites your old private key.") {
			err = keyManager.Init(KeyRing, 0, true)
		}
		exit(err)
	case len(SecretFile) > 0:
		SecretFile = ethutil.ExpandHomePath(SecretFile)

		if NonInteractive || confirm("This action overwrites your old private key.") {
			err = keyManager.InitFromSecretsFile(KeyRing, 0, SecretFile)
		}
		exit(err)
	case len(ExportDir) > 0:
		err = keyManager.Init(KeyRing, 0, false)
		if err == nil {
			err = keyManager.Export(ExportDir)
		}
		exit(err)
	default:
		// Creates a keypair if none exists
		err = keyManager.Init(KeyRing, 0, false)
		if err != nil {
			exit(err)
		}
	}
}

func StartRpc(ethereum *eth.Ethereum, RpcPort int) {
	var err error
	ethereum.RpcServer, err = ethrpc.NewJsonRpcServer(ethpub.NewPEthereum(ethereum), RpcPort)
	if err != nil {
		logger.Errorf("Could not start RPC interface (port %v): %v", RpcPort, err)
	} else {
		go ethereum.RpcServer.Start()
	}
}

var miner *ethminer.Miner

func GetMiner() *ethminer.Miner {
	return miner
}

func StartMining(ethereum *eth.Ethereum) bool {
	if !ethereum.Mining {
		ethereum.Mining = true

		addr := ethereum.KeyManager().Address()

		go func() {
			if miner == nil {
				miner = ethminer.NewDefaultMiner(addr, ethereum)
			}

			// Give it some time to connect with peers
			time.Sleep(3 * time.Second)
			for !ethereum.IsUpToDate() {
				time.Sleep(5 * time.Second)
			}

			logger.Infoln("Miner started")
			miner.Start()
		}()
		RegisterInterrupt(func(os.Signal) {
			StopMining(ethereum)
		})
		return true
	}
	return false
}

func StopMining(ethereum *eth.Ethereum) bool {
	if ethereum.Mining && miner != nil {
		miner.Stop()

		logger.Infoln("Miner stopped")

		ethereum.Mining = false

		return true
	}

	return false
}

// Replay block
func BlockDo(ethereum *eth.Ethereum, hash []byte) error {
	block := ethereum.BlockChain().GetBlock(hash)
	if block == nil {
		return fmt.Errorf("unknown block %x", hash)
	}

	parent := ethereum.BlockChain().GetBlock(block.PrevHash)

	_, err := ethereum.StateManager().ApplyDiff(parent.State(), parent, block)
	if err != nil {
		return err
	}

	return nil

}
<|endoftext|>


<commit_before>// +build bindata

/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package bindata

import (
	"net/http"
	"strings"
	"os"

	"github.com/admpub/nging/application/initialize/backend"

	assetfs "github.com/admpub/go-bindata-assetfs"
	"github.com/admpub/nging/application/cmd/event"
	"github.com/admpub/nging/application/library/modal"
	"github.com/webx-top/echo"
	"github.com/webx-top/echo/middleware/bindata"
	"github.com/webx-top/image"
)

func NewAssetFS(prefix string) *assetfs.AssetFS {
	return &assetfs.AssetFS{
		Asset:     Asset,
		AssetDir:  AssetDir,
		AssetInfo: AssetInfo,
		Prefix:    prefix,
	}
}

var (
	StaticAssetPrefix       string
	BackendTmplAssetPrefix  = "template/backend"
	FrontendTmplAssetPrefix = "template/frontend"
	StaticAssetFS           *assetfs.AssetFS
	BackendTmplAssetFS      *assetfs.AssetFS
	FrontendTmplAssetFS     *assetfs.AssetFS
	LanguageAssetFSFunc     = func(dir string) http.FileSystem {
		return NewAssetFS(dir)
	}
)

func Initialize() {
	event.Bindata = true
	if StaticAssetFS == nil {
		StaticAssetFS = NewAssetFS(StaticAssetPrefix)
	}
	if BackendTmplAssetFS == nil {
		BackendTmplAssetFS = NewAssetFS(BackendTmplAssetPrefix)
	}
	if FrontendTmplAssetFS == nil {
		FrontendTmplAssetFS = NewAssetFS(FrontendTmplAssetPrefix)
	}
	event.StaticMW = bindata.Static("/public/assets/", StaticAssetFS)
	event.FaviconHandler = func(c echo.Context) error {
		return c.File(event.FaviconPath, StaticAssetFS)
	}
	event.BackendTmplMgr = bindata.NewTmplManager(BackendTmplAssetFS)
	event.FrontendTmplMgr = bindata.NewTmplManager(FrontendTmplAssetFS)
	modal.ReadConfigFile = func(file string) ([]byte, error) {
		file = strings.TrimPrefix(file, backend.TemplateDir)
		return event.BackendTmplMgr.GetTemplate(file)
	}
	image.WatermarkOpen = func(file string) (http.File, error) {
		f, err := image.DefaultHTTPSystemOpen(file)
		if err != nil {
			if os.IsNotExist(err) && strings.HasPrefix(file, echo.Wd()) {
				file = strings.TrimPrefix(file, echo.Wd())
				return StaticAssetFS.Open(file)
			}
		}
		return f, err
	}
	event.LangFSFunc = LanguageAssetFSFunc
}
<commit_msg>update<commit_after>// +build bindata

/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package bindata

import (
	"net/http"
	"strings"
	"os"

	"github.com/admpub/nging/application/initialize/backend"

	assetfs "github.com/admpub/go-bindata-assetfs"
	"github.com/admpub/nging/application/cmd/event"
	"github.com/admpub/nging/application/library/modal"
	"github.com/webx-top/echo"
	"github.com/webx-top/echo/middleware/bindata"
	"github.com/webx-top/image"
)

func NewAssetFS(prefix string) *assetfs.AssetFS {
	return &assetfs.AssetFS{
		Asset:     Asset,
		AssetDir:  AssetDir,
		AssetInfo: AssetInfo,
		Prefix:    prefix,
	}
}

var (
	StaticAssetPrefix       string
	BackendTmplAssetPrefix  = "template/backend"
	FrontendTmplAssetPrefix = "template/frontend"
	StaticAssetFS           *assetfs.AssetFS
	BackendTmplAssetFS      *assetfs.AssetFS
	FrontendTmplAssetFS     *assetfs.AssetFS
	LanguageAssetFSFunc     = func(dir string) http.FileSystem {
		return NewAssetFS(dir)
	}
)

func Initialize() {
	event.Bindata = true
	if StaticAssetFS == nil {
		StaticAssetFS = NewAssetFS(StaticAssetPrefix)
	}
	if BackendTmplAssetFS == nil {
		BackendTmplAssetFS = NewAssetFS(BackendTmplAssetPrefix)
	}
	if FrontendTmplAssetFS == nil {
		FrontendTmplAssetFS = NewAssetFS(FrontendTmplAssetPrefix)
	}
	event.StaticMW = bindata.Static("/public/assets/", StaticAssetFS)
	event.FaviconHandler = func(c echo.Context) error {
		return c.File(event.FaviconPath, StaticAssetFS)
	}
	event.BackendTmplMgr = bindata.NewTmplManager(BackendTmplAssetFS)
	event.FrontendTmplMgr = bindata.NewTmplManager(FrontendTmplAssetFS)
	modal.ReadConfigFile = func(file string) ([]byte, error) {
		file = strings.TrimPrefix(file, backend.TemplateDir)
		return event.BackendTmplMgr.GetTemplate(file)
	}
	image.WatermarkOpen = func(file string) (http.File, error) {
		f, err := image.DefaultHTTPSystemOpen(file)
		if err != nil {
			if os.IsNotExist(err) {
				if strings.HasPrefix(file, echo.Wd()) {
					file = strings.TrimPrefix(file, echo.Wd())
					return StaticAssetFS.Open(file)
				}
				if strings.HasPrefix(file, `./`) {
					file = strings.TrimPrefix(file, `./`)
					return StaticAssetFS.Open(file)
				}
			}
		}
		return f, err
	}
	event.LangFSFunc = LanguageAssetFSFunc
}
<|endoftext|>


<commit_before>// Copyright 2015 Luke Shumaker

package httpentity

import (
	"net/http"
	"net/url"
	"fmt"
)

func (req Request) StatusOK(entity NetEntity) Response {
	return Response{
		status:  200,
		Headers: http.Header{},
		entity:  entity,
	}
}

func (req Request) StatusCreated(parent Entity, child_name string) Response {
	child := parent.Subentity(child_name, req)
	if child == nil {
		panic("called StatusCreated, but the subentity doesn't exist")
	}
	handler, ok := child.Methods()["GET"]
	if !ok {
		panic("called StatusCreated, but can't GET the subentity")
	}
	response := handler(req)
	response.Headers.Set("Location", url.QueryEscape(child_name))
	if response.entity == nil {
		panic("called StatusCreated, but GET on subentity doesn't return an entity")
	}
	mimetypes := encoders2mimetypes(response.entity.Encoders())
	u, _ := url.Parse("")
	return Response{
		status:  201,
		Headers: response.Headers,
		entity:  mimetypes2net(u, mimetypes), // gets modified by Route() filled in the rest of the way by Route()
	}
}

func (req Request) statusMultipleChoices(u *url.URL, mimetypes []string) Response {
	return Response{
		status: 300,
		Headers: http.Header{},
		entity: mimetypes2net(u, mimetypes),
	}
}

func (req Request) StatusMoved(u *url.URL) Response {
	return Response{
		status: 301,
		Headers: http.Header{
			"Location":     {u.String()},
		},
		entity: NetString("301: Moved"),
	}
}

func (req Request) StatusFound(u *url.URL) Response {
	return Response{
		status: 302,
		Headers: http.Header{
			"Location":     {u.String()},
		},
		entity: NetString("302: Found"),
	}
}

func (req Request) statusNotFound() Response {
	return Response{
		status:  404,
		Headers: http.Header{},
		entity:  NetString("404 Not Found"),
	}
}

func (req Request) statusMethodNotAllowed(methods string) Response {
	return Response{
		status: 405,
		Headers: http.Header{},
		entity: NetString("405 Method Not Allowed"),
	}
}

func (req Request) statusNotAcceptable(u *url.URL, mimetypes []string) Response {
	return Response{
		status: 406,
		Headers: http.Header{},
		entity: mimetypes2net(u, mimetypes),
	}
}

func (req Request) statusInternalServerError(err interface{}) Response {
	return Response{
		status:  500,
		Headers: http.Header{},
		entity:  NetString(fmt.Sprintf("500 Internal Server Error: %v", err)),
	}
}
<commit_msg>httpentity: add HTTP 204 and 401 support<commit_after>// Copyright 2015 Luke Shumaker

package httpentity

import (
	"net/http"
	"net/url"
	"fmt"
)

func (req Request) StatusOK(entity NetEntity) Response {
	return Response{
		status:  200,
		Headers: http.Header{},
		entity:  entity,
	}
}

func (req Request) StatusCreated(parent Entity, child_name string) Response {
	child := parent.Subentity(child_name, req)
	if child == nil {
		panic("called StatusCreated, but the subentity doesn't exist")
	}
	handler, ok := child.Methods()["GET"]
	if !ok {
		panic("called StatusCreated, but can't GET the subentity")
	}
	response := handler(req)
	response.Headers.Set("Location", url.QueryEscape(child_name))
	if response.entity == nil {
		panic("called StatusCreated, but GET on subentity doesn't return an entity")
	}
	mimetypes := encoders2mimetypes(response.entity.Encoders())
	u, _ := url.Parse("")
	return Response{
		status:  201,
		Headers: response.Headers,
		entity:  mimetypes2net(u, mimetypes), // gets modified by Route() filled in the rest of the way by Route()
	}
}

func (req Request) StatusNoContent() Response {
	return Response{
		status:  204,
		Headers: http.Header{},
		entity:  nil,
	}
}

func (req Request) statusMultipleChoices(u *url.URL, mimetypes []string) Response {
	return Response{
		status: 300,
		Headers: http.Header{},
		entity: mimetypes2net(u, mimetypes),
	}
}

func (req Request) StatusMoved(u *url.URL) Response {
	return Response{
		status: 301,
		Headers: http.Header{
			"Location":     {u.String()},
		},
		entity: NetString("301: Moved"),
	}
}

func (req Request) StatusFound(u *url.URL) Response {
	return Response{
		status: 302,
		Headers: http.Header{
			"Location":     {u.String()},
		},
		entity: NetString("302: Found"),
	}
}

func (req Request) StatusUnauthorized(e NetEntity) Response {
	return Response{
		status:  401,
		Headers: http.Header{
			"WWW-Authenticate": {"TODO"},
		},
		entity:  e,
	}
}

func (req Request) statusNotFound() Response {
	return Response{
		status:  404,
		Headers: http.Header{},
		entity:  NetString("404 Not Found"),
	}
}

func (req Request) statusMethodNotAllowed(methods string) Response {
	return Response{
		status: 405,
		Headers: http.Header{},
		entity: NetString("405 Method Not Allowed"),
	}
}

func (req Request) statusNotAcceptable(u *url.URL, mimetypes []string) Response {
	return Response{
		status: 406,
		Headers: http.Header{},
		entity: mimetypes2net(u, mimetypes),
	}
}

func (req Request) statusInternalServerError(err interface{}) Response {
	return Response{
		status:  500,
		Headers: http.Header{},
		entity:  NetString(fmt.Sprintf("500 Internal Server Error: %v", err)),
	}
}
<|endoftext|>


<commit_before>package stripe

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/url"
)

// SourceParams is a union struct used to describe an
// arbitrary payment source.
type SourceParams struct {
	Token string
	Card  *CardParams
}

// AppendDetails adds the source's details to the query string values.
// For cards: when creating a new one, the parameters are passed as a dictionary, but
// on updates they are simply the parameter name.
func (sp *SourceParams) AppendDetails(values *url.Values, creating bool) {
	if len(sp.Token) > 0 {
		values.Add("source", sp.Token)
	} else if sp.Card != nil {
		sp.Card.AppendDetails(values, creating)
	}
}

// CustomerSourceParams are used to manipulate a given Stripe
// Customer object's payment sources.
// For more details see https://stripe.com/docs/api#sources
type CustomerSourceParams struct {
	Params
	Customer string
	Source   *SourceParams
}

// SetSource adds valid sources to a CustomerSourceParams object,
// returning an error for unsupported sources.
func (cp *CustomerSourceParams) SetSource(sp interface{}) error {
	source, err := SourceParamsFor(sp)
	cp.Source = source
	return err
}

// SourceParamsFor creates SourceParams objects around supported
// payment sources, returning errors if not.
//
// Currently supported source types are Card (CardParams) and
// Tokens/IDs (string), where Tokens could be single use card
// tokens or bitcoin receiver ids
func SourceParamsFor(obj interface{}) (*SourceParams, error) {
	var sp *SourceParams
	var err error
	switch p := obj.(type) {
	case *CardParams:
		sp = &SourceParams{
			Card: p,
		}
	case string:
		sp = &SourceParams{
			Token: p,
		}
	default:
		err = errors.New(fmt.Sprintf("Unsupported source type %s", p))
	}
	return sp, err
}

// Displayer provides a human readable representation of a struct
type Displayer interface {
	Display() string
}

// PaymentSourceType consts represent valid payment sources
type PaymentSourceType string

const (
	PaymentSourceBitcoinReceiver PaymentSourceType = "bitcoin_receiver"
	PaymentSourceCard            PaymentSourceType = "card"
)

// PaymentSource describes the payment source used to make a Charge.
// The Type should indicate which object is fleshed out (eg. BitcoinReceiver or Card)
// For more details see https://stripe.com/docs/api#retrieve_charge
type PaymentSource struct {
	Type            PaymentSourceType `json:"object"`
	ID              string            `json:"id"`
	Card            *Card             `json:"-"`
	BitcoinReceiver *BitcoinReceiver  `json:"-"`
}

// SourceList is a list object for cards.
type SourceList struct {
	ListMeta
	Values []*PaymentSource `json:"data"`
}

// PaymentSourceListParams are used to enumerate the payment sources
// that are attached to a Customer.
type SourceListParams struct {
	ListParams
	Customer string
}

// Display human readable representation of source.
func (s *PaymentSource) Display() string {
	switch s.Type {
	case PaymentSourceBitcoinReceiver:
		return s.BitcoinReceiver.Display()
	case PaymentSourceCard:
		return s.Card.Display()
	}

	return ""
}

// UnmarshalJSON handles deserialization of a PaymentSource.
// This custom unmarshaling is needed because the specific
// type of payment instrument it refers to is specified in the JSON
func (s *PaymentSource) UnmarshalJSON(data []byte) error {
	type source PaymentSource
	var ss source
	err := json.Unmarshal(data, &ss)
	if err == nil {
		*s = PaymentSource(ss)

		switch s.Type {
		case PaymentSourceBitcoinReceiver:
			json.Unmarshal(data, &s.BitcoinReceiver)
		case PaymentSourceCard:
			json.Unmarshal(data, &s.Card)
		}
	} else {
		// the id is surrounded by "\" characters, so strip them
		s.ID = string(data[1 : len(data)-1])
	}

	return nil
}

// MarshalJSON handles serialization of a PaymentSource.
// This custom marshaling is needed because the specific type
// of payment instrument it represents is specified by the PaymentSourceType
func (s *PaymentSource) MarshalJSON() ([]byte, error) {
	type source PaymentSource
	var target interface{}

	switch s.Type {
	case PaymentSourceBitcoinReceiver:
		target = struct {
			Type PaymentSourceType `json:"object"`
			*BitcoinReceiver
		}{
			Type:            s.Type,
			BitcoinReceiver: s.BitcoinReceiver,
		}
	case PaymentSourceCard:
		target = struct {
			Type     PaymentSourceType `json:"object"`
			Customer string            `json:"customer"`
			*Card
		}{
			Type:     s.Type,
			Customer: s.Card.Customer.ID,
			Card:     s.Card,
		}
	default:
		target = source(*s)
	}

	return json.Marshal(target)
}
<commit_msg>Following the implementation of UnmarshalJSON, if we don't have a type, just assume its a string.<commit_after>package stripe

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/url"
)

// SourceParams is a union struct used to describe an
// arbitrary payment source.
type SourceParams struct {
	Token string
	Card  *CardParams
}

// AppendDetails adds the source's details to the query string values.
// For cards: when creating a new one, the parameters are passed as a dictionary, but
// on updates they are simply the parameter name.
func (sp *SourceParams) AppendDetails(values *url.Values, creating bool) {
	if len(sp.Token) > 0 {
		values.Add("source", sp.Token)
	} else if sp.Card != nil {
		sp.Card.AppendDetails(values, creating)
	}
}

// CustomerSourceParams are used to manipulate a given Stripe
// Customer object's payment sources.
// For more details see https://stripe.com/docs/api#sources
type CustomerSourceParams struct {
	Params
	Customer string
	Source   *SourceParams
}

// SetSource adds valid sources to a CustomerSourceParams object,
// returning an error for unsupported sources.
func (cp *CustomerSourceParams) SetSource(sp interface{}) error {
	source, err := SourceParamsFor(sp)
	cp.Source = source
	return err
}

// SourceParamsFor creates SourceParams objects around supported
// payment sources, returning errors if not.
//
// Currently supported source types are Card (CardParams) and
// Tokens/IDs (string), where Tokens could be single use card
// tokens or bitcoin receiver ids
func SourceParamsFor(obj interface{}) (*SourceParams, error) {
	var sp *SourceParams
	var err error
	switch p := obj.(type) {
	case *CardParams:
		sp = &SourceParams{
			Card: p,
		}
	case string:
		sp = &SourceParams{
			Token: p,
		}
	default:
		err = errors.New(fmt.Sprintf("Unsupported source type %s", p))
	}
	return sp, err
}

// Displayer provides a human readable representation of a struct
type Displayer interface {
	Display() string
}

// PaymentSourceType consts represent valid payment sources
type PaymentSourceType string

const (
	PaymentSourceBitcoinReceiver PaymentSourceType = "bitcoin_receiver"
	PaymentSourceCard            PaymentSourceType = "card"
)

// PaymentSource describes the payment source used to make a Charge.
// The Type should indicate which object is fleshed out (eg. BitcoinReceiver or Card)
// For more details see https://stripe.com/docs/api#retrieve_charge
type PaymentSource struct {
	Type            PaymentSourceType `json:"object"`
	ID              string            `json:"id"`
	Card            *Card             `json:"-"`
	BitcoinReceiver *BitcoinReceiver  `json:"-"`
}

// SourceList is a list object for cards.
type SourceList struct {
	ListMeta
	Values []*PaymentSource `json:"data"`
}

// PaymentSourceListParams are used to enumerate the payment sources
// that are attached to a Customer.
type SourceListParams struct {
	ListParams
	Customer string
}

// Display human readable representation of source.
func (s *PaymentSource) Display() string {
	switch s.Type {
	case PaymentSourceBitcoinReceiver:
		return s.BitcoinReceiver.Display()
	case PaymentSourceCard:
		return s.Card.Display()
	}

	return ""
}

// UnmarshalJSON handles deserialization of a PaymentSource.
// This custom unmarshaling is needed because the specific
// type of payment instrument it refers to is specified in the JSON
func (s *PaymentSource) UnmarshalJSON(data []byte) error {
	type source PaymentSource
	var ss source
	err := json.Unmarshal(data, &ss)
	if err == nil {
		*s = PaymentSource(ss)

		switch s.Type {
		case PaymentSourceBitcoinReceiver:
			json.Unmarshal(data, &s.BitcoinReceiver)
		case PaymentSourceCard:
			json.Unmarshal(data, &s.Card)
		}
	} else {
		// the id is surrounded by "\" characters, so strip them
		s.ID = string(data[1 : len(data)-1])
	}

	return nil
}

// MarshalJSON handles serialization of a PaymentSource.
// This custom marshaling is needed because the specific type
// of payment instrument it represents is specified by the PaymentSourceType
func (s *PaymentSource) MarshalJSON() ([]byte, error) {
	var target interface{}

	switch s.Type {
	case PaymentSourceBitcoinReceiver:
		target = struct {
			Type PaymentSourceType `json:"object"`
			*BitcoinReceiver
		}{
			Type:            s.Type,
			BitcoinReceiver: s.BitcoinReceiver,
		}
	case PaymentSourceCard:
		target = struct {
			Type     PaymentSourceType `json:"object"`
			Customer string            `json:"customer"`
			*Card
		}{
			Type:     s.Type,
			Customer: s.Card.Customer.ID,
			Card:     s.Card,
		}
	case "":
		target = s.ID
	}

	return json.Marshal(target)
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package vm

// mtail programs may be updated while emtail is running, and they will be
// reloaded without having to restart the mtail process. Programs can be
// created and deleted as well, and some configuration systems do an atomic
// rename of the program when it is installed, so mtail is also aware of file
// moves.

import (
	"errors"
	"expvar"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"sync"

	"github.com/golang/glog"
	"github.com/jaqx0r/afero"

	"github.com/google/mtail/metrics"
	"github.com/google/mtail/watcher"
)

var (
	// ProgLoads counts the number of program load events.
	ProgLoads = expvar.NewMap("prog_loads_total")
	// ProgLoadErrors counts the number of program load errors.
	ProgLoadErrors = expvar.NewMap("prog_load_errors")
)

var (
	// LineCount counts the number of lines read by the virtual machine engine from the input channel.
	LineCount = expvar.NewInt("line_count")
)

const (
	fileExt = ".mtail"
)

// LoadProgs loads all programs in a directory and starts watching the
// directory for filesystem changes.  The total number of program errors is
// returned.
func (l *Loader) LoadProgs(programPath string) error {
	l.w.Add(programPath)

	s, err := os.Stat(programPath)
	if err != nil {
		return fmt.Errorf("failed to stat: %s", err)
	}
	switch {
	case s.IsDir():
		fis, err := ioutil.ReadDir(programPath)
		if err != nil {
			return fmt.Errorf("Failed to list programs in %q: %s", programPath, err)
		}

		for _, fi := range fis {
			if fi.IsDir() {
				continue
			}
			l.LoadProg(path.Join(programPath, fi.Name()))
		}
		return nil
	default:
		return l.LoadProg(programPath)
	}
}

// LoadProg loads or reloads a program from the path specified.  The name of
// the program is the basename of the file.
func (l *Loader) LoadProg(programPath string) error {
	name := filepath.Base(programPath)
	if filepath.Ext(name) != fileExt {
		glog.Infof("Skipping %s due to file extension.", programPath)
		return nil
	}
	f, err := l.fs.Open(programPath)
	if err != nil {
		ProgLoadErrors.Add(name, 1)
		return fmt.Errorf("Failed to read program %q: %s", programPath, err)
	}
	defer f.Close()
	return l.CompileAndRun(name, f)
}

// CompileAndRun compiles a program read from the input, starting execution if
// it succeeds.  If an existing virtual machine of the same name already
// exists, the previous virtual machine is terminated and the new loaded over
// it.  If the new program fails to compile, any existing virtual machine with
// the same name remains running.
func (l *Loader) CompileAndRun(name string, input io.Reader) error {
	o := &Options{CompileOnly: l.compileOnly, SyslogUseCurrentYear: l.syslogUseCurrentYear}
	v, errs := Compile(name, input, o)
	if errs != nil {
		ProgLoadErrors.Add(name, 1)
		return fmt.Errorf("compile failed for %s:\n%s", name, errs)
	}
	if v == nil {
		glog.Warning("No program returned, but no errors.")
		return nil
	}
	for _, m := range v.m {
		if !m.Hidden {
			l.ms.Add(m)
		}
	}
	if l.dumpBytecode {
		v.DumpByteCode(name)
	}
	ProgLoads.Add(name, 1)
	glog.Infof("Loaded program %s", name)

	l.handleMu.Lock()
	defer l.handleMu.Unlock()
	// Stop any previous VM.
	if handle, ok := l.handles[name]; ok {
		close(handle.lines)
		<-handle.done
	}
	l.handles[name] = &vmHandle{make(chan string), make(chan struct{})}
	go v.Run(l.handles[name].lines, l.handles[name].done)
	return nil
}

// Loader handles the lifecycle of programs and virtual machines, by watching
// the configured program source directory, compiling changes to programs, and
// managing the running virtual machines that receive input from the lines
// channel.
type Loader struct {
	w  watcher.Watcher // watches for program changes
	fs afero.Fs        // filesystem interface
	ms *metrics.Store  // pointer to store to pass to compiler

	handles  map[string]*vmHandle // map of program names to virtual machines
	handleMu sync.RWMutex         // guards accesses to handles

	watcherDone chan struct{} // Synchronise shutdown of the watcher and lines handlers.
	VMsDone     chan struct{} // Notify mtail when all running VMs are shutdown.

	compileOnly          bool // Only compile programs and report errors, do not load VMs.
	dumpBytecode         bool // Instructs the loader to dump to stdout the compiled program after compilation.
	syslogUseCurrentYear bool // Instructs the VM to overwrite zero years with the current year in a strptime instruction.
}

// LoaderOptions contains the required and optional parameters for creating a
// new Loader.
type LoaderOptions struct {
	Store *metrics.Store
	Lines <-chan string
	W     watcher.Watcher // Not required, will use watcher.LogWatcher if zero.
	FS    afero.Fs        // Not required, will use afero.OsFs if zero.

	CompileOnly          bool
	DumpBytecode         bool
	SyslogUseCurrentYear bool
}

// NewLoader creates a new program loader.  It takes a filesystem watcher
// and a filesystem interface as arguments.  If fs is nil, it will use the
// default filesystem interface.
func NewLoader(o LoaderOptions) (*Loader, error) {
	if o.Store == nil || o.Lines == nil {
		return nil, errors.New("loader needs a store and lines")
	}
	fs := o.FS
	if fs == nil {
		fs = &afero.OsFs{}
	}
	w := o.W
	if w == nil {
		var err error
		w, err = watcher.NewLogWatcher()
		if err != nil {
			return nil, fmt.Errorf("Couldn't create a watcher for loader: %s", err)
		}
	}
	l := &Loader{
		w:                    w,
		ms:                   o.Store,
		fs:                   fs,
		handles:              make(map[string]*vmHandle),
		watcherDone:          make(chan struct{}),
		VMsDone:              make(chan struct{}),
		compileOnly:          o.CompileOnly,
		dumpBytecode:         o.DumpBytecode,
		syslogUseCurrentYear: o.SyslogUseCurrentYear}

	go l.processEvents()
	go l.processLines(o.Lines)
	return l, nil
}

type vmHandle struct {
	lines chan string
	done  chan struct{}
}

// processEvents manages program lifecycle triggered by events from the
// filesystem watcher.
func (l *Loader) processEvents() {
	defer close(l.watcherDone)
	for event := range l.w.Events() {
		switch event := event.(type) {
		case watcher.DeleteEvent:
			glog.Infof("delete prog %s", event.Pathname)
			l.UnloadProgram(event.Pathname)
		case watcher.UpdateEvent:
			glog.Infof("update prog %s", event.Pathname)
			l.LoadProg(event.Pathname)
		case watcher.CreateEvent:
			l.w.Add(event.Pathname)
		default:
			glog.V(1).Infof("Unexected event type %+#v", event)
		}
	}
}

// processLines provides fanout of the input log lines to each virtual machine
// running.  Upon close of the incoming lines channel, it also communicates
// shutdown to the target VMs via channel close.
func (l *Loader) processLines(lines <-chan string) {
	for line := range lines {
		LineCount.Add(1)
		l.handleMu.RLock()
		for prog := range l.handles {
			l.handles[prog].lines <- line
		}
		l.handleMu.RUnlock()
	}
	glog.Info("Shutting down loader.")
	l.w.Close()
	<-l.watcherDone
	l.handleMu.Lock()
	defer l.handleMu.Unlock()
	for prog := range l.handles {
		close(l.handles[prog].lines)
		<-l.handles[prog].done
		delete(l.handles, prog)
	}
	close(l.VMsDone)
}

// UnloadProgram removes the named program from the watcher to prevent future
// updates, and terminates any currently running VM goroutine.
func (l *Loader) UnloadProgram(pathname string) {
	if err := l.w.Remove(pathname); err != nil {
		glog.Infof("Remove watch on %s failed: %s", pathname, err)
	}
	name := filepath.Base(pathname)
	l.handleMu.Lock()
	defer l.handleMu.Unlock()
	if handle, ok := l.handles[name]; ok {
		close(handle.lines)
		<-handle.done
		delete(l.handles, name)
	}
}
<commit_msg>Return error when program loading failed<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package vm

// mtail programs may be updated while emtail is running, and they will be
// reloaded without having to restart the mtail process. Programs can be
// created and deleted as well, and some configuration systems do an atomic
// rename of the program when it is installed, so mtail is also aware of file
// moves.

import (
	"errors"
	"expvar"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"sync"

	"github.com/golang/glog"
	"github.com/jaqx0r/afero"

	"github.com/google/mtail/metrics"
	"github.com/google/mtail/watcher"
)

var (
	// ProgLoads counts the number of program load events.
	ProgLoads = expvar.NewMap("prog_loads_total")
	// ProgLoadErrors counts the number of program load errors.
	ProgLoadErrors = expvar.NewMap("prog_load_errors")
)

var (
	// LineCount counts the number of lines read by the virtual machine engine from the input channel.
	LineCount = expvar.NewInt("line_count")
)

const (
	fileExt = ".mtail"
)

// LoadProgs loads all programs in a directory and starts watching the
// directory for filesystem changes.  The total number of program errors is
// returned.
func (l *Loader) LoadProgs(programPath string) error {
	l.w.Add(programPath)

	s, err := os.Stat(programPath)
	if err != nil {
		return fmt.Errorf("failed to stat: %s", err)
	}
	switch {
	case s.IsDir():
		fis, err := ioutil.ReadDir(programPath)
		if err != nil {
			return fmt.Errorf("Failed to list programs in %q: %s", programPath, err)
		}

		for _, fi := range fis {
			if fi.IsDir() {
				continue
			}
			err = l.LoadProg(path.Join(programPath, fi.Name()))
			if err != nil {
				return err
			}
		}
		return nil
	default:
		return l.LoadProg(programPath)
	}
}

// LoadProg loads or reloads a program from the path specified.  The name of
// the program is the basename of the file.
func (l *Loader) LoadProg(programPath string) error {
	name := filepath.Base(programPath)
	if filepath.Ext(name) != fileExt {
		glog.Infof("Skipping %s due to file extension.", programPath)
		return nil
	}
	f, err := l.fs.Open(programPath)
	if err != nil {
		ProgLoadErrors.Add(name, 1)
		return fmt.Errorf("Failed to read program %q: %s", programPath, err)
	}
	defer f.Close()
	return l.CompileAndRun(name, f)
}

// CompileAndRun compiles a program read from the input, starting execution if
// it succeeds.  If an existing virtual machine of the same name already
// exists, the previous virtual machine is terminated and the new loaded over
// it.  If the new program fails to compile, any existing virtual machine with
// the same name remains running.
func (l *Loader) CompileAndRun(name string, input io.Reader) error {
	o := &Options{CompileOnly: l.compileOnly, SyslogUseCurrentYear: l.syslogUseCurrentYear}
	v, errs := Compile(name, input, o)
	if errs != nil {
		ProgLoadErrors.Add(name, 1)
		return fmt.Errorf("compile failed for %s:\n%s", name, errs)
	}
	if v == nil {
		glog.Warning("No program returned, but no errors.")
		return nil
	}
	for _, m := range v.m {
		if !m.Hidden {
			l.ms.Add(m)
		}
	}
	if l.dumpBytecode {
		v.DumpByteCode(name)
	}
	ProgLoads.Add(name, 1)
	glog.Infof("Loaded program %s", name)

	l.handleMu.Lock()
	defer l.handleMu.Unlock()
	// Stop any previous VM.
	if handle, ok := l.handles[name]; ok {
		close(handle.lines)
		<-handle.done
	}
	l.handles[name] = &vmHandle{make(chan string), make(chan struct{})}
	go v.Run(l.handles[name].lines, l.handles[name].done)
	return nil
}

// Loader handles the lifecycle of programs and virtual machines, by watching
// the configured program source directory, compiling changes to programs, and
// managing the running virtual machines that receive input from the lines
// channel.
type Loader struct {
	w  watcher.Watcher // watches for program changes
	fs afero.Fs        // filesystem interface
	ms *metrics.Store  // pointer to store to pass to compiler

	handles  map[string]*vmHandle // map of program names to virtual machines
	handleMu sync.RWMutex         // guards accesses to handles

	watcherDone chan struct{} // Synchronise shutdown of the watcher and lines handlers.
	VMsDone     chan struct{} // Notify mtail when all running VMs are shutdown.

	compileOnly          bool // Only compile programs and report errors, do not load VMs.
	dumpBytecode         bool // Instructs the loader to dump to stdout the compiled program after compilation.
	syslogUseCurrentYear bool // Instructs the VM to overwrite zero years with the current year in a strptime instruction.
}

// LoaderOptions contains the required and optional parameters for creating a
// new Loader.
type LoaderOptions struct {
	Store *metrics.Store
	Lines <-chan string
	W     watcher.Watcher // Not required, will use watcher.LogWatcher if zero.
	FS    afero.Fs        // Not required, will use afero.OsFs if zero.

	CompileOnly          bool
	DumpBytecode         bool
	SyslogUseCurrentYear bool
}

// NewLoader creates a new program loader.  It takes a filesystem watcher
// and a filesystem interface as arguments.  If fs is nil, it will use the
// default filesystem interface.
func NewLoader(o LoaderOptions) (*Loader, error) {
	if o.Store == nil || o.Lines == nil {
		return nil, errors.New("loader needs a store and lines")
	}
	fs := o.FS
	if fs == nil {
		fs = &afero.OsFs{}
	}
	w := o.W
	if w == nil {
		var err error
		w, err = watcher.NewLogWatcher()
		if err != nil {
			return nil, fmt.Errorf("Couldn't create a watcher for loader: %s", err)
		}
	}
	l := &Loader{
		w:                    w,
		ms:                   o.Store,
		fs:                   fs,
		handles:              make(map[string]*vmHandle),
		watcherDone:          make(chan struct{}),
		VMsDone:              make(chan struct{}),
		compileOnly:          o.CompileOnly,
		dumpBytecode:         o.DumpBytecode,
		syslogUseCurrentYear: o.SyslogUseCurrentYear}

	go l.processEvents()
	go l.processLines(o.Lines)
	return l, nil
}

type vmHandle struct {
	lines chan string
	done  chan struct{}
}

// processEvents manages program lifecycle triggered by events from the
// filesystem watcher.
func (l *Loader) processEvents() {
	defer close(l.watcherDone)
	for event := range l.w.Events() {
		switch event := event.(type) {
		case watcher.DeleteEvent:
			glog.Infof("delete prog %s", event.Pathname)
			l.UnloadProgram(event.Pathname)
		case watcher.UpdateEvent:
			glog.Infof("update prog %s", event.Pathname)
			l.LoadProg(event.Pathname)
		case watcher.CreateEvent:
			l.w.Add(event.Pathname)
		default:
			glog.V(1).Infof("Unexected event type %+#v", event)
		}
	}
}

// processLines provides fanout of the input log lines to each virtual machine
// running.  Upon close of the incoming lines channel, it also communicates
// shutdown to the target VMs via channel close.
func (l *Loader) processLines(lines <-chan string) {
	for line := range lines {
		LineCount.Add(1)
		l.handleMu.RLock()
		for prog := range l.handles {
			l.handles[prog].lines <- line
		}
		l.handleMu.RUnlock()
	}
	glog.Info("Shutting down loader.")
	l.w.Close()
	<-l.watcherDone
	l.handleMu.Lock()
	defer l.handleMu.Unlock()
	for prog := range l.handles {
		close(l.handles[prog].lines)
		<-l.handles[prog].done
		delete(l.handles, prog)
	}
	close(l.VMsDone)
}

// UnloadProgram removes the named program from the watcher to prevent future
// updates, and terminates any currently running VM goroutine.
func (l *Loader) UnloadProgram(pathname string) {
	if err := l.w.Remove(pathname); err != nil {
		glog.Infof("Remove watch on %s failed: %s", pathname, err)
	}
	name := filepath.Base(pathname)
	l.handleMu.Lock()
	defer l.handleMu.Unlock()
	if handle, ok := l.handles[name]; ok {
		close(handle.lines)
		<-handle.done
		delete(l.handles, name)
	}
}
<|endoftext|>


<commit_before>package webrtc

import (
	"testing"
	"time"

	"github.com/pion/logging"
	"github.com/pion/transport/vnet"
	"github.com/stretchr/testify/assert"
)

func createVNetPair(t *testing.T) (*PeerConnection, *PeerConnection, *vnet.Router) {
	// Create a root router
	wan, err := vnet.NewRouter(&vnet.RouterConfig{
		CIDR:          "1.2.3.0/24",
		LoggerFactory: logging.NewDefaultLoggerFactory(),
	})
	assert.NoError(t, err)

	// Create a network interface for offerer
	offerVNet := vnet.NewNet(&vnet.NetConfig{
		StaticIPs: []string{"1.2.3.4"},
	})
	// Add the network interface to the router
	assert.NoError(t, wan.AddNet(offerVNet))

	offerSettingEngine := SettingEngine{}
	offerSettingEngine.SetVNet(offerVNet)
	offerSettingEngine.SetICETimeouts(time.Second, time.Second, time.Millisecond*200)

	// Create a network interface for answerer
	answerVNet := vnet.NewNet(&vnet.NetConfig{
		StaticIPs: []string{"1.2.3.5"},
	})
	// Add the network interface to the router
	assert.NoError(t, wan.AddNet(answerVNet))

	answerSettingEngine := SettingEngine{}
	answerSettingEngine.SetVNet(answerVNet)
	answerSettingEngine.SetICETimeouts(time.Second, time.Second, time.Millisecond*200)

	// Start the virtual network by calling Start() on the root router
	assert.NoError(t, wan.Start())

	offerPeerConnection, err := NewAPI(WithSettingEngine(offerSettingEngine)).NewPeerConnection(Configuration{})
	assert.NoError(t, err)

	answerPeerConnection, err := NewAPI(WithSettingEngine(answerSettingEngine)).NewPeerConnection(Configuration{})
	assert.NoError(t, err)

	return offerPeerConnection, answerPeerConnection, wan
}
<commit_msg>Add !js to vnet<commit_after>// +build !js

package webrtc

import (
	"testing"
	"time"

	"github.com/pion/logging"
	"github.com/pion/transport/vnet"
	"github.com/stretchr/testify/assert"
)

func createVNetPair(t *testing.T) (*PeerConnection, *PeerConnection, *vnet.Router) {
	// Create a root router
	wan, err := vnet.NewRouter(&vnet.RouterConfig{
		CIDR:          "1.2.3.0/24",
		LoggerFactory: logging.NewDefaultLoggerFactory(),
	})
	assert.NoError(t, err)

	// Create a network interface for offerer
	offerVNet := vnet.NewNet(&vnet.NetConfig{
		StaticIPs: []string{"1.2.3.4"},
	})
	// Add the network interface to the router
	assert.NoError(t, wan.AddNet(offerVNet))

	offerSettingEngine := SettingEngine{}
	offerSettingEngine.SetVNet(offerVNet)
	offerSettingEngine.SetICETimeouts(time.Second, time.Second, time.Millisecond*200)

	// Create a network interface for answerer
	answerVNet := vnet.NewNet(&vnet.NetConfig{
		StaticIPs: []string{"1.2.3.5"},
	})
	// Add the network interface to the router
	assert.NoError(t, wan.AddNet(answerVNet))

	answerSettingEngine := SettingEngine{}
	answerSettingEngine.SetVNet(answerVNet)
	answerSettingEngine.SetICETimeouts(time.Second, time.Second, time.Millisecond*200)

	// Start the virtual network by calling Start() on the root router
	assert.NoError(t, wan.Start())

	offerPeerConnection, err := NewAPI(WithSettingEngine(offerSettingEngine)).NewPeerConnection(Configuration{})
	assert.NoError(t, err)

	answerPeerConnection, err := NewAPI(WithSettingEngine(answerSettingEngine)).NewPeerConnection(Configuration{})
	assert.NoError(t, err)

	return offerPeerConnection, answerPeerConnection, wan
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
)

type VoicePipe struct {
	RootDir   string
	Directive *Directive
}

func NewVoicePipe(path string) (*VoicePipe, error) {
	d, err := NewDirective(path)
	if err != nil {
		return nil, err
	}
	return &VoicePipe{RootDir: path, Directive: d}, nil
}

func (vp *VoicePipe) Resources() ([]os.FileInfo, error) {
	rs := make([]os.FileInfo, 0)
	fis, err := ioutil.ReadDir(vp.RootDir)
	if err != nil {
		return rs, err
	}
	for _, fi := range fis {
		n := fi.Name()
		if n != ".voicepipe" && n != "voicepipe.yml" && n != "Dockerfile" {
			rs = append(rs, fi)
		}
	}
	return rs, nil
}

func (vp *VoicePipe) SetupWorkDirFor(id ImageDirective, rs []os.FileInfo) error {
	dir := vp.RootDir + "/.voicepipe/" + id.Tag
	if err := os.RemoveAll(dir); err != nil {
		return err
	}
	if err := os.MkdirAll(dir, 0775); err != nil {
		return err
	}
	for _, fi := range rs {
		if fi.Name() != "Dockerfile" {
			if err := os.Link(vp.RootDir+"/"+fi.Name(), dir+"/"+fi.Name()); err != nil {
				return err
			}
			continue
		}
		buf, err := ioutil.ReadFile(vp.RootDir + "/" + fi.Name())
		if err != nil {
			return err
		}
		df, err := Unmarshal(buf)
		if err != nil {
			return err
		}
		// TODO: copying structures costs a lot
		for k, v := range id.Parameters {
			df = ReplaceEnv(*df, k, v)
		}
		if err := ioutil.WriteFile(fi.Name(), df.Marshal(), 775); err != nil {
			return err
		}
	}
	return nil
}

func (vp *VoicePipe) SetupWorkingDir() error {
	rs, err := vp.Resources()
	if err != nil {
		return err
	}
	for _, id := range vp.Directive.ImageDirectives {
		if err := vp.SetupWorkDirFor(*id, rs); err != nil {
			return err
		}
	}
	return nil
}

func (vp *VoicePipe) BuildImage(id ImageDirective, stdout, stderr io.Writer) error {
	dir := vp.RootDir + "/.voicepipe/" + id.Tag
	tag := vp.Directive.Repository + ":" + id.Tag
	cmd := exec.Command("docker", "build", "--rm", "-t", tag, dir)
	cmd.Stdout = stdout
	cmd.Stderr = stderr
	if err := cmd.Run(); err != nil {
		return err
	}
	return nil
}

func (vp *VoicePipe) BuildImages(stdout, stderr io.Writer) error {
	for _, id := range vp.Directive.ImageDirectives {
		if err := vp.BuildImage(*id, stdout, stderr); err != nil {
			return err
		}
	}
	return nil
}

func (vp *VoicePipe) Run() error {
	err := vp.SetupWorkingDir()
	if err != nil {
		return err
	}
	stdout := bufio.NewWriter(os.Stdout)
	stderr := bufio.NewWriter(os.Stderr)
	err = vp.BuildImages(stdout, stderr)
	if err != nil {
		return err
	}
	return nil
}
<commit_msg>Introduce the path package<commit_after>package main

import (
	"bufio"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
)

type VoicePipe struct {
	RootDir   string
	Directive *Directive
}

func NewVoicePipe(path string) (*VoicePipe, error) {
	d, err := NewDirective(path)
	if err != nil {
		return nil, err
	}
	return &VoicePipe{RootDir: path, Directive: d}, nil
}

func (vp *VoicePipe) Resources() ([]os.FileInfo, error) {
	rs := make([]os.FileInfo, 0)
	fis, err := ioutil.ReadDir(vp.RootDir)
	if err != nil {
		return rs, err
	}
	for _, fi := range fis {
		n := fi.Name()
		if n != ".voicepipe" && n != "voicepipe.yml" && n != "Dockerfile" {
			rs = append(rs, fi)
		}
	}
	return rs, nil
}

func (vp *VoicePipe) SetupWorkDirFor(id ImageDirective, rs []os.FileInfo) error {
	dir := path.Join(vp.RootDir, ".voicepipe", id.Tag)
	if err := os.RemoveAll(dir); err != nil {
		return err
	}
	if err := os.MkdirAll(dir, 0775); err != nil {
		return err
	}
	for _, fi := range rs {
		if fi.Name() != "Dockerfile" {
			src := path.Join(vp.RootDir, fi.Name())
			tgt := path.Join(dir, fi.Name())
			if err := os.Link(src, tgt); err != nil {
				return err
			}
			continue
		}
		buf, err := ioutil.ReadFile(path.Join(vp.RootDir, fi.Name()))
		if err != nil {
			return err
		}
		df, err := Unmarshal(buf)
		if err != nil {
			return err
		}
		// TODO: copying structures costs a lot
		for k, v := range id.Parameters {
			df = ReplaceEnv(*df, k, v)
		}
		if err := ioutil.WriteFile(fi.Name(), df.Marshal(), 775); err != nil {
			return err
		}
	}
	return nil
}

func (vp *VoicePipe) SetupWorkingDir() error {
	rs, err := vp.Resources()
	if err != nil {
		return err
	}
	for _, id := range vp.Directive.ImageDirectives {
		if err := vp.SetupWorkDirFor(*id, rs); err != nil {
			return err
		}
	}
	return nil
}

func (vp *VoicePipe) BuildImage(id ImageDirective, stdout, stderr io.Writer) error {
	dir := path.Join(vp.RootDir, ".voicepipe", id.Tag)
	tag := vp.Directive.Repository + ":" + id.Tag
	cmd := exec.Command("docker", "build", "--rm", "-t", tag, dir)
	cmd.Stdout = stdout
	cmd.Stderr = stderr
	if err := cmd.Run(); err != nil {
		return err
	}
	return nil
}

func (vp *VoicePipe) BuildImages(stdout, stderr io.Writer) error {
	for _, id := range vp.Directive.ImageDirectives {
		if err := vp.BuildImage(*id, stdout, stderr); err != nil {
			return err
		}
	}
	return nil
}

func (vp *VoicePipe) Run() error {
	err := vp.SetupWorkingDir()
	if err != nil {
		return err
	}
	stdout := bufio.NewWriter(os.Stdout)
	stderr := bufio.NewWriter(os.Stderr)
	err = vp.BuildImages(stdout, stderr)
	if err != nil {
		return err
	}
	return nil
}
<|endoftext|>


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

// This file was auto-generated via go generate.
// DO NOT UPDATE MANUALLY

package vlog_test

import (
	"os"
	"testing"

	"v.io/x/ref/test"
	"v.io/x/ref/test/modules"
)

func TestMain(m *testing.M) {
	test.Init()
	modules.DispatchAndExitIfChild()
	os.Exit(m.Run())
}
<commit_msg>Counterpart of https://vanadium-review.googlesource.com/17148<commit_after>// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file was auto-generated via go generate.
// DO NOT UPDATE MANUALLY

package vlog_test

import (
	"os"
	"testing"

	"v.io/x/ref/test/modules"
)

func TestMain(m *testing.M) {
	modules.DispatchAndExitIfChild()
	os.Exit(m.Run())
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"syscall"

	"github.com/urfave/cli"
)

type VoiceChannel struct {
	IMEI   string `json:"imei"`
	IMSI   string `json:"imsi"`
	Name   string `json:"name"`
	Number string `json:"number"`
	RxGain int    `json:"rx-gain,omitempty"`
	TxGain int    `json:"tx-gain,omitempty"`
	Label  string `json:"label"`
}

type VoiceState struct {
	Enabled bool          `json:"enabled"`
	Config  *VoiceChannel `json:"config"`
}

func VoiceChannelCMD(ctx *cli.Context) error {
	if ctx.IsSet(enableFlag) {
		return EnableVoiceChan(ctx)
	}
	if ctx.IsSet(disableFlag) {
		return DisableVoiceChan(ctx)
	}
	if ctx.IsSet(removeFlag) {
		return RemoveVoiceChan(ctx)
	}
	if ctx.IsSet(configFlag) {
		return configVoice(ctx)
	}
	return nil
}

func configVoice(ctx *cli.Context) error {
	src := ctx.String("config")
	if src == "" {
		return errors.New("fconf: missing configuration source file")
	}
	var b []byte
	var err error
	if src == "stdin" {
		b, err = ReadFromStdin()
		if err != nil {
			return err
		}
	} else {
		b, err = ioutil.ReadFile(src)
		if err != nil {
			return err
		}
	}
	e := VoiceChannel{}
	err = json.Unmarshal(b, &e)
	if err != nil {
		return err
	}
	state := &VoiceState{Config: &e}
	ws, err := voiceChanState(e.IMSI)
	if err == nil {
		state.Enabled = ws.Enabled
	}
	b, _ = json.Marshal(state)
	setInterface(ctx, e.IMSI)
	return keepState(
		fmt.Sprintf(defaultVoiceChanConfig, e.IMSI), b)
}

func voiceChanState(i string) (*VoiceState, error) {
	dir := os.Getenv("FCONF_CONFIGDIR")
	if dir == "" {
		dir = fconfConfigDir
	}
	b, err := ioutil.ReadFile(filepath.Join(dir,
		fmt.Sprintf(defaultVoiceChanConfig, i)))
	if err != nil {
		return nil, err
	}
	w := &VoiceState{}
	err = json.Unmarshal(b, w)
	if err != nil {
		return nil, err
	}
	if w.Config == nil {
		return nil, ErrWrongStateFile
	}
	return w, nil
}

func EnableVoiceChan(ctx *cli.Context) error {
	if ctx.IsSet(configFlag) {
		err := configVoice(ctx)
		if err != nil {
			return err
		}
	}
	i := getInterface(ctx)
	if i == "" {
		return errors.New("missing imei , you must specify imei")
	}
	w, err := voiceChanState(i)
	if err != nil {
		return err
	}
	w.Enabled = true
	data, err := json.Marshal(w)
	if err != nil {
		return err
	}
	err = keepState(
		fmt.Sprintf(defaultVoiceChanConfig, w.Config.IMEI), data)
	if err != nil {
		return err
	}
	return notify(ctx)
}

func DisableVoiceChan(ctx *cli.Context) error {
	i := getInterface(ctx)
	if i == "" {
		return errors.New("missing imei , you must specify imei")
	}
	w, err := voiceChanState(i)
	if err != nil {
		return err
	}
	w.Enabled = false
	data, err := json.Marshal(w)
	if err != nil {
		return err
	}
	err = keepState(
		fmt.Sprintf(defaultVoiceChanConfig, w.Config.IMEI), data)
	if err != nil {
		return err
	}
	return notify(ctx)
}

func RemoveVoiceChan(ctx *cli.Context) error {
	i := getInterface(ctx)
	if i == "" {
		return errors.New("missing imei , you must specify imei")
	}
	w, err := voiceChanState(i)
	if err != nil {
		return err
	}
	dir := os.Getenv("FCONF_CONFIGDIR")
	if dir == "" {
		dir = fconfConfigDir
	}
	err = checkDir(dir)
	if err != nil {
		return err
	}
	name := filepath.Join(dir, fmt.Sprintf(defaultVoiceChanConfig, w.Config.IMEI))
	err = removeFile(name)
	if err != nil {
		return err
	}
	return notify(ctx)
}

func notify(ctx *cli.Context) error {
	if ctx.GlobalIsSet("pid") {
		pid := ctx.GlobalInt("pid")
		fmt.Printf("sending SIGHUP to %d\n", pid)
		return syscall.Kill(pid, syscall.SIGHUP)
	}
	return nil

}
<commit_msg>voice_channel: add sms_out and calls_out fields<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"syscall"

	"github.com/urfave/cli"
)

type VoiceChannel struct {
	IMEI   string `json:"imei"`
	IMSI   string `json:"imsi"`
	Name   string `json:"name"`
	Number string `json:"number"`
	RxGain int    `json:"rx-gain,omitempty"`
	TxGain int    `json:"tx-gain,omitempty"`
	Label  string `json:"label"`
	SMS    string `json:"sms_out"`
	Calls  string `json:"calls_out"`
}

type VoiceState struct {
	Enabled bool          `json:"enabled"`
	Config  *VoiceChannel `json:"config"`
}

func VoiceChannelCMD(ctx *cli.Context) error {
	if ctx.IsSet(enableFlag) {
		return EnableVoiceChan(ctx)
	}
	if ctx.IsSet(disableFlag) {
		return DisableVoiceChan(ctx)
	}
	if ctx.IsSet(removeFlag) {
		return RemoveVoiceChan(ctx)
	}
	if ctx.IsSet(configFlag) {
		return configVoice(ctx)
	}
	return nil
}

func configVoice(ctx *cli.Context) error {
	src := ctx.String("config")
	if src == "" {
		return errors.New("fconf: missing configuration source file")
	}
	var b []byte
	var err error
	if src == "stdin" {
		b, err = ReadFromStdin()
		if err != nil {
			return err
		}
	} else {
		b, err = ioutil.ReadFile(src)
		if err != nil {
			return err
		}
	}
	e := VoiceChannel{}
	err = json.Unmarshal(b, &e)
	if err != nil {
		return err
	}
	state := &VoiceState{Config: &e}
	ws, err := voiceChanState(e.IMSI)
	if err == nil {
		state.Enabled = ws.Enabled
	}
	b, _ = json.Marshal(state)
	setInterface(ctx, e.IMSI)
	return keepState(
		fmt.Sprintf(defaultVoiceChanConfig, e.IMSI), b)
}

func voiceChanState(i string) (*VoiceState, error) {
	dir := os.Getenv("FCONF_CONFIGDIR")
	if dir == "" {
		dir = fconfConfigDir
	}
	b, err := ioutil.ReadFile(filepath.Join(dir,
		fmt.Sprintf(defaultVoiceChanConfig, i)))
	if err != nil {
		return nil, err
	}
	w := &VoiceState{}
	err = json.Unmarshal(b, w)
	if err != nil {
		return nil, err
	}
	if w.Config == nil {
		return nil, ErrWrongStateFile
	}
	return w, nil
}

func EnableVoiceChan(ctx *cli.Context) error {
	if ctx.IsSet(configFlag) {
		err := configVoice(ctx)
		if err != nil {
			return err
		}
	}
	i := getInterface(ctx)
	if i == "" {
		return errors.New("missing imei , you must specify imei")
	}
	w, err := voiceChanState(i)
	if err != nil {
		return err
	}
	w.Enabled = true
	data, err := json.Marshal(w)
	if err != nil {
		return err
	}
	err = keepState(
		fmt.Sprintf(defaultVoiceChanConfig, w.Config.IMEI), data)
	if err != nil {
		return err
	}
	return notify(ctx)
}

func DisableVoiceChan(ctx *cli.Context) error {
	i := getInterface(ctx)
	if i == "" {
		return errors.New("missing imei , you must specify imei")
	}
	w, err := voiceChanState(i)
	if err != nil {
		return err
	}
	w.Enabled = false
	data, err := json.Marshal(w)
	if err != nil {
		return err
	}
	err = keepState(
		fmt.Sprintf(defaultVoiceChanConfig, w.Config.IMEI), data)
	if err != nil {
		return err
	}
	return notify(ctx)
}

func RemoveVoiceChan(ctx *cli.Context) error {
	i := getInterface(ctx)
	if i == "" {
		return errors.New("missing imei , you must specify imei")
	}
	w, err := voiceChanState(i)
	if err != nil {
		return err
	}
	dir := os.Getenv("FCONF_CONFIGDIR")
	if dir == "" {
		dir = fconfConfigDir
	}
	err = checkDir(dir)
	if err != nil {
		return err
	}
	name := filepath.Join(dir, fmt.Sprintf(defaultVoiceChanConfig, w.Config.IMEI))
	err = removeFile(name)
	if err != nil {
		return err
	}
	return notify(ctx)
}

func notify(ctx *cli.Context) error {
	if ctx.GlobalIsSet("pid") {
		pid := ctx.GlobalInt("pid")
		fmt.Printf("sending SIGHUP to %d\n", pid)
		return syscall.Kill(pid, syscall.SIGHUP)
	}
	return nil

}
<|endoftext|>


<commit_before>package volume

import (
	"fmt"
	"strconv"
	"strings"
)

func cmdEnv() []string {
	return nil
}

func getVolumeCmd() []string {
	return []string{"osascript", "-e", "output volume of (get volume settings)"}
}

func parseVolume(out string) (int, error) {
	return strconv.Atoi(strings.TrimSuffix(out, "\n"))
}

func setVolumeCmd(volume int) []string {
	return []string{"osascript", "-e", "set volume output volume " + strconv.Itoa(volume)}
}

func getMutedCmd() []string {
	return []string{"osascript", "-e", "output muted of (get volume settings)"}
}

func parseMuted(out string) (bool, error) {
	switch strings.TrimSpace(out) {
	case "true":
		return true, nil
	case "false":
		return false, nil
	}
	return false, fmt.Errorf("unknown muted status: %s", out)
}

func muteCmd() []string {
	return []string{"osascript", "-e", "set volume output muted true"}
}

func unmuteCmd() []string {
	return []string{"osascript", "-e", "set volume output muted false"}
}
<commit_msg>handling `missing value` on macOS<commit_after>package volume

import (
	"fmt"
	"strconv"
	"strings"
)

func cmdEnv() []string {
	return nil
}

func getVolumeCmd() []string {
	return []string{"osascript", "-e", "output volume of (get volume settings)"}
}

func parseVolume(out string) (int, error) {
	out = strings.TrimSuffix(out, "\n")
	if out == "missing value" {
		return 0, fmt.Errorf("failed to get volume settings: %s", out)
	}
	return strconv.Atoi(out)
}

func setVolumeCmd(volume int) []string {
	return []string{"osascript", "-e", "set volume output volume " + strconv.Itoa(volume)}
}

func getMutedCmd() []string {
	return []string{"osascript", "-e", "output muted of (get volume settings)"}
}

func parseMuted(out string) (bool, error) {
	switch strings.TrimSpace(out) {
	case "true":
		return true, nil
	case "false":
		return false, nil
	}
	return false, fmt.Errorf("unknown muted status: %s", out)
}

func muteCmd() []string {
	return []string{"osascript", "-e", "set volume output muted true"}
}

func unmuteCmd() []string {
	return []string{"osascript", "-e", "set volume output muted false"}
}
<|endoftext|>


<commit_before>package mpawsrds

import (
	"errors"
	"flag"
	"log"
	"os"
	"strings"
	"time"

	"github.com/crowdmob/goamz/aws"
	"github.com/crowdmob/goamz/cloudwatch"
	mp "github.com/mackerelio/go-mackerel-plugin"
)

// RDSPlugin mackerel plugin for amazon RDS
type RDSPlugin struct {
	Region          string
	AccessKeyID     string
	SecretAccessKey string
	Identifier      string
	Engine          string
	Prefix          string
	LabelPrefix     string
}

func getLastPoint(cloudWatch *cloudwatch.CloudWatch, dimension *cloudwatch.Dimension, metricName string) (float64, error) {
	now := time.Now()

	response, err := cloudWatch.GetMetricStatistics(&cloudwatch.GetMetricStatisticsRequest{
		Dimensions: []cloudwatch.Dimension{*dimension},
		StartTime:  now.Add(time.Duration(180) * time.Second * -1), // 3 min (to fetch at least 1 data-point)
		EndTime:    now,
		MetricName: metricName,
		Period:     60,
		Statistics: []string{"Average"},
		Namespace:  "AWS/RDS",
	})
	if err != nil {
		return 0, err
	}

	datapoints := response.GetMetricStatisticsResult.Datapoints
	if len(datapoints) == 0 {
		return 0, errors.New("fetched no datapoints")
	}

	latest := time.Unix(0, 0)
	var latestVal float64
	for _, dp := range datapoints {
		if dp.Timestamp.Before(latest) {
			continue
		}

		latest = dp.Timestamp
		latestVal = dp.Average
	}

	return latestVal, nil
}

// FetchMetrics interface for mackerel-plugin
func (p RDSPlugin) FetchMetrics() (map[string]float64, error) {
	auth, err := aws.GetAuth(p.AccessKeyID, p.SecretAccessKey, "", time.Now())
	if err != nil {
		return nil, err
	}

	cloudWatch, err := cloudwatch.NewCloudWatch(auth, aws.Regions[p.Region].CloudWatchServicepoint)
	if err != nil {
		return nil, err
	}

	stat := make(map[string]float64)

	perInstance := &cloudwatch.Dimension{
		Name:  "DBInstanceIdentifier",
		Value: p.Identifier,
	}

	for _, met := range p.rdsMetrics() {
		v, err := getLastPoint(cloudWatch, perInstance, met)
		if err == nil {
			stat[met] = v
		} else {
			log.Printf("%s: %s", met, err)
		}
	}

	return stat, nil
}

func (p RDSPlugin) baseGraphDefs() map[string]mp.Graphs {
	return map[string]mp.Graphs{
		p.Prefix + ".BinLogDiskUsage": {
			Label: p.LabelPrefix + " BinLogDiskUsage",
			Unit:  "bytes",
			Metrics: []mp.Metrics{
				{Name: "BinLogDiskUsage", Label: "Usage"},
			},
		},
		p.Prefix + ".DiskQueueDepth": {
			Label: p.LabelPrefix + " BinLogDiskUsage",
			Unit:  "bytes",
			Metrics: []mp.Metrics{
				{Name: "DiskQueueDepth", Label: "Depth"},
			},
		},
		p.Prefix + ".CPUUtilization": {
			Label: p.LabelPrefix + " CPU Utilization",
			Unit:  "percentage",
			Metrics: []mp.Metrics{
				{Name: "CPUUtilization", Label: "CPUUtilization"},
			},
		},
		p.Prefix + ".DatabaseConnections": {
			Label: p.LabelPrefix + " Database Connections",
			Unit:  "float",
			Metrics: []mp.Metrics{
				{Name: "DatabaseConnections", Label: "DatabaseConnections"},
			},
		},
		p.Prefix + ".FreeableMemory": {
			Label: p.LabelPrefix + " Freeable Memory",
			Unit:  "bytes",
			Metrics: []mp.Metrics{
				{Name: "FreeableMemory", Label: "FreeableMemory"},
			},
		},
		p.Prefix + ".FreeStorageSpace": {
			Label: p.LabelPrefix + " Free Storage Space",
			Unit:  "bytes",
			Metrics: []mp.Metrics{
				{Name: "FreeStorageSpace", Label: "FreeStorageSpace"},
			},
		},
		p.Prefix + ".ReplicaLag": {
			Label: p.LabelPrefix + " Replica Lag",
			Unit:  "float",
			Metrics: []mp.Metrics{
				{Name: "ReplicaLag", Label: "ReplicaLag"},
			},
		},
		p.Prefix + ".SwapUsage": {
			Label: p.LabelPrefix + " Swap Usage",
			Unit:  "bytes",
			Metrics: []mp.Metrics{
				{Name: "SwapUsage", Label: "SwapUsage"},
			},
		},
		p.Prefix + ".IOPS": {
			Label: p.LabelPrefix + " IOPS",
			Unit:  "iops",
			Metrics: []mp.Metrics{
				{Name: "ReadIOPS", Label: "Read"},
				{Name: "WriteIOPS", Label: "Write"},
			},
		},
		p.Prefix + ".Latency": {
			Label: p.LabelPrefix + " Latency in second",
			Unit:  "float",
			Metrics: []mp.Metrics{
				{Name: "ReadLatency", Label: "Read"},
				{Name: "WriteLatency", Label: "Write"},
			},
		},
		p.Prefix + ".Throughput": {
			Label: p.LabelPrefix + " Throughput",
			Unit:  "bytes/sec",
			Metrics: []mp.Metrics{
				{Name: "ReadThroughput", Label: "Read"},
				{Name: "WriteThroughput", Label: "Write"},
			},
		},
		p.Prefix + ".NetworkThroughput": {
			Label: p.LabelPrefix + " Network Throughput",
			Unit:  "bytes/sec",
			Metrics: []mp.Metrics{
				{Name: "NetworkTransmitThroughput", Label: "Transmit"},
				{Name: "NetworkReceiveThroughput", Label: "Receive"},
			},
		},
	}
}

// GraphDefinition interface for mackerel plugin
func (p RDSPlugin) GraphDefinition() map[string]mp.Graphs {
	graphdef := p.baseGraphDefs()
	switch p.Engine {
	case "mysql", "mariadb":
		graphdef = mergeGraphDefs(graphdef, p.mySQLGraphDefinition())
	case "aurora":
		graphdef = mergeGraphDefs(graphdef, p.auroraGraphDefinition())
	case "postgresql":
		graphdef = mergeGraphDefs(graphdef, p.postgreSQLGraphDefinition())
	}
	return graphdef
}

// Do the plugin
func Do() {
	optRegion := flag.String("region", "", "AWS Region")
	optAccessKeyID := flag.String("access-key-id", "", "AWS Access Key ID")
	optSecretAccessKey := flag.String("secret-access-key", "", "AWS Secret Access Key")
	optIdentifier := flag.String("identifier", "", "DB Instance Identifier")
	optEngine := flag.String("engine", "", "RDS Engine")
	optPrefix := flag.String("metric-key-prefix", "rds", "Metric key prefix")
	optLabelPrefix := flag.String("metric-label-prefix", "", "Metric Label prefix")
	optTempfile := flag.String("tempfile", "", "Temp file name")
	flag.Parse()

	rds := RDSPlugin{
		Prefix: *optPrefix,
	}
	if *optLabelPrefix == "" {
		if *optPrefix == "rds" {
			rds.LabelPrefix = "RDS"
		} else {
			rds.LabelPrefix = strings.Title(*optPrefix)
		}
	} else {
		rds.LabelPrefix = *optLabelPrefix
	}

	if *optRegion == "" {
		rds.Region = aws.InstanceRegion()
	} else {
		rds.Region = *optRegion
	}

	rds.Identifier = *optIdentifier
	rds.AccessKeyID = *optAccessKeyID
	rds.SecretAccessKey = *optSecretAccessKey
	rds.Engine = *optEngine

	helper := mp.NewMackerelPlugin(rds)
	if *optTempfile != "" {
		helper.Tempfile = *optTempfile
	} else {
		helper.Tempfile = "/tmp/mackerel-plugin-rds"
	}

	if os.Getenv("MACKEREL_AGENT_PLUGIN_META") != "" {
		helper.OutputDefinitions()
	} else {
		helper.OutputValues()
	}
}
<commit_msg>[aws-rds] migrate from goamz to aws-sdk-go<commit_after>package mpawsrds

import (
	"errors"
	"flag"
	"log"
	"os"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/cloudwatch"
	mp "github.com/mackerelio/go-mackerel-plugin"
)

// RDSPlugin mackerel plugin for amazon RDS
type RDSPlugin struct {
	Region          string
	AccessKeyID     string
	SecretAccessKey string
	Identifier      string
	Engine          string
	Prefix          string
	LabelPrefix     string
}

func getLastPoint(cloudWatch *cloudwatch.CloudWatch, dimension *cloudwatch.Dimension, metricName string) (float64, error) {
	now := time.Now()

	response, err := cloudWatch.GetMetricStatistics(&cloudwatch.GetMetricStatisticsInput{
		Dimensions: []*cloudwatch.Dimension{dimension},
		StartTime:  aws.Time(now.Add(time.Duration(180) * time.Second * -1)), // 3 min (to fetch at least 1 data-point)
		EndTime:    aws.Time(now),
		MetricName: aws.String(metricName),
		Period:     aws.Int64(60),
		Statistics: []*string{aws.String("Average")},
		Namespace:  aws.String("AWS/RDS"),
	})
	if err != nil {
		return 0, err
	}

	datapoints := response.Datapoints
	if len(datapoints) == 0 {
		return 0, errors.New("fetched no datapoints")
	}

	latest := new(time.Time)
	var latestVal float64
	for _, dp := range datapoints {
		if dp.Timestamp.Before(*latest) {
			continue
		}

		latest = dp.Timestamp
		latestVal = *dp.Average
	}

	return latestVal, nil
}

// FetchMetrics interface for mackerel-plugin
func (p RDSPlugin) FetchMetrics() (map[string]float64, error) {
	sess, err := session.NewSession()
	if err != nil {
		return nil, err
	}

	config := aws.NewConfig()
	if p.AccessKeyID != "" && p.SecretAccessKey != "" {
		config = config.WithCredentials(credentials.NewStaticCredentials(p.AccessKeyID, p.SecretAccessKey, ""))
	}
	if p.Region != "" {
		config = config.WithRegion(p.Region)
	}

	cloudWatch := cloudwatch.New(sess, config)

	stat := make(map[string]float64)

	perInstance := &cloudwatch.Dimension{
		Name:  aws.String("DBInstanceIdentifier"),
		Value: aws.String(p.Identifier),
	}

	for _, met := range p.rdsMetrics() {
		v, err := getLastPoint(cloudWatch, perInstance, met)
		if err == nil {
			stat[met] = v
		} else {
			log.Printf("%s: %s", met, err)
		}
	}

	return stat, nil
}

func (p RDSPlugin) baseGraphDefs() map[string]mp.Graphs {
	return map[string]mp.Graphs{
		p.Prefix + ".BinLogDiskUsage": {
			Label: p.LabelPrefix + " BinLogDiskUsage",
			Unit:  "bytes",
			Metrics: []mp.Metrics{
				{Name: "BinLogDiskUsage", Label: "Usage"},
			},
		},
		p.Prefix + ".DiskQueueDepth": {
			Label: p.LabelPrefix + " BinLogDiskUsage",
			Unit:  "bytes",
			Metrics: []mp.Metrics{
				{Name: "DiskQueueDepth", Label: "Depth"},
			},
		},
		p.Prefix + ".CPUUtilization": {
			Label: p.LabelPrefix + " CPU Utilization",
			Unit:  "percentage",
			Metrics: []mp.Metrics{
				{Name: "CPUUtilization", Label: "CPUUtilization"},
			},
		},
		p.Prefix + ".DatabaseConnections": {
			Label: p.LabelPrefix + " Database Connections",
			Unit:  "float",
			Metrics: []mp.Metrics{
				{Name: "DatabaseConnections", Label: "DatabaseConnections"},
			},
		},
		p.Prefix + ".FreeableMemory": {
			Label: p.LabelPrefix + " Freeable Memory",
			Unit:  "bytes",
			Metrics: []mp.Metrics{
				{Name: "FreeableMemory", Label: "FreeableMemory"},
			},
		},
		p.Prefix + ".FreeStorageSpace": {
			Label: p.LabelPrefix + " Free Storage Space",
			Unit:  "bytes",
			Metrics: []mp.Metrics{
				{Name: "FreeStorageSpace", Label: "FreeStorageSpace"},
			},
		},
		p.Prefix + ".ReplicaLag": {
			Label: p.LabelPrefix + " Replica Lag",
			Unit:  "float",
			Metrics: []mp.Metrics{
				{Name: "ReplicaLag", Label: "ReplicaLag"},
			},
		},
		p.Prefix + ".SwapUsage": {
			Label: p.LabelPrefix + " Swap Usage",
			Unit:  "bytes",
			Metrics: []mp.Metrics{
				{Name: "SwapUsage", Label: "SwapUsage"},
			},
		},
		p.Prefix + ".IOPS": {
			Label: p.LabelPrefix + " IOPS",
			Unit:  "iops",
			Metrics: []mp.Metrics{
				{Name: "ReadIOPS", Label: "Read"},
				{Name: "WriteIOPS", Label: "Write"},
			},
		},
		p.Prefix + ".Latency": {
			Label: p.LabelPrefix + " Latency in second",
			Unit:  "float",
			Metrics: []mp.Metrics{
				{Name: "ReadLatency", Label: "Read"},
				{Name: "WriteLatency", Label: "Write"},
			},
		},
		p.Prefix + ".Throughput": {
			Label: p.LabelPrefix + " Throughput",
			Unit:  "bytes/sec",
			Metrics: []mp.Metrics{
				{Name: "ReadThroughput", Label: "Read"},
				{Name: "WriteThroughput", Label: "Write"},
			},
		},
		p.Prefix + ".NetworkThroughput": {
			Label: p.LabelPrefix + " Network Throughput",
			Unit:  "bytes/sec",
			Metrics: []mp.Metrics{
				{Name: "NetworkTransmitThroughput", Label: "Transmit"},
				{Name: "NetworkReceiveThroughput", Label: "Receive"},
			},
		},
	}
}

// GraphDefinition interface for mackerel plugin
func (p RDSPlugin) GraphDefinition() map[string]mp.Graphs {
	graphdef := p.baseGraphDefs()
	switch p.Engine {
	case "mysql", "mariadb":
		graphdef = mergeGraphDefs(graphdef, p.mySQLGraphDefinition())
	case "aurora":
		graphdef = mergeGraphDefs(graphdef, p.auroraGraphDefinition())
	case "postgresql":
		graphdef = mergeGraphDefs(graphdef, p.postgreSQLGraphDefinition())
	}
	return graphdef
}

// Do the plugin
func Do() {
	optRegion := flag.String("region", "", "AWS Region")
	optAccessKeyID := flag.String("access-key-id", "", "AWS Access Key ID")
	optSecretAccessKey := flag.String("secret-access-key", "", "AWS Secret Access Key")
	optIdentifier := flag.String("identifier", "", "DB Instance Identifier")
	optEngine := flag.String("engine", "", "RDS Engine")
	optPrefix := flag.String("metric-key-prefix", "rds", "Metric key prefix")
	optLabelPrefix := flag.String("metric-label-prefix", "", "Metric Label prefix")
	optTempfile := flag.String("tempfile", "", "Temp file name")
	flag.Parse()

	rds := RDSPlugin{
		Prefix: *optPrefix,
	}
	if *optLabelPrefix == "" {
		if *optPrefix == "rds" {
			rds.LabelPrefix = "RDS"
		} else {
			rds.LabelPrefix = strings.Title(*optPrefix)
		}
	} else {
		rds.LabelPrefix = *optLabelPrefix
	}

	rds.Region = *optRegion
	rds.Identifier = *optIdentifier
	rds.AccessKeyID = *optAccessKeyID
	rds.SecretAccessKey = *optSecretAccessKey
	rds.Engine = *optEngine

	helper := mp.NewMackerelPlugin(rds)
	if *optTempfile != "" {
		helper.Tempfile = *optTempfile
	} else {
		helper.Tempfile = "/tmp/mackerel-plugin-rds"
	}

	if os.Getenv("MACKEREL_AGENT_PLUGIN_META") != "" {
		helper.OutputDefinitions()
	} else {
		helper.OutputValues()
	}
}
<|endoftext|>


<commit_before>package text

import (
	"bytes"
	"testing"
)

var text = "The quick brown fox jumps over the lazy dog."

func TestWrap(t *testing.T) {
	exp := [][][]byte{
		{[]byte("The"), []byte("quick"), []byte("brown"), []byte("fox")},
		{[]byte("jumps"), []byte("over"), []byte("the"), []byte("lazy"), []byte("dog.")},
	}
	words := bytes.Split([]byte(text), sp)
	got := WrapWords(words, 1, 24, defaultPenalty)
	if len(exp) != len(got) {
		t.Fail()
	}
	for i := range exp {
		if len(exp[i]) != len(got[i]) {
			t.Fail()
		}
		for j := range exp[i] {
			if string(exp[i][j]) != string(got[i][j]) {
				t.Fatal(i, exp[i][j], got[i][j])
			}
		}
	}
}

func TestWrapNarrow(t *testing.T) {
	exp := "The\nquick\nbrown\nfox\njumps\nover\nthe\nlazy\ndog."
	if Wrap(text, 5) != exp {
		t.Fail()
	}
}

func TestWrapOneLine(t *testing.T) {
	exp := "The quick brown fox jumps over the lazy dog."
	if Wrap(text, 500) != exp {
		t.Fail()
	}
}
<commit_msg>refactor<commit_after>package text

import (
	"bytes"
	"testing"
)

var text = "The quick brown fox jumps over the lazy dog."

func TestWrap(t *testing.T) {
	exp := [][]string{
		{"The", "quick", "brown", "fox"},
		{"jumps", "over", "the", "lazy", "dog."},
	}
	words := bytes.Split([]byte(text), sp)
	got := WrapWords(words, 1, 24, defaultPenalty)
	if len(exp) != len(got) {
		t.Fail()
	}
	for i := range exp {
		if len(exp[i]) != len(got[i]) {
			t.Fail()
		}
		for j := range exp[i] {
			if exp[i][j] != string(got[i][j]) {
				t.Fatal(i, exp[i][j], got[i][j])
			}
		}
	}
}

func TestWrapNarrow(t *testing.T) {
	exp := "The\nquick\nbrown\nfox\njumps\nover\nthe\nlazy\ndog."
	if Wrap(text, 5) != exp {
		t.Fail()
	}
}

func TestWrapOneLine(t *testing.T) {
	exp := "The quick brown fox jumps over the lazy dog."
	if Wrap(text, 500) != exp {
		t.Fail()
	}
}
<|endoftext|>


<commit_before>package env

import (
	"os"
	"testing"
)

func TestCanGetTheEnvAppModeDefault(t *testing.T) {
	e := Set{}
	if e.AppMode() != "development" {
		t.Fatalf("expected the environment to be development, got %v instead", e.AppMode)
	}
}

func TestCanDefineTheAppModeUsingEnvVars(t *testing.T) {
	e := Set{}
	os.Setenv("APP_MODE", "production")
	if e.AppMode() != "production" {
		t.Fatalf("expected the environment to be production, got %v instead", e.AppMode)
	}
	if e.AppMode() == "development" {
		t.Fatalf("expected the environment to be production, got %v instead", e.AppMode)
	}
}

func TestGetOrWillReturnTheRequestedEnvVarOrTheDefaultThatWasPassed(t *testing.T) {
	e := Set{}
	notSet := e.GetOr("APP_FAKE_VAR", "https://mccallister.io")
	if notSet != "https://mccallister.io" {
		t.Fatalf("expected the environment var to be development, got %v instead", e.AppMode)
	}
	os.Setenv("APP_FAKE_VAR", "1234")
	set := e.GetOr("APP_FAKE_VAR", "https://www.google.com")
	if set != "1234" {
		t.Fatalf("expected the environment var to be 1234, got %v instead", e.AppMode)
	}
	if set == "https://www.google.com" {
		t.Fatalf("expected the environment var to be 1234, got %v instead", e.AppMode)
	}
}

func TestEnvCanSetADefaultModeToOverrideThePackageDefaultAppMode(t *testing.T) {
	// clear the env to be sure
	os.Unsetenv("APP_MODE")
	e := Set{DefaultMode: "staging"}
	m := e.AppMode()
	if m != "staging" {
		t.Fatalf("expected the app mode to be staging, got %v instead", m)
	}
}

func TestCanGetTheAppKeyFromEnv(t *testing.T) {
	os.Setenv("APP_KEY", "1234")
	e := Set{}
	k, err := e.AppKey()
	if err != nil {
		t.Fatalf("could not get the AppKey from the Env, got %v instead", err)
	}
	if k != "1234" {
		t.Fatalf("expected the key to not be empty, got %v instead", k)
	}
}

func TestGettingTheAppKeyWithoutTheEnvVarReturnsAnError(t *testing.T) {
	os.Unsetenv("APP_KEY")
	e := Set{}
	_, err := e.AppKey()
	if err == nil {
		t.Fatal("expected an error, but none was returned")
	}
}

func TestDefaultAppKeyCanBeSetAndReturnedIfTheAppKeyIsNotSetInEnv(t *testing.T) {
	os.Unsetenv("APP_KEY")
	e := Set{DefaultKey: "654321"}
	k, err := e.AppKey()
	if err != nil {
		t.Fatalf("an unexpected error occured, %v", err)
	}
	if k != "654321" {
		t.Fatalf("expected the app key to be 654321, got %v instead", k)
	}
}
<commit_msg>fix tests<commit_after>package env

import (
	"os"
	"testing"
)

func TestCanGetTheEnvAppModeDefault(t *testing.T) {
	e := Set{}
	if e.AppMode() != "development" {
		t.Errorf("expected the environment to be development, got %v instead", e.AppMode())
	}
}

func TestCanDefineTheAppModeUsingEnvVars(t *testing.T) {
	e := Set{}
	os.Setenv("APP_MODE", "production")
	if e.AppMode() != "production" {
		t.Fatalf("expected the environment to be production, got %v instead", e.AppMode())
	}
	if e.AppMode() == "development" {
		t.Fatalf("expected the environment to be production, got %v instead", e.AppMode())
	}
}

func TestGetOrWillReturnTheRequestedEnvVarOrTheDefaultThatWasPassed(t *testing.T) {
	e := Set{}
	notSet := e.GetOr("APP_FAKE_VAR", "https://mccallister.io")
	if notSet != "https://mccallister.io" {
		t.Fatalf("expected the environment var to be development, got %v instead", e.AppMode())
	}
	os.Setenv("APP_FAKE_VAR", "1234")
	set := e.GetOr("APP_FAKE_VAR", "https://www.google.com")
	if set != "1234" {
		t.Fatalf("expected the environment var to be 1234, got %v instead", e.AppMode())
	}
	if set == "https://www.google.com" {
		t.Fatalf("expected the environment var to be 1234, got %v instead", e.AppMode())
	}
}

func TestEnvCanSetADefaultModeToOverrideThePackageDefaultAppMode(t *testing.T) {
	// clear the env to be sure
	os.Unsetenv("APP_MODE")
	e := Set{DefaultMode: "staging"}
	m := e.AppMode()
	if m != "staging" {
		t.Fatalf("expected the app mode to be staging, got %v instead", m)
	}
}

func TestCanGetTheAppKeyFromEnv(t *testing.T) {
	os.Setenv("APP_KEY", "1234")
	e := Set{}
	k, err := e.AppKey()
	if err != nil {
		t.Fatalf("could not get the AppKey from the Env, got %v instead", err)
	}
	if k != "1234" {
		t.Fatalf("expected the key to not be empty, got %v instead", k)
	}
}

func TestGettingTheAppKeyWithoutTheEnvVarReturnsAnError(t *testing.T) {
	os.Unsetenv("APP_KEY")
	e := Set{}
	_, err := e.AppKey()
	if err == nil {
		t.Fatal("expected an error, but none was returned")
	}
}

func TestDefaultAppKeyCanBeSetAndReturnedIfTheAppKeyIsNotSetInEnv(t *testing.T) {
	os.Unsetenv("APP_KEY")
	e := Set{DefaultKey: "654321"}
	k, err := e.AppKey()
	if err != nil {
		t.Fatalf("an unexpected error occured, %v", err)
	}
	if k != "654321" {
		t.Fatalf("expected the app key to be 654321, got %v instead", k)
	}
}
<|endoftext|>