<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"syscall"

	"github.com/codegangsta/cli"

	"github.com/learnin/fail-notifier/plugin"
)

type config struct {
	Plugins []interface{}
}

var plugins = map[string]*plugin.Plugin{}

func main() {
	app := cli.NewApp()
	app.Name = "fail-notifier"
	app.Version = "0.0.1"
	app.Author = "Manabu Inoue"
	app.Email = ""
	app.HideVersion = true
	app.EnableBashCompletion = true
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "help, h",
			Usage: "show help",
		},
		cli.BoolFlag{
			Name:  "version, v",
			Usage: "show the version",
		},
		// FIXME configファイル指定可能にする
	}
	app.HideHelp = true
	app.ArgsUsage = "command"
	app.Usage = "Send notifications when a given command fails"
	app.Action = func(c *cli.Context) {
		action(c)
	}
	app.Run(os.Args)
}

func action(c *cli.Context) {
	if !(c.Args().Present()) {
		cli.ShowAppHelp(c)
		return
	}

	cfg, err := loadConfig("config.json")
	if err != nil {
		panic(err)
	}
	if len(cfg.Plugins) == 0 {
		// FIXME
		println("config error. no plugins")
		return
	}
	if !setupPlugins(&cfg) {
		// FIXME
		println("config error. the plugin does not exist.")
		return
	}

	var cmd *exec.Cmd
	if len(c.Args()) == 1 {
		cmd = exec.Command(c.Args().First())
	} else {
		cmd = exec.Command(c.Args().First(), c.Args().Tail()...)
	}
	var stdout bytes.Buffer
	var stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr

	if err := cmd.Run(); err != nil {
		if err2, ok := err.(*exec.ExitError); ok {
			if s, ok := err2.Sys().(syscall.WaitStatus); ok {
				// FIXME 文字列渡しではなく、exitStatus/stdout/stderrをもった構造体を渡すようにする
				notice(fmt.Sprintf("command failed. exitStatus=%v stdout=%v stderr=%v", s.ExitStatus(), stdout.String(), stderr.String()))
				return
			} else {
				// Unix や Winodws とは異なり、 exec.ExitError.Sys() が syscall.WaitStatus ではないOSの場合
				notice(fmt.Sprintf("command failed. stdout=%v stderr=%v", stdout.String(), stderr.String()))
				return
			}
		} else {
			// may be returned for I/O problems.
			notice(fmt.Sprintf("command can't execute. err=%v", err))
			return
		}
	}
	notice(stdout.String())
}

func loadConfig(path string) (config, error) {
	var cfg config
	cfgJson, err := ioutil.ReadFile(path)
	if err != nil {
		return cfg, err
	}
	if err := json.Unmarshal(cfgJson, &cfg); err != nil {
		return cfg, err
	}
	return cfg, nil
}

func setupPlugins(cfg *config) bool {
	for _, p := range cfg.Plugins {
		p, ok := p.(map[string]interface{})
		if !ok {
			return false
		}
		typeName, ok := p["name"].(string)
		if !ok {
			return false
		}
		typeName = "plugin." + typeName
		pluginInstance, ok := plugin.CreatePlugin(typeName, p)
		if !ok {
			return false
		}
		plugins[typeName] = pluginInstance
	}
	return true
}

func notice(s string) {
	for _, p := range plugins {
		(*p).Notice(s)
	}
}
<commit_msg>Add config option<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"syscall"

	"github.com/codegangsta/cli"

	"github.com/learnin/fail-notifier/plugin"
)

type config struct {
	Plugins []interface{}
}

var plugins = map[string]*plugin.Plugin{}

func main() {
	app := cli.NewApp()
	app.Name = "fail-notifier"
	app.Version = "0.0.1"
	app.Author = "Manabu Inoue"
	app.Email = ""
	app.HideVersion = true
	app.EnableBashCompletion = true
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "help, h",
			Usage: "show help",
		},
		cli.BoolFlag{
			Name:  "version, v",
			Usage: "show the version",
		},
		cli.StringFlag{
			Name:  "config, c",
			Value: "config.json",
			Usage: "specify the path to the configuration file",
		},
	}
	app.HideHelp = true
	app.ArgsUsage = "command"
	app.Usage = "Send notifications when a given command fails"
	app.Action = func(c *cli.Context) {
		action(c)
	}
	app.Run(os.Args)
}

func action(c *cli.Context) {
	if !(c.Args().Present()) {
		cli.ShowAppHelp(c)
		return
	}

	cfg, err := loadConfig(c.String("config"))
	if err != nil {
		panic(err)
	}
	if len(cfg.Plugins) == 0 {
		// FIXME
		println("config error. no plugins")
		return
	}
	if !setupPlugins(&cfg) {
		// FIXME
		println("config error. the plugin does not exist.")
		return
	}

	var cmd *exec.Cmd
	if len(c.Args()) == 1 {
		cmd = exec.Command(c.Args().First())
	} else {
		cmd = exec.Command(c.Args().First(), c.Args().Tail()...)
	}
	var stdout bytes.Buffer
	var stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr

	if err := cmd.Run(); err != nil {
		if err2, ok := err.(*exec.ExitError); ok {
			if s, ok := err2.Sys().(syscall.WaitStatus); ok {
				// FIXME 文字列渡しではなく、exitStatus/stdout/stderrをもった構造体を渡すようにする
				notice(fmt.Sprintf("command failed. exitStatus=%v stdout=%v stderr=%v", s.ExitStatus(), stdout.String(), stderr.String()))
				return
			} else {
				// Unix や Winodws とは異なり、 exec.ExitError.Sys() が syscall.WaitStatus ではないOSの場合
				notice(fmt.Sprintf("command failed. stdout=%v stderr=%v", stdout.String(), stderr.String()))
				return
			}
		} else {
			// may be returned for I/O problems.
			notice(fmt.Sprintf("command can't execute. err=%v", err))
			return
		}
	}
	notice(stdout.String())
}

func loadConfig(path string) (config, error) {
	var cfg config
	cfgJson, err := ioutil.ReadFile(path)
	if err != nil {
		return cfg, err
	}
	if err := json.Unmarshal(cfgJson, &cfg); err != nil {
		return cfg, err
	}
	return cfg, nil
}

func setupPlugins(cfg *config) bool {
	for _, p := range cfg.Plugins {
		p, ok := p.(map[string]interface{})
		if !ok {
			return false
		}
		typeName, ok := p["name"].(string)
		if !ok {
			return false
		}
		typeName = "plugin." + typeName
		pluginInstance, ok := plugin.CreatePlugin(typeName, p)
		if !ok {
			return false
		}
		plugins[typeName] = pluginInstance
	}
	return true
}

func notice(s string) {
	for _, p := range plugins {
		(*p).Notice(s)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"syscall"

	"github.com/codegangsta/cli"

	"github.com/learnin/fail-notifier/plugin"
)

type config struct {
	Plugins []interface{}
}

var plugins = map[string]*plugin.Plugin{}

func main() {
	app := cli.NewApp()
	app.Name = "fail-notifier"
	app.Version = "0.0.1"
	app.Author = "Manabu Inoue"
	app.Email = ""
	app.HideVersion = true
	app.EnableBashCompletion = true
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "help, h",
			Usage: "show help",
		},
		cli.BoolFlag{
			Name:  "version, v",
			Usage: "show the version",
		},
		cli.StringFlag{
			Name:  "config, c",
			Value: "config.json",
			Usage: "specify the path to the configuration file",
		},
	}
	app.HideHelp = true
	app.ArgsUsage = "command"
	app.Usage = "Send notifications when a given command fails"
	app.Action = func(c *cli.Context) {
		action(c)
	}
	app.Run(os.Args)
}

func action(c *cli.Context) {
	if !(c.Args().Present()) {
		cli.ShowAppHelp(c)
		return
	}

	cfg, err := loadConfig(c.String("config"))
	if err != nil {
		panic(err)
	}
	if len(cfg.Plugins) == 0 {
		// FIXME
		println("config error. no plugins")
		return
	}
	if !setupPlugins(&cfg) {
		// FIXME
		println("config error. the plugin does not exist.")
		return
	}

	var cmd *exec.Cmd
	if len(c.Args()) == 1 {
		cmd = exec.Command(c.Args().First())
	} else {
		cmd = exec.Command(c.Args().First(), c.Args().Tail()...)
	}
	var stdout bytes.Buffer
	var stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr

	if err := cmd.Run(); err != nil {
		if err2, ok := err.(*exec.ExitError); ok {
			if s, ok := err2.Sys().(syscall.WaitStatus); ok {
				// FIXME 文字列渡しではなく、exitStatus/stdout/stderrをもった構造体を渡すようにする
				notice(fmt.Sprintf("command failed. exitStatus=%v stdout=%v stderr=%v", s.ExitStatus(), stdout.String(), stderr.String()))
				return
			} else {
				// Unix や Winodws とは異なり、 exec.ExitError.Sys() が syscall.WaitStatus ではないOSの場合
				notice(fmt.Sprintf("command failed. stdout=%v stderr=%v", stdout.String(), stderr.String()))
				return
			}
		} else {
			// may be returned for I/O problems.
			notice(fmt.Sprintf("command can't execute. err=%v", err))
			return
		}
	}
}

func loadConfig(path string) (config, error) {
	var cfg config
	cfgJson, err := ioutil.ReadFile(path)
	if err != nil {
		return cfg, err
	}
	if err := json.Unmarshal(cfgJson, &cfg); err != nil {
		return cfg, err
	}
	return cfg, nil
}

func setupPlugins(cfg *config) bool {
	for _, p := range cfg.Plugins {
		p, ok := p.(map[string]interface{})
		if !ok {
			return false
		}
		typeName, ok := p["name"].(string)
		if !ok {
			return false
		}
		typeName = "plugin." + typeName
		pluginInstance, ok := plugin.CreatePlugin(typeName, p)
		if !ok {
			return false
		}
		plugins[typeName] = pluginInstance
	}
	return true
}

func notice(s string) {
	for _, p := range plugins {
		(*p).Notice(s)
	}
}
<commit_msg>Improve error message<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"syscall"

	"github.com/codegangsta/cli"

	"github.com/learnin/fail-notifier/plugin"
)

type config struct {
	Plugins []interface{}
}

var plugins = map[string]*plugin.Plugin{}

func main() {
	app := cli.NewApp()
	app.Name = "fail-notifier"
	app.Version = "0.0.1"
	app.Author = "Manabu Inoue"
	app.Email = ""
	app.HideVersion = true
	app.EnableBashCompletion = true
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "help, h",
			Usage: "show help",
		},
		cli.BoolFlag{
			Name:  "version, v",
			Usage: "show the version",
		},
		cli.StringFlag{
			Name:  "config, c",
			Value: "config.json",
			Usage: "specify the path to the configuration file",
		},
	}
	app.HideHelp = true
	app.ArgsUsage = "command"
	app.Usage = "Send notifications when a given command fails"
	app.Action = func(c *cli.Context) {
		action(c)
	}
	app.Run(os.Args)
}

func action(c *cli.Context) {
	if !(c.Args().Present()) {
		cli.ShowAppHelp(c)
		return
	}

	cfg, err := loadConfig(c.String("config"))
	if err != nil {
		panic(err)
	}
	if len(cfg.Plugins) == 0 {
		// FIXME
		println("config error. no plugins")
		return
	}
	if !setupPlugins(&cfg) {
		// FIXME
		println("config error. the plugin does not exist.")
		return
	}

	var cmd *exec.Cmd
	command := c.Args().First()
	if len(c.Args()) == 1 {
		cmd = exec.Command(command)
	} else {
		cmd = exec.Command(command, c.Args().Tail()...)
	}
	var stdout bytes.Buffer
	var stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr

	if err := cmd.Run(); err != nil {
		if err2, ok := err.(*exec.ExitError); ok {
			if s, ok := err2.Sys().(syscall.WaitStatus); ok {
				// FIXME 文字列渡しではなく、exitStatus/stdout/stderrをもった構造体を渡すようにする
				notice(fmt.Sprintf("%s failed. exitStatus=%v stdout=%v stderr=%v", command, s.ExitStatus(), stdout.String(), stderr.String()))
				return
			} else {
				// Unix や Winodws とは異なり、 exec.ExitError.Sys() が syscall.WaitStatus ではないOSの場合
				notice(fmt.Sprintf("%s failed. stdout=%v stderr=%v", command, stdout.String(), stderr.String()))
				return
			}
		} else {
			// may be returned for I/O problems.
			notice(fmt.Sprintf("%s can't execute. err=%v", command, err))
			return
		}
	}
}

func loadConfig(path string) (config, error) {
	var cfg config
	cfgJson, err := ioutil.ReadFile(path)
	if err != nil {
		return cfg, err
	}
	if err := json.Unmarshal(cfgJson, &cfg); err != nil {
		return cfg, err
	}
	return cfg, nil
}

func setupPlugins(cfg *config) bool {
	for _, p := range cfg.Plugins {
		p, ok := p.(map[string]interface{})
		if !ok {
			return false
		}
		typeName, ok := p["name"].(string)
		if !ok {
			return false
		}
		typeName = "plugin." + typeName
		pluginInstance, ok := plugin.CreatePlugin(typeName, p)
		if !ok {
			return false
		}
		plugins[typeName] = pluginInstance
	}
	return true
}

func notice(s string) {
	for _, p := range plugins {
		(*p).Notice(s)
	}
}
<|endoftext|>


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

package proto

import (
	"crypto/rand"
	"crypto/rsa"
	"fmt"
	"io"
	"testing"
	"time"
)

type fakeAuthorizer struct {
}

func (self *fakeAuthorizer) Authenticate(service, name, token string) (bool, error) {
	if service != "service" {
		return false, nil
	}
	if name != "username" {
		return false, nil
	}
	if token != "token" {
		return false, nil
	}
	return true, nil
}

func testMessageExchange(addr string, token string, msgs ...*Message) error {
	c2sConn, s2cConn, err := buildServerClient(addr)
	if err != nil {
		return err
	}
	defer c2sConn.Close()
	defer s2cConn.Close()
	priv, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		return err
	}
	pub := &priv.PublicKey

	ch := make(chan bool)
	var ec error
	var es error
	go func() {
		defer func() {
			ch <- true
		}()
		cliConn, err := Dial(c2sConn, pub, "service", "username", token)
		if err != nil {
			es = fmt.Errorf("Client: Auth error: %v", err)
			return
		}
		for i, msg := range msgs {
			m, err := cliConn.ReadMessage()
			if err != nil {
				ec = err
				return
			}
			if !m.Eq(msg) {
				ec = fmt.Errorf("%vth message corrupted", i)
				return
			}
		}
		ec = nil
	}()
	go func() {
		defer func() {
			ch <- true
		}()
		auth := &fakeAuthorizer{}
		servConn, err := AuthConn(s2cConn, priv, auth, 800*time.Millisecond)
		if err != nil {
			es = fmt.Errorf("Server: Auth error: %v", err)
			return
		}
		// Make sure we have cleared the deadline
		time.Sleep(1 * time.Second)
		for _, msg := range msgs {
			err := servConn.WriteMessage(msg, true, true)
			if err != nil {
				es = err
				return
			}
		}
	}()
	i := 0
	for _ = range ch {
		if es != nil {
			return es
		}
		if ec != nil {
			return ec
		}
		i++
		if i >= 2 {
			break
		}
	}
	return nil
}

func randomMessage() *Message {
	msg := new(Message)
	msg.Body = make([]byte, 10)
	io.ReadFull(rand.Reader, msg.Body)
	msg.Header = make(map[string]string, 2)
	msg.Header["aaa"] = "hello"
	msg.Header["aa"] = "hell"
	return msg
}

func TestExchangingSingleMessage(t *testing.T) {
	msg := randomMessage()
	err := testMessageExchange("127.0.0.1:8088", "token", msg)
	if err != nil {
		t.Errorf("%v", err)
	}
	return
}

func TestAuthFail(t *testing.T) {
	msg := randomMessage()
	err := testMessageExchange("127.0.0.1:8088", "wrong token", msg)
	if err == nil {
		t.Errorf("Should auth faile")
	}
	return
}
<commit_msg>Passed the basic test cases.<commit_after>/*
 * Copyright 2012 Nan Deng
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package proto

import (
	"crypto/rand"
	"crypto/rsa"
	"fmt"
	"io"
	"testing"
)

func testMessageExchange(addr string, msgs ...*Message) error {
	c2sConn, s2cConn, err := buildServerClient(addr)
	if err != nil {
		return err
	}
	defer c2sConn.Close()
	defer s2cConn.Close()
	priv, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		return err
	}
	pub := &priv.PublicKey

	ch := make(chan bool)
	var ec error
	var es error
	go func() {
		defer func() {
			ch <- true
		}()
		ks, err := ClientKeyExchange(pub, c2sConn)
		if err != nil {
			es = fmt.Errorf("Client: key ex error: %v", err)
			return
		}
		cmdio := ks.ClientCommandIO(c2sConn)
		cliConn := NewConn(cmdio, "service", "username", c2sConn, nil)
		for i, msg := range msgs {
			m, err := cliConn.ReadMessage()
			if err != nil {
				ec = err
				return
			}
			if !m.Eq(msg) {
				ec = fmt.Errorf("%vth message corrupted", i)
				return
			}
		}
		ec = nil
	}()
	go func() {
		defer func() {
			ch <- true
		}()
		ks, err := ServerKeyExchange(priv, s2cConn)
		if err != nil {
			es = fmt.Errorf("Server: key ex error: %v", err)
			return
		}
		cmdio := ks.ServerCommandIO(s2cConn)
		servConn := NewConn(cmdio, "service", "username", s2cConn, nil)
		for _, msg := range msgs {
			err := servConn.WriteMessage(msg, true, true)
			if err != nil {
				es = err
				return
			}
		}
	}()
	i := 0
	for _ = range ch {
		if es != nil {
			return es
		}
		if ec != nil {
			return ec
		}
		i++
		if i >= 2 {
			break
		}
	}
	return nil
}

func randomMessage() *Message {
	msg := new(Message)
	msg.Body = make([]byte, 10)
	io.ReadFull(rand.Reader, msg.Body)
	msg.Header = make(map[string]string, 2)
	msg.Header["aaa"] = "hello"
	msg.Header["aa"] = "hell"
	return msg
}

func TestExchangingSingleMessage(t *testing.T) {
	msg := randomMessage()
	err := testMessageExchange("127.0.0.1:8088", msg)
	if err != nil {
		t.Errorf("%v", err)
	}
	return
}

<|endoftext|>


<commit_before>// Package geom implements fast and GC-efficient Open Geo Consortium-style
// geometries.
package geom

import (
	"errors"
	"fmt"
	"math"
)

// A Layout describes the meaning of an N-dimensional coordinate. Layout(N) for
// N > 4 is a valid layout, in which case the first dimensions are interpreted
// to be X, Y, Z, and M and extra dimensions have no special meaning.  M values
// are considered part of a linear referencing system (e.g. classical time or
// distance along a path). 1-dimensional layouts are not supported.
type Layout int

const (
	// NoLayout is an unknown layout
	NoLayout Layout = iota
	// XY is a 2D layout (X and Y)
	XY
	// XYZ is 3D layout (X, Y, and Z)
	XYZ
	// XYM is a 2D layout with an M value
	XYM
	// XYZM is a 3D layout with an M value
	XYZM
)

// An ErrLayoutMismatch is returned when geometries with different layouts
// cannot be combined.
type ErrLayoutMismatch struct {
	Got  Layout
	Want Layout
}

func (e ErrLayoutMismatch) Error() string {
	return fmt.Sprintf("geom: layout mismatch, got %s, want %s", e.Got, e.Want)
}

// An ErrSRIDMismatch is returned when an SRID does not match the expected
// SRID.
type ErrSRIDMismatch struct {
	Got  int
	Want int
}

func (e ErrSRIDMismatch) Error() string {
	return fmt.Sprintf("geom: SRID mismatch, got %d, want %d", e.Got, e.Want)
}

// An ErrStrideMismatch is returned when the stride does not match the expected
// stride.
type ErrStrideMismatch struct {
	Got  int
	Want int
}

func (e ErrStrideMismatch) Error() string {
	return fmt.Sprintf("geom: stride mismatch, got %d, want %d", e.Got, e.Want)
}

// An ErrUnsupportedLayout is returned when the requested layout is not
// supported.
type ErrUnsupportedLayout Layout

func (e ErrUnsupportedLayout) Error() string {
	return fmt.Sprintf("geom: unsupported layout %s", Layout(e))
}

// An ErrUnsupportedType is returned when the requested type is not supported.
type ErrUnsupportedType struct {
	Value interface{}
}

func (e ErrUnsupportedType) Error() string {
	return fmt.Sprintf("geom: unsupported type %T", e.Value)
}

// A Coord represents an N-dimensional coordinate.
type Coord []float64

// X returns the x coordinate of the coordinate.  X is assumed to be the first ordinate
func (c Coord) X() float64 {
	return c[0]
}

// Y returns the x coordinate of the coordinate.  Y is assumed to be the second ordinate
func (c Coord) Y() float64 {
	return c[1]
}

// Set copies the ordinate data from the other coord to this coord
func (c Coord) Set(other Coord) {
	copy(c, other)
}

// Equal compares that all ordinates are the same in this and the other coords.
// It is assumed that this coord and other coord both have the same (provided) layout
func (c Coord) Equal(layout Layout, other Coord) bool {

	numOrds := len(c)

	if layout.Stride() < numOrds {
		numOrds = layout.Stride()
	}

	if (len(c) < layout.Stride() || len(other) < layout.Stride()) && len(c) != len(other) {
		return false
	}

	for i := 0; i < numOrds; i++ {
		if math.IsNaN(c[i]) || math.IsNaN(other[i]) {
			if !math.IsNaN(c[i]) || !math.IsNaN(other[i]) {
				return false
			}
		} else if c[i] != other[i] {
			return false
		}
	}

	return true
}

// T is a generic interface implemented by all geometry types.
type T interface {
	Layout() Layout
	Stride() int
	Bounds() *Bounds
	FlatCoords() []float64
	Ends() []int
	Endss() [][]int
	SRID() int
}

// MIndex returns the index of the M dimension, or -1 if the l does not have an M dimension.
func (l Layout) MIndex() int {
	switch l {
	case NoLayout, XY, XYZ:
		return -1
	case XYM:
		return 2
	case XYZM:
		return 3
	default:
		return 3
	}
}

// Stride returns l's number of dimensions.
func (l Layout) Stride() int {
	switch l {
	case NoLayout:
		return 0
	case XY:
		return 2
	case XYZ:
		return 3
	case XYM:
		return 3
	case XYZM:
		return 4
	default:
		return int(l)
	}
}

// String returns a human-readable string representing l.
func (l Layout) String() string {
	switch l {
	case NoLayout:
		return "NoLayout"
	case XY:
		return "XY"
	case XYZ:
		return "XYZ"
	case XYM:
		return "XYM"
	case XYZM:
		return "XYZM"
	default:
		return fmt.Sprintf("Layout(%d)", int(l))
	}
}

// ZIndex returns the index of l's Z dimension, or -1 if l does not have a Z dimension.
func (l Layout) ZIndex() int {
	switch l {
	case NoLayout, XY, XYM:
		return -1
	default:
		return 2
	}
}

// Must panics if err is not nil, otherwise it returns g.
func Must(g T, err error) T {
	if err != nil {
		panic(err)
	}
	return g
}

var (
	errIncorrectEnd         = errors.New("geom: incorrect end")
	errLengthStrideMismatch = errors.New("geom: length/stride mismatch")
	errMisalignedEnd        = errors.New("geom: misaligned end")
	errNonEmptyEnds         = errors.New("geom: non-empty ends")
	errNonEmptyEndss        = errors.New("geom: non-empty endss")
	errNonEmptyFlatCoords   = errors.New("geom: non-empty flatCoords")
	errOutOfOrderEnd        = errors.New("geom: out-of-order end")
	errStrideLayoutMismatch = errors.New("geom: stride/layout mismatch")
)
<commit_msg>Add Coord.Clone<commit_after>// Package geom implements fast and GC-efficient Open Geo Consortium-style
// geometries.
package geom

import (
	"errors"
	"fmt"
	"math"
)

// A Layout describes the meaning of an N-dimensional coordinate. Layout(N) for
// N > 4 is a valid layout, in which case the first dimensions are interpreted
// to be X, Y, Z, and M and extra dimensions have no special meaning.  M values
// are considered part of a linear referencing system (e.g. classical time or
// distance along a path). 1-dimensional layouts are not supported.
type Layout int

const (
	// NoLayout is an unknown layout
	NoLayout Layout = iota
	// XY is a 2D layout (X and Y)
	XY
	// XYZ is 3D layout (X, Y, and Z)
	XYZ
	// XYM is a 2D layout with an M value
	XYM
	// XYZM is a 3D layout with an M value
	XYZM
)

// An ErrLayoutMismatch is returned when geometries with different layouts
// cannot be combined.
type ErrLayoutMismatch struct {
	Got  Layout
	Want Layout
}

func (e ErrLayoutMismatch) Error() string {
	return fmt.Sprintf("geom: layout mismatch, got %s, want %s", e.Got, e.Want)
}

// An ErrSRIDMismatch is returned when an SRID does not match the expected
// SRID.
type ErrSRIDMismatch struct {
	Got  int
	Want int
}

func (e ErrSRIDMismatch) Error() string {
	return fmt.Sprintf("geom: SRID mismatch, got %d, want %d", e.Got, e.Want)
}

// An ErrStrideMismatch is returned when the stride does not match the expected
// stride.
type ErrStrideMismatch struct {
	Got  int
	Want int
}

func (e ErrStrideMismatch) Error() string {
	return fmt.Sprintf("geom: stride mismatch, got %d, want %d", e.Got, e.Want)
}

// An ErrUnsupportedLayout is returned when the requested layout is not
// supported.
type ErrUnsupportedLayout Layout

func (e ErrUnsupportedLayout) Error() string {
	return fmt.Sprintf("geom: unsupported layout %s", Layout(e))
}

// An ErrUnsupportedType is returned when the requested type is not supported.
type ErrUnsupportedType struct {
	Value interface{}
}

func (e ErrUnsupportedType) Error() string {
	return fmt.Sprintf("geom: unsupported type %T", e.Value)
}

// A Coord represents an N-dimensional coordinate.
type Coord []float64

// Clone returns a deep copy of c.
func (c Coord) Clone() Coord {
	clone := make(Coord, len(c))
	copy(clone, c)
	return clone
}

// X returns the x coordinate of the coordinate.  X is assumed to be the first ordinate
func (c Coord) X() float64 {
	return c[0]
}

// Y returns the x coordinate of the coordinate.  Y is assumed to be the second ordinate
func (c Coord) Y() float64 {
	return c[1]
}

// Set copies the ordinate data from the other coord to this coord
func (c Coord) Set(other Coord) {
	copy(c, other)
}

// Equal compares that all ordinates are the same in this and the other coords.
// It is assumed that this coord and other coord both have the same (provided) layout
func (c Coord) Equal(layout Layout, other Coord) bool {

	numOrds := len(c)

	if layout.Stride() < numOrds {
		numOrds = layout.Stride()
	}

	if (len(c) < layout.Stride() || len(other) < layout.Stride()) && len(c) != len(other) {
		return false
	}

	for i := 0; i < numOrds; i++ {
		if math.IsNaN(c[i]) || math.IsNaN(other[i]) {
			if !math.IsNaN(c[i]) || !math.IsNaN(other[i]) {
				return false
			}
		} else if c[i] != other[i] {
			return false
		}
	}

	return true
}

// T is a generic interface implemented by all geometry types.
type T interface {
	Layout() Layout
	Stride() int
	Bounds() *Bounds
	FlatCoords() []float64
	Ends() []int
	Endss() [][]int
	SRID() int
}

// MIndex returns the index of the M dimension, or -1 if the l does not have an M dimension.
func (l Layout) MIndex() int {
	switch l {
	case NoLayout, XY, XYZ:
		return -1
	case XYM:
		return 2
	case XYZM:
		return 3
	default:
		return 3
	}
}

// Stride returns l's number of dimensions.
func (l Layout) Stride() int {
	switch l {
	case NoLayout:
		return 0
	case XY:
		return 2
	case XYZ:
		return 3
	case XYM:
		return 3
	case XYZM:
		return 4
	default:
		return int(l)
	}
}

// String returns a human-readable string representing l.
func (l Layout) String() string {
	switch l {
	case NoLayout:
		return "NoLayout"
	case XY:
		return "XY"
	case XYZ:
		return "XYZ"
	case XYM:
		return "XYM"
	case XYZM:
		return "XYZM"
	default:
		return fmt.Sprintf("Layout(%d)", int(l))
	}
}

// ZIndex returns the index of l's Z dimension, or -1 if l does not have a Z dimension.
func (l Layout) ZIndex() int {
	switch l {
	case NoLayout, XY, XYM:
		return -1
	default:
		return 2
	}
}

// Must panics if err is not nil, otherwise it returns g.
func Must(g T, err error) T {
	if err != nil {
		panic(err)
	}
	return g
}

var (
	errIncorrectEnd         = errors.New("geom: incorrect end")
	errLengthStrideMismatch = errors.New("geom: length/stride mismatch")
	errMisalignedEnd        = errors.New("geom: misaligned end")
	errNonEmptyEnds         = errors.New("geom: non-empty ends")
	errNonEmptyEndss        = errors.New("geom: non-empty endss")
	errNonEmptyFlatCoords   = errors.New("geom: non-empty flatCoords")
	errOutOfOrderEnd        = errors.New("geom: out-of-order end")
	errStrideLayoutMismatch = errors.New("geom: stride/layout mismatch")
)
<|endoftext|>


<commit_before>package cli

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

	log "github.com/Sirupsen/logrus"
	"github.com/bitrise-io/bitrise-cli/bitrise"
	"github.com/bitrise-io/goinp/goinp"
	"github.com/codegangsta/cli"
)

func doSetup(c *cli.Context) {
	log.Infoln("[BITRISE_CLI] - Setup - Still work-in-progress")
	log.Infoln("Detected OS:", runtime.GOOS)
	switch runtime.GOOS {
	case "darwin":
		if err := doSetupOnOSX(); err != nil {
			log.Fatalln("Setup failed:", err)
		}
	case "linux":
		if err := doSetupOnLinux(); err != nil {
			log.Fatalln("Setup failed:", err)
		}
	default:
		log.Fatalln("Sorry, unsupported platform :(")
	}

	// guide
	fmt.Println()
	log.Infoln("We're ready to rock!!")
	fmt.Println()
	log.Infoln("To start using bitrise-cli:")
	log.Infoln("* cd into your project's directory (if you're not there already)")
	log.Infoln("* call: bitrise-cli init")
	log.Infoln("* follow the guide")
	fmt.Println()
	log.Infoln("That's all :)")
}

func checkProgramInstalledPath(clcommand string) (string, error) {
	cmd := exec.Command("which", clcommand)
	cmd.Stderr = os.Stderr
	outBytes, err := cmd.Output()
	outStr := string(outBytes)
	return strings.TrimSpace(outStr), err

	// var stdoutBuff bytes.Buffer
	// cmd := exec.Command("which", clcommand)
	// cmd.Stdin = os.Stdin
	// cmd.Stdout = &stdoutBuff
	// cmd.Stderr = os.Stderr
	// cmdErr := cmd.Run()
	// return string(stdoutBuff.Bytes()), cmdErr
}

func checkIsHomebrewInstalled() error {
	brewRubyInstallCmdString := `$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"`
	officialSiteURL := "http://brew.sh/"

	progInstallPth, err := checkProgramInstalledPath("brew")
	if err != nil {
		log.Infoln("")
		log.Infoln("It seems that Homebrew is not installed on your system.")
		log.Infoln("Homebrew (short: brew) is required in order to be able to auto-install all the bitrise dependencies.")
		log.Infoln("You should be able to install brew by copying this command and running it in your Terminal:")
		log.Infoln(brewRubyInstallCmdString)
		log.Infoln("You can find more information about Homebrew on it's official site at:", officialSiteURL)
		log.Infoln("Once the installation of brew is finished you can call the bitrise setup again.")
		return err
	}
	verStr, err := bitrise.RunCommandAndReturnStdout("brew", "--version")
	if err != nil {
		log.Infoln("")
		return errors.New("Failed to get version")
	}
	log.Infoln(" * [OK] Homebrew :", progInstallPth)
	log.Infoln("        version :", verStr)
	return nil
}

func checkIsAnsibleInstalled() error {
	progInstallPth, err := checkProgramInstalledPath("ansible")
	if err != nil {
		officialSiteURL := "http://www.ansible.com/home"
		officialGitHubURL := "https://github.com/ansible/ansible"
		log.Infoln("")
		log.Infoln("Ansible was not found.")
		log.Infoln("Ansible is used for system provisioning.")
		log.Infoln("You can find more information on Ansible's official website:", officialSiteURL)
		log.Infoln(" or on it's GitHub page:", officialGitHubURL)
		log.Infoln("You can install Ansible through brew:")
		log.Infoln("$ brew update && brew install ansible")
		isInstall, err := goinp.AskForBool("Would you like to install Ansible right now?")
		if err != nil {
			return err
		}
		if !isInstall {
			return errors.New("Ansible not found and install was not initiated.")
		}

		// Install
		log.Infoln("$ brew update --verbose")
		if err := bitrise.RunCommand("brew", "update", "--verbose"); err != nil {
			return err
		}
		log.Infoln("$ brew install ansible")
		if err := bitrise.RunCommand("brew", "install", "ansible"); err != nil {
			return err
		}

		// just check again
		return checkIsAnsibleInstalled()
	}
	log.Infoln(" * [OK] Ansible :", progInstallPth)
	return nil
}

func checkIsEnvmanInstalled() error {
	progInstallPth, err := checkProgramInstalledPath("envman")
	if err != nil {
		installCmdLines := []string{
			"curl -L https://github.com/bitrise-io/envman/releases/download/0.9.1/envman-`uname -s`-`uname -m` > /usr/local/bin/envman",
			"chmod +x /usr/local/bin/envman",
		}
		officialGitHubURL := "https://github.com/bitrise-io/envman"
		fmt.Println()
		log.Warnln("Envman was not found.")
		log.Infoln("You can find more information on envman's official GitHub page:", officialGitHubURL)
		fmt.Println()
		log.Infoln("You can install envman by running:")
		fmt.Println(strings.Join(installCmdLines, "\n"))
		fmt.Println()
		isInstall, err := goinp.AskForBool("Would you like to install envman automatically?")
		if err != nil {
			return err
		}
		if !isInstall {
			return errors.New("envman not found and install was not initiated")
		}

		// Install
		log.Infoln("Running script:")
		if err := bitrise.RunBashCommandLines(installCmdLines); err != nil {
			return err
		}

		// just check again
		return checkIsEnvmanInstalled()
	}
	verStr, err := bitrise.RunCommandAndReturnStdout("envman", "-version")
	if err != nil {
		log.Infoln("")
		return errors.New("Failed to get version")
	}
	log.Infoln(" * [OK] envman :", progInstallPth)
	log.Infoln("        version :", verStr)
	return nil
}

func checkIsStepmanInstalled() error {
	progInstallPth, err := checkProgramInstalledPath("stepman")
	if err != nil {
		log.Infoln("")
		log.Infoln("stepman was not found.")
		return errors.New("stepman was not found")
	}
	verStr, err := bitrise.RunCommandAndReturnStdout("stepman", "-version")
	if err != nil {
		log.Infoln("")
		return errors.New("Failed to get version")
	}
	log.Infoln(" * [OK] stepman :", progInstallPth)
	log.Infoln("        version :", verStr)
	return nil
}

func doSetupOnOSX() error {
	log.Infoln("Doing OS X specific setup")
	log.Infoln("Checking required tools...")
	if err := checkIsHomebrewInstalled(); err != nil {
		return errors.New("Homebrew failed to install")
	}
	// if err := checkIsAnsibleInstalled(); err != nil {
	// 	return errors.New("Ansible failed to install")
	// }
	if err := checkIsEnvmanInstalled(); err != nil {
		return errors.New(fmt.Sprint("Envman failed to install:", err))
	}
	if err := checkIsStepmanInstalled(); err != nil {
		return errors.New(fmt.Sprint("Stepman failed to install:", err))
	}
	log.Infoln("All the required tools are installed!")
	return nil
}

func doSetupOnLinux() error {
	return errors.New("doSetupOnLinux -- Coming soon")
}
<commit_msg>cool ASCII Art header in Setup<commit_after>package cli

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

	log "github.com/Sirupsen/logrus"
	"github.com/bitrise-io/bitrise-cli/bitrise"
	"github.com/bitrise-io/goinp/goinp"
	"github.com/codegangsta/cli"
)

func printBitriseHeaderASCIIArt() {
	// generated here: http://patorjk.com/software/taag/#p=display&f=ANSI%20Shadow&t=Bitrise
	fmt.Println(`
  ██████╗ ██╗████████╗██████╗ ██╗███████╗███████╗
  ██╔══██╗██║╚══██╔══╝██╔══██╗██║██╔════╝██╔════╝
  ██████╔╝██║   ██║   ██████╔╝██║███████╗█████╗
  ██╔══██╗██║   ██║   ██╔══██╗██║╚════██║██╔══╝
  ██████╔╝██║   ██║   ██║  ██║██║███████║███████╗
  ╚═════╝ ╚═╝   ╚═╝   ╚═╝  ╚═╝╚═╝╚══════╝╚══════╝`)
	fmt.Println()
}

func doSetup(c *cli.Context) {
	printBitriseHeaderASCIIArt()
	log.Infoln("[BITRISE_CLI] - Setup")
	log.Infoln("Detected OS:", runtime.GOOS)
	switch runtime.GOOS {
	case "darwin":
		if err := doSetupOnOSX(); err != nil {
			log.Fatalln("Setup failed:", err)
		}
	case "linux":
		if err := doSetupOnLinux(); err != nil {
			log.Fatalln("Setup failed:", err)
		}
	default:
		log.Fatalln("Sorry, unsupported platform :(")
	}

	// guide
	fmt.Println()
	log.Infoln("We're ready to rock!!")
	fmt.Println()
	log.Infoln("To start using bitrise-cli:")
	log.Infoln("* cd into your project's directory (if you're not there already)")
	log.Infoln("* call: bitrise-cli init")
	log.Infoln("* follow the guide")
	fmt.Println()
	log.Infoln("That's all :)")
}

func checkProgramInstalledPath(clcommand string) (string, error) {
	cmd := exec.Command("which", clcommand)
	cmd.Stderr = os.Stderr
	outBytes, err := cmd.Output()
	outStr := string(outBytes)
	return strings.TrimSpace(outStr), err

	// var stdoutBuff bytes.Buffer
	// cmd := exec.Command("which", clcommand)
	// cmd.Stdin = os.Stdin
	// cmd.Stdout = &stdoutBuff
	// cmd.Stderr = os.Stderr
	// cmdErr := cmd.Run()
	// return string(stdoutBuff.Bytes()), cmdErr
}

func checkIsHomebrewInstalled() error {
	brewRubyInstallCmdString := `$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"`
	officialSiteURL := "http://brew.sh/"

	progInstallPth, err := checkProgramInstalledPath("brew")
	if err != nil {
		log.Infoln("")
		log.Infoln("It seems that Homebrew is not installed on your system.")
		log.Infoln("Homebrew (short: brew) is required in order to be able to auto-install all the bitrise dependencies.")
		log.Infoln("You should be able to install brew by copying this command and running it in your Terminal:")
		log.Infoln(brewRubyInstallCmdString)
		log.Infoln("You can find more information about Homebrew on it's official site at:", officialSiteURL)
		log.Infoln("Once the installation of brew is finished you can call the bitrise setup again.")
		return err
	}
	verStr, err := bitrise.RunCommandAndReturnStdout("brew", "--version")
	if err != nil {
		log.Infoln("")
		return errors.New("Failed to get version")
	}
	log.Infoln(" * [OK] Homebrew :", progInstallPth)
	log.Infoln("        version :", verStr)
	return nil
}

func checkIsAnsibleInstalled() error {
	progInstallPth, err := checkProgramInstalledPath("ansible")
	if err != nil {
		officialSiteURL := "http://www.ansible.com/home"
		officialGitHubURL := "https://github.com/ansible/ansible"
		log.Infoln("")
		log.Infoln("Ansible was not found.")
		log.Infoln("Ansible is used for system provisioning.")
		log.Infoln("You can find more information on Ansible's official website:", officialSiteURL)
		log.Infoln(" or on it's GitHub page:", officialGitHubURL)
		log.Infoln("You can install Ansible through brew:")
		log.Infoln("$ brew update && brew install ansible")
		isInstall, err := goinp.AskForBool("Would you like to install Ansible right now?")
		if err != nil {
			return err
		}
		if !isInstall {
			return errors.New("Ansible not found and install was not initiated.")
		}

		// Install
		log.Infoln("$ brew update --verbose")
		if err := bitrise.RunCommand("brew", "update", "--verbose"); err != nil {
			return err
		}
		log.Infoln("$ brew install ansible")
		if err := bitrise.RunCommand("brew", "install", "ansible"); err != nil {
			return err
		}

		// just check again
		return checkIsAnsibleInstalled()
	}
	log.Infoln(" * [OK] Ansible :", progInstallPth)
	return nil
}

func checkIsEnvmanInstalled() error {
	progInstallPth, err := checkProgramInstalledPath("envman")
	if err != nil {
		installCmdLines := []string{
			"curl -L https://github.com/bitrise-io/envman/releases/download/0.9.1/envman-`uname -s`-`uname -m` > /usr/local/bin/envman",
			"chmod +x /usr/local/bin/envman",
		}
		officialGitHubURL := "https://github.com/bitrise-io/envman"
		fmt.Println()
		log.Warnln("Envman was not found.")
		log.Infoln("You can find more information on envman's official GitHub page:", officialGitHubURL)
		fmt.Println()
		log.Infoln("You can install envman by running:")
		fmt.Println(strings.Join(installCmdLines, "\n"))
		fmt.Println()
		isInstall, err := goinp.AskForBool("Would you like to install envman automatically?")
		if err != nil {
			return err
		}
		if !isInstall {
			return errors.New("envman not found and install was not initiated")
		}

		// Install
		log.Infoln("Running script:")
		if err := bitrise.RunBashCommandLines(installCmdLines); err != nil {
			return err
		}

		// just check again
		return checkIsEnvmanInstalled()
	}
	verStr, err := bitrise.RunCommandAndReturnStdout("envman", "-version")
	if err != nil {
		log.Infoln("")
		return errors.New("Failed to get version")
	}
	log.Infoln(" * [OK] envman :", progInstallPth)
	log.Infoln("        version :", verStr)
	return nil
}

func checkIsStepmanInstalled() error {
	progInstallPth, err := checkProgramInstalledPath("stepman")
	if err != nil {
		log.Infoln("")
		log.Infoln("stepman was not found.")
		return errors.New("stepman was not found")
	}
	verStr, err := bitrise.RunCommandAndReturnStdout("stepman", "-version")
	if err != nil {
		log.Infoln("")
		return errors.New("Failed to get version")
	}
	log.Infoln(" * [OK] stepman :", progInstallPth)
	log.Infoln("        version :", verStr)
	return nil
}

func doSetupOnOSX() error {
	log.Infoln("Doing OS X specific setup")
	log.Infoln("Checking required tools...")
	if err := checkIsHomebrewInstalled(); err != nil {
		return errors.New("Homebrew failed to install")
	}
	// if err := checkIsAnsibleInstalled(); err != nil {
	// 	return errors.New("Ansible failed to install")
	// }
	if err := checkIsEnvmanInstalled(); err != nil {
		return errors.New(fmt.Sprint("Envman failed to install:", err))
	}
	if err := checkIsStepmanInstalled(); err != nil {
		return errors.New(fmt.Sprint("Stepman failed to install:", err))
	}
	log.Infoln("All the required tools are installed!")
	return nil
}

func doSetupOnLinux() error {
	return errors.New("doSetupOnLinux -- Coming soon")
}
<|endoftext|>


<commit_before>package zipfs

import (
	"archive/zip"
	"fmt"
	"os"
	"strings"
	"path/filepath"
	"syscall"
	"log"
)

var _ = log.Printf

type ZipFile struct {
	*zip.File
}

func (me *ZipFile) Stat() *os.FileInfo {
	// TODO - do something intelligent with timestamps.
	return &os.FileInfo{
		Mode: syscall.S_IFREG | 0444,
		Size: int64(me.File.UncompressedSize),
	}
}

func (me *ZipFile) Data() []byte {
	data := make([]byte, me.UncompressedSize)
	zf := (*me)
	rc, err := zf.Open()
	if err != nil {
		panic("zip open")
	}

	start := 0
	for {
		n, err := rc.Read(data[start:])
		start += n
		if err == os.EOF {
			break
		}
		if err != nil && err != os.EOF {
			panic(fmt.Sprintf("read err: %v, n %v, sz %v", err, n, len(data)))
		}
	}
	return data
}

func zipFilesToTree(files []*zip.File) *MemTree {
	t := NewMemTree()
	for _, f := range files {
		parent := t
		comps := strings.Split(filepath.Clean(f.Name), "/", -1)
		base := ""

		// Ugh - zip files have directories separate.
		if !strings.HasSuffix(f.Name, "/") {
			base = comps[len(comps)-1]
			comps = comps[:len(comps)-1]
		}
		for _, c := range comps {
			parent = parent.FindDir(c)
		}
		if base != "" {
			parent.files[base] = &ZipFile{File: f}
		}
	}
	return t
}

// NewZipArchiveFileSystem creates a new file-system for the
// zip file named name.
func NewZipTree(name string) (*MemTree, os.Error) {
	r, err := zip.OpenReader(name)
	if err != nil {
		return nil, err
	}
	return zipFilesToTree(r.File), nil
}

func NewArchiveFileSystem(name string) (fs *MemTreeFileSystem, err os.Error) {
	var tree *MemTree
	if strings.HasSuffix(name, ".zip") {
		tree, err = NewZipTree(name)
	}
	if strings.HasSuffix(name, ".tar.gz") {
		tree, err = NewTarCompressedTree(name, "gz")
	}
	if strings.HasSuffix(name, ".tar.bz2") {
		tree, err = NewTarCompressedTree(name, "bz2")
	}
	if err != nil {
		return nil, err
	}

	if tree == nil {
		return nil, os.NewError(fmt.Sprintf("Unknown type for %v", name))
	}

	return NewMemTreeFileSystem(tree), nil
}
<commit_msg>Support plain tar files too.<commit_after>package zipfs

import (
	"archive/zip"
	"fmt"
	"os"
	"strings"
	"path/filepath"
	"syscall"
	"log"
)

var _ = log.Printf

type ZipFile struct {
	*zip.File
}

func (me *ZipFile) Stat() *os.FileInfo {
	// TODO - do something intelligent with timestamps.
	return &os.FileInfo{
		Mode: syscall.S_IFREG | 0444,
		Size: int64(me.File.UncompressedSize),
	}
}

func (me *ZipFile) Data() []byte {
	data := make([]byte, me.UncompressedSize)
	zf := (*me)
	rc, err := zf.Open()
	if err != nil {
		panic("zip open")
	}

	start := 0
	for {
		n, err := rc.Read(data[start:])
		start += n
		if err == os.EOF {
			break
		}
		if err != nil && err != os.EOF {
			panic(fmt.Sprintf("read err: %v, n %v, sz %v", err, n, len(data)))
		}
	}
	return data
}

func zipFilesToTree(files []*zip.File) *MemTree {
	t := NewMemTree()
	for _, f := range files {
		parent := t
		comps := strings.Split(filepath.Clean(f.Name), "/", -1)
		base := ""

		// Ugh - zip files have directories separate.
		if !strings.HasSuffix(f.Name, "/") {
			base = comps[len(comps)-1]
			comps = comps[:len(comps)-1]
		}
		for _, c := range comps {
			parent = parent.FindDir(c)
		}
		if base != "" {
			parent.files[base] = &ZipFile{File: f}
		}
	}
	return t
}

// NewZipArchiveFileSystem creates a new file-system for the
// zip file named name.
func NewZipTree(name string) (*MemTree, os.Error) {
	r, err := zip.OpenReader(name)
	if err != nil {
		return nil, err
	}
	return zipFilesToTree(r.File), nil
}

func NewArchiveFileSystem(name string) (fs *MemTreeFileSystem, err os.Error) {
	var tree *MemTree
	if strings.HasSuffix(name, ".zip") {
		tree, err = NewZipTree(name)
	}
	if strings.HasSuffix(name, ".tar.gz") {
		tree, err = NewTarCompressedTree(name, "gz")
	}
	if strings.HasSuffix(name, ".tar.bz2") {
		tree, err = NewTarCompressedTree(name, "bz2")
	}
	if strings.HasSuffix(name, ".tar") {
		f, err := os.Open(name)
		if err != nil {
			return nil, err
		}
		tree = NewTarTree(f)
	}
	if err != nil {
		return nil, err
	}

	if tree == nil {
		return nil, os.NewError(fmt.Sprintf("Unknown type for %v", name))
	}

	return NewMemTreeFileSystem(tree), nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/xml" // gelbooru parsing
	"errors"
	"fmt"
	"github.com/jcline/goty"
	"html"
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"regexp"
	"time"
)

var user = ""

var matchGelbooru = regexp.MustCompile(`(?:https?://|)\Qgelbooru.com/index.php?page=post&s=view&id=\E([\d]+)`)
var matchYouTube = regexp.MustCompile(`(?:https?://|)(?:www\.|)(youtu(?:\.be|be\.com)/[^ ]+)`)
var matchAmiAmi = regexp.MustCompile(`(?:https?://|)(?:www\.|)amiami.com/([^/ ]+/detail/[^ ]+)`)
var matchReddit = regexp.MustCompile(`(?:http://|)(?:www\.|https://pay\.|)redd(?:\.it|it\.com)/(r/[^/ ]+/comments/[^/ ]+)/?(?: .*|\z)`)

func auth(con *goty.IRCConn, writeMessage chan IRCMessage) {
	var pswd string
	_, err := fmt.Scanf("%s", &pswd)
	if err != nil {
		os.Exit(1)
	}

	msg := IRCMessage{channel: "NickServ", msg: "IDENTIFY Laala " + pswd}
	writeMessage <- msg
}

func main() {
	args := os.Args
	if len(args) < 4 {
		os.Exit(1)
	}

	con, err := goty.Dial(args[1], args[2], args[3])
	user = args[2]
	if err != nil {
		fmt.Fprintf(os.Stderr, "err: %s\n", err.Error())
	}

	writeMessage := make(chan IRCMessage, 1000)
	go messageHandler(con, writeMessage)

	amiAmiEvent := make(chan unparsedMessage, 1000)
	bastilleEvent := make(chan unparsedMessage, 1000)
	gelbooruEvent := make(chan unparsedMessage, 1000)
	redditEvent := make(chan unparsedMessage, 1000)
	youtubeEvent := make(chan unparsedMessage, 1000)

	go amiami(amiAmiEvent, writeMessage)
	go bastille(bastilleEvent, writeMessage)
	go gelbooru(gelbooruEvent, writeMessage)
	go reddit(redditEvent, writeMessage)
	go youtube(youtubeEvent, writeMessage)

	//auth(con, writeMessage)
	con.Write <- "JOIN " + args[4]

	for msg := range con.Read {
		prepared := unparsedMessage{msg, time.Now()}
		fmt.Printf("%s||%s\n", prepared.when, prepared.msg)

		switch {
		case matchAmiAmi.MatchString(msg):
			amiAmiEvent <- prepared
		case matchGelbooru.MatchString(msg):
			//gelbooruEvent <- matchGelbooru.FindAllStringSubmatch(msg, -1)[0][1]
		case matchReddit.MatchString(msg):
			redditEvent <- prepared
		case matchYouTube.MatchString(msg):
			youtubeEvent <- prepared
		default:
		}
	}
	con.Close()
}

type unparsedMessage struct {
	msg  string
	when time.Time
}

type IRCMessage struct {
	channel string
	msg     string
	user    string
}

func message(con *goty.IRCConn, msg IRCMessage) {
	con.Write <- "PRIVMSG " + msg.channel + " :" + msg.msg + "\r\n"
}

func messageHandler(con *goty.IRCConn, event chan IRCMessage) {
	allBooks := map[string]time.Time{}
	chanBooks := map[string]time.Time{}
	for msg := range event {
		now := time.Now()
		key := msg.channel + ":" + msg.user
		if now.Sub(allBooks[key]) < time.Second*10 || now.Sub(chanBooks[key]) < time.Second*2 {
			continue
		}
		allBooks[key] = now
		chanBooks[key] = now
		message(con, msg)
	}
}

var PRIVMSG = regexp.MustCompile(`:(.+)![^ ]+ PRIVMSG ([^ ]+) :(.*)`)

func getMsgInfo(msg string) (*IRCMessage, error) {
	// :nick!~realname@0.0.0.0 PRIVMSG #chan :msg
	imsg := new(IRCMessage)
	match := PRIVMSG.FindAllStringSubmatch(msg, -1)
	if len(match) < 1 {
		return imsg, errors.New("could not parse message")
	}
	if len(match[0]) < 3 {
		return imsg, errors.New("could not parse message")
	}
	imsg.user = user
	imsg.channel = match[0][2]
	if imsg.channel == user {
		imsg.channel = match[0][1]
	}
	imsg.msg = match[0][3]
	return imsg, nil
}

func bastille(event chan unparsedMessage, writeMessage chan IRCMessage) {
	msgs := []string{
		"Bastille, yo brodudedudebro!!!!1",
		"Bastille, wat up homie",
		"Bastille, word",
		"Bastille, duuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuude",
		"'sup Bastille?",
	}

	for msg := range event {
		parsed, err := getMsgInfo(msg.msg)
		if err != nil {
			continue
		}
		writeMessage <- IRCMessage{parsed.channel, msgs[rand.Intn(len(msgs))-1], parsed.user}
	}
}

type uriFunc func(*string) (*string, error)
type writeFunc func(*IRCMessage, *string) error

func scrapeAndSend(event chan unparsedMessage, findUri uriFunc, write writeFunc) {
	for msg := range event {
		parsed, err := getMsgInfo(msg.msg)
		if err != nil {
			fmt.Printf("%v\n", err)
			continue
		}

		uri, err := findUri(&parsed.msg)
		if err != nil {
			fmt.Printf("%v\n", err)
			continue
		}

		resp, err := http.Get(*uri)
		if err != nil {
			fmt.Printf("%v\n", err)
			continue
		}

		bodyBytes, err := ioutil.ReadAll(resp.Body)
		resp.Body.Close()
		if err != nil {
			fmt.Printf("%v\n", err)
			continue
		}
		body := string(bodyBytes)

		if write(parsed, &body) != nil {
			fmt.Printf("%v\n", err)
			continue
		}
	}
}

func getFirstMatch(re *regexp.Regexp, matchee *string) (*string, error) {
	match := re.FindAllStringSubmatch(*matchee, -1)
	if len(match) < 1 {
		return nil, errors.New("Could not match")
	}
	if len(match[0]) < 2 {
		return nil, errors.New("Could not match")
	}
	return &match[0][1], nil
}

func amiami(event chan unparsedMessage, writeMessage chan IRCMessage) {
	matchTitle := regexp.MustCompile(`.*<meta property="og:title" content="(.+)" />.*`)
	matchDiscount := regexp.MustCompile(`[0-9]+\%OFF `)
	scrapeAndSend(event, func(msg *string) (*string, error) {
		uri, err := getFirstMatch(matchAmiAmi, msg)
		if err != nil {
			return nil, err
		}

		fullUri := "http://amiami.com/" + *uri
		return &fullUri, nil
	},
		func(msg *IRCMessage, body *string) error {
			title, err := getFirstMatch(matchTitle, body)
			if err != nil {
				return err
			}

			writeMessage <- IRCMessage{msg.channel, "[AmiAmi]: " + matchDiscount.ReplaceAllLiteralString(*title, ""), msg.user}
			return nil
		})
}

func reddit(event chan unparsedMessage, writeMessage chan IRCMessage) {
	matchTitle := regexp.MustCompile(`.*<title>(.+)</title>.*`)

	scrapeAndSend(event, func(msg *string) (*string, error) {
		uri, err := getFirstMatch(matchReddit, msg)
		if err != nil {
			return nil, err
		}

		fullUri := "http://reddit.com/" + *uri
		return &fullUri, nil
	},
		func(msg *IRCMessage, body *string) error {
			title, err := getFirstMatch(matchTitle, body)
			if err != nil {
				return err
			}

			writeMessage <- IRCMessage{msg.channel, "[Reddit]: " + html.UnescapeString(*title), msg.user}
			return nil
		})
}

func youtube(event chan unparsedMessage, writeMessage chan IRCMessage) {
	matchTitle := regexp.MustCompile(`.*<title>(.+)(?: - YouTube){1}</title>.*`)
	matchUser := regexp.MustCompile(`.*<a[^>]+class="[^"]+yt-user-name[^>]+>([^<]+)</a>.*`)

	scrapeAndSend(event, func(msg *string) (*string, error) {
		uri, err := getFirstMatch(matchYouTube, msg)
		if err != nil {
			return nil, err
		}

		fullUri := "http://" + *uri
		return &fullUri, nil
	},
		func(msg *IRCMessage, body *string) error {
			title, err := getFirstMatch(matchTitle, body)
			if err != nil {
				return err
			}
			user, err := getFirstMatch(matchUser, body)
			if err != nil {
				return err
			}
			writeMessage <- IRCMessage{msg.channel, "[YouTube]: " + html.UnescapeString(*title+" uploaded by "+*user), msg.user}
			return nil
		})
}

func gelbooru(event chan unparsedMessage, writeMessage chan IRCMessage) {
	type Post struct {
		post string
		tags string `xml:",attr"`
	}

	for msg := range event {
		parsed, err := getMsgInfo(msg.msg)
		if err != nil {
			continue
		}

		resp, err := http.Get("http://gelbooru.com/index.php?page=dapi&s=post&q=index&tags&id=" + msg.msg)
		if err != nil {
			fmt.Printf("%v\n", err)
			continue
		}

		body, err := ioutil.ReadAll(resp.Body)
		resp.Body.Close()
		if err != nil {
			fmt.Printf("%v\n", err)
			continue
		}

		fmt.Printf("%s\n", body)

		var result Post

		err = xml.Unmarshal(body, &result)
		if err != nil {
			fmt.Printf("%v\n", err)
			continue
		}

		fmt.Printf("%s\n", result.tags)
		writeMessage <- IRCMessage{parsed.channel, "tobedone", parsed.user}
	}
}
<commit_msg>Uncomment auth call<commit_after>package main

import (
	"encoding/xml" // gelbooru parsing
	"errors"
	"fmt"
	"github.com/jcline/goty"
	"html"
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"regexp"
	"time"
)

var user = ""

var matchGelbooru = regexp.MustCompile(`(?:https?://|)\Qgelbooru.com/index.php?page=post&s=view&id=\E([\d]+)`)
var matchYouTube = regexp.MustCompile(`(?:https?://|)(?:www\.|)(youtu(?:\.be|be\.com)/[^ ]+)`)
var matchAmiAmi = regexp.MustCompile(`(?:https?://|)(?:www\.|)amiami.com/([^/ ]+/detail/[^ ]+)`)
var matchReddit = regexp.MustCompile(`(?:http://|)(?:www\.|https://pay\.|)redd(?:\.it|it\.com)/(r/[^/ ]+/comments/[^/ ]+)/?(?: .*|\z)`)

func auth(con *goty.IRCConn, writeMessage chan IRCMessage) {
	var pswd string
	_, err := fmt.Scanf("%s", &pswd)
	if err != nil {
		os.Exit(1)
	}

	msg := IRCMessage{channel: "NickServ", msg: "IDENTIFY Laala " + pswd}
	writeMessage <- msg
}

func main() {
	args := os.Args
	if len(args) < 4 {
		os.Exit(1)
	}

	con, err := goty.Dial(args[1], args[2], args[3])
	user = args[2]
	if err != nil {
		fmt.Fprintf(os.Stderr, "err: %s\n", err.Error())
	}

	writeMessage := make(chan IRCMessage, 1000)
	go messageHandler(con, writeMessage)

	amiAmiEvent := make(chan unparsedMessage, 1000)
	bastilleEvent := make(chan unparsedMessage, 1000)
	gelbooruEvent := make(chan unparsedMessage, 1000)
	redditEvent := make(chan unparsedMessage, 1000)
	youtubeEvent := make(chan unparsedMessage, 1000)

	go amiami(amiAmiEvent, writeMessage)
	go bastille(bastilleEvent, writeMessage)
	go gelbooru(gelbooruEvent, writeMessage)
	go reddit(redditEvent, writeMessage)
	go youtube(youtubeEvent, writeMessage)

	auth(con, writeMessage)
	con.Write <- "JOIN " + args[4]

	for msg := range con.Read {
		prepared := unparsedMessage{msg, time.Now()}
		fmt.Printf("%s||%s\n", prepared.when, prepared.msg)

		switch {
		case matchAmiAmi.MatchString(msg):
			amiAmiEvent <- prepared
		case matchGelbooru.MatchString(msg):
			//gelbooruEvent <- matchGelbooru.FindAllStringSubmatch(msg, -1)[0][1]
		case matchReddit.MatchString(msg):
			redditEvent <- prepared
		case matchYouTube.MatchString(msg):
			youtubeEvent <- prepared
		default:
		}
	}
	con.Close()
}

type unparsedMessage struct {
	msg  string
	when time.Time
}

type IRCMessage struct {
	channel string
	msg     string
	user    string
}

func message(con *goty.IRCConn, msg IRCMessage) {
	con.Write <- "PRIVMSG " + msg.channel + " :" + msg.msg + "\r\n"
}

func messageHandler(con *goty.IRCConn, event chan IRCMessage) {
	allBooks := map[string]time.Time{}
	chanBooks := map[string]time.Time{}
	for msg := range event {
		now := time.Now()
		key := msg.channel + ":" + msg.user
		if now.Sub(allBooks[key]) < time.Second*10 || now.Sub(chanBooks[key]) < time.Second*2 {
			continue
		}
		allBooks[key] = now
		chanBooks[key] = now
		message(con, msg)
	}
}

var PRIVMSG = regexp.MustCompile(`:(.+)![^ ]+ PRIVMSG ([^ ]+) :(.*)`)

func getMsgInfo(msg string) (*IRCMessage, error) {
	// :nick!~realname@0.0.0.0 PRIVMSG #chan :msg
	imsg := new(IRCMessage)
	match := PRIVMSG.FindAllStringSubmatch(msg, -1)
	if len(match) < 1 {
		return imsg, errors.New("could not parse message")
	}
	if len(match[0]) < 3 {
		return imsg, errors.New("could not parse message")
	}
	imsg.user = user
	imsg.channel = match[0][2]
	if imsg.channel == user {
		imsg.channel = match[0][1]
	}
	imsg.msg = match[0][3]
	return imsg, nil
}

func bastille(event chan unparsedMessage, writeMessage chan IRCMessage) {
	msgs := []string{
		"Bastille, yo brodudedudebro!!!!1",
		"Bastille, wat up homie",
		"Bastille, word",
		"Bastille, duuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuude",
		"'sup Bastille?",
	}

	for msg := range event {
		parsed, err := getMsgInfo(msg.msg)
		if err != nil {
			continue
		}
		writeMessage <- IRCMessage{parsed.channel, msgs[rand.Intn(len(msgs))-1], parsed.user}
	}
}

type uriFunc func(*string) (*string, error)
type writeFunc func(*IRCMessage, *string) error

func scrapeAndSend(event chan unparsedMessage, findUri uriFunc, write writeFunc) {
	for msg := range event {
		parsed, err := getMsgInfo(msg.msg)
		if err != nil {
			fmt.Printf("%v\n", err)
			continue
		}

		uri, err := findUri(&parsed.msg)
		if err != nil {
			fmt.Printf("%v\n", err)
			continue
		}

		resp, err := http.Get(*uri)
		if err != nil {
			fmt.Printf("%v\n", err)
			continue
		}

		bodyBytes, err := ioutil.ReadAll(resp.Body)
		resp.Body.Close()
		if err != nil {
			fmt.Printf("%v\n", err)
			continue
		}
		body := string(bodyBytes)

		if write(parsed, &body) != nil {
			fmt.Printf("%v\n", err)
			continue
		}
	}
}

func getFirstMatch(re *regexp.Regexp, matchee *string) (*string, error) {
	match := re.FindAllStringSubmatch(*matchee, -1)
	if len(match) < 1 {
		return nil, errors.New("Could not match")
	}
	if len(match[0]) < 2 {
		return nil, errors.New("Could not match")
	}
	return &match[0][1], nil
}

func amiami(event chan unparsedMessage, writeMessage chan IRCMessage) {
	matchTitle := regexp.MustCompile(`.*<meta property="og:title" content="(.+)" />.*`)
	matchDiscount := regexp.MustCompile(`[0-9]+\%OFF `)
	scrapeAndSend(event, func(msg *string) (*string, error) {
		uri, err := getFirstMatch(matchAmiAmi, msg)
		if err != nil {
			return nil, err
		}

		fullUri := "http://amiami.com/" + *uri
		return &fullUri, nil
	},
		func(msg *IRCMessage, body *string) error {
			title, err := getFirstMatch(matchTitle, body)
			if err != nil {
				return err
			}

			writeMessage <- IRCMessage{msg.channel, "[AmiAmi]: " + matchDiscount.ReplaceAllLiteralString(*title, ""), msg.user}
			return nil
		})
}

func reddit(event chan unparsedMessage, writeMessage chan IRCMessage) {
	matchTitle := regexp.MustCompile(`.*<title>(.+)</title>.*`)

	scrapeAndSend(event, func(msg *string) (*string, error) {
		uri, err := getFirstMatch(matchReddit, msg)
		if err != nil {
			return nil, err
		}

		fullUri := "http://reddit.com/" + *uri
		return &fullUri, nil
	},
		func(msg *IRCMessage, body *string) error {
			title, err := getFirstMatch(matchTitle, body)
			if err != nil {
				return err
			}

			writeMessage <- IRCMessage{msg.channel, "[Reddit]: " + html.UnescapeString(*title), msg.user}
			return nil
		})
}

func youtube(event chan unparsedMessage, writeMessage chan IRCMessage) {
	matchTitle := regexp.MustCompile(`.*<title>(.+)(?: - YouTube){1}</title>.*`)
	matchUser := regexp.MustCompile(`.*<a[^>]+class="[^"]+yt-user-name[^>]+>([^<]+)</a>.*`)

	scrapeAndSend(event, func(msg *string) (*string, error) {
		uri, err := getFirstMatch(matchYouTube, msg)
		if err != nil {
			return nil, err
		}

		fullUri := "http://" + *uri
		return &fullUri, nil
	},
		func(msg *IRCMessage, body *string) error {
			title, err := getFirstMatch(matchTitle, body)
			if err != nil {
				return err
			}
			user, err := getFirstMatch(matchUser, body)
			if err != nil {
				return err
			}
			writeMessage <- IRCMessage{msg.channel, "[YouTube]: " + html.UnescapeString(*title+" uploaded by "+*user), msg.user}
			return nil
		})
}

func gelbooru(event chan unparsedMessage, writeMessage chan IRCMessage) {
	type Post struct {
		post string
		tags string `xml:",attr"`
	}

	for msg := range event {
		parsed, err := getMsgInfo(msg.msg)
		if err != nil {
			continue
		}

		resp, err := http.Get("http://gelbooru.com/index.php?page=dapi&s=post&q=index&tags&id=" + msg.msg)
		if err != nil {
			fmt.Printf("%v\n", err)
			continue
		}

		body, err := ioutil.ReadAll(resp.Body)
		resp.Body.Close()
		if err != nil {
			fmt.Printf("%v\n", err)
			continue
		}

		fmt.Printf("%s\n", body)

		var result Post

		err = xml.Unmarshal(body, &result)
		if err != nil {
			fmt.Printf("%v\n", err)
			continue
		}

		fmt.Printf("%s\n", result.tags)
		writeMessage <- IRCMessage{parsed.channel, "tobedone", parsed.user}
	}
}
<|endoftext|>


<commit_before>/**
gp数据库连接
create by gloomy 2017-3-30 15:24:11
*/
package common

import (
	"database/sql"
	"fmt"
	"github.com/smtc/glog"
)

// GP数据库连接对象
// create by gloomy 2017-3-30 15:27:26
type GpDBStruct struct {
	DbUser string //数据库用户名
	DbHost string //数据库地址
	DbPort int    //数据库端口
	DbPass string //数据库密码
	DbName string //数据库库名
}

// GP数据库连接
// create by gloomy 2017-3-30 15:29:12
func GpSqlConntion(model GpDBStruct) (*sql.DB, error) {
	dbClause := fmt.Sprintf("postgres://%s:%s@%s:%d/%s?sslmode=disable", model.DbUser, model.DbPass, model.DbHost, model.DbPort, model.DbName)
	db, err := sql.Open("postgres", dbClause)
	if err != nil {
		return nil, fmt.Errorf("gp can't connection gpClause: %s err: %s ", dbClause, err.Error())
	}
	err = db.Ping()
	if err != nil {
		return nil, fmt.Errorf("gp can't ping dbClause: %s err: %s ", dbClause, err.Error())
	}
	return db, err
}

// GP数据库关闭
// create by gloomy 2017-3-30 15:39:10
func GpSqlClose(db *sql.DB) {
	db.Close()
}

// 查询方法
// create by gloomy 2017-3-30 16:04:53
// dbs数据库连接对象 model数据库对象 sqlStr 要执行的sql语句 param执行SQL的语句参数化传递
// 查询返回条数  错误对象输出
func GpSqlSelect(dbs *sql.DB, model GpDBStruct, sqlStr string, param ...interface{}) (*sql.Rows, error) {
	var (
		row *sql.Rows
		err error
	)
	err = dbs.Ping()
	if err != nil {
		GpSqlClose(dbs)
		dbs, err = GpSqlConntion(model)
		if err != nil {
			return nil, fmt.Errorf("GpSqlSelect gpConntion err! err: %s ", err.Error())
		}
	}
	if param == nil {
		row, err = dbs.Query(sqlStr)
	} else {
		row, err = dbs.Query(sqlStr, param...)
	}
	if err != nil {
		return nil, fmt.Errorf("GpSqlSelect query can't select sql: %s err: %s \n", sqlStr, err.Error())
	}
	return row, nil
}

/**
数据库运行方法
创建人:邵炜
创建时间:2015年12月29日17:33:06
修正时间：2017年03月11日16:21:36
输入参数: dbs数据库连接对象 model数据库对象 sqlStr 要执行的sql语句  param执行SQL的语句参数化传递
输出参数: 执行结果对象  错误对象输出
*/
func GpSqlExec(dbs *sql.DB, model GpDBStruct, sqlStr string, param ...interface{}) (sql.Result, error) {
	var (
		exec sql.Result
		err  error
	)

	err = dbs.Ping()

	if err != nil {
		GpSqlClose(dbs)
		dbs, err = GpSqlConntion(model)
		if err != nil {
			return nil, fmt.Errorf("GpSqlSelect gpConntion err! err: %s ", err.Error())
		}
	}

	if param == nil {
		exec, err = dbs.Exec(sqlStr)
	} else {
		exec, err = dbs.Exec(sqlStr, param...)
	}

	if err != nil {
		return nil, fmt.Errorf("GpSqlExec query can't select sql: %s err: %s \n", sqlStr, err.Error())
	}

	return exec, err
}
<commit_msg>修正处理,增加gp类<commit_after>/**
gp数据库连接
create by gloomy 2017-3-30 15:24:11
*/
package common

import (
	"database/sql"
	"fmt"
	_ "github.com/lib/pq"
)

// GP数据库连接对象
// create by gloomy 2017-3-30 15:27:26
type GpDBStruct struct {
	DbUser string //数据库用户名
	DbHost string //数据库地址
	DbPort int    //数据库端口
	DbPass string //数据库密码
	DbName string //数据库库名
}

// GP数据库连接
// create by gloomy 2017-3-30 15:29:12
func GpSqlConntion(model GpDBStruct) (*sql.DB, error) {
	dbClause := fmt.Sprintf("postgres://%s:%s@%s:%d/%s?sslmode=disable", model.DbUser, model.DbPass, model.DbHost, model.DbPort, model.DbName)
	db, err := sql.Open("postgres", dbClause)
	if err != nil {
		return nil, fmt.Errorf("gp can't connection gpClause: %s err: %s ", dbClause, err.Error())
	}
	err = db.Ping()
	if err != nil {
		return nil, fmt.Errorf("gp can't ping dbClause: %s err: %s ", dbClause, err.Error())
	}
	return db, err
}

// GP数据库关闭
// create by gloomy 2017-3-30 15:39:10
func GpSqlClose(db *sql.DB) {
	db.Close()
}

// 查询方法
// create by gloomy 2017-3-30 16:04:53
// dbs数据库连接对象 model数据库对象 sqlStr 要执行的sql语句 param执行SQL的语句参数化传递
// 查询返回条数  错误对象输出
func GpSqlSelect(dbs *sql.DB, model GpDBStruct, sqlStr string, param ...interface{}) (*sql.Rows, error) {
	var (
		row *sql.Rows
		err error
	)
	err = dbs.Ping()
	if err != nil {
		GpSqlClose(dbs)
		dbs, err = GpSqlConntion(model)
		if err != nil {
			return nil, fmt.Errorf("GpSqlSelect gpConntion err! err: %s ", err.Error())
		}
	}
	if param == nil {
		row, err = dbs.Query(sqlStr)
	} else {
		row, err = dbs.Query(sqlStr, param...)
	}
	if err != nil {
		return nil, fmt.Errorf("GpSqlSelect query can't select sql: %s err: %s \n", sqlStr, err.Error())
	}
	return row, nil
}

/**
数据库运行方法
创建人:邵炜
创建时间:2015年12月29日17:33:06
修正时间：2017年03月11日16:21:36
输入参数: dbs数据库连接对象 model数据库对象 sqlStr 要执行的sql语句  param执行SQL的语句参数化传递
输出参数: 执行结果对象  错误对象输出
*/
func GpSqlExec(dbs *sql.DB, model GpDBStruct, sqlStr string, param ...interface{}) (sql.Result, error) {
	var (
		exec sql.Result
		err  error
	)

	err = dbs.Ping()

	if err != nil {
		GpSqlClose(dbs)
		dbs, err = GpSqlConntion(model)
		if err != nil {
			return nil, fmt.Errorf("GpSqlSelect gpConntion err! err: %s ", err.Error())
		}
	}

	if param == nil {
		exec, err = dbs.Exec(sqlStr)
	} else {
		exec, err = dbs.Exec(sqlStr, param...)
	}

	if err != nil {
		return nil, fmt.Errorf("GpSqlExec query can't select sql: %s err: %s \n", sqlStr, err.Error())
	}

	return exec, err
}
<|endoftext|>


<commit_before>package gopisysfs

import (
	"fmt"
	"path/filepath"
	"sync"
	"time"
)

type GPIOFlag struct {
	flag bool
	err  error
}

type GPIOMode int

const (
	GPIOInput GPIOMode = iota
	GPIOOutput
	GPIOOutputLow
	GPIOOutputHigh

	// from https://www.kernel.org/doc/Documentation/gpio/sysfs.txt
	direction_in     = "in"
	direction_out    = "out"
	direction_outlow = "low"
	direction_outhi  = "high"

	// the longest time to wait for an operation to complete
	timelimit = time.Second

	low  = "0"
	high = "1"
)

type GPIOPort interface {
	State() string
	IsEnabled() bool
	Enable() error
	Reset() error
	SetMode(GPIOMode) error
	IsOutput() (bool, error)
	SetValue(bool) error
	Value() (bool, error)
	Values() (<-chan bool, error)
}

type gport struct {
	mu        sync.Mutex
	host      *pi
	port      int
	sport     string
	folder    string
	value     string
	direction string
	edge      string
	export    string
	unexport  string
}

func newGPIO(host *pi, port int) *gport {

	sport := fmt.Sprintf("%d", port)
	gpio := host.gpiodir
	folder := filepath.Join(gpio, fmt.Sprintf("gpio%s", sport))
	export := filepath.Join(gpio, "export")
	unexport := filepath.Join(gpio, "unexport")

	return &gport{
		mu:        sync.Mutex{},
		host:      host,
		port:      port,
		sport:     sport,
		folder:    folder,
		value:     filepath.Join(folder, "value"),
		direction: filepath.Join(folder, "direction"),
		edge:      filepath.Join(folder, "edge"),
		export:    export,
		unexport:  unexport,
	}
}

func (p *gport) String() string {
	return p.folder
}

func (p *gport) IsEnabled() bool {

	defer p.unlock(p.lock())

	return checkFile(p.folder)
}

func (p *gport) Enable() error {

	defer p.unlock(p.lock())

	if checkFile(p.folder) {
		return nil
	}

	info("GPIO Enabling %v\n", p)

	if err := writeFile(p.export, p.sport); err != nil {
		return err
	}

	start := time.Now()
	// wait for folder to arrive....
	// and for all control files to exist and be readable
	// there's an issue with timeouts perhaps.... but that's OK.
	for _, fname := range []string{p.folder, p.direction, p.value, p.edge} {
		remaining := timelimit - time.Since(start)

		//fmt.Printf("Await timeout reevaluated to be %v\n", remaining)

		ch, err := awaitFileCreate(fname, remaining)
		if err != nil {
			return err
		}
		if err := <-ch; err != nil {
			return err
		}
	}

	info("GPIO Enabled %v\n", p)

	return nil
}

func (p *gport) Reset() error {

	defer p.unlock(p.lock())

	if !checkFile(p.folder) {
		// already reset
		return nil
	}
	info("GPIO Resetting  %v\n", p)
	if err := writeFile(p.unexport, p.sport); err != nil {
		return err
	}
	ch, err := awaitFileRemove(p.folder, timelimit)
	if err != nil {
		return err
	}

	if err := <-ch; err != nil {
		return err
	}

	// wait for the file to be removed, and then return
	info("GPIO Reset  %v\n", p)
	return nil

}

// GPIOResetAsync will reset the specified port and only return when it is complete
// Configure will
func (p *gport) SetMode(mode GPIOMode) error {

	defer p.unlock(p.lock())

	err := p.checkEnabled()
	if err != nil {
		return err
	}

	switch mode {
	case GPIOInput:
		return p.writeDirection(direction_in)
	case GPIOOutput:
		return p.writeDirection(direction_out)
	case GPIOOutputHigh:
		return p.writeDirection(direction_outhi)
	case GPIOOutputLow:
		return p.writeDirection(direction_outlow)
	}
	return fmt.Errorf("GPIOMode %v does not exist")
}

func (p *gport) IsOutput() (bool, error) {

	defer p.unlock(p.lock())

	err := p.checkEnabled()
	if err != nil {
		return false, err
	}
	d, err := p.readDirection()
	if err != nil {
		return false, err
	}
	return d != "in", nil
}

func (p *gport) State() string {

	defer p.unlock(p.lock())

	base := fmt.Sprintf("GPIO %v: ", p.sport)
	if !checkFile(p.folder) {
		return base + "Reset"
	}

	dir, err := p.readDirection()
	if err != nil {
		return fmt.Sprintf("%v%v", base, err)
	}
	val, err := p.readValue()
	if err != nil {
		return fmt.Sprintf("%v%v", base, err)
	}

	return fmt.Sprintf("%v %v with value %v", base, dir, val)
}

func (p *gport) Value() (bool, error) {

	defer p.unlock(p.lock())

	err := p.checkEnabled()
	if err != nil {
		return false, err
	}

	d, err := p.readValue()
	if err != nil {
		return false, err
	}

	return d == "1", nil
}

func (p *gport) SetValue(value bool) error {

	defer p.unlock(p.lock())

	err := p.checkEnabled()
	if err != nil {
		return err
	}

	val := low
	if value {
		val = high
	}

	return p.writeValue(val)

}

func (p *gport) Values() (<-chan bool, error) {
	defer p.unlock(p.lock())
	return nil, nil
}

func (p *gport) writeDirection(direction string) error {
	info("GPIO Setting mode on  %v to %v\n", p, direction)

	return writeFile(p.direction, direction)
}

func (p *gport) readDirection() (string, error) {
	return readFile(p.direction)
}

func (p *gport) writeValue(value string) error {
	return writeFile(p.value, value)
}

func (p *gport) readValue() (string, error) {
	return readFile(p.value)
}

func (p *gport) checkEnabled() error {
	if checkFile(p.folder) {
		return nil
	}
	return fmt.Errorf("GPIO %v is not enabled", p.port)
}

func (p *gport) lock() bool {
	p.mu.Lock()
	return true
}

func (p *gport) unlock(bool) {
	p.mu.Unlock()
}
<commit_msg>Add info to set value<commit_after>package gopisysfs

import (
	"fmt"
	"path/filepath"
	"sync"
	"time"
)

type GPIOFlag struct {
	flag bool
	err  error
}

type GPIOMode int

const (
	GPIOInput GPIOMode = iota
	GPIOOutput
	GPIOOutputLow
	GPIOOutputHigh

	// from https://www.kernel.org/doc/Documentation/gpio/sysfs.txt
	direction_in     = "in"
	direction_out    = "out"
	direction_outlow = "low"
	direction_outhi  = "high"

	// the longest time to wait for an operation to complete
	timelimit = time.Second

	low  = "0"
	high = "1"
)

type GPIOPort interface {
	State() string
	IsEnabled() bool
	Enable() error
	Reset() error
	SetMode(GPIOMode) error
	IsOutput() (bool, error)
	SetValue(bool) error
	Value() (bool, error)
	Values() (<-chan bool, error)
}

type gport struct {
	mu        sync.Mutex
	host      *pi
	port      int
	sport     string
	folder    string
	value     string
	direction string
	edge      string
	export    string
	unexport  string
}

func newGPIO(host *pi, port int) *gport {

	sport := fmt.Sprintf("%d", port)
	gpio := host.gpiodir
	folder := filepath.Join(gpio, fmt.Sprintf("gpio%s", sport))
	export := filepath.Join(gpio, "export")
	unexport := filepath.Join(gpio, "unexport")

	return &gport{
		mu:        sync.Mutex{},
		host:      host,
		port:      port,
		sport:     sport,
		folder:    folder,
		value:     filepath.Join(folder, "value"),
		direction: filepath.Join(folder, "direction"),
		edge:      filepath.Join(folder, "edge"),
		export:    export,
		unexport:  unexport,
	}
}

func (p *gport) String() string {
	return p.folder
}

func (p *gport) IsEnabled() bool {

	defer p.unlock(p.lock())

	return checkFile(p.folder)
}

func (p *gport) Enable() error {

	defer p.unlock(p.lock())

	if checkFile(p.folder) {
		return nil
	}

	info("GPIO Enabling %v\n", p)

	if err := writeFile(p.export, p.sport); err != nil {
		return err
	}

	start := time.Now()
	// wait for folder to arrive....
	// and for all control files to exist and be readable
	// there's an issue with timeouts perhaps.... but that's OK.
	for _, fname := range []string{p.folder, p.direction, p.value, p.edge} {
		remaining := timelimit - time.Since(start)

		//fmt.Printf("Await timeout reevaluated to be %v\n", remaining)

		ch, err := awaitFileCreate(fname, remaining)
		if err != nil {
			return err
		}
		if err := <-ch; err != nil {
			return err
		}
	}

	info("GPIO Enabled %v\n", p)

	return nil
}

func (p *gport) Reset() error {

	defer p.unlock(p.lock())

	if !checkFile(p.folder) {
		// already reset
		return nil
	}
	info("GPIO Resetting  %v\n", p)
	if err := writeFile(p.unexport, p.sport); err != nil {
		return err
	}
	ch, err := awaitFileRemove(p.folder, timelimit)
	if err != nil {
		return err
	}

	if err := <-ch; err != nil {
		return err
	}

	// wait for the file to be removed, and then return
	info("GPIO Reset  %v\n", p)
	return nil

}

// GPIOResetAsync will reset the specified port and only return when it is complete
// Configure will
func (p *gport) SetMode(mode GPIOMode) error {

	defer p.unlock(p.lock())

	err := p.checkEnabled()
	if err != nil {
		return err
	}

	switch mode {
	case GPIOInput:
		return p.writeDirection(direction_in)
	case GPIOOutput:
		return p.writeDirection(direction_out)
	case GPIOOutputHigh:
		return p.writeDirection(direction_outhi)
	case GPIOOutputLow:
		return p.writeDirection(direction_outlow)
	}
	return fmt.Errorf("GPIOMode %v does not exist")
}

func (p *gport) IsOutput() (bool, error) {

	defer p.unlock(p.lock())

	err := p.checkEnabled()
	if err != nil {
		return false, err
	}
	d, err := p.readDirection()
	if err != nil {
		return false, err
	}
	return d != "in", nil
}

func (p *gport) State() string {

	defer p.unlock(p.lock())

	base := fmt.Sprintf("GPIO %v: ", p.sport)
	if !checkFile(p.folder) {
		return base + "Reset"
	}

	dir, err := p.readDirection()
	if err != nil {
		return fmt.Sprintf("%v%v", base, err)
	}
	val, err := p.readValue()
	if err != nil {
		return fmt.Sprintf("%v%v", base, err)
	}

	return fmt.Sprintf("%v %v with value %v", base, dir, val)
}

func (p *gport) Value() (bool, error) {

	defer p.unlock(p.lock())

	err := p.checkEnabled()
	if err != nil {
		return false, err
	}

	d, err := p.readValue()
	if err != nil {
		return false, err
	}

	return d == "1", nil
}

func (p *gport) SetValue(value bool) error {

	defer p.unlock(p.lock())

	err := p.checkEnabled()
	if err != nil {
		return err
	}

	info("GPIO Set Value on %v to %v\n", p, value)

	val := low
	if value {
		val = high
	}

	return p.writeValue(val)

}

func (p *gport) Values() (<-chan bool, error) {
	defer p.unlock(p.lock())
	return nil, nil
}

func (p *gport) writeDirection(direction string) error {
	info("GPIO Setting mode on  %v to %v\n", p, direction)

	return writeFile(p.direction, direction)
}

func (p *gport) readDirection() (string, error) {
	return readFile(p.direction)
}

func (p *gport) writeValue(value string) error {
	return writeFile(p.value, value)
}

func (p *gport) readValue() (string, error) {
	return readFile(p.value)
}

func (p *gport) checkEnabled() error {
	if checkFile(p.folder) {
		return nil
	}
	return fmt.Errorf("GPIO %v is not enabled", p.port)
}

func (p *gport) lock() bool {
	p.mu.Lock()
	return true
}

func (p *gport) unlock(bool) {
	p.mu.Unlock()
}
<|endoftext|>


<commit_before>// The gzmq package provides abstractions that make ZeroMQ more
// accessible to idiomatic Go.
//
// ZeroMQ's sockets and Go's channels are similar in purpose, but have
// some significant differences.  ZeroMQ's sockets can communicate
// across process and machine boundaries, while Go's channels cannot.
// Go's channels are thread-safe, while ZeroMQ's sockets are not.
//
// ZeroMQ's Poll() method and Go's "select" statement are attempts to
// solve the same problem: efficient reads from multiple sources of
// information.  However, ZeroMQ's Poll() method cannot be used to poll
// a combination of sockets and channels, while Go's "select" statement
// requires explicit code blocks for each information source.
//
// The Polling defined in this package is an attempt to make ZeroMQ sockets
// available, through a Poll() loop, as channels for use in Go "select"
// statements.
package gzmq

// TODO: make polling.fault available to callers outside this package.

import (
	"strconv"
	"sync"

	zmq "github.com/alecthomas/gozmq"
)

// A Polling is a ZeroMQ poll loop running in a goroutine.
type Polling interface {
	Include(zmq.Socket) (<-chan [][]byte, error)
	Sync(func())
	Close() error
}

type polling struct {
	notifySend zmq.Socket     // to notify goroutine of pending commands
	commands   chan func()    // pending commands
	items      []pollingItem  // sockets with their channels
	fault      error          // error, if any, that caused polling to stop
	closing    bool           // true if polling is either stopping or stopped
	running    sync.WaitGroup // becomes zero when polling is finished
}

type pollingItem struct {
	socket  zmq.Socket    // socket that is/will be polled
	channel chan [][]byte // messages that have been received
}

// NewPolling starts a ZeroMQ poll loop in a goroutine.
func NewPolling(context zmq.Context) (Polling, error) {
	notifySend, notifyRecv, err := newPair(context)
	if err != nil {
		return nil, err
	}
	p := polling{
		notifySend: notifySend,
		commands:   make(chan func(), 4),
		items: []pollingItem{
			pollingItem{notifyRecv, nil},
		},
	}
	p.running.Add(1)
	go p.loop(notifyRecv)
	return &p, nil
}

// Close causes the poll loop to exit, and blocks until it is done.
//
// Message channels will be closed, but polled sockets will be left
// open.
func (p *polling) Close() error {
	p.Sync(func() { p.closing = true })
	p.notifySend.Close()
	p.running.Wait()
	return nil
}

// Include adds a ZeroMQ socket to a poll loop, so that it will be
// polled for incoming messages.
//
// Notice that while this polling is running you must not use the socket
// in any other way except within the scope of a func passed to the Lock
// method.
//
// The returned channel must be used to receive messages from this
// socket until the polling is closed.
func (p *polling) Include(s zmq.Socket) (result <-chan [][]byte, err error) {
	done := make(chan int)
	p.Sync(func() {
		var ok bool
		for _, existing := range p.items {
			if existing.socket == s {
				ok = true
			}
		}
		if !ok {
			ch := make(chan [][]byte, 4)
			p.items = append(p.items, pollingItem{s, ch})
			result = ch
		}
		done <- 1
	})
	<-done
	return
}

// Sync executes a function outside of the poll.
//
// Useful for performing operations on the sockets being polled.
func (p *polling) Sync(f func()) {
	p.notifySend.Send([]byte{0}, 0)
	p.commands <- f
}

func (p *polling) loop(notifyRecv zmq.Socket) {

	defer func() {
		// Close all "received message" channels :
		for _, pi := range p.items {
			if pi.channel != nil {
				close(pi.channel)
			}
		}

		// For sockets that may have queued out-going messages, this call
		// may block until they are sent:
		notifyRecv.Close()

		// Indicate to any waiting code that this poll loop is all done:
		p.running.Done()
	}()

	for !p.closing {

		// TODO: refactor so that pollItems is re-constructed only when
		// necessary.
		pollItems := make(zmq.PollItems, len(p.items))
		for i, item := range p.items {
			pollItems[i].Socket = item.socket
			pollItems[i].Events = zmq.POLLIN
		}

		// Poll with an infinite timeout: this loop never spins idle.
		_, err := zmq.Poll(pollItems, -1)

		// Possible errors returned from Poll() are: ETERM, meaning a
		// context was closed; EFAULT, meaning a mistake was made in
		// setting up the PollItems list; and EINTR, meaning a signal
		// was delivered before any events were available.  Here, we
		// treat all errors the same:
		if err != nil {
			p.fault = err
			p.closing = true
			break
		}

		// Check for incoming commands first.  For each message
		// available in notifyRecv, dequeue one command and execute it:
		if (pollItems[0].REvents & zmq.POLLIN) != 0 {
			_, err := notifyRecv.RecvMultipart(0)
			if err != nil {
				p.fault = err
				p.closing = true
				break
			}
			cmd := <-p.commands
			cmd()
		}

		// Check all other sockets, sending any available messages to
		// their associated channels:
		for i := 1; i < len(pollItems); i++ {
			item := pollItems[i]
			if (item.REvents & zmq.POLLIN) != 0 {
				msg, err := item.Socket.RecvMultipart(0)
				if err != nil {
					p.fault = err
					p.closing = true
					continue //?
				}
				pitem := p.items[i]
				pitem.channel <- msg
			}
		}
	}
}

func newPair(c zmq.Context) (send zmq.Socket, recv zmq.Socket, err error) {
	send, err = c.NewSocket(zmq.PUSH)
	if err != nil {
		return
	}
	recv, err = c.NewSocket(zmq.PULL)
	if err != nil {
		return
	}
	addr := newInprocAddress()
	err = send.Bind(addr)
	if err != nil {
		return
	}
	err = recv.Connect(addr)
	if err != nil {
		return
	}
	return
}

var inprocNext = 1

func newInprocAddress() string {
	inprocNext += 1
	return "inproc://github.com/jtacoma/gzmq/" + strconv.Itoa(inprocNext-1)
}
<commit_msg>Fix a lingering typo.<commit_after>// The gzmq package provides abstractions that make ZeroMQ more
// accessible to idiomatic Go.
//
// ZeroMQ's sockets and Go's channels are similar in purpose, but have
// some significant differences.  ZeroMQ's sockets can communicate
// across process and machine boundaries, while Go's channels cannot.
// Go's channels are thread-safe, while ZeroMQ's sockets are not.
//
// ZeroMQ's Poll() method and Go's "select" statement are attempts to
// solve the same problem: efficient reads from multiple sources of
// information.  However, ZeroMQ's Poll() method cannot be used to poll
// a combination of sockets and channels, while Go's "select" statement
// requires explicit code blocks for each information source.
//
// The Polling defined in this package is an attempt to make ZeroMQ sockets
// available, through a Poll() loop, as channels for use in Go "select"
// statements.
package gzmq

// TODO: make polling.fault available to callers outside this package.

import (
	"strconv"
	"sync"

	zmq "github.com/alecthomas/gozmq"
)

// A Polling is a ZeroMQ poll loop running in a goroutine.
type Polling interface {
	Include(zmq.Socket) (<-chan [][]byte, error)
	Sync(func())
	Close() error
}

type polling struct {
	notifySend zmq.Socket     // to notify goroutine of pending commands
	commands   chan func()    // pending commands
	items      []pollingItem  // sockets with their channels
	fault      error          // error, if any, that caused polling to stop
	closing    bool           // true if polling is either stopping or stopped
	running    sync.WaitGroup // becomes zero when polling is finished
}

type pollingItem struct {
	socket  zmq.Socket    // socket that is/will be polled
	channel chan [][]byte // messages that have been received
}

// NewPolling starts a ZeroMQ poll loop in a goroutine.
func NewPolling(context zmq.Context) (Polling, error) {
	notifySend, notifyRecv, err := newPair(context)
	if err != nil {
		return nil, err
	}
	p := polling{
		notifySend: notifySend,
		commands:   make(chan func(), 4),
		items: []pollingItem{
			pollingItem{notifyRecv, nil},
		},
	}
	p.running.Add(1)
	go p.loop(notifyRecv)
	return &p, nil
}

// Close causes the poll loop to exit, and blocks until it is done.
//
// Message channels will be closed, but polled sockets will be left
// open.
func (p *polling) Close() error {
	p.Sync(func() { p.closing = true })
	p.notifySend.Close()
	p.running.Wait()
	return nil
}

// Include adds a ZeroMQ socket to a poll loop, so that it will be
// polled for incoming messages.
//
// Notice that while this polling is running you must not use the socket
// in any other way except within the scope of a func passed to the Sync
// method.
//
// The returned channel must be used to receive messages from this
// socket until the polling is closed.
func (p *polling) Include(s zmq.Socket) (result <-chan [][]byte, err error) {
	done := make(chan int)
	p.Sync(func() {
		var ok bool
		for _, existing := range p.items {
			if existing.socket == s {
				ok = true
			}
		}
		if !ok {
			ch := make(chan [][]byte, 4)
			p.items = append(p.items, pollingItem{s, ch})
			result = ch
		}
		done <- 1
	})
	<-done
	return
}

// Sync executes a function outside of the poll.
//
// Useful for performing operations on the sockets being polled.
func (p *polling) Sync(f func()) {
	p.notifySend.Send([]byte{0}, 0)
	p.commands <- f
}

func (p *polling) loop(notifyRecv zmq.Socket) {

	defer func() {
		// Close all "received message" channels :
		for _, pi := range p.items {
			if pi.channel != nil {
				close(pi.channel)
			}
		}

		// For sockets that may have queued out-going messages, this call
		// may block until they are sent:
		notifyRecv.Close()

		// Indicate to any waiting code that this poll loop is all done:
		p.running.Done()
	}()

	for !p.closing {

		// TODO: refactor so that pollItems is re-constructed only when
		// necessary.
		pollItems := make(zmq.PollItems, len(p.items))
		for i, item := range p.items {
			pollItems[i].Socket = item.socket
			pollItems[i].Events = zmq.POLLIN
		}

		// Poll with an infinite timeout: this loop never spins idle.
		_, err := zmq.Poll(pollItems, -1)

		// Possible errors returned from Poll() are: ETERM, meaning a
		// context was closed; EFAULT, meaning a mistake was made in
		// setting up the PollItems list; and EINTR, meaning a signal
		// was delivered before any events were available.  Here, we
		// treat all errors the same:
		if err != nil {
			p.fault = err
			p.closing = true
			break
		}

		// Check for incoming commands first.  For each message
		// available in notifyRecv, dequeue one command and execute it:
		if (pollItems[0].REvents & zmq.POLLIN) != 0 {
			_, err := notifyRecv.RecvMultipart(0)
			if err != nil {
				p.fault = err
				p.closing = true
				break
			}
			cmd := <-p.commands
			cmd()
		}

		// Check all other sockets, sending any available messages to
		// their associated channels:
		for i := 1; i < len(pollItems); i++ {
			item := pollItems[i]
			if (item.REvents & zmq.POLLIN) != 0 {
				msg, err := item.Socket.RecvMultipart(0)
				if err != nil {
					p.fault = err
					p.closing = true
					continue //?
				}
				pitem := p.items[i]
				pitem.channel <- msg
			}
		}
	}
}

func newPair(c zmq.Context) (send zmq.Socket, recv zmq.Socket, err error) {
	send, err = c.NewSocket(zmq.PUSH)
	if err != nil {
		return
	}
	recv, err = c.NewSocket(zmq.PULL)
	if err != nil {
		return
	}
	addr := newInprocAddress()
	err = send.Bind(addr)
	if err != nil {
		return
	}
	err = recv.Connect(addr)
	if err != nil {
		return
	}
	return
}

var inprocNext = 1

func newInprocAddress() string {
	inprocNext += 1
	return "inproc://github.com/jtacoma/gzmq/" + strconv.Itoa(inprocNext-1)
}
<|endoftext|>


<commit_before>package client

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"
	"strconv"
	"strings"

	"github.com/deis/workflow-cli/version"
)

// CreateHTTPClient creates a HTTP Client with proper SSL options.
func CreateHTTPClient(sslVerify bool) *http.Client {
	tr := &http.Transport{
		TLSClientConfig:   &tls.Config{InsecureSkipVerify: !sslVerify},
		DisableKeepAlives: true,
		Proxy:             http.ProxyFromEnvironment,
	}
	return &http.Client{Transport: tr}
}

// Request makes a HTTP request on the controller.
func (c Client) Request(method string, path string, body []byte) (*http.Response, error) {
	url := c.ControllerURL

	if strings.Contains(path, "?") {
		parts := strings.Split(path, "?")
		url.Path = parts[0]
		url.RawQuery = parts[1]
	} else {
		url.Path = path
	}

	req, err := http.NewRequest(method, url.String(), bytes.NewBuffer(body))

	if err != nil {
		return nil, err
	}

	req.Header.Add("Content-Type", "application/json")

	if c.Token != "" {
		req.Header.Add("Authorization", "token "+c.Token)
	}

	addUserAgent(&req.Header)

	res, err := c.HTTPClient.Do(req)

	if err != nil {
		return nil, err
	}

	if err = checkForErrors(res, ""); err != nil {
		return nil, err
	}

	checkAPICompatibility(res.Header.Get("DEIS_API_VERSION"))

	return res, nil
}

// LimitedRequest allows limiting the number of responses in a request.
func (c Client) LimitedRequest(path string, results int) (string, int, error) {
	body, err := c.BasicRequest("GET", path+"?limit="+strconv.Itoa(results), nil)

	if err != nil {
		return "", -1, err
	}

	res := make(map[string]interface{})
	if err = json.Unmarshal([]byte(body), &res); err != nil {
		return "", -1, err
	}

	out, err := json.Marshal(res["results"].([]interface{}))

	if err != nil {
		return "", -1, err
	}

	return string(out), int(res["count"].(float64)), nil
}

// BasicRequest makes a simple http request on the controller.
func (c Client) BasicRequest(method string, path string, body []byte) (string, error) {
	res, err := c.Request(method, path, body)

	if err != nil {
		return "", err
	}
	defer res.Body.Close()

	resBody, err := ioutil.ReadAll(res.Body)

	if err != nil {
		return "", err
	}
	return string(resBody), checkForErrors(res, string(resBody))
}

func checkForErrors(res *http.Response, body string) error {

	// If response is not an error, return nil.
	if res.StatusCode > 199 && res.StatusCode < 400 {
		return nil
	}

	// Read the response body if none was provided.
	if body == "" {
		defer res.Body.Close()
		resBody, err := ioutil.ReadAll(res.Body)
		if err != nil {
			return err
		}
		body = string(resBody)
	}

	// Unmarshal the response as JSON, or return the status and body.
	bodyMap := make(map[string]interface{})
	if err := json.Unmarshal([]byte(body), &bodyMap); err != nil {
		return fmt.Errorf("\n%s\n%s\n", res.Status, body)
	}

	errorMessage := fmt.Sprintf("\n%s\n", res.Status)
	for key, value := range bodyMap {
		switch v := value.(type) {
		case string:
			errorMessage += fmt.Sprintf("%s: %s\n", key, v)
		case []interface{}:
			for _, subValue := range v {
				switch sv := subValue.(type) {
				case string:
					errorMessage += fmt.Sprintf("%s: %s\n", key, sv)
				default:
					fmt.Printf("Unexpected type in %s error message array. Contents: %v",
						reflect.TypeOf(value), sv)
				}
			}
		default:
			fmt.Printf("Cannot handle key %s in error message, type %s. Contents: %v",
				key, reflect.TypeOf(value), bodyMap[key])
		}
	}

	return errors.New(errorMessage)
}

// CheckConnection checks that the user is connected to a network and the URL points to a valid controller.
func CheckConnection(client *http.Client, controllerURL url.URL) error {
	errorMessage := `%s does not appear to be a valid Deis controller.
Make sure that the Controller URI is correct and the server is running.`

	baseURL := controllerURL.String()

	controllerURL.Path = "/v2/"

	req, err := http.NewRequest("GET", controllerURL.String(), bytes.NewBuffer(nil))
	addUserAgent(&req.Header)

	if err != nil {
		return err
	}

	res, err := client.Do(req)

	if err != nil {
		fmt.Printf(errorMessage+"\n", baseURL)
		return err
	}
	defer res.Body.Close()

	if res.StatusCode != 401 {
		return fmt.Errorf(errorMessage, baseURL)
	}

	checkAPICompatibility(res.Header.Get("DEIS_API_VERSION"))

	return nil
}

func addUserAgent(headers *http.Header) {
	headers.Add("User-Agent", "Deis Client v"+version.Version)
}
<commit_msg>ref(http.go): improve client error message<commit_after>package client

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"
	"strconv"
	"strings"

	"github.com/deis/workflow-cli/version"
)

// CreateHTTPClient creates a HTTP Client with proper SSL options.
func CreateHTTPClient(sslVerify bool) *http.Client {
	tr := &http.Transport{
		TLSClientConfig:   &tls.Config{InsecureSkipVerify: !sslVerify},
		DisableKeepAlives: true,
		Proxy:             http.ProxyFromEnvironment,
	}
	return &http.Client{Transport: tr}
}

// Request makes a HTTP request on the controller.
func (c Client) Request(method string, path string, body []byte) (*http.Response, error) {
	url := c.ControllerURL

	if strings.Contains(path, "?") {
		parts := strings.Split(path, "?")
		url.Path = parts[0]
		url.RawQuery = parts[1]
	} else {
		url.Path = path
	}

	req, err := http.NewRequest(method, url.String(), bytes.NewBuffer(body))

	if err != nil {
		return nil, err
	}

	req.Header.Add("Content-Type", "application/json")

	if c.Token != "" {
		req.Header.Add("Authorization", "token "+c.Token)
	}

	addUserAgent(&req.Header)

	res, err := c.HTTPClient.Do(req)

	if err != nil {
		return nil, err
	}

	if err = checkForErrors(res, ""); err != nil {
		return nil, err
	}

	checkAPICompatibility(res.Header.Get("DEIS_API_VERSION"))

	return res, nil
}

// LimitedRequest allows limiting the number of responses in a request.
func (c Client) LimitedRequest(path string, results int) (string, int, error) {
	body, err := c.BasicRequest("GET", path+"?limit="+strconv.Itoa(results), nil)

	if err != nil {
		return "", -1, err
	}

	res := make(map[string]interface{})
	if err = json.Unmarshal([]byte(body), &res); err != nil {
		return "", -1, err
	}

	out, err := json.Marshal(res["results"].([]interface{}))

	if err != nil {
		return "", -1, err
	}

	return string(out), int(res["count"].(float64)), nil
}

// BasicRequest makes a simple http request on the controller.
func (c Client) BasicRequest(method string, path string, body []byte) (string, error) {
	res, err := c.Request(method, path, body)

	if err != nil {
		return "", err
	}
	defer res.Body.Close()

	resBody, err := ioutil.ReadAll(res.Body)

	if err != nil {
		return "", err
	}
	return string(resBody), checkForErrors(res, string(resBody))
}

func checkForErrors(res *http.Response, body string) error {

	// If response is not an error, return nil.
	if res.StatusCode > 199 && res.StatusCode < 400 {
		return nil
	}

	// Read the response body if none was provided.
	if body == "" {
		defer res.Body.Close()
		resBody, err := ioutil.ReadAll(res.Body)
		if err != nil {
			return err
		}
		body = string(resBody)
	}

	// Unmarshal the response as JSON, or return the status and body.
	bodyMap := make(map[string]interface{})
	if err := json.Unmarshal([]byte(body), &bodyMap); err != nil {
		return fmt.Errorf("\n%s\n%s\n", res.Status, body)
	}

	errorMessage := fmt.Sprintf("\n%s\n", res.Status)
	for key, value := range bodyMap {
		switch v := value.(type) {
		case string:
			errorMessage += fmt.Sprintf("%s: %s\n", key, v)
		case []interface{}:
			for _, subValue := range v {
				switch sv := subValue.(type) {
				case string:
					errorMessage += fmt.Sprintf("%s: %s\n", key, sv)
				default:
					fmt.Printf("Unexpected type in %s error message array. Contents: %v",
						reflect.TypeOf(value), sv)
				}
			}
		default:
			fmt.Printf("Cannot handle key %s in error message, type %s. Contents: %v",
				key, reflect.TypeOf(value), bodyMap[key])
		}
	}

	return errors.New(errorMessage)
}

// CheckConnection checks that the user is connected to a network and the URL points to a valid controller.
func CheckConnection(client *http.Client, controllerURL url.URL) error {
	errorMessage := `%s does not appear to be a valid Deis controller.
Make sure that the Controller URI is correct, the server is running and
your client version is correct.`

	controllerURL.Path = "/v2/"

	req, err := http.NewRequest("GET", controllerURL.String(), bytes.NewBuffer(nil))
	addUserAgent(&req.Header)

	if err != nil {
		return err
	}

	res, err := client.Do(req)

	if err != nil {
		fmt.Printf(errorMessage+"\n", controllerURL.String())
		return err
	}
	defer res.Body.Close()

	if res.StatusCode != 401 {
		return fmt.Errorf(errorMessage, controllerURL.String())
	}

	checkAPICompatibility(res.Header.Get("DEIS_API_VERSION"))

	return nil
}

func addUserAgent(headers *http.Header) {
	headers.Add("User-Agent", "Deis Client v"+version.Version)
}
<|endoftext|>


<commit_before>package gozodiac

import (
	"testing"
	"time"

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

const shortForm = "2006-Jan-02"

func TestGetZodiacSign(t *testing.T) {
	// sign := GetZodiacSign(time.Now())
	// log.Printf("sign: %v", sign)

	testTime, err := time.Parse(shortForm, "2013-Feb-03")
	assert.NoError(t, err)
	sign := GetZodiacSign(testTime)
	assert.Equal(t, []ZodiacSign{Aquarius}, sign)

	testTime, err = time.Parse(shortForm, "2001-Nov-15")
	assert.NoError(t, err)
	sign = GetZodiacSign(testTime)
	assert.Equal(t, []ZodiacSign{Scorpio}, sign)
}
<commit_msg>minro<commit_after>package gozodiac

import (
	"testing"
	"time"

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

const shortForm = "2006-Jan-02"

func TestGetZodiacSign(t *testing.T) {
	// sign := GetZodiacSign(time.Now())
	// log.Printf("sign: %v", sign)

	testTime, err := time.Parse(shortForm, "2013-Feb-03")
	assert.NoError(t, err)
	sign := GetZodiacSign(testTime)
	assert.Equal(t, []ZodiacSign{Aquarius}, sign)

	testTime, err = time.Parse(shortForm, "2001-Nov-15")
	assert.NoError(t, err)
	sign = GetZodiacSign(testTime)
	assert.Equal(t, []ZodiacSign{Scorpio}, sign)

	testTime, err = time.Parse(shortForm, "1942-Oct-11")
	assert.NoError(t, err)
	sign = GetZodiacSign(testTime)
	assert.Equal(t, []ZodiacSign{Libra}, sign)
}
<|endoftext|>