<commit_before>package fs

import (
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/pkg/errors"
	"gotest.tools/v3/assert"
)

const defaultFileMode = 0644

// PathOp is a function which accepts a Path and performs an operation on that
// path. When called with real filesystem objects (File or Dir) a PathOp modifies
// the filesystem at the path. When used with a Manifest object a PathOp updates
// the manifest to expect a value.
type PathOp func(path Path) error

type manifestResource interface {
	SetMode(mode os.FileMode)
	SetUID(uid uint32)
	SetGID(gid uint32)
}

type manifestFile interface {
	manifestResource
	SetContent(content io.ReadCloser)
}

type manifestDirectory interface {
	manifestResource
	AddSymlink(path, target string) error
	AddFile(path string, ops ...PathOp) error
	AddDirectory(path string, ops ...PathOp) error
}

// WithContent writes content to a file at Path
func WithContent(content string) PathOp {
	return func(path Path) error {
		if m, ok := path.(manifestFile); ok {
			m.SetContent(ioutil.NopCloser(strings.NewReader(content)))
			return nil
		}
		return ioutil.WriteFile(path.Path(), []byte(content), defaultFileMode)
	}
}

// WithBytes write bytes to a file at Path
func WithBytes(raw []byte) PathOp {
	return func(path Path) error {
		if m, ok := path.(manifestFile); ok {
			m.SetContent(ioutil.NopCloser(bytes.NewReader(raw)))
			return nil
		}
		return ioutil.WriteFile(path.Path(), raw, defaultFileMode)
	}
}

// WithReaderContent copies the reader contents to the file at Path
func WithReaderContent(r io.Reader) PathOp {
	return func(path Path) error {
		if m, ok := path.(manifestFile); ok {
			m.SetContent(ioutil.NopCloser(r))
			return nil
		}
		f, err := os.OpenFile(path.Path(), os.O_WRONLY, defaultFileMode)
		if err != nil {
			return err
		}
		_, err = io.Copy(f, r)
		f.Close()
		return err
	}
}

// AsUser changes ownership of the file system object at Path
func AsUser(uid, gid int) PathOp {
	return func(path Path) error {
		if m, ok := path.(manifestResource); ok {
			m.SetUID(uint32(uid))
			m.SetGID(uint32(gid))
			return nil
		}
		return os.Chown(path.Path(), uid, gid)
	}
}

// WithFile creates a file in the directory at path with content
func WithFile(filename, content string, ops ...PathOp) PathOp {
	return func(path Path) error {
		if m, ok := path.(manifestDirectory); ok {
			ops = append([]PathOp{WithContent(content), WithMode(defaultFileMode)}, ops...)
			return m.AddFile(filename, ops...)
		}

		fullpath := filepath.Join(path.Path(), filepath.FromSlash(filename))
		if err := createFile(fullpath, content); err != nil {
			return err
		}
		return applyPathOps(&File{path: fullpath}, ops)
	}
}

func createFile(fullpath string, content string) error {
	return ioutil.WriteFile(fullpath, []byte(content), defaultFileMode)
}

// WithFiles creates all the files in the directory at path with their content
func WithFiles(files map[string]string) PathOp {
	return func(path Path) error {
		if m, ok := path.(manifestDirectory); ok {
			for filename, content := range files {
				// TODO: remove duplication with WithFile
				if err := m.AddFile(filename, WithContent(content), WithMode(defaultFileMode)); err != nil {
					return err
				}
			}
			return nil
		}

		for filename, content := range files {
			fullpath := filepath.Join(path.Path(), filepath.FromSlash(filename))
			if err := createFile(fullpath, content); err != nil {
				return err
			}
		}
		return nil
	}
}

// FromDir copies the directory tree from the source path into the new Dir
func FromDir(source string) PathOp {
	return func(path Path) error {
		if _, ok := path.(manifestDirectory); ok {
			return errors.New("use manifest.FromDir")
		}
		return copyDirectory(source, path.Path())
	}
}

// WithDir creates a subdirectory in the directory at path. Additional PathOp
// can be used to modify the subdirectory
func WithDir(name string, ops ...PathOp) PathOp {
	const defaultMode = 0755
	return func(path Path) error {
		if m, ok := path.(manifestDirectory); ok {
			ops = append([]PathOp{WithMode(defaultMode)}, ops...)
			return m.AddDirectory(name, ops...)
		}

		fullpath := filepath.Join(path.Path(), filepath.FromSlash(name))
		err := os.MkdirAll(fullpath, defaultMode)
		if err != nil {
			return err
		}
		return applyPathOps(&Dir{path: fullpath}, ops)
	}
}

// Apply the PathOps to the File
func Apply(t assert.TestingT, path Path, ops ...PathOp) {
	if ht, ok := t.(helperT); ok {
		ht.Helper()
	}
	assert.NilError(t, applyPathOps(path, ops))
}

func applyPathOps(path Path, ops []PathOp) error {
	for _, op := range ops {
		if err := op(path); err != nil {
			return err
		}
	}
	return nil
}

// WithMode sets the file mode on the directory or file at path
func WithMode(mode os.FileMode) PathOp {
	return func(path Path) error {
		if m, ok := path.(manifestResource); ok {
			m.SetMode(mode)
			return nil
		}
		return os.Chmod(path.Path(), mode)
	}
}

func copyDirectory(source, dest string) error {
	entries, err := ioutil.ReadDir(source)
	if err != nil {
		return err
	}
	for _, entry := range entries {
		sourcePath := filepath.Join(source, entry.Name())
		destPath := filepath.Join(dest, entry.Name())
		switch {
		case entry.IsDir():
			if err := os.Mkdir(destPath, 0755); err != nil {
				return err
			}
			if err := copyDirectory(sourcePath, destPath); err != nil {
				return err
			}
		case entry.Mode()&os.ModeSymlink != 0:
			if err := copySymLink(sourcePath, destPath); err != nil {
				return err
			}
		default:
			if err := copyFile(sourcePath, destPath); err != nil {
				return err
			}
		}
	}
	return nil
}

func copySymLink(source, dest string) error {
	link, err := os.Readlink(source)
	if err != nil {
		return err
	}
	return os.Symlink(link, dest)
}

func copyFile(source, dest string) error {
	content, err := ioutil.ReadFile(source)
	if err != nil {
		return err
	}
	return ioutil.WriteFile(dest, content, 0644)
}

// WithSymlink creates a symlink in the directory which links to target.
// Target must be a path relative to the directory.
//
// Note: the argument order is the inverse of os.Symlink to be consistent with
// the other functions in this package.
func WithSymlink(path, target string) PathOp {
	return func(root Path) error {
		if v, ok := root.(manifestDirectory); ok {
			return v.AddSymlink(path, target)
		}
		return os.Symlink(filepath.Join(root.Path(), target), filepath.Join(root.Path(), path))
	}
}

// WithHardlink creates a link in the directory which links to target.
// Target must be a path relative to the directory.
//
// Note: the argument order is the inverse of os.Link to be consistent with
// the other functions in this package.
func WithHardlink(path, target string) PathOp {
	return func(root Path) error {
		if _, ok := root.(manifestDirectory); ok {
			return errors.New("WithHardlink not implemented for manifests")
		}
		return os.Link(filepath.Join(root.Path(), target), filepath.Join(root.Path(), path))
	}
}

// WithTimestamps sets the access and modification times of the file system object
// at path.
func WithTimestamps(atime, mtime time.Time) PathOp {
	return func(root Path) error {
		if _, ok := root.(manifestDirectory); ok {
			return errors.New("WithTimestamp not implemented for manifests")
		}
		return os.Chtimes(root.Path(), atime, mtime)
	}
}
<commit_msg>defer file close in case io.Reader panics<commit_after>package fs

import (
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/pkg/errors"
	"gotest.tools/v3/assert"
)

const defaultFileMode = 0644

// PathOp is a function which accepts a Path and performs an operation on that
// path. When called with real filesystem objects (File or Dir) a PathOp modifies
// the filesystem at the path. When used with a Manifest object a PathOp updates
// the manifest to expect a value.
type PathOp func(path Path) error

type manifestResource interface {
	SetMode(mode os.FileMode)
	SetUID(uid uint32)
	SetGID(gid uint32)
}

type manifestFile interface {
	manifestResource
	SetContent(content io.ReadCloser)
}

type manifestDirectory interface {
	manifestResource
	AddSymlink(path, target string) error
	AddFile(path string, ops ...PathOp) error
	AddDirectory(path string, ops ...PathOp) error
}

// WithContent writes content to a file at Path
func WithContent(content string) PathOp {
	return func(path Path) error {
		if m, ok := path.(manifestFile); ok {
			m.SetContent(ioutil.NopCloser(strings.NewReader(content)))
			return nil
		}
		return ioutil.WriteFile(path.Path(), []byte(content), defaultFileMode)
	}
}

// WithBytes write bytes to a file at Path
func WithBytes(raw []byte) PathOp {
	return func(path Path) error {
		if m, ok := path.(manifestFile); ok {
			m.SetContent(ioutil.NopCloser(bytes.NewReader(raw)))
			return nil
		}
		return ioutil.WriteFile(path.Path(), raw, defaultFileMode)
	}
}

// WithReaderContent copies the reader contents to the file at Path
func WithReaderContent(r io.Reader) PathOp {
	return func(path Path) error {
		if m, ok := path.(manifestFile); ok {
			m.SetContent(ioutil.NopCloser(r))
			return nil
		}
		f, err := os.OpenFile(path.Path(), os.O_WRONLY, defaultFileMode)
		if err != nil {
			return err
		}
		defer f.Close()
		_, err = io.Copy(f, r)
		return err
	}
}

// AsUser changes ownership of the file system object at Path
func AsUser(uid, gid int) PathOp {
	return func(path Path) error {
		if m, ok := path.(manifestResource); ok {
			m.SetUID(uint32(uid))
			m.SetGID(uint32(gid))
			return nil
		}
		return os.Chown(path.Path(), uid, gid)
	}
}

// WithFile creates a file in the directory at path with content
func WithFile(filename, content string, ops ...PathOp) PathOp {
	return func(path Path) error {
		if m, ok := path.(manifestDirectory); ok {
			ops = append([]PathOp{WithContent(content), WithMode(defaultFileMode)}, ops...)
			return m.AddFile(filename, ops...)
		}

		fullpath := filepath.Join(path.Path(), filepath.FromSlash(filename))
		if err := createFile(fullpath, content); err != nil {
			return err
		}
		return applyPathOps(&File{path: fullpath}, ops)
	}
}

func createFile(fullpath string, content string) error {
	return ioutil.WriteFile(fullpath, []byte(content), defaultFileMode)
}

// WithFiles creates all the files in the directory at path with their content
func WithFiles(files map[string]string) PathOp {
	return func(path Path) error {
		if m, ok := path.(manifestDirectory); ok {
			for filename, content := range files {
				// TODO: remove duplication with WithFile
				if err := m.AddFile(filename, WithContent(content), WithMode(defaultFileMode)); err != nil {
					return err
				}
			}
			return nil
		}

		for filename, content := range files {
			fullpath := filepath.Join(path.Path(), filepath.FromSlash(filename))
			if err := createFile(fullpath, content); err != nil {
				return err
			}
		}
		return nil
	}
}

// FromDir copies the directory tree from the source path into the new Dir
func FromDir(source string) PathOp {
	return func(path Path) error {
		if _, ok := path.(manifestDirectory); ok {
			return errors.New("use manifest.FromDir")
		}
		return copyDirectory(source, path.Path())
	}
}

// WithDir creates a subdirectory in the directory at path. Additional PathOp
// can be used to modify the subdirectory
func WithDir(name string, ops ...PathOp) PathOp {
	const defaultMode = 0755
	return func(path Path) error {
		if m, ok := path.(manifestDirectory); ok {
			ops = append([]PathOp{WithMode(defaultMode)}, ops...)
			return m.AddDirectory(name, ops...)
		}

		fullpath := filepath.Join(path.Path(), filepath.FromSlash(name))
		err := os.MkdirAll(fullpath, defaultMode)
		if err != nil {
			return err
		}
		return applyPathOps(&Dir{path: fullpath}, ops)
	}
}

// Apply the PathOps to the File
func Apply(t assert.TestingT, path Path, ops ...PathOp) {
	if ht, ok := t.(helperT); ok {
		ht.Helper()
	}
	assert.NilError(t, applyPathOps(path, ops))
}

func applyPathOps(path Path, ops []PathOp) error {
	for _, op := range ops {
		if err := op(path); err != nil {
			return err
		}
	}
	return nil
}

// WithMode sets the file mode on the directory or file at path
func WithMode(mode os.FileMode) PathOp {
	return func(path Path) error {
		if m, ok := path.(manifestResource); ok {
			m.SetMode(mode)
			return nil
		}
		return os.Chmod(path.Path(), mode)
	}
}

func copyDirectory(source, dest string) error {
	entries, err := ioutil.ReadDir(source)
	if err != nil {
		return err
	}
	for _, entry := range entries {
		sourcePath := filepath.Join(source, entry.Name())
		destPath := filepath.Join(dest, entry.Name())
		switch {
		case entry.IsDir():
			if err := os.Mkdir(destPath, 0755); err != nil {
				return err
			}
			if err := copyDirectory(sourcePath, destPath); err != nil {
				return err
			}
		case entry.Mode()&os.ModeSymlink != 0:
			if err := copySymLink(sourcePath, destPath); err != nil {
				return err
			}
		default:
			if err := copyFile(sourcePath, destPath); err != nil {
				return err
			}
		}
	}
	return nil
}

func copySymLink(source, dest string) error {
	link, err := os.Readlink(source)
	if err != nil {
		return err
	}
	return os.Symlink(link, dest)
}

func copyFile(source, dest string) error {
	content, err := ioutil.ReadFile(source)
	if err != nil {
		return err
	}
	return ioutil.WriteFile(dest, content, 0644)
}

// WithSymlink creates a symlink in the directory which links to target.
// Target must be a path relative to the directory.
//
// Note: the argument order is the inverse of os.Symlink to be consistent with
// the other functions in this package.
func WithSymlink(path, target string) PathOp {
	return func(root Path) error {
		if v, ok := root.(manifestDirectory); ok {
			return v.AddSymlink(path, target)
		}
		return os.Symlink(filepath.Join(root.Path(), target), filepath.Join(root.Path(), path))
	}
}

// WithHardlink creates a link in the directory which links to target.
// Target must be a path relative to the directory.
//
// Note: the argument order is the inverse of os.Link to be consistent with
// the other functions in this package.
func WithHardlink(path, target string) PathOp {
	return func(root Path) error {
		if _, ok := root.(manifestDirectory); ok {
			return errors.New("WithHardlink not implemented for manifests")
		}
		return os.Link(filepath.Join(root.Path(), target), filepath.Join(root.Path(), path))
	}
}

// WithTimestamps sets the access and modification times of the file system object
// at path.
func WithTimestamps(atime, mtime time.Time) PathOp {
	return func(root Path) error {
		if _, ok := root.(manifestDirectory); ok {
			return errors.New("WithTimestamp not implemented for manifests")
		}
		return os.Chtimes(root.Path(), atime, mtime)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math/rand"
	"os"
	"strings"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/moul/bolosseum"
	"github.com/moul/bolosseum/bots"
	"github.com/moul/bolosseum/bots/filebot"
	"github.com/moul/bolosseum/bots/httpbot"
	"github.com/moul/bolosseum/games"
	"github.com/moul/bolosseum/games/coinflip"
	"github.com/moul/bolosseum/games/connectfour"
	"github.com/moul/bolosseum/games/russianbullet"
	"github.com/moul/bolosseum/games/tictactoe"
	"github.com/urfave/cli"
)

var availableGames = []string{
	"coinflip",
	"connectfour",
}

func getGame(gameName string) (games.Game, error) {
	switch gameName {
	case "coinflip":
		return coinflip.NewGame()
	case "connectfour":
		return connectfour.NewGame()
	case "russianbullet":
		return russianbullet.NewGame()
	case "tictactoe":
		return tictactoe.NewGame()
	default:
		return nil, fmt.Errorf("")
	}
}

func getBot(botPath string) (bots.Bot, error) {
	logrus.Warnf("Getting bot %q", botPath)
	splt := strings.Split(botPath, "://")
	if len(splt) != 2 {
		return nil, fmt.Errorf("invalid bot path")
	}

	scheme := splt[0]
	path := splt[1]

	switch scheme {
	case "file":
		return filebot.NewBot(path)
	case "http":
		return httpbot.NewBot(path, "GET", "http")
	case "http+post":
		return httpbot.NewBot(path, "POST", "http")
	default:
		return nil, fmt.Errorf("invalid bot scheme: %q (%q)", scheme, path)
	}
}

func main() {
	// seed random
	rand.Seed(time.Now().UTC().UnixNano())

	// configure CLI
	app := cli.NewApp()
	app.Name = "bolosseum"
	app.Usage = "colosseum for bots"
	app.Version = bolosseum.VERSION

	app.Commands = []cli.Command{
		{
			Name:   "run",
			Usage:  "Start a battle",
			Action: run,
		},
	}
	app.Run(os.Args)
}

func run(c *cli.Context) error {
	args := c.Args()
	if len(args) < 1 {
		return cli.NewExitError("You need to specify the game", -1)
	}

	// initialize game
	logrus.Warnf("Initializing game %q", args[0])
	game, err := getGame(args[0])
	if err != nil {
		return cli.NewExitError(fmt.Sprintf("No such game %q", args[0]), -1)
	}
	logrus.Warnf("Game: %q: %q", game.Name(), game)

	if err = game.CheckArgs(args[1:]); err != nil {
		return cli.NewExitError(fmt.Sprintf("%v", err), -1)
	}

	// initialize bots
	hasError := false
	for _, botPath := range args[1:] {
		bot, err := getBot(botPath)
		if err != nil {
			hasError = true
			logrus.Errorf("Failed to initialize bot %q", bot)
		} else {
			logrus.Warnf("Registering bot %q", bot.Path())
			game.RegisterBot(bot)
		}
	}
	if hasError {
		return cli.NewExitError("Invalid bots", -1)
	}

	// run
	if err = game.Run("gameid"); err != nil {
		logrus.Errorf("Run error: %v", err)
	}

	return nil
}
<commit_msg>support http bots (fix #14)<commit_after>package main

import (
	"fmt"
	"math/rand"
	"os"
	"strings"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/moul/bolosseum"
	"github.com/moul/bolosseum/bots"
	"github.com/moul/bolosseum/bots/filebot"
	"github.com/moul/bolosseum/bots/httpbot"
	"github.com/moul/bolosseum/games"
	"github.com/moul/bolosseum/games/coinflip"
	"github.com/moul/bolosseum/games/connectfour"
	"github.com/moul/bolosseum/games/russianbullet"
	"github.com/moul/bolosseum/games/tictactoe"
	"github.com/urfave/cli"
)

var availableGames = []string{
	"coinflip",
	"connectfour",
}

func getGame(gameName string) (games.Game, error) {
	switch gameName {
	case "coinflip":
		return coinflip.NewGame()
	case "connectfour":
		return connectfour.NewGame()
	case "russianbullet":
		return russianbullet.NewGame()
	case "tictactoe":
		return tictactoe.NewGame()
	default:
		return nil, fmt.Errorf("")
	}
}

func getBot(botPath string) (bots.Bot, error) {
	logrus.Warnf("Getting bot %q", botPath)
	splt := strings.Split(botPath, "://")
	if len(splt) != 2 {
		return nil, fmt.Errorf("invalid bot path")
	}

	scheme := splt[0]
	path := splt[1]

	switch scheme {
	case "file":
		return filebot.NewBot(path)
	case "http+get":
		return httpbot.NewBot(path, "GET", "http")
	case "http+post", "http":
		return httpbot.NewBot(path, "POST", "http")
	case "https+get":
		return httpbot.NewBot(path, "GET", "https")
	case "https+post", "https":
		return httpbot.NewBot(path, "POST", "https")
	default:
		return nil, fmt.Errorf("invalid bot scheme: %q (%q)", scheme, path)
	}
}

func main() {
	// seed random
	rand.Seed(time.Now().UTC().UnixNano())

	// configure CLI
	app := cli.NewApp()
	app.Name = "bolosseum"
	app.Usage = "colosseum for bots"
	app.Version = bolosseum.VERSION

	app.Commands = []cli.Command{
		{
			Name:   "run",
			Usage:  "Start a battle",
			Action: run,
		},
	}
	app.Run(os.Args)
}

func run(c *cli.Context) error {
	args := c.Args()
	if len(args) < 1 {
		return cli.NewExitError("You need to specify the game", -1)
	}

	// initialize game
	logrus.Warnf("Initializing game %q", args[0])
	game, err := getGame(args[0])
	if err != nil {
		return cli.NewExitError(fmt.Sprintf("No such game %q", args[0]), -1)
	}
	logrus.Warnf("Game: %q: %q", game.Name(), game)

	if err = game.CheckArgs(args[1:]); err != nil {
		return cli.NewExitError(fmt.Sprintf("%v", err), -1)
	}

	// initialize bots
	hasError := false
	for _, botPath := range args[1:] {
		bot, err := getBot(botPath)
		if err != nil {
			hasError = true
			logrus.Errorf("Failed to initialize bot %q", bot)
		} else {
			logrus.Warnf("Registering bot %q", bot.Path())
			game.RegisterBot(bot)
		}
	}
	if hasError {
		return cli.NewExitError("Invalid bots", -1)
	}

	// run
	if err = game.Run("gameid"); err != nil {
		logrus.Errorf("Run error: %v", err)
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"sync"

	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"

	"github.com/relab/gorums/byzq"
)

type register struct {
	sync.RWMutex
	state map[string]byzq.Value
}

func main() {
	port := flag.Int("port", 8080, "port to listen on")
	f := flag.Int("f", 0, "fault tolerance, supported values f=1,2,3 (this is ignored if addrs is provided)")
	key := flag.String("key", "", "public/private key file this server")

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [OPTIONS]\n", os.Args[0])
		fmt.Fprintf(os.Stderr, "\nOptions:\n")
		flag.PrintDefaults()
	}
	flag.Parse()

	if *f > 0 {
		// we are running only local since we have asked for 3f+1 servers
		done := make(chan bool)
		n := 3**f + 1
		for i := 0; i < n; i++ {
			go serve(*port+i, *key)
		}
		// wait indefinitely
		<-done
	}
	// run only one server
	serve(*port, *key)
}

func serve(port int, keyFile string) {
	l, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
	defer l.Close()
	if err != nil {
		log.Fatal(err)
	}
	if keyFile == "" {
		log.Fatalln("required server keys not provided")
	}
	creds, err := credentials.NewServerTLSFromFile(keyFile+".pem", keyFile+".key")
	if err != nil {
		log.Fatalf("failed to load credentials %v", err)
	}
	opts := []grpc.ServerOption{grpc.Creds(creds)}
	grpcServer := grpc.NewServer(opts...)
	smap := make(map[string]byzq.Value)
	byzq.RegisterRegisterServer(grpcServer, &register{state: smap})
	log.Printf("Server %s running", l.Addr())
	log.Fatal(grpcServer.Serve(l))
}

func (r *register) Read(ctx context.Context, k *byzq.Key) (*byzq.Value, error) {
	r.RLock()
	value := r.state[k.Key]
	r.RUnlock()
	return &value, nil
}

func (r *register) Write(ctx context.Context, v *byzq.Value) (*byzq.WriteResponse, error) {
	wr := &byzq.WriteResponse{Timestamp: v.C.Timestamp}
	r.Lock()
	val, found := r.state[v.C.Key]
	if !found || v.C.Timestamp > val.C.Timestamp {
		r.state[v.C.Key] = *v
	}
	r.Unlock()
	return wr, nil
}
<commit_msg>cmd/byzserver: should check returned error before deferring l.Close()<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"sync"

	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"

	"github.com/relab/gorums/byzq"
)

type register struct {
	sync.RWMutex
	state map[string]byzq.Value
}

func main() {
	port := flag.Int("port", 8080, "port to listen on")
	f := flag.Int("f", 0, "fault tolerance, supported values f=1,2,3 (this is ignored if addrs is provided)")
	key := flag.String("key", "", "public/private key file this server")

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [OPTIONS]\n", os.Args[0])
		fmt.Fprintf(os.Stderr, "\nOptions:\n")
		flag.PrintDefaults()
	}
	flag.Parse()

	if *f > 0 {
		// we are running only local since we have asked for 3f+1 servers
		done := make(chan bool)
		n := 3**f + 1
		for i := 0; i < n; i++ {
			go serve(*port+i, *key)
		}
		// wait indefinitely
		<-done
	}
	// run only one server
	serve(*port, *key)
}

func serve(port int, keyFile string) {
	l, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
	if err != nil {
		log.Fatal(err)
	}
	defer l.Close()
	if keyFile == "" {
		log.Fatalln("required server keys not provided")
	}
	creds, err := credentials.NewServerTLSFromFile(keyFile+".pem", keyFile+".key")
	if err != nil {
		log.Fatalf("failed to load credentials %v", err)
	}
	opts := []grpc.ServerOption{grpc.Creds(creds)}
	grpcServer := grpc.NewServer(opts...)
	smap := make(map[string]byzq.Value)
	byzq.RegisterRegisterServer(grpcServer, &register{state: smap})
	log.Printf("Server %s running", l.Addr())
	log.Fatal(grpcServer.Serve(l))
}

func (r *register) Read(ctx context.Context, k *byzq.Key) (*byzq.Value, error) {
	r.RLock()
	value := r.state[k.Key]
	r.RUnlock()
	return &value, nil
}

func (r *register) Write(ctx context.Context, v *byzq.Value) (*byzq.WriteResponse, error) {
	wr := &byzq.WriteResponse{Timestamp: v.C.Timestamp}
	r.Lock()
	val, found := r.state[v.C.Key]
	if !found || v.C.Timestamp > val.C.Timestamp {
		r.state[v.C.Key] = *v
	}
	r.Unlock()
	return wr, nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"sync"

	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"

	"github.com/relab/gorums/byzq"
)

type register struct {
	sync.RWMutex
	state map[string]byzq.Value
}

func main() {
	var (
		port   = flag.Int("port", 8080, "port to listen on")
		f      = flag.Int("f", 0, "fault tolerance")
		noauth = flag.Bool("noauth", false, "don't use authenticated channels")
		key    = flag.String("key", "", "public/private key file this server")
	)

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [OPTIONS]\n", os.Args[0])
		fmt.Fprintf(os.Stderr, "\nOptions:\n")
		flag.PrintDefaults()
	}
	flag.Parse()

	if *f > 0 {
		// We are running only local since we have asked for 3f+1 servers.
		done := make(chan bool)
		n := 3**f + 1
		for i := 0; i < n; i++ {
			go serve(*port+i, *key, *noauth)
		}
		// Wait indefinitely.
		<-done
	}
	// Run only one server.
	serve(*port, *key, *noauth)
}

func serve(port int, keyFile string, noauth bool) {
	l, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", port))
	if err != nil {
		log.Fatal(err)
	}
	defer l.Close()
	if keyFile == "" {
		log.Fatalln("required server keys not provided")
	}
	opts := []grpc.ServerOption{}
	if !noauth {
		creds, err := credentials.NewServerTLSFromFile(keyFile+".pem", keyFile+".key")
		if err != nil {
			log.Fatalf("failed to load credentials: %v", err)
		}
		opts = []grpc.ServerOption{grpc.Creds(creds)}
	}
	grpcServer := grpc.NewServer(opts...)
	smap := make(map[string]byzq.Value)
	byzq.RegisterRegisterServer(grpcServer, &register{state: smap})
	log.Printf("server %s running", l.Addr())
	log.Fatal(grpcServer.Serve(l))
}

func (r *register) Read(ctx context.Context, k *byzq.Key) (*byzq.Value, error) {
	r.RLock()
	value := r.state[k.Key]
	r.RUnlock()
	return &value, nil
}

func (r *register) Write(ctx context.Context, v *byzq.Value) (*byzq.WriteResponse, error) {
	wr := &byzq.WriteResponse{Timestamp: v.C.Timestamp}
	r.Lock()
	val, found := r.state[v.C.Key]
	if !found || v.C.Timestamp > val.C.Timestamp {
		r.state[v.C.Key] = *v
	}
	r.Unlock()
	return wr, nil
}
<commit_msg>cmd/byzsever: rename Register->Storage<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"sync"

	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"

	"github.com/relab/gorums/byzq"
)

type storage struct {
	sync.RWMutex
	state map[string]byzq.Value
}

func main() {
	var (
		port   = flag.Int("port", 8080, "port to listen on")
		f      = flag.Int("f", 0, "fault tolerance")
		noauth = flag.Bool("noauth", false, "don't use authenticated channels")
		key    = flag.String("key", "", "public/private key file this server")
	)

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [OPTIONS]\n", os.Args[0])
		fmt.Fprintf(os.Stderr, "\nOptions:\n")
		flag.PrintDefaults()
	}
	flag.Parse()

	if *f > 0 {
		// We are running only local since we have asked for 3f+1 servers.
		done := make(chan bool)
		n := 3**f + 1
		for i := 0; i < n; i++ {
			go serve(*port+i, *key, *noauth)
		}
		// Wait indefinitely.
		<-done
	}
	// Run only one server.
	serve(*port, *key, *noauth)
}

func serve(port int, keyFile string, noauth bool) {
	l, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", port))
	if err != nil {
		log.Fatal(err)
	}
	defer l.Close()
	if keyFile == "" {
		log.Fatalln("required server keys not provided")
	}
	opts := []grpc.ServerOption{}
	if !noauth {
		creds, err := credentials.NewServerTLSFromFile(keyFile+".pem", keyFile+".key")
		if err != nil {
			log.Fatalf("failed to load credentials: %v", err)
		}
		opts = []grpc.ServerOption{grpc.Creds(creds)}
	}
	grpcServer := grpc.NewServer(opts...)
	smap := make(map[string]byzq.Value)
	byzq.RegisterStorageServer(grpcServer, &storage{state: smap})
	log.Printf("server %s running", l.Addr())
	log.Fatal(grpcServer.Serve(l))
}

func (r *storage) Read(ctx context.Context, k *byzq.Key) (*byzq.Value, error) {
	r.RLock()
	value := r.state[k.Key]
	r.RUnlock()
	return &value, nil
}

func (r *storage) Write(ctx context.Context, v *byzq.Value) (*byzq.WriteResponse, error) {
	wr := &byzq.WriteResponse{Timestamp: v.C.Timestamp}
	r.Lock()
	val, found := r.state[v.C.Key]
	if !found || v.C.Timestamp > val.C.Timestamp {
		r.state[v.C.Key] = *v
	}
	r.Unlock()
	return wr, nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/cloudformation"
	"github.com/aws/aws-sdk-go/service/ecs"
	"github.com/lox/ecsy/api"
	"github.com/lox/ecsy/compose"
	"github.com/lox/ecsy/templates"
	"gopkg.in/alecthomas/kingpin.v2"
)

func ConfigureCreateService(app *kingpin.Application, svc api.Services) {
	var cluster, projectName, healthCheck, certificateID, logPrefix string
	var composeFiles []string
	var disableRollback bool

	cmd := app.Command("create-service", "Create an ECS service for your app")
	cmd.Flag("cluster", "The name of the ECS cluster to use").
		Required().
		StringVar(&cluster)

	cmd.Flag("project-name", "The name of the Compose project").
		Short('p').
		Default(currentDirName()).
		StringVar(&projectName)

	cmd.Flag("healthcheck", "Path to check for HTTP health check").
		Default("/").
		StringVar(&healthCheck)

	cmd.Flag("ssl-certificate-id", "The identifier of the SSL certificate to associate with the service").
		Default("").
		StringVar(&certificateID)

	cmd.Flag("file", "The paths to docker-compose files to convert to service definitions").
		Short('f').
		Default("docker-compose.yml").
		ExistingFilesVar(&composeFiles)

	cmd.Flag("disable-rollback", "Don't rollback created infrastructure if a failure occurs").
		BoolVar(&disableRollback)

	cmd.Flag("log-prefix", "The prefix to provide to cloudwatch logs for container output, defaults to project name").
		StringVar(&logPrefix)

	cmd.Action(func(c *kingpin.ParseContext) error {
		log.Printf("Creating service %s on %s", projectName, cluster)

		clusterStack, err := api.FindClusterStack(svc.Cloudformation, cluster)
		if clusterStack == nil {
			return fmt.Errorf("No cluster exists for %q. Use `create-cluster`",
				cluster)
		}

		stack, _ := api.FindServiceStack(svc.Cloudformation, cluster, projectName)
		if stack != nil {
			return fmt.Errorf("A service already exists for %q in cluster %q. Use `deploy` or `update-service`",
				projectName, cluster)
		}

		log.Printf("Generating task definition from %v", composeFiles)
		t := compose.Transformer{
			ComposeFiles: composeFiles,
			ProjectName:  projectName,
		}

		taskDefinitionInput, err := t.Transform()
		if err != nil {
			return err
		}

		if logPrefix == nil {
			logPrefix = &projectName
		}

		if logGroup, exists := api.GetStackOutputByKey(clusterStack, "LogGroupName"); exists {
			log.Printf("Setting tasks to use log group %s", logGroup)

			for _, def := range taskDefinitionInput.ContainerDefinitions {
				if def.LogConfiguration == nil {
					def.LogConfiguration = &ecs.LogConfiguration{
						LogDriver: aws.String("awslogs"),
						Options: map[string]*string{
							"awslogs-group":         aws.String(logGroup),
							"awslogs-region":        aws.String(os.Getenv("AWS_REGION")),
							"awslogs-stream-prefix": logPrefix,
						},
					}
				}
			}
		}

		log.Printf("Registering a task for %s", projectName)
		resp, err := svc.ECS.RegisterTaskDefinition(taskDefinitionInput)
		if err != nil {
			return err
		}
		log.Printf("Registered task definition %s:%d", *resp.TaskDefinition.Family, *resp.TaskDefinition.Revision)

		network, err := api.FindNetworkStack(svc.Cloudformation, cluster)
		if err != nil {
			return err
		}
		log.Printf("Found network stack %s", network.StackName)

		ctx := api.CreateStackContext{
			Params: map[string]string{
				"ECSCluster":       cluster,
				"TaskFamily":       *resp.TaskDefinition.Family,
				"TaskDefinition":   *resp.TaskDefinition.TaskDefinitionArn,
				"Subnets":          network.Subnets,
				"Vpc":              network.Vpc,
				"ECSSecurityGroup": network.SecurityGroup,
				"SSLCertificateId": certificateID,
			},
			DisableRollback: disableRollback,
		}

		exposedPorts := api.ExposedPorts(resp.TaskDefinition)

		if len(exposedPorts) != 1 {
			return fmt.Errorf("Task definition without exactly 1 host mapped port are not yet supported")
		}

		// for now this is a single value
		for container, mappings := range exposedPorts {
			for _, mapping := range mappings {
				ctx.Params["ContainerName"] = container
				ctx.Params["ContainerPort"] = strconv.FormatInt(*mapping.ContainerPort, 10)
				ctx.Params["HealthCheckUrl"] = healthCheck
				ctx.Params["ELBPort"] = strconv.FormatInt(*mapping.HostPort, 10)
			}
		}

		timer := time.Now()
		stackName := cluster + "-ecs-service-" + time.Now().Format(stackDateFormat)

		log.Printf("Creating service cloudformation stack %s", stackName)

		err = api.CreateStack(svc.Cloudformation, stackName, templates.EcsService(), ctx)
		if err != nil {
			return err
		}

		err = api.PollUntilCreated(svc.Cloudformation, stackName, func(event *cloudformation.StackEvent) {
			log.Printf("%s\n", api.FormatStackEvent(event))
		})
		if err != nil {
			return err
		}

		stackOutputs, err := api.StackOutputs(svc.Cloudformation, stackName)
		if err != nil {
			return err
		}

		var printer = func(e *ecs.ServiceEvent) {
			log.Println(*e.Message)
		}

		log.Printf("Waiting for service to reach a steady state.")
		err = api.PollUntilTaskDeployed(svc.ECS, cluster, stackOutputs["ECSService"], *resp.TaskDefinition.TaskDefinitionArn, printer)
		if err != nil {
			return err
		}

		// ui.Printf("Waiting for service to stabilize")
		// if err = apient.WaitUntilServicesStable(input.ClusterName, serviceOutputs["ECSService"]); err != nil {
		// 	ui.Fatal(err)
		// }

		log.Printf("Service created in %s", time.Now().Sub(timer).String())
		log.Printf("Service available at %s", stackOutputs["ECSLoadBalancer"])
		return nil
	})
}

func currentDirName() string {
	cwd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	return filepath.Base(cwd)
}
<commit_msg>Fix incorrect assignment<commit_after>package cmd

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/cloudformation"
	"github.com/aws/aws-sdk-go/service/ecs"
	"github.com/lox/ecsy/api"
	"github.com/lox/ecsy/compose"
	"github.com/lox/ecsy/templates"
	"gopkg.in/alecthomas/kingpin.v2"
)

func ConfigureCreateService(app *kingpin.Application, svc api.Services) {
	var cluster, projectName, healthCheck, certificateID, logPrefix string
	var composeFiles []string
	var disableRollback bool

	cmd := app.Command("create-service", "Create an ECS service for your app")
	cmd.Flag("cluster", "The name of the ECS cluster to use").
		Required().
		StringVar(&cluster)

	cmd.Flag("project-name", "The name of the Compose project").
		Short('p').
		Default(currentDirName()).
		StringVar(&projectName)

	cmd.Flag("healthcheck", "Path to check for HTTP health check").
		Default("/").
		StringVar(&healthCheck)

	cmd.Flag("ssl-certificate-id", "The identifier of the SSL certificate to associate with the service").
		Default("").
		StringVar(&certificateID)

	cmd.Flag("file", "The paths to docker-compose files to convert to service definitions").
		Short('f').
		Default("docker-compose.yml").
		ExistingFilesVar(&composeFiles)

	cmd.Flag("disable-rollback", "Don't rollback created infrastructure if a failure occurs").
		BoolVar(&disableRollback)

	cmd.Flag("log-prefix", "The prefix to provide to cloudwatch logs for container output, defaults to project name").
		StringVar(&logPrefix)

	cmd.Action(func(c *kingpin.ParseContext) error {
		log.Printf("Creating service %s on %s", projectName, cluster)

		clusterStack, err := api.FindClusterStack(svc.Cloudformation, cluster)
		if clusterStack == nil {
			return fmt.Errorf("No cluster exists for %q. Use `create-cluster`",
				cluster)
		}

		stack, _ := api.FindServiceStack(svc.Cloudformation, cluster, projectName)
		if stack != nil {
			return fmt.Errorf("A service already exists for %q in cluster %q. Use `deploy` or `update-service`",
				projectName, cluster)
		}

		log.Printf("Generating task definition from %v", composeFiles)
		t := compose.Transformer{
			ComposeFiles: composeFiles,
			ProjectName:  projectName,
		}

		taskDefinitionInput, err := t.Transform()
		if err != nil {
			return err
		}

		if logPrefix == "" {
			logPrefix = projectName
		}

		if logGroup, exists := api.GetStackOutputByKey(clusterStack, "LogGroupName"); exists {
			log.Printf("Setting tasks to use log group %s", logGroup)

			for _, def := range taskDefinitionInput.ContainerDefinitions {
				if def.LogConfiguration == nil {
					def.LogConfiguration = &ecs.LogConfiguration{
						LogDriver: aws.String("awslogs"),
						Options: map[string]*string{
							"awslogs-group":         aws.String(logGroup),
							"awslogs-region":        aws.String(os.Getenv("AWS_REGION")),
							"awslogs-stream-prefix": aws.String(logPrefix),
						},
					}
				}
			}
		}

		log.Printf("Registering a task for %s", projectName)
		resp, err := svc.ECS.RegisterTaskDefinition(taskDefinitionInput)
		if err != nil {
			return err
		}
		log.Printf("Registered task definition %s:%d", *resp.TaskDefinition.Family, *resp.TaskDefinition.Revision)

		network, err := api.FindNetworkStack(svc.Cloudformation, cluster)
		if err != nil {
			return err
		}
		log.Printf("Found network stack %s", network.StackName)

		ctx := api.CreateStackContext{
			Params: map[string]string{
				"ECSCluster":       cluster,
				"TaskFamily":       *resp.TaskDefinition.Family,
				"TaskDefinition":   *resp.TaskDefinition.TaskDefinitionArn,
				"Subnets":          network.Subnets,
				"Vpc":              network.Vpc,
				"ECSSecurityGroup": network.SecurityGroup,
				"SSLCertificateId": certificateID,
			},
			DisableRollback: disableRollback,
		}

		exposedPorts := api.ExposedPorts(resp.TaskDefinition)

		if len(exposedPorts) != 1 {
			return fmt.Errorf("Task definition without exactly 1 host mapped port are not yet supported")
		}

		// for now this is a single value
		for container, mappings := range exposedPorts {
			for _, mapping := range mappings {
				ctx.Params["ContainerName"] = container
				ctx.Params["ContainerPort"] = strconv.FormatInt(*mapping.ContainerPort, 10)
				ctx.Params["HealthCheckUrl"] = healthCheck
				ctx.Params["ELBPort"] = strconv.FormatInt(*mapping.HostPort, 10)
			}
		}

		timer := time.Now()
		stackName := cluster + "-ecs-service-" + time.Now().Format(stackDateFormat)

		log.Printf("Creating service cloudformation stack %s", stackName)

		err = api.CreateStack(svc.Cloudformation, stackName, templates.EcsService(), ctx)
		if err != nil {
			return err
		}

		err = api.PollUntilCreated(svc.Cloudformation, stackName, func(event *cloudformation.StackEvent) {
			log.Printf("%s\n", api.FormatStackEvent(event))
		})
		if err != nil {
			return err
		}

		stackOutputs, err := api.StackOutputs(svc.Cloudformation, stackName)
		if err != nil {
			return err
		}

		var printer = func(e *ecs.ServiceEvent) {
			log.Println(*e.Message)
		}

		log.Printf("Waiting for service to reach a steady state.")
		err = api.PollUntilTaskDeployed(svc.ECS, cluster, stackOutputs["ECSService"], *resp.TaskDefinition.TaskDefinitionArn, printer)
		if err != nil {
			return err
		}

		// ui.Printf("Waiting for service to stabilize")
		// if err = apient.WaitUntilServicesStable(input.ClusterName, serviceOutputs["ECSService"]); err != nil {
		// 	ui.Fatal(err)
		// }

		log.Printf("Service created in %s", time.Now().Sub(timer).String())
		log.Printf("Service available at %s", stackOutputs["ECSLoadBalancer"])
		return nil
	})
}

func currentDirName() string {
	cwd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	return filepath.Base(cwd)
}
<|endoftext|>


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

package cmd

import (
	"github.com/spf13/cobra"

	"cuelang.org/go/internal/encoding"
	"cuelang.org/go/internal/filetypes"
)

// newExportCmd creates and export command
func newExportCmd(c *Command) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "export",
		Short: "output data in a standard format",
		Long: `export evaluates the configuration found in the current
directory and prints the emit value to stdout.

Examples:
Evaluated and emit

	# a single file
	cue export config.cue

	# multiple files: these are combined at the top-level. Order doesn't matter.
	cue export file1.cue foo/file2.cue

	# all files within the "mypkg" package: this includes all files in the
	# current directory and its ancestor directories that are marked with the
	# same package.
	cue export -p cloud

	# the -p flag can be omitted if the directory only contains files for
	# the "mypkg" package.
	cue export

Emit value:
For CUE files, the generated configuration is derived from the top-level
single expression, the emit value. For example, the file

	// config.cue
	arg1: 1
	arg2: "my string"

	{
		a: arg1
		b: arg2
	}

yields the following JSON:

	{
		"a": 1,
		"b", "my string"
	}

In absence of arguments, the current directory is loaded as a package instance.
A package instance for a directory contains all files in the directory and its
ancestor directories, up to the module root, belonging to the same package.
If the package is not explicitly defined by the '-p' flag, it must be uniquely
defined by the files in the current directory.

Formats
The following formats are recognized:

json    output as JSON
		Outputs any CUE value.

text    output as raw text
        The evaluated value must be of type string.
`,

		RunE: mkRunE(c, runExport),
	}

	addOrphanFlags(cmd.Flags())

	flagMedia.Add(cmd)
	cmd.Flags().Bool(string(flagEscape), false, "use HTML escaping")

	cmd.Flags().StringArrayP(string(flagExpression), "e", nil, "export this expression only")

	cmd.Flags().StringArrayP(string(flagTags), "t", nil,
		"set the value of a tagged field")

	return cmd
}

func runExport(cmd *Command, args []string) error {
	b, err := parseArgs(cmd, args, nil)
	exitOnErr(cmd, err, true)

	format := flagMedia.String(cmd) + ":-"
	f, err := filetypes.ParseFile(format, filetypes.Export)
	exitOnErr(cmd, err, true)

	enc, err := encoding.NewEncoder(f, b.encConfig)
	exitOnErr(cmd, err, true)
	defer enc.Close()

	for _, inst := range b.instances() {
		if b.expressions == nil {
			err = enc.Encode(inst.Value())
			exitOnErr(cmd, err, true)
			continue
		}
		for _, e := range b.expressions {
			v := inst.Eval(e)
			exitOnErr(cmd, v.Err(), true)
			err = enc.Encode(v)
			exitOnErr(cmd, err, true)
		}
	}
	return nil
}
<commit_msg>Add help text to show yaml export option<commit_after>// Copyright 2018 The CUE Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"github.com/spf13/cobra"

	"cuelang.org/go/internal/encoding"
	"cuelang.org/go/internal/filetypes"
)

// newExportCmd creates and export command
func newExportCmd(c *Command) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "export",
		Short: "output data in a standard format",
		Long: `export evaluates the configuration found in the current
directory and prints the emit value to stdout.

Examples:
Evaluated and emit

	# a single file
	cue export config.cue

	# multiple files: these are combined at the top-level. Order doesn't matter.
	cue export file1.cue foo/file2.cue

	# all files within the "mypkg" package: this includes all files in the
	# current directory and its ancestor directories that are marked with the
	# same package.
	cue export -p cloud

	# the -p flag can be omitted if the directory only contains files for
	# the "mypkg" package.
	cue export

Emit value:
For CUE files, the generated configuration is derived from the top-level
single expression, the emit value. For example, the file

	// config.cue
	arg1: 1
	arg2: "my string"

	{
		a: arg1
		b: arg2
	}

yields the following JSON:

	{
		"a": 1,
		"b", "my string"
	}

In absence of arguments, the current directory is loaded as a package instance.
A package instance for a directory contains all files in the directory and its
ancestor directories, up to the module root, belonging to the same package.
If the package is not explicitly defined by the '-p' flag, it must be uniquely
defined by the files in the current directory.

Formats
The following formats are recognized:

json    output as JSON
               Outputs any CUE value.

text    output as raw text
                The evaluated value must be of type string.

yaml    output as YAML
                Outputs any CUE value.
`,

		RunE: mkRunE(c, runExport),
	}

	addOrphanFlags(cmd.Flags())

	flagMedia.Add(cmd)
	cmd.Flags().Bool(string(flagEscape), false, "use HTML escaping")

	cmd.Flags().StringArrayP(string(flagExpression), "e", nil, "export this expression only")

	cmd.Flags().StringArrayP(string(flagTags), "t", nil,
		"set the value of a tagged field")

	return cmd
}

func runExport(cmd *Command, args []string) error {
	b, err := parseArgs(cmd, args, nil)
	exitOnErr(cmd, err, true)

	format := flagMedia.String(cmd) + ":-"
	f, err := filetypes.ParseFile(format, filetypes.Export)
	exitOnErr(cmd, err, true)

	enc, err := encoding.NewEncoder(f, b.encConfig)
	exitOnErr(cmd, err, true)
	defer enc.Close()

	for _, inst := range b.instances() {
		if b.expressions == nil {
			err = enc.Encode(inst.Value())
			exitOnErr(cmd, err, true)
			continue
		}
		for _, e := range b.expressions {
			v := inst.Eval(e)
			exitOnErr(cmd, v.Err(), true)
			err = enc.Encode(v)
			exitOnErr(cmd, err, true)
		}
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2012-2015 Vladimir Gorbunov. All rights reserved.  Use of
// this source code is governed by a MIT license that can be found in
// the LICENSE file.

/*
Command-line interface for http://www.multitran.ru/
*/
package main

import (
	"errors"
	"flag"
	"fmt"
	"github.com/vladimir-g/gmtrn"
	"os"
	"sort"
	"strings"
	"unicode/utf8"
)

var lang string
var availableLangs []string

// Set command-line flags
func init() {
	// Get languages in alphabetical order
	availableLangs = make([]string, len(gmtrn.Languages))
	var i int
	for k, _ := range gmtrn.Languages {
		availableLangs[i] = k
		i++
	}
	sort.Strings(availableLangs)
	// Get list of available languages for usage
	usage := "Translation language. Available values:\n\t" +
		strings.Join(availableLangs, "\n\t")
	defaultLang := "english"
	flag.StringVar(&lang, "language", defaultLang, usage)
	flag.StringVar(&lang, "l", defaultLang, "Same as -language")
}

// Usage text
func usage() {
	fmt.Fprintf(os.Stderr, "Usage: %s [-l|-language lang] query\n",
		os.Args[0])
	flag.PrintDefaults()
}

// Validate command-line arguments
func parseArgs() (query string, err error) {
	var found bool
	for _, v := range availableLangs {
		if v == lang {
			found = true
		}
	}
	if !found {
		err = errors.New("Language not available")
	}
	query = strings.Join(flag.Args(), " ")
	if len(query) == 0 {
		err = errors.New("Query required")
	}
	return
}

// Get maximum length of word topic (left column)
func getMaxTopicLen(wl *[]gmtrn.WordList) int {
	var maxLen int
	var max string
	for _, wlist := range *wl {
		for _, w := range wlist.Words {
			for _, m := range w.Meanings {
				if len(m.Abbrev) > maxLen {
					maxLen = len(m.Abbrev)
					max = m.Abbrev
				}
			}
		}
	}
	return utf8.RuneCountInString(max)
}

// Print WordList heading
func printWordList(wlist *gmtrn.WordList, maxTopicLen int) {
	length := utf8.RuneCountInString(wlist.Query)
	fmt.Printf(" %s\n", strings.Repeat("=", length))
	fmt.Printf(" %s\n", wlist.Query)
	fmt.Printf(" %s\n", strings.Repeat("=", length))
	printWordListContents(wlist, maxTopicLen)
}

// Print WordList contents
func printWordListContents(wlist *gmtrn.WordList, maxTopicLen int) {
	for _, word := range wlist.Words {
		partLen := 0
		if len(word.Part) > 0 {
			partLen += utf8.RuneCountInString(word.Part) + 1
		}
		length := utf8.RuneCountInString(word.Word) + partLen
		// fmt.Printf("%s\n", strings.Repeat("-", length))
		fmt.Printf(" %s %s\n", word.Word, word.Part)
		fmt.Printf(" %s\n", strings.Repeat("-", length))
		printWord(&word, maxTopicLen)
	}
}

// Print one word
func printWord(word *gmtrn.Word, maxTopicLen int) {
	for _, m := range word.Meanings {
		fmt.Printf(" %*s  ", maxTopicLen, m.Abbrev)
		words := make([]string, 0, len(m.Words))
		for _, w := range m.Words {
			// Add space to additional info if needed
			if len(w.Add) > 0 && !strings.HasPrefix(w.Add, " ") {
				w.Add = " " + w.Add
			}
			words = append(words,
				fmt.Sprintf("%s%s", w.Word, w.Add))
		}
		fmt.Printf("%s\n", strings.Join(words, ", "))
	}
}

// Print meaning list
func printResult(result *[]gmtrn.WordList) {
	// Get longest column for pretty printing
	maxTopicLen := getMaxTopicLen(result)
	for _, wlist := range *result {
		printWordList(&wlist, maxTopicLen)
		fmt.Printf("\n")
	}
}

func main() {
	flag.Usage = usage
	flag.Parse()
	query, err := parseArgs()
	if err != nil {
		fmt.Printf("Error: %s\n", err)
		usage()
		return
	}
	result, err := gmtrn.Query(query, gmtrn.Languages[lang])
	if err != nil {
		fmt.Printf("Error: %s\n", err)
		return
	}
	printResult(&result)
}
<commit_msg>gofmt<commit_after>// Copyright 2012-2015 Vladimir Gorbunov. All rights reserved.  Use of
// this source code is governed by a MIT license that can be found in
// the LICENSE file.

/*
Command-line interface for http://www.multitran.ru/
*/
package main

import (
	"errors"
	"flag"
	"fmt"
	"github.com/vladimir-g/gmtrn"
	"os"
	"sort"
	"strings"
	"unicode/utf8"
)

var lang string
var availableLangs []string

// Set command-line flags
func init() {
	// Get languages in alphabetical order
	availableLangs = make([]string, len(gmtrn.Languages))
	var i int
	for k, _ := range gmtrn.Languages {
		availableLangs[i] = k
		i++
	}
	sort.Strings(availableLangs)
	// Get list of available languages for usage
	usage := "Translation language. Available values:\n\t" +
		strings.Join(availableLangs, "\n\t")
	defaultLang := "english"
	flag.StringVar(&lang, "language", defaultLang, usage)
	flag.StringVar(&lang, "l", defaultLang, "Same as -language")
}

// Usage text
func usage() {
	fmt.Fprintf(os.Stderr, "Usage: %s [-l|-language lang] query\n",
		os.Args[0])
	flag.PrintDefaults()
}

// Validate command-line arguments
func parseArgs() (query string, err error) {
	var found bool
	for _, v := range availableLangs {
		if v == lang {
			found = true
		}
	}
	if !found {
		err = errors.New("Language not available")
	}
	query = strings.Join(flag.Args(), " ")
	if len(query) == 0 {
		err = errors.New("Query required")
	}
	return
}

// Get maximum length of word topic (left column)
func getMaxTopicLen(wl *[]gmtrn.WordList) int {
	var maxLen int
	var max string
	for _, wlist := range *wl {
		for _, w := range wlist.Words {
			for _, m := range w.Meanings {
				if len(m.Abbrev) > maxLen {
					maxLen = len(m.Abbrev)
					max = m.Abbrev
				}
			}
		}
	}
	return utf8.RuneCountInString(max)
}

// Print WordList heading
func printWordList(wlist *gmtrn.WordList, maxTopicLen int) {
	length := utf8.RuneCountInString(wlist.Query)
	fmt.Printf(" %s\n", strings.Repeat("=", length))
	fmt.Printf(" %s\n", wlist.Query)
	fmt.Printf(" %s\n", strings.Repeat("=", length))
	printWordListContents(wlist, maxTopicLen)
}

// Print WordList contents
func printWordListContents(wlist *gmtrn.WordList, maxTopicLen int) {
	for _, word := range wlist.Words {
		partLen := 0
		if len(word.Part) > 0 {
			partLen += utf8.RuneCountInString(word.Part) + 1
		}
		length := utf8.RuneCountInString(word.Word) + partLen
		// fmt.Printf("%s\n", strings.Repeat("-", length))
		fmt.Printf(" %s %s\n", word.Word, word.Part)
		fmt.Printf(" %s\n", strings.Repeat("-", length))
		printWord(&word, maxTopicLen)
	}
}

// Print one word
func printWord(word *gmtrn.Word, maxTopicLen int) {
	for _, m := range word.Meanings {
		fmt.Printf(" %*s  ", maxTopicLen, m.Abbrev)
		words := make([]string, 0, len(m.Words))
		for _, w := range m.Words {
			// Add space to additional info if needed
			if len(w.Add) > 0 && !strings.HasPrefix(w.Add, " ") {
				w.Add = " " + w.Add
			}
			words = append(words,
				fmt.Sprintf("%s%s", w.Word, w.Add))
		}
		fmt.Printf("%s\n", strings.Join(words, ", "))
	}
}

// Print meaning list
func printResult(result *[]gmtrn.WordList) {
	// Get longest column for pretty printing
	maxTopicLen := getMaxTopicLen(result)
	for _, wlist := range *result {
		printWordList(&wlist, maxTopicLen)
		fmt.Printf("\n")
	}
}

func main() {
	flag.Usage = usage
	flag.Parse()
	query, err := parseArgs()
	if err != nil {
		fmt.Printf("Error: %s\n", err)
		usage()
		return
	}
	result, err := gmtrn.Query(query, gmtrn.Languages[lang])
	if err != nil {
		fmt.Printf("Error: %s\n", err)
		return
	}
	printResult(&result)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/jkomoros/sudoku"
)

type model struct {
	grid *sudoku.Grid
}

//TODO: rename Mutator to command
type command interface {
	Apply(m *model)
	Undo(m *model)
}

type markCommand struct {
	row, col    int
	marksToggle map[int]bool
}

type numberCommand struct {
	row, col int
	number   int
	//Necessary so we can undo.
	oldNumber int
}

func (m *model) SetGrid(grid *sudoku.Grid) {
	m.grid = grid
}

func (m *model) SetMarks(row, col int, marksToggle map[int]bool) {
	command := m.newMarkCommand(row, col, marksToggle)
	if command == nil {
		return
	}
	command.Apply(m)
}

func (m *model) newMarkCommand(row, col int, marksToggle map[int]bool) *markCommand {
	//Only keep marks in the toggle that won't be a no-op
	newMarksToggle := make(map[int]bool)

	cell := m.grid.Cell(row, col)

	if cell == nil {
		return nil
	}
	for key, value := range marksToggle {
		if cell.Mark(key) != value {
			//Good, keep it
			newMarksToggle[key] = value
		}
	}

	if len(newMarksToggle) == 0 {
		//The command would be a no op!
		return nil
	}

	return &markCommand{row, col, newMarksToggle}
}

func (m *model) SetNumber(row, col int, num int) {
	command := m.newNumberCommand(row, col, num)
	if command == nil {
		return
	}
	command.Apply(m)
}

func (m *model) newNumberCommand(row, col int, num int) *numberCommand {
	cell := m.grid.Cell(row, col)

	if cell == nil {
		return nil
	}

	if cell.Number() == num {
		return nil
	}

	return &numberCommand{row, col, num, cell.Number()}
}

func (m *markCommand) Apply(model *model) {
	cell := model.grid.Cell(m.row, m.col)
	if cell == nil {
		return
	}
	for key, value := range m.marksToggle {
		cell.SetMark(key, value)
	}
}

func (m *markCommand) Undo(model *model) {
	cell := model.grid.Cell(m.row, m.col)
	if cell == nil {
		return
	}
	for key, value := range m.marksToggle {
		//Set the opposite since we're undoing.
		cell.SetMark(key, !value)
	}
}

func (n *numberCommand) Apply(model *model) {
	cell := model.grid.Cell(n.row, n.col)
	if cell == nil {
		return
	}
	cell.SetNumber(n.number)
}

func (n *numberCommand) Undo(model *model) {
	cell := model.grid.Cell(n.row, n.col)
	if cell == nil {
		return
	}
	cell.SetNumber(n.oldNumber)
}
<commit_msg>Removed old TODO<commit_after>package main

import (
	"github.com/jkomoros/sudoku"
)

type model struct {
	grid *sudoku.Grid
}

type command interface {
	Apply(m *model)
	Undo(m *model)
}

type markCommand struct {
	row, col    int
	marksToggle map[int]bool
}

type numberCommand struct {
	row, col int
	number   int
	//Necessary so we can undo.
	oldNumber int
}

func (m *model) SetGrid(grid *sudoku.Grid) {
	m.grid = grid
}

func (m *model) SetMarks(row, col int, marksToggle map[int]bool) {
	command := m.newMarkCommand(row, col, marksToggle)
	if command == nil {
		return
	}
	command.Apply(m)
}

func (m *model) newMarkCommand(row, col int, marksToggle map[int]bool) *markCommand {
	//Only keep marks in the toggle that won't be a no-op
	newMarksToggle := make(map[int]bool)

	cell := m.grid.Cell(row, col)

	if cell == nil {
		return nil
	}
	for key, value := range marksToggle {
		if cell.Mark(key) != value {
			//Good, keep it
			newMarksToggle[key] = value
		}
	}

	if len(newMarksToggle) == 0 {
		//The command would be a no op!
		return nil
	}

	return &markCommand{row, col, newMarksToggle}
}

func (m *model) SetNumber(row, col int, num int) {
	command := m.newNumberCommand(row, col, num)
	if command == nil {
		return
	}
	command.Apply(m)
}

func (m *model) newNumberCommand(row, col int, num int) *numberCommand {
	cell := m.grid.Cell(row, col)

	if cell == nil {
		return nil
	}

	if cell.Number() == num {
		return nil
	}

	return &numberCommand{row, col, num, cell.Number()}
}

func (m *markCommand) Apply(model *model) {
	cell := model.grid.Cell(m.row, m.col)
	if cell == nil {
		return
	}
	for key, value := range m.marksToggle {
		cell.SetMark(key, value)
	}
}

func (m *markCommand) Undo(model *model) {
	cell := model.grid.Cell(m.row, m.col)
	if cell == nil {
		return
	}
	for key, value := range m.marksToggle {
		//Set the opposite since we're undoing.
		cell.SetMark(key, !value)
	}
}

func (n *numberCommand) Apply(model *model) {
	cell := model.grid.Cell(n.row, n.col)
	if cell == nil {
		return
	}
	cell.SetNumber(n.number)
}

func (n *numberCommand) Undo(model *model) {
	cell := model.grid.Cell(n.row, n.col)
	if cell == nil {
		return
	}
	cell.SetNumber(n.oldNumber)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"launchpad.net/gnuflag"
	. "launchpad.net/gocheck"
	"launchpad.net/juju-core/cmd"
	"launchpad.net/juju-core/environs/config"
	_ "launchpad.net/juju-core/environs/dummy"
	"launchpad.net/juju-core/testing"
	"launchpad.net/juju-core/version"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	stdtesting "testing"
)

func TestPackage(t *stdtesting.T) {
	testing.MgoTestPackage(t)
}

type MainSuite struct{}

var _ = Suite(&MainSuite{})

var (
	flagRunMain = flag.Bool("run-main", false, "Run the application's main function for recursive testing")
)

// Reentrancy point for testing (something as close as possible to) the juju
// tool itself.
func TestRunMain(t *stdtesting.T) {
	if *flagRunMain {
		Main(flag.Args())
	}
}

func badrun(c *C, exit int, args ...string) string {
	localArgs := append([]string{"-test.run", "TestRunMain", "-run-main", "--", "juju"}, args...)
	ps := exec.Command(os.Args[0], localArgs...)
	ps.Env = append(os.Environ(), "JUJU_HOME="+config.JujuHome())
	output, err := ps.CombinedOutput()
	if exit != 0 {
		c.Assert(err, ErrorMatches, fmt.Sprintf("exit status %d", exit))
	}
	return string(output)
}

func helpText(command cmd.Command, name string) string {
	buff := &bytes.Buffer{}
	info := command.Info()
	info.Name = name
	f := gnuflag.NewFlagSet(info.Name, gnuflag.ContinueOnError)
	command.SetFlags(f)
	buff.Write(info.Help(f))
	return buff.String()
}

func deployHelpText() string {
	return helpText(&DeployCommand{}, "juju deploy")
}

func syncToolsHelpText() string {
	return helpText(&SyncToolsCommand{}, "juju sync-tools")
}

var runMainTests = []struct {
	summary string
	args    []string
	code    int
	out     string
}{
	{
		summary: "no params shows help",
		args:    []string{},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju help is the same as juju",
		args:    []string{"help"},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju --help works too",
		args:    []string{"--help"},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju help basics is the same as juju",
		args:    []string{"help", "basics"},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju help foo doesn't exist",
		args:    []string{"help", "foo"},
		code:    1,
		out:     "error: unknown command or topic for foo\n",
	}, {
		summary: "juju help deploy shows the default help without global options",
		args:    []string{"help", "deploy"},
		code:    0,
		out:     deployHelpText(),
	}, {
		summary: "juju --help deploy shows the same help as 'help deploy'",
		args:    []string{"--help", "deploy"},
		code:    0,
		out:     deployHelpText(),
	}, {
		summary: "juju deploy --help shows the same help as 'help deploy'",
		args:    []string{"deploy", "--help"},
		code:    0,
		out:     deployHelpText(),
	}, {
		summary: "unknown command",
		args:    []string{"discombobulate"},
		code:    2,
		out:     "error: unrecognized command: juju discombobulate\n",
	}, {
		summary: "unknown option before command",
		args:    []string{"--cheese", "bootstrap"},
		code:    2,
		out:     "error: flag provided but not defined: --cheese\n",
	}, {
		summary: "unknown option after command",
		args:    []string{"bootstrap", "--cheese"},
		code:    2,
		out:     "error: flag provided but not defined: --cheese\n",
	}, {
		summary: "known option, but specified before command",
		args:    []string{"--environment", "blah", "bootstrap"},
		code:    2,
		out:     "error: flag provided but not defined: --environment\n",
	}, {
		summary: "juju sync-tools registered properly",
		args:    []string{"sync-tools", "--help"},
		code:    0,
		out:     syncToolsHelpText(),
	}, {
		summary: "check version command registered properly",
		args:    []string{"version"},
		code:    0,
		out:     version.Current.String() + "\n",
	},
}

func (s *MainSuite) TestRunMain(c *C) {
	defer config.SetJujuHome(config.SetJujuHome(c.MkDir()))
	for i, t := range runMainTests {
		c.Logf("test %d: %s", i, t.summary)
		out := badrun(c, t.code, t.args...)
		c.Assert(out, Equals, t.out)
	}
}

var brokenConfig = `
environments:
    one:
        type: dummy
        state-server: false
        authorized-keys: i-am-a-key
        broken: %s
`

// breakJuju forces the dummy environment to return an error when
// environMethod is called.
func breakJuju(c *C, environMethod string) (msg string) {
	yaml := fmt.Sprintf(brokenConfig, environMethod)
	err := ioutil.WriteFile(config.JujuHomePath("environments.yaml"), []byte(yaml), 0666)
	c.Assert(err, IsNil)

	return fmt.Sprintf("dummy.%s is broken", environMethod)
}

func (s *MainSuite) TestActualRunJujuArgsBeforeCommand(c *C) {
	defer testing.MakeFakeHomeNoEnvironments(c, "one").Restore()
	// Check global args work when specified before command
	msg := breakJuju(c, "Bootstrap")
	logpath := filepath.Join(c.MkDir(), "log")
	out := badrun(c, 1, "--log-file", logpath, "--verbose", "--debug", "bootstrap")
	c.Assert(out, Equals, "error: "+msg+"\n")
	content, err := ioutil.ReadFile(logpath)
	c.Assert(err, IsNil)
	fullmsg := fmt.Sprintf(`.*\n.*ERROR JUJU:juju:bootstrap juju bootstrap command failed: %s\n`, msg)
	c.Assert(string(content), Matches, fullmsg)
}

func (s *MainSuite) TestActualRunJujuArgsAfterCommand(c *C) {
	defer testing.MakeFakeHomeNoEnvironments(c, "one").Restore()
	// Check global args work when specified after command
	msg := breakJuju(c, "Bootstrap")
	logpath := filepath.Join(c.MkDir(), "log")
	out := badrun(c, 1, "bootstrap", "--log-file", logpath, "--verbose", "--debug")
	c.Assert(out, Equals, "error: "+msg+"\n")
	content, err := ioutil.ReadFile(logpath)
	c.Assert(err, IsNil)
	fullmsg := fmt.Sprintf(`.*\n.*ERROR JUJU:juju:bootstrap juju bootstrap command failed: %s\n`, msg)
	c.Assert(string(content), Matches, fullmsg)
}

var commandNames = []string{
	"add-relation",
	"add-unit",
	"bootstrap",
	"debug-log",
	"deploy",
	"destroy-environment",
	"destroy-machine",
	"destroy-relation",
	"destroy-service",
	"destroy-unit",
	"expose",
	"generate-config", // alias for init
	"get",
	"get-constraints",
	"get-env", // alias for set-environment
	"get-environment",
	"help",
	"init",
	"publish",
	"remove-relation", // alias for destroy-relation
	"remove-unit",     // alias for destroy-unit
	"resolved",
	"scp",
	"set",
	"set-constraints",
	"ssh",
	"stat", // alias for status
	"status",
	"sync-tools",
	"terminate-machine", // alias for destroy-machine
	"unexpose",
	"upgrade-charm",
	"upgrade-juju",
	"version",
}

func (s *MainSuite) TestHelpCommands(c *C) {
	// Check that we have correctly registered all the commands
	// by checking the help output.
	defer config.SetJujuHome(config.SetJujuHome(c.MkDir()))
	out := badrun(c, 0, "help", "commands")
	lines := strings.Split(out, "\n")
	var names []string
	for _, line := range lines {
		f := strings.Fields(line)
		if len(f) == 0 {
			continue
		}
		names = append(names, f[0])
	}
	// The names should be output in alphabetical order, so don't sort.
	c.Assert(names, DeepEquals, commandNames)
}

var topicNames = []string{
	"basics",
	"commands",
	"global-options",
	"topics",
}

func (s *MainSuite) TestHelpTopics(c *C) {
	// Check that we have correctly registered all the topics
	// by checking the help output.
	defer config.SetJujuHome(config.SetJujuHome(c.MkDir()))
	out := badrun(c, 0, "help", "topics")
	lines := strings.Split(out, "\n")
	var names []string
	for _, line := range lines {
		f := strings.Fields(line)
		if len(f) == 0 {
			continue
		}
		names = append(names, f[0])
	}
	// The names should be output in alphabetical order, so don't sort.
	c.Assert(names, DeepEquals, topicNames)
}

var globalFlags = []string{
	"--debug .*",
	"-h, --help .*",
	"--log-file .*",
	"-v, --verbose .*",
}

func (s *MainSuite) TestHelpGlobalOptions(c *C) {
	// Check that we have correctly registered all the topics
	// by checking the help output.
	defer config.SetJujuHome(config.SetJujuHome(c.MkDir()))
	out := badrun(c, 0, "help", "global-options")
	c.Assert(out, Matches, `Global Options

These options may be used with any command, and may appear in front of any
command\.(.|\n)*`)
	lines := strings.Split(out, "\n")
	var flags []string
	for _, line := range lines {
		f := strings.Fields(line)
		if len(f) == 0 || line[0] != '-' {
			continue
		}
		flags = append(flags, line)
	}
	c.Assert(len(flags), Equals, len(globalFlags))
	for i, line := range flags {
		c.Assert(line, Matches, globalFlags[i])
	}
}
<commit_msg>Add new command to main test.<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"launchpad.net/gnuflag"
	. "launchpad.net/gocheck"
	"launchpad.net/juju-core/cmd"
	"launchpad.net/juju-core/environs/config"
	_ "launchpad.net/juju-core/environs/dummy"
	"launchpad.net/juju-core/testing"
	"launchpad.net/juju-core/version"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	stdtesting "testing"
)

func TestPackage(t *stdtesting.T) {
	testing.MgoTestPackage(t)
}

type MainSuite struct{}

var _ = Suite(&MainSuite{})

var (
	flagRunMain = flag.Bool("run-main", false, "Run the application's main function for recursive testing")
)

// Reentrancy point for testing (something as close as possible to) the juju
// tool itself.
func TestRunMain(t *stdtesting.T) {
	if *flagRunMain {
		Main(flag.Args())
	}
}

func badrun(c *C, exit int, args ...string) string {
	localArgs := append([]string{"-test.run", "TestRunMain", "-run-main", "--", "juju"}, args...)
	ps := exec.Command(os.Args[0], localArgs...)
	ps.Env = append(os.Environ(), "JUJU_HOME="+config.JujuHome())
	output, err := ps.CombinedOutput()
	if exit != 0 {
		c.Assert(err, ErrorMatches, fmt.Sprintf("exit status %d", exit))
	}
	return string(output)
}

func helpText(command cmd.Command, name string) string {
	buff := &bytes.Buffer{}
	info := command.Info()
	info.Name = name
	f := gnuflag.NewFlagSet(info.Name, gnuflag.ContinueOnError)
	command.SetFlags(f)
	buff.Write(info.Help(f))
	return buff.String()
}

func deployHelpText() string {
	return helpText(&DeployCommand{}, "juju deploy")
}

func syncToolsHelpText() string {
	return helpText(&SyncToolsCommand{}, "juju sync-tools")
}

var runMainTests = []struct {
	summary string
	args    []string
	code    int
	out     string
}{
	{
		summary: "no params shows help",
		args:    []string{},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju help is the same as juju",
		args:    []string{"help"},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju --help works too",
		args:    []string{"--help"},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju help basics is the same as juju",
		args:    []string{"help", "basics"},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju help foo doesn't exist",
		args:    []string{"help", "foo"},
		code:    1,
		out:     "error: unknown command or topic for foo\n",
	}, {
		summary: "juju help deploy shows the default help without global options",
		args:    []string{"help", "deploy"},
		code:    0,
		out:     deployHelpText(),
	}, {
		summary: "juju --help deploy shows the same help as 'help deploy'",
		args:    []string{"--help", "deploy"},
		code:    0,
		out:     deployHelpText(),
	}, {
		summary: "juju deploy --help shows the same help as 'help deploy'",
		args:    []string{"deploy", "--help"},
		code:    0,
		out:     deployHelpText(),
	}, {
		summary: "unknown command",
		args:    []string{"discombobulate"},
		code:    2,
		out:     "error: unrecognized command: juju discombobulate\n",
	}, {
		summary: "unknown option before command",
		args:    []string{"--cheese", "bootstrap"},
		code:    2,
		out:     "error: flag provided but not defined: --cheese\n",
	}, {
		summary: "unknown option after command",
		args:    []string{"bootstrap", "--cheese"},
		code:    2,
		out:     "error: flag provided but not defined: --cheese\n",
	}, {
		summary: "known option, but specified before command",
		args:    []string{"--environment", "blah", "bootstrap"},
		code:    2,
		out:     "error: flag provided but not defined: --environment\n",
	}, {
		summary: "juju sync-tools registered properly",
		args:    []string{"sync-tools", "--help"},
		code:    0,
		out:     syncToolsHelpText(),
	}, {
		summary: "check version command registered properly",
		args:    []string{"version"},
		code:    0,
		out:     version.Current.String() + "\n",
	},
}

func (s *MainSuite) TestRunMain(c *C) {
	defer config.SetJujuHome(config.SetJujuHome(c.MkDir()))
	for i, t := range runMainTests {
		c.Logf("test %d: %s", i, t.summary)
		out := badrun(c, t.code, t.args...)
		c.Assert(out, Equals, t.out)
	}
}

var brokenConfig = `
environments:
    one:
        type: dummy
        state-server: false
        authorized-keys: i-am-a-key
        broken: %s
`

// breakJuju forces the dummy environment to return an error when
// environMethod is called.
func breakJuju(c *C, environMethod string) (msg string) {
	yaml := fmt.Sprintf(brokenConfig, environMethod)
	err := ioutil.WriteFile(config.JujuHomePath("environments.yaml"), []byte(yaml), 0666)
	c.Assert(err, IsNil)

	return fmt.Sprintf("dummy.%s is broken", environMethod)
}

func (s *MainSuite) TestActualRunJujuArgsBeforeCommand(c *C) {
	defer testing.MakeFakeHomeNoEnvironments(c, "one").Restore()
	// Check global args work when specified before command
	msg := breakJuju(c, "Bootstrap")
	logpath := filepath.Join(c.MkDir(), "log")
	out := badrun(c, 1, "--log-file", logpath, "--verbose", "--debug", "bootstrap")
	c.Assert(out, Equals, "error: "+msg+"\n")
	content, err := ioutil.ReadFile(logpath)
	c.Assert(err, IsNil)
	fullmsg := fmt.Sprintf(`.*\n.*ERROR JUJU:juju:bootstrap juju bootstrap command failed: %s\n`, msg)
	c.Assert(string(content), Matches, fullmsg)
}

func (s *MainSuite) TestActualRunJujuArgsAfterCommand(c *C) {
	defer testing.MakeFakeHomeNoEnvironments(c, "one").Restore()
	// Check global args work when specified after command
	msg := breakJuju(c, "Bootstrap")
	logpath := filepath.Join(c.MkDir(), "log")
	out := badrun(c, 1, "bootstrap", "--log-file", logpath, "--verbose", "--debug")
	c.Assert(out, Equals, "error: "+msg+"\n")
	content, err := ioutil.ReadFile(logpath)
	c.Assert(err, IsNil)
	fullmsg := fmt.Sprintf(`.*\n.*ERROR JUJU:juju:bootstrap juju bootstrap command failed: %s\n`, msg)
	c.Assert(string(content), Matches, fullmsg)
}

var commandNames = []string{
	"add-relation",
	"add-unit",
	"bootstrap",
	"debug-log",
	"deploy",
	"destroy-environment",
	"destroy-machine",
	"destroy-relation",
	"destroy-service",
	"destroy-unit",
	"expose",
	"generate-config", // alias for init
	"get",
	"get-constraints",
	"get-env", // alias for set-environment
	"get-environment",
	"help",
	"init",
	"publish",
	"remove-relation", // alias for destroy-relation
	"remove-unit",     // alias for destroy-unit
	"resolved",
	"scp",
	"set",
	"set-constraints",
	"set-env", // alias for set-environment
	"set-environment",
	"ssh",
	"stat", // alias for status
	"status",
	"sync-tools",
	"terminate-machine", // alias for destroy-machine
	"unexpose",
	"upgrade-charm",
	"upgrade-juju",
	"version",
}

func (s *MainSuite) TestHelpCommands(c *C) {
	// Check that we have correctly registered all the commands
	// by checking the help output.
	defer config.SetJujuHome(config.SetJujuHome(c.MkDir()))
	out := badrun(c, 0, "help", "commands")
	lines := strings.Split(out, "\n")
	var names []string
	for _, line := range lines {
		f := strings.Fields(line)
		if len(f) == 0 {
			continue
		}
		names = append(names, f[0])
	}
	// The names should be output in alphabetical order, so don't sort.
	c.Assert(names, DeepEquals, commandNames)
}

var topicNames = []string{
	"basics",
	"commands",
	"global-options",
	"topics",
}

func (s *MainSuite) TestHelpTopics(c *C) {
	// Check that we have correctly registered all the topics
	// by checking the help output.
	defer config.SetJujuHome(config.SetJujuHome(c.MkDir()))
	out := badrun(c, 0, "help", "topics")
	lines := strings.Split(out, "\n")
	var names []string
	for _, line := range lines {
		f := strings.Fields(line)
		if len(f) == 0 {
			continue
		}
		names = append(names, f[0])
	}
	// The names should be output in alphabetical order, so don't sort.
	c.Assert(names, DeepEquals, topicNames)
}

var globalFlags = []string{
	"--debug .*",
	"-h, --help .*",
	"--log-file .*",
	"-v, --verbose .*",
}

func (s *MainSuite) TestHelpGlobalOptions(c *C) {
	// Check that we have correctly registered all the topics
	// by checking the help output.
	defer config.SetJujuHome(config.SetJujuHome(c.MkDir()))
	out := badrun(c, 0, "help", "global-options")
	c.Assert(out, Matches, `Global Options

These options may be used with any command, and may appear in front of any
command\.(.|\n)*`)
	lines := strings.Split(out, "\n")
	var flags []string
	for _, line := range lines {
		f := strings.Fields(line)
		if len(f) == 0 || line[0] != '-' {
			continue
		}
		flags = append(flags, line)
	}
	c.Assert(len(flags), Equals, len(globalFlags))
	for i, line := range flags {
		c.Assert(line, Matches, globalFlags[i])
	}
}
<|endoftext|>


<commit_before>package mountlib

import (
	"io"
	"sync"

	"github.com/ncw/rclone/fs"
	"github.com/pkg/errors"
)

// WriteFileHandle is an open for write handle on a File
type WriteFileHandle struct {
	mu          sync.Mutex
	closed      bool // set if handle has been closed
	remote      string
	pipeReader  *io.PipeReader
	pipeWriter  *io.PipeWriter
	o           fs.Object
	result      chan error
	file        *File
	writeCalled bool // set the first time Write() is called
	offset      int64
	hash        *fs.MultiHasher
}

func newWriteFileHandle(d *Dir, f *File, src fs.ObjectInfo) (*WriteFileHandle, error) {
	var hash *fs.MultiHasher
	if !f.d.fsys.noChecksum {
		var err error
		hash, err = fs.NewMultiHasherTypes(src.Fs().Hashes())
		if err != nil {
			fs.Errorf(src.Fs(), "newWriteFileHandle hash error: %v", err)
		}
	}

	fh := &WriteFileHandle{
		remote: src.Remote(),
		result: make(chan error, 1),
		file:   f,
		hash:   hash,
	}
	fh.pipeReader, fh.pipeWriter = io.Pipe()
	r := fs.NewAccountSizeName(fh.pipeReader, 0, src.Remote()).WithBuffer() // account the transfer
	go func() {
		o, err := d.f.Put(r, src)
		fh.o = o
		fh.result <- err
	}()
	fh.file.addWriters(1)
	fh.file.setSize(0)
	fs.Stats.Transferring(fh.remote)
	return fh, nil
}

// String converts it to printable
func (fh *WriteFileHandle) String() string {
	if fh == nil {
		return "<nil *WriteFileHandle>"
	}
	if fh.file == nil {
		return "<nil *WriteFileHandle.file>"
	}
	return fh.file.String() + " (w)"
}

// Node returns the Node assocuated with this - satisfies Noder interface
func (fh *WriteFileHandle) Node() Node {
	return fh.file
}

// Write data to the file handle
func (fh *WriteFileHandle) Write(data []byte, offset int64) (written int64, err error) {
	// fs.Debugf(fh.remote, "WriteFileHandle.Write len=%d", len(data))
	fh.mu.Lock()
	defer fh.mu.Unlock()
	if fh.offset != offset {
		fs.Errorf(fh.remote, "WriteFileHandle.Write can't seek in file")
		return 0, ESPIPE
	}
	if fh.closed {
		fs.Errorf(fh.remote, "WriteFileHandle.Write error: %v", EBADF)
		return 0, EBADF
	}
	fh.writeCalled = true
	// FIXME should probably check the file isn't being seeked?
	n, err := fh.pipeWriter.Write(data)
	written = int64(n)
	fh.offset += written
	fh.file.setSize(fh.offset)
	if err != nil {
		fs.Errorf(fh.remote, "WriteFileHandle.Write error: %v", err)
		return 0, err
	}
	// fs.Debugf(fh.remote, "WriteFileHandle.Write OK (%d bytes written)", n)
	if fh.hash != nil {
		_, err = fh.hash.Write(data[:n])
		if err != nil {
			fs.Errorf(fh.remote, "WriteFileHandle.Write HashError: %v", err)
			return written, err
		}
	}
	return written, nil
}

// Offset returns the offset of the file pointer
func (fh *WriteFileHandle) Offset() (offset int64) {
	return fh.offset
}

// close the file handle returning EBADF if it has been
// closed already.
//
// Must be called with fh.mu held
func (fh *WriteFileHandle) close() error {
	if fh.closed {
		return EBADF
	}
	fh.closed = true
	fs.Stats.DoneTransferring(fh.remote, true)
	fh.file.addWriters(-1)
	writeCloseErr := fh.pipeWriter.Close()
	err := <-fh.result
	readCloseErr := fh.pipeReader.Close()
	if err == nil {
		fh.file.setObject(fh.o)
		err = writeCloseErr
	}
	if err == nil {
		err = readCloseErr
	}
	if err == nil && fh.hash != nil {
		for hashType, srcSum := range fh.hash.Sums() {
			dstSum, err := fh.o.Hash(hashType)
			if err != nil {
				return err
			}
			if !fs.HashEquals(srcSum, dstSum) {
				return errors.Errorf("corrupted on transfer: %v hash differ %q vs %q", hashType, srcSum, dstSum)
			}
		}
	}
	return err
}

// Flush is called on each close() of a file descriptor. So if a
// filesystem wants to return write errors in close() and the file has
// cached dirty data, this is a good place to write back data and
// return any errors. Since many applications ignore close() errors
// this is not always useful.
//
// NOTE: The flush() method may be called more than once for each
// open(). This happens if more than one file descriptor refers to an
// opened file due to dup(), dup2() or fork() calls. It is not
// possible to determine if a flush is final, so each flush should be
// treated equally. Multiple write-flush sequences are relatively
// rare, so this shouldn't be a problem.
//
// Filesystems shouldn't assume that flush will always be called after
// some writes, or that if will be called at all.
func (fh *WriteFileHandle) Flush() error {
	fh.mu.Lock()
	defer fh.mu.Unlock()
	// fs.Debugf(fh.remote, "WriteFileHandle.Flush")
	// If Write hasn't been called then ignore the Flush - Release
	// will pick it up
	if !fh.writeCalled {
		fs.Debugf(fh.remote, "WriteFileHandle.Flush ignoring flush on unwritten handle")
		return nil

	}
	err := fh.close()
	if err != nil {
		fs.Errorf(fh.remote, "WriteFileHandle.Flush error: %v", err)
	} else {
		// fs.Debugf(fh.remote, "WriteFileHandle.Flush OK")
	}
	return err
}

// Release is called when we are finished with the file handle
//
// It isn't called directly from userspace so the error is ignored by
// the kernel
func (fh *WriteFileHandle) Release() error {
	fh.mu.Lock()
	defer fh.mu.Unlock()
	if fh.closed {
		fs.Debugf(fh.remote, "WriteFileHandle.Release nothing to do")
		return nil
	}
	fs.Debugf(fh.remote, "WriteFileHandle.Release closing")
	err := fh.close()
	if err != nil {
		fs.Errorf(fh.remote, "WriteFileHandle.Release error: %v", err)
	} else {
		// fs.Debugf(fh.remote, "WriteFileHandle.Release OK")
	}
	return err
}
<commit_msg>mount: fix hang on errored upload<commit_after>package mountlib

import (
	"io"
	"sync"

	"github.com/ncw/rclone/fs"
	"github.com/pkg/errors"
)

// WriteFileHandle is an open for write handle on a File
type WriteFileHandle struct {
	mu          sync.Mutex
	closed      bool // set if handle has been closed
	remote      string
	pipeWriter  *io.PipeWriter
	o           fs.Object
	result      chan error
	file        *File
	writeCalled bool // set the first time Write() is called
	offset      int64
	hash        *fs.MultiHasher
}

func newWriteFileHandle(d *Dir, f *File, src fs.ObjectInfo) (*WriteFileHandle, error) {
	var hash *fs.MultiHasher
	if !f.d.fsys.noChecksum {
		var err error
		hash, err = fs.NewMultiHasherTypes(src.Fs().Hashes())
		if err != nil {
			fs.Errorf(src.Fs(), "newWriteFileHandle hash error: %v", err)
		}
	}

	fh := &WriteFileHandle{
		remote: src.Remote(),
		result: make(chan error, 1),
		file:   f,
		hash:   hash,
	}
	var pipeReader *io.PipeReader
	pipeReader, fh.pipeWriter = io.Pipe()
	go func() {
		r := fs.NewAccountSizeName(pipeReader, 0, src.Remote()).WithBuffer() // account the transfer
		o, err := d.f.Put(r, src)
		if err != nil {
			fs.Errorf(fh.remote, "WriteFileHandle.New Put failed: %v", err)
		}
		// Close the Account and thus the pipeReader so the pipeWriter fails with ErrClosedPipe
		_ = r.Close()
		fh.o = o
		fh.result <- err
	}()
	fh.file.addWriters(1)
	fh.file.setSize(0)
	fs.Stats.Transferring(fh.remote)
	return fh, nil
}

// String converts it to printable
func (fh *WriteFileHandle) String() string {
	if fh == nil {
		return "<nil *WriteFileHandle>"
	}
	if fh.file == nil {
		return "<nil *WriteFileHandle.file>"
	}
	return fh.file.String() + " (w)"
}

// Node returns the Node assocuated with this - satisfies Noder interface
func (fh *WriteFileHandle) Node() Node {
	return fh.file
}

// Write data to the file handle
func (fh *WriteFileHandle) Write(data []byte, offset int64) (written int64, err error) {
	// fs.Debugf(fh.remote, "WriteFileHandle.Write len=%d", len(data))
	fh.mu.Lock()
	defer fh.mu.Unlock()
	if fh.offset != offset {
		fs.Errorf(fh.remote, "WriteFileHandle.Write can't seek in file")
		return 0, ESPIPE
	}
	if fh.closed {
		fs.Errorf(fh.remote, "WriteFileHandle.Write error: %v", EBADF)
		return 0, EBADF
	}
	fh.writeCalled = true
	// FIXME should probably check the file isn't being seeked?
	n, err := fh.pipeWriter.Write(data)
	written = int64(n)
	fh.offset += written
	fh.file.setSize(fh.offset)
	if err != nil {
		fs.Errorf(fh.remote, "WriteFileHandle.Write error: %v", err)
		return 0, err
	}
	// fs.Debugf(fh.remote, "WriteFileHandle.Write OK (%d bytes written)", n)
	if fh.hash != nil {
		_, err = fh.hash.Write(data[:n])
		if err != nil {
			fs.Errorf(fh.remote, "WriteFileHandle.Write HashError: %v", err)
			return written, err
		}
	}
	return written, nil
}

// Offset returns the offset of the file pointer
func (fh *WriteFileHandle) Offset() (offset int64) {
	return fh.offset
}

// close the file handle returning EBADF if it has been
// closed already.
//
// Must be called with fh.mu held
func (fh *WriteFileHandle) close() error {
	if fh.closed {
		return EBADF
	}
	fh.closed = true
	fs.Stats.DoneTransferring(fh.remote, true)
	fh.file.addWriters(-1)
	writeCloseErr := fh.pipeWriter.Close()
	err := <-fh.result
	if err == nil {
		fh.file.setObject(fh.o)
		err = writeCloseErr
	}
	if err == nil && fh.hash != nil {
		for hashType, srcSum := range fh.hash.Sums() {
			dstSum, err := fh.o.Hash(hashType)
			if err != nil {
				return err
			}
			if !fs.HashEquals(srcSum, dstSum) {
				return errors.Errorf("corrupted on transfer: %v hash differ %q vs %q", hashType, srcSum, dstSum)
			}
		}
	}
	return err
}

// Flush is called on each close() of a file descriptor. So if a
// filesystem wants to return write errors in close() and the file has
// cached dirty data, this is a good place to write back data and
// return any errors. Since many applications ignore close() errors
// this is not always useful.
//
// NOTE: The flush() method may be called more than once for each
// open(). This happens if more than one file descriptor refers to an
// opened file due to dup(), dup2() or fork() calls. It is not
// possible to determine if a flush is final, so each flush should be
// treated equally. Multiple write-flush sequences are relatively
// rare, so this shouldn't be a problem.
//
// Filesystems shouldn't assume that flush will always be called after
// some writes, or that if will be called at all.
func (fh *WriteFileHandle) Flush() error {
	fh.mu.Lock()
	defer fh.mu.Unlock()
	// fs.Debugf(fh.remote, "WriteFileHandle.Flush")
	// If Write hasn't been called then ignore the Flush - Release
	// will pick it up
	if !fh.writeCalled {
		fs.Debugf(fh.remote, "WriteFileHandle.Flush ignoring flush on unwritten handle")
		return nil

	}
	err := fh.close()
	if err != nil {
		fs.Errorf(fh.remote, "WriteFileHandle.Flush error: %v", err)
	} else {
		// fs.Debugf(fh.remote, "WriteFileHandle.Flush OK")
	}
	return err
}

// Release is called when we are finished with the file handle
//
// It isn't called directly from userspace so the error is ignored by
// the kernel
func (fh *WriteFileHandle) Release() error {
	fh.mu.Lock()
	defer fh.mu.Unlock()
	if fh.closed {
		fs.Debugf(fh.remote, "WriteFileHandle.Release nothing to do")
		return nil
	}
	fs.Debugf(fh.remote, "WriteFileHandle.Release closing")
	err := fh.close()
	if err != nil {
		fs.Errorf(fh.remote, "WriteFileHandle.Release error: %v", err)
	} else {
		// fs.Debugf(fh.remote, "WriteFileHandle.Release OK")
	}
	return err
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"path"
	"text/tabwriter"

	"github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/moul/onlinenet/pkg/api"
)

func main() {
	app := cli.NewApp()
	app.Name = path.Base(os.Args[0])
	app.Author = "Manfred Touron"
	app.Email = "https://github.com/moul"
	app.Version = "dev"
	app.Usage = "Client for api.online.net"

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "token",
			Value:  "",
			Usage:  "API token",
			EnvVar: "ONLINENET_TOKEN",
		},
	}

	app.Commands = []cli.Command{
		{
			Name:   "servers",
			Action: actionServers,
		},
		{
			Name:   "abuses",
			Action: actionAbuses,
		},
		{
			Name:   "user",
			Action: actionUser,
		},
		{
			Name:   "ddos",
			Action: actionDdos,
		},
	}

	app.Run(os.Args)
}

func actionAbuses(c *cli.Context) {
	client := api.NewClientWithToken(c.GlobalString("token"))

	abuses, err := client.ListAbuses()
	if err != nil {
		logrus.Fatalf("Cannot list abuses: %v", err)
	}

	for _, abuse := range *abuses {
		fmt.Println(abuse)
	}
}

func actionDdos(c *cli.Context) {
	client := api.NewClientWithToken(c.GlobalString("token"))

	ddosList, err := client.ListDdos()
	if err != nil {
		logrus.Fatalf("Cannot list ddos: %v", err)
	}

	w := new(tabwriter.Writer)
	w.Init(os.Stdout, 10, 1, 3, ' ', 0)
	defer w.Flush()

	fmt.Fprintln(w, "ID\tTarget\tStart\tEnd\tMitigation\tType\tMax PPS\tMax BPS\tTimeline")

	for _, ddos := range *ddosList {
		fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%s\t%d\t%d\t%d items\n", ddos.Identifier, ddos.Target, ddos.Start, ddos.End, ddos.Mitigation, ddos.Type, ddos.MaxPPS, ddos.MaxBPS, len(ddos.Timeline))
	}
}

func actionUser(c *cli.Context) {
	client := api.NewClientWithToken(c.GlobalString("token"))

	user, err := client.GetCurrentUser()
	if err != nil {
		logrus.Fatalf("Cannot get current user: %v", err)
	}

	w := new(tabwriter.Writer)
	w.Init(os.Stdout, 10, 1, 3, ' ', 0)
	fmt.Fprintln(w, "ID\tLogin\tName\tCompany")
	fmt.Fprintf(w, "%d\t%s\t%s %s\t%s\n", user.Identifier, user.Login, user.FirstName, user.LastName, user.Company)
	w.Flush()
}

func actionServers(c *cli.Context) {
	client := api.NewClientWithToken(c.GlobalString("token"))

	serverPaths, err := client.ListServers()
	if err != nil {
		logrus.Fatalf("Cannot list servers: %v", err)
	}

	w := new(tabwriter.Writer)
	w.Init(os.Stdout, 10, 1, 3, ' ', 0)

	fmt.Fprintln(w, "ID\tName\tOs\tOffer")

	for _, serverPath := range *serverPaths {
		server, err := serverPath.Get(client)
		if err != nil {
			panic(err)
		}
		fmt.Fprintf(w, "%d\t%s\t%s\t%s\n", server.Identifier, server.Hostname, server.Os.Name, server.Offer)
	}

	w.Flush()
}
<commit_msg>Add server-show action<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"os"
	"path"
	"strconv"
	"text/tabwriter"

	"github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/moul/onlinenet/pkg/api"
)

func main() {
	app := cli.NewApp()
	app.Name = path.Base(os.Args[0])
	app.Author = "Manfred Touron"
	app.Email = "https://github.com/moul"
	app.Version = "dev"
	app.Usage = "Client for api.online.net"

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "token",
			Value:  "",
			Usage:  "API token",
			EnvVar: "ONLINENET_TOKEN",
		},
	}

	app.Commands = []cli.Command{
		{
			Name:   "servers",
			Action: actionServers,
		},
		{
			Name:   "server-show",
			Action: actionServerShow,
		},
		{
			Name:   "abuses",
			Action: actionAbuses,
		},
		{
			Name:   "user",
			Action: actionUser,
		},
		{
			Name:   "ddos",
			Action: actionDdos,
		},
	}

	app.Run(os.Args)
}

func actionAbuses(c *cli.Context) {
	client := api.NewClientWithToken(c.GlobalString("token"))

	abuses, err := client.ListAbuses()
	if err != nil {
		logrus.Fatalf("Cannot list abuses: %v", err)
	}

	for _, abuse := range *abuses {
		fmt.Println(abuse)
	}
}

func actionDdos(c *cli.Context) {
	client := api.NewClientWithToken(c.GlobalString("token"))

	ddosList, err := client.ListDdos()
	if err != nil {
		logrus.Fatalf("Cannot list ddos: %v", err)
	}

	w := new(tabwriter.Writer)
	w.Init(os.Stdout, 10, 1, 3, ' ', 0)
	defer w.Flush()

	fmt.Fprintln(w, "ID\tTarget\tStart\tEnd\tMitigation\tType\tMax PPS\tMax BPS\tTimeline")

	for _, ddos := range *ddosList {
		fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%s\t%d\t%d\t%d items\n", ddos.Identifier, ddos.Target, ddos.Start, ddos.End, ddos.Mitigation, ddos.Type, ddos.MaxPPS, ddos.MaxBPS, len(ddos.Timeline))
	}
}

func actionUser(c *cli.Context) {
	client := api.NewClientWithToken(c.GlobalString("token"))

	user, err := client.GetCurrentUser()
	if err != nil {
		logrus.Fatalf("Cannot get current user: %v", err)
	}

	w := new(tabwriter.Writer)
	w.Init(os.Stdout, 10, 1, 3, ' ', 0)
	fmt.Fprintln(w, "ID\tLogin\tName\tCompany")
	fmt.Fprintf(w, "%d\t%s\t%s %s\t%s\n", user.Identifier, user.Login, user.FirstName, user.LastName, user.Company)
	w.Flush()
}

func actionServers(c *cli.Context) {
	client := api.NewClientWithToken(c.GlobalString("token"))

	serverPaths, err := client.ListServers()
	if err != nil {
		logrus.Fatalf("Cannot list servers: %v", err)
	}

	w := new(tabwriter.Writer)
	w.Init(os.Stdout, 10, 1, 3, ' ', 0)

	fmt.Fprintln(w, "ID\tName\tOs\tOffer")

	for _, serverPath := range *serverPaths {
		server, err := serverPath.Get(client)
		if err != nil {
			panic(err)
		}
		fmt.Fprintf(w, "%d\t%s\t%s\t%s\n", server.Identifier, server.Hostname, server.Os.Name, server.Offer)
	}

	w.Flush()
}

func actionServerShow(c *cli.Context) {
	if len(c.Args()) < 1 {
		logrus.Fatalf("You must specify a server")
	}
	serverID, err := strconv.Atoi(c.Args()[0])
	if err != nil {
		logrus.Fatalf("ServerID %q is not a valid number: %v", c.Args()[0], err)
	}

	client := api.NewClientWithToken(c.GlobalString("token"))

	server, err := client.GetServer(serverID)
	if err != nil {
		logrus.Fatalf("Failed to get server %d: %v", serverID, err)
	}

	body, err := json.MarshalIndent(server, "", "  ")
	if err != nil {
		logrus.Fatalf("Failed to marshal JSON: %v", err)
	}

	fmt.Println(string(body))
}
<|endoftext|>


<commit_before>// Copyright 2016 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"flag"
	"os"
	"os/signal"
	"syscall"

	"github.com/juju/errors"
	"github.com/ngaut/log"
	"github.com/pingcap/pd/server"
	"github.com/pingcap/pd/server/api"
)

func main() {
	cfg := server.NewConfig()
	err := cfg.Parse(os.Args[1:])

	if cfg.Version {
		server.PrintPDInfo()
		os.Exit(0)
	}

	switch errors.Cause(err) {
	case nil:
	case flag.ErrHelp:
		os.Exit(0)
	default:
		log.Errorf("parse cmd flags err %s\n", err)
		os.Exit(2)
	}

	err = server.InitLogger(cfg)
	if err != nil {
		log.Fatalf("initalize logger err %s\n", err)
	}

	server.LogPDInfo()

	server.PushMetric(cfg)

	svr, err := server.CreateServer(cfg)
	if err != nil {
		log.Errorf("create pd server err %s\n", err)
		return
	}
	err = svr.StartEtcd(api.NewHandler(svr))
	if err != nil {
		log.Errorf("server start etcd failed - %v", errors.Trace(err))
		return
	}

	sc := make(chan os.Signal, 1)
	signal.Notify(sc,
		syscall.SIGHUP,
		syscall.SIGINT,
		syscall.SIGTERM,
		syscall.SIGQUIT)

	go func() {
		sig := <-sc
		log.Infof("Got signal [%d] to exit.", sig)
		svr.Close()
		os.Exit(0)
	}()

	svr.Run()
}
<commit_msg>cmd: exit with 2 if server start failed (#405)<commit_after>// Copyright 2016 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"flag"
	"os"
	"os/signal"
	"syscall"

	"github.com/juju/errors"
	"github.com/ngaut/log"
	"github.com/pingcap/pd/server"
	"github.com/pingcap/pd/server/api"
)

func main() {
	cfg := server.NewConfig()
	err := cfg.Parse(os.Args[1:])

	if cfg.Version {
		server.PrintPDInfo()
		os.Exit(0)
	}

	switch errors.Cause(err) {
	case nil:
	case flag.ErrHelp:
		os.Exit(0)
	default:
		log.Fatalf("parse cmd flags err %s\n", err)
	}

	err = server.InitLogger(cfg)
	if err != nil {
		log.Fatalf("initalize logger err %s\n", err)
	}

	server.LogPDInfo()

	server.PushMetric(cfg)

	svr, err := server.CreateServer(cfg)
	if err != nil {
		log.Fatalf("create pd server err %s\n", err)
	}
	err = svr.StartEtcd(api.NewHandler(svr))
	if err != nil {
		log.Fatalf("server start etcd failed - %v", errors.Trace(err))
	}

	sc := make(chan os.Signal, 1)
	signal.Notify(sc,
		syscall.SIGHUP,
		syscall.SIGINT,
		syscall.SIGTERM,
		syscall.SIGQUIT)

	go func() {
		sig := <-sc
		log.Infof("Got signal [%d] to exit.", sig)
		svr.Close()
		os.Exit(0)
	}()

	svr.Run()
}
<|endoftext|>