<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"syscall"

	"github.com/dickeyxxx/gode"
	"github.com/dickeyxxx/golock"
)

// Plugin represents a javascript plugin
type Plugin struct {
	Name     string     `json:"name"`
	Topics   TopicSet   `json:"topics"`
	Commands CommandSet `json:"commands"`
}

var node = gode.NewClient(AppDir)

func init() {
	node.Registry = "https://d3nfsbmspisrno.cloudfront.net"
	node.NodeVersion = "2.0.1"
	node.NpmVersion = "2.9.0"
}

// SetupNode sets up node and npm in ~/.heroku
func SetupNode() {
	if !node.IsSetup() {
		golock.Lock(updateLockPath)
		defer golock.Unlock(updateLockPath)
		Debugln("setting up iojs", node.NodeVersion)
		if err := node.Setup(); err != nil {
			panic(err)
		}
		clearOldNodeInstalls()
	}
}

func clearOldNodeInstalls() {
	files, _ := ioutil.ReadDir(AppDir)
	for _, f := range files {
		name := f.Name()
		if name != node.NodeBase() && strings.HasPrefix(name, "iojs-v") {
			os.RemoveAll(filepath.Join(AppDir, name))
		}
	}
}

// LoadPlugins loads the topics and commands from the JavaScript plugins into the CLI
func (cli *Cli) LoadPlugins(plugins []Plugin) {
	for _, plugin := range plugins {
		for _, topic := range plugin.Topics {
			cli.AddTopic(topic)
		}
		for _, command := range plugin.Commands {
			if !cli.AddCommand(command) {
				Errf("WARNING: command %s has already been defined\n", command)
			}
		}
	}
}

var pluginsTopic = &Topic{
	Name:        "plugins",
	Description: "manage plugins",
}

var pluginsInstallCmd = &Command{
	Topic:       "plugins",
	Command:     "install",
	Hidden:      true,
	Args:        []Arg{{Name: "name"}},
	Description: "Installs a plugin into the CLI",
	Help: `Install a Heroku plugin

  Example:
  $ heroku plugins:install dickeyxxx/heroku-production-status`,

	Run: func(ctx *Context) {
		name := ctx.Args.(map[string]string)["name"]
		if len(name) == 0 {
			Errln("Must specify a plugin name")
			return
		}
		Errf("Installing plugin %s... ", name)
		err := node.InstallPackage(name)
		ExitIfError(err)
		plugin := getPlugin(name, false)
		if plugin == nil || len(plugin.Commands) == 0 {
			Err("This does not appear to be a Heroku plugin, uninstalling... ")
			err := (node.RemovePackage(name))
			ExitIfError(err)
		}
		ClearPluginCache()
		WritePluginCache(GetPlugins())
		Errln("done")
	},
}

var pluginsLinkCmd = &Command{
	Topic:       "plugins",
	Command:     "link",
	Description: "Links a local plugin into CLI",
	Args:        []Arg{{Name: "path", Optional: true}},
	Help: `Links a local plugin into CLI.
	This is useful when developing plugins locally.
	It simply symlinks the specified path into ~/.heroku/node_modules

  Example:
	$ heroku plugins:link .`,

	Run: func(ctx *Context) {
		path := ctx.Args.(map[string]string)["path"]
		if path == "" {
			path = "."
		}
		path, err := filepath.Abs(path)
		if err != nil {
			panic(err)
		}
		if _, err := os.Stat(path); err != nil {
			panic(err)
		}
		name := filepath.Base(path)
		newPath := filepath.Join(ctx.HerokuDir, "node_modules", name)
		os.Remove(newPath)
		os.RemoveAll(newPath)
		err = os.Symlink(path, newPath)
		if err != nil {
			panic(err)
		}
		plugin := getPlugin(name, false)
		if plugin == nil || len(plugin.Commands) == 0 {
			Errln(name + " does not appear to be a Heroku plugin")
			if err := os.Remove(newPath); err != nil {
				panic(err)
			}
		}
		if name != plugin.Name {
			path = newPath
			newPath = filepath.Join(ctx.HerokuDir, "node_modules", plugin.Name)
			os.Remove(newPath)
			os.RemoveAll(newPath)
			os.Rename(path, newPath)
		}
		Println("symlinked", plugin.Name)
		Err("Updating plugin cache... ")
		ClearPluginCache()
		WritePluginCache(GetPlugins())
		Errln("done")
	},
}

var pluginsUninstallCmd = &Command{
	Topic:       "plugins",
	Command:     "uninstall",
	Hidden:      true,
	Args:        []Arg{{Name: "name"}},
	Description: "Uninstalls a plugin from the CLI",
	Help: `Uninstalls a Heroku plugin

  Example:
  $ heroku plugins:uninstall heroku-production-status`,

	Run: func(ctx *Context) {
		name := ctx.Args.(map[string]string)["name"]
		Errf("Uninstalling plugin %s... ", name)
		err := node.RemovePackage(name)
		ExitIfError(err)
		Errln("done")
	},
}

var pluginsListCmd = &Command{
	Topic:       "plugins",
	Hidden:      true,
	Description: "Lists the installed plugins",
	Help: `Lists installed plugins

  Example:
  $ heroku plugins`,

	Run: func(ctx *Context) {
		packages, err := node.Packages()
		if err != nil {
			panic(err)
		}
		for _, pkg := range packages {
			Println(pkg.Name, pkg.Version)
		}
	},
}

func runFn(module, topic, command string) func(ctx *Context) {
	return func(ctx *Context) {
		ctxJSON, err := json.Marshal(ctx)
		if err != nil {
			panic(err)
		}
		script := fmt.Sprintf(`
		'use strict';
		var module = '%s';
		var topic = '%s';
		var command = '%s';
		var ctx = %s;
		var logPath = %s;
		process.on('uncaughtException', function (err) {
			console.error(' !   Error in ' + module + ':')
			if (err.message) {
				console.error(' !   ' + err.message);
			} else {
				console.error(' !   ' + err);
			}
			if (err.stack) {
				var fs = require('fs');
				var log = function (line) {
					var d = new Date().toISOString()
					.replace(/T/, ' ')
					.replace(/-/g, '/')
					.replace(/\..+/, '');
					fs.appendFileSync(logPath, d + ' ' + line + '\n');
				}
				log('Error during ' + topic + ':' + command);
				log(err.stack);
				console.error(' !   See ' + logPath + ' for more info.');
			}
			process.exit(1);
		});
		if (command === '') { command = null }
		var cmd = require(module)
		.commands.filter(function (c) {
			return c.topic === topic && c.command == command;
		})[0];
		cmd.run(ctx);`, module, topic, command, ctxJSON, strconv.Quote(ErrLogPath))

		// swallow sigint since the plugin will handle it
		swallowSignal(os.Interrupt)

		cmd := node.RunScript(script)
		if ctx.Flags["debugger"] == true {
			cmd = node.DebugScript(script)
		}
		os.Chdir(cmd.Dir)
		execBin(cmd.Path, cmd.Args)
	}
}

func execBin(bin string, args []string) {
	if runtime.GOOS == "windows" {
		cmd := exec.Command(bin, args[1:]...)
		cmd.Stdin = os.Stdin
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		if err := cmd.Run(); err != nil {
			os.Exit(getExitCode(err))
		}
	} else {
		if err := syscall.Exec(bin, args, os.Environ()); err != nil {
			panic(err)
		}
	}
}

func swallowSignal(s os.Signal) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, s)
	go func() {
		<-c
	}()
}

func getExitCode(err error) int {
	switch e := err.(type) {
	case *exec.ExitError:
		status, ok := e.Sys().(syscall.WaitStatus)
		if !ok {
			panic(err)
		}
		return status.ExitStatus()
	default:
		panic(err)
	}
}

func getPlugin(name string, attemptReinstall bool) *Plugin {
	script := `
	var plugin = require('` + name + `');
	plugin.name = require('` + name + `/package.json').name;
	console.log(JSON.stringify(plugin))`
	cmd := node.RunScript(script)
	output, err := cmd.CombinedOutput()
	if err != nil {
		if attemptReinstall && strings.Contains(string(output), "Error: Cannot find module") {
			Errf("Error reading plugin %s. Reinstalling... ", name)
			if err := node.InstallPackage(name); err != nil {
				panic(err)
			}
			Errln("done")
			return getPlugin(name, false)
		}
		Errf("Error reading plugin: %s. See %s for more information.\n", name, ErrLogPath)
		Logln(err, "\n", string(output))
		return nil
	}
	var plugin Plugin
	json.Unmarshal([]byte(output), &plugin)
	return &plugin
}

// GetPlugins goes through all the node plugins and returns them in Go stucts
func GetPlugins() []Plugin {
	cache := FetchPluginCache()
	names := PluginNames()
	plugins := make([]Plugin, 0, len(names))
	for _, name := range names {
		plugin := cache[name]
		if plugin == nil {
			plugin = getPlugin(name, true)
		}
		if plugin != nil {
			for _, command := range plugin.Commands {
				command.Plugin = name
				command.Run = runFn(name, command.Topic, command.Command)
			}
			plugins = append(plugins, *plugin)
		}
	}
	return plugins
}

// PluginNames just lists the files in ~/.heroku/node_modules
func PluginNames() []string {
	files, _ := ioutil.ReadDir(filepath.Join(AppDir, "node_modules"))
	names := make([]string, 0, len(files))
	for _, f := range files {
		if !ignorePlugin(f.Name()) {
			names = append(names, f.Name())
		}
	}
	return names
}

func ignorePlugin(plugin string) bool {
	ignored := []string{".bin", "node-inspector"}
	for _, p := range ignored {
		if plugin == p {
			return true
		}
	}
	return false
}
<commit_msg>do not panic on setup errors<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"syscall"

	"github.com/dickeyxxx/gode"
	"github.com/dickeyxxx/golock"
)

// Plugin represents a javascript plugin
type Plugin struct {
	Name     string     `json:"name"`
	Topics   TopicSet   `json:"topics"`
	Commands CommandSet `json:"commands"`
}

var node = gode.NewClient(AppDir)

func init() {
	node.Registry = "https://d3nfsbmspisrno.cloudfront.net"
	node.NodeVersion = "2.0.1"
	node.NpmVersion = "2.9.0"
}

// SetupNode sets up node and npm in ~/.heroku
func SetupNode() {
	if !node.IsSetup() {
		golock.Lock(updateLockPath)
		defer golock.Unlock(updateLockPath)
		Debugln("setting up iojs", node.NodeVersion)
		ExitIfError(node.Setup())
		clearOldNodeInstalls()
	}
}

func clearOldNodeInstalls() {
	files, _ := ioutil.ReadDir(AppDir)
	for _, f := range files {
		name := f.Name()
		if name != node.NodeBase() && strings.HasPrefix(name, "iojs-v") {
			os.RemoveAll(filepath.Join(AppDir, name))
		}
	}
}

// LoadPlugins loads the topics and commands from the JavaScript plugins into the CLI
func (cli *Cli) LoadPlugins(plugins []Plugin) {
	for _, plugin := range plugins {
		for _, topic := range plugin.Topics {
			cli.AddTopic(topic)
		}
		for _, command := range plugin.Commands {
			if !cli.AddCommand(command) {
				Errf("WARNING: command %s has already been defined\n", command)
			}
		}
	}
}

var pluginsTopic = &Topic{
	Name:        "plugins",
	Description: "manage plugins",
}

var pluginsInstallCmd = &Command{
	Topic:       "plugins",
	Command:     "install",
	Hidden:      true,
	Args:        []Arg{{Name: "name"}},
	Description: "Installs a plugin into the CLI",
	Help: `Install a Heroku plugin

  Example:
  $ heroku plugins:install dickeyxxx/heroku-production-status`,

	Run: func(ctx *Context) {
		name := ctx.Args.(map[string]string)["name"]
		if len(name) == 0 {
			Errln("Must specify a plugin name")
			return
		}
		Errf("Installing plugin %s... ", name)
		err := node.InstallPackage(name)
		ExitIfError(err)
		plugin := getPlugin(name, false)
		if plugin == nil || len(plugin.Commands) == 0 {
			Err("This does not appear to be a Heroku plugin, uninstalling... ")
			err := (node.RemovePackage(name))
			ExitIfError(err)
		}
		ClearPluginCache()
		WritePluginCache(GetPlugins())
		Errln("done")
	},
}

var pluginsLinkCmd = &Command{
	Topic:       "plugins",
	Command:     "link",
	Description: "Links a local plugin into CLI",
	Args:        []Arg{{Name: "path", Optional: true}},
	Help: `Links a local plugin into CLI.
	This is useful when developing plugins locally.
	It simply symlinks the specified path into ~/.heroku/node_modules

  Example:
	$ heroku plugins:link .`,

	Run: func(ctx *Context) {
		path := ctx.Args.(map[string]string)["path"]
		if path == "" {
			path = "."
		}
		path, err := filepath.Abs(path)
		if err != nil {
			panic(err)
		}
		if _, err := os.Stat(path); err != nil {
			panic(err)
		}
		name := filepath.Base(path)
		newPath := filepath.Join(ctx.HerokuDir, "node_modules", name)
		os.Remove(newPath)
		os.RemoveAll(newPath)
		err = os.Symlink(path, newPath)
		if err != nil {
			panic(err)
		}
		plugin := getPlugin(name, false)
		if plugin == nil || len(plugin.Commands) == 0 {
			Errln(name + " does not appear to be a Heroku plugin")
			if err := os.Remove(newPath); err != nil {
				panic(err)
			}
		}
		if name != plugin.Name {
			path = newPath
			newPath = filepath.Join(ctx.HerokuDir, "node_modules", plugin.Name)
			os.Remove(newPath)
			os.RemoveAll(newPath)
			os.Rename(path, newPath)
		}
		Println("symlinked", plugin.Name)
		Err("Updating plugin cache... ")
		ClearPluginCache()
		WritePluginCache(GetPlugins())
		Errln("done")
	},
}

var pluginsUninstallCmd = &Command{
	Topic:       "plugins",
	Command:     "uninstall",
	Hidden:      true,
	Args:        []Arg{{Name: "name"}},
	Description: "Uninstalls a plugin from the CLI",
	Help: `Uninstalls a Heroku plugin

  Example:
  $ heroku plugins:uninstall heroku-production-status`,

	Run: func(ctx *Context) {
		name := ctx.Args.(map[string]string)["name"]
		Errf("Uninstalling plugin %s... ", name)
		err := node.RemovePackage(name)
		ExitIfError(err)
		Errln("done")
	},
}

var pluginsListCmd = &Command{
	Topic:       "plugins",
	Hidden:      true,
	Description: "Lists the installed plugins",
	Help: `Lists installed plugins

  Example:
  $ heroku plugins`,

	Run: func(ctx *Context) {
		packages, err := node.Packages()
		if err != nil {
			panic(err)
		}
		for _, pkg := range packages {
			Println(pkg.Name, pkg.Version)
		}
	},
}

func runFn(module, topic, command string) func(ctx *Context) {
	return func(ctx *Context) {
		ctxJSON, err := json.Marshal(ctx)
		if err != nil {
			panic(err)
		}
		script := fmt.Sprintf(`
		'use strict';
		var module = '%s';
		var topic = '%s';
		var command = '%s';
		var ctx = %s;
		var logPath = %s;
		process.on('uncaughtException', function (err) {
			console.error(' !   Error in ' + module + ':')
			if (err.message) {
				console.error(' !   ' + err.message);
			} else {
				console.error(' !   ' + err);
			}
			if (err.stack) {
				var fs = require('fs');
				var log = function (line) {
					var d = new Date().toISOString()
					.replace(/T/, ' ')
					.replace(/-/g, '/')
					.replace(/\..+/, '');
					fs.appendFileSync(logPath, d + ' ' + line + '\n');
				}
				log('Error during ' + topic + ':' + command);
				log(err.stack);
				console.error(' !   See ' + logPath + ' for more info.');
			}
			process.exit(1);
		});
		if (command === '') { command = null }
		var cmd = require(module)
		.commands.filter(function (c) {
			return c.topic === topic && c.command == command;
		})[0];
		cmd.run(ctx);`, module, topic, command, ctxJSON, strconv.Quote(ErrLogPath))

		// swallow sigint since the plugin will handle it
		swallowSignal(os.Interrupt)

		cmd := node.RunScript(script)
		if ctx.Flags["debugger"] == true {
			cmd = node.DebugScript(script)
		}
		os.Chdir(cmd.Dir)
		execBin(cmd.Path, cmd.Args)
	}
}

func execBin(bin string, args []string) {
	if runtime.GOOS == "windows" {
		cmd := exec.Command(bin, args[1:]...)
		cmd.Stdin = os.Stdin
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		if err := cmd.Run(); err != nil {
			os.Exit(getExitCode(err))
		}
	} else {
		if err := syscall.Exec(bin, args, os.Environ()); err != nil {
			panic(err)
		}
	}
}

func swallowSignal(s os.Signal) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, s)
	go func() {
		<-c
	}()
}

func getExitCode(err error) int {
	switch e := err.(type) {
	case *exec.ExitError:
		status, ok := e.Sys().(syscall.WaitStatus)
		if !ok {
			panic(err)
		}
		return status.ExitStatus()
	default:
		panic(err)
	}
}

func getPlugin(name string, attemptReinstall bool) *Plugin {
	script := `
	var plugin = require('` + name + `');
	plugin.name = require('` + name + `/package.json').name;
	console.log(JSON.stringify(plugin))`
	cmd := node.RunScript(script)
	output, err := cmd.CombinedOutput()
	if err != nil {
		if attemptReinstall && strings.Contains(string(output), "Error: Cannot find module") {
			Errf("Error reading plugin %s. Reinstalling... ", name)
			if err := node.InstallPackage(name); err != nil {
				panic(err)
			}
			Errln("done")
			return getPlugin(name, false)
		}
		Errf("Error reading plugin: %s. See %s for more information.\n", name, ErrLogPath)
		Logln(err, "\n", string(output))
		return nil
	}
	var plugin Plugin
	json.Unmarshal([]byte(output), &plugin)
	return &plugin
}

// GetPlugins goes through all the node plugins and returns them in Go stucts
func GetPlugins() []Plugin {
	cache := FetchPluginCache()
	names := PluginNames()
	plugins := make([]Plugin, 0, len(names))
	for _, name := range names {
		plugin := cache[name]
		if plugin == nil {
			plugin = getPlugin(name, true)
		}
		if plugin != nil {
			for _, command := range plugin.Commands {
				command.Plugin = name
				command.Run = runFn(name, command.Topic, command.Command)
			}
			plugins = append(plugins, *plugin)
		}
	}
	return plugins
}

// PluginNames just lists the files in ~/.heroku/node_modules
func PluginNames() []string {
	files, _ := ioutil.ReadDir(filepath.Join(AppDir, "node_modules"))
	names := make([]string, 0, len(files))
	for _, f := range files {
		if !ignorePlugin(f.Name()) {
			names = append(names, f.Name())
		}
	}
	return names
}

func ignorePlugin(plugin string) bool {
	ignored := []string{".bin", "node-inspector"}
	for _, p := range ignored {
		if plugin == p {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package main

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

	"github.com/dickeyxxx/gode"
)

// Plugin represents a javascript plugin
type Plugin struct {
	Topics   TopicSet   `json:"topics"`
	Commands CommandSet `json:"commands"`
}

var node = gode.NewClient(AppDir)

func init() {
	node.Registry = "http://54.173.158.18"
	node.NodeVersion = "1.4.1"
	node.NpmVersion = "2.6.0"
}

// SetupNode sets up node and npm in ~/.heroku
func SetupNode() {
	if !node.IsSetup() {
		Log("setting up plugins... ")
		if err := node.Setup(); err != nil {
			panic(err)
		}
		Logln("done")
	}
}

// LoadPlugins loads the topics and commands from the JavaScript plugins into the CLI
func (cli *Cli) LoadPlugins(plugins []Plugin) {
	for _, plugin := range plugins {
		for _, topic := range plugin.Topics {
			cli.AddTopic(topic)
		}
		for _, command := range plugin.Commands {
			if !cli.AddCommand(command) {
				Errln("WARNING: command %s has already been defined", command)
			}
		}
	}
}

var pluginsTopic = &Topic{
	Name:        "plugins",
	Description: "manage plugins",
}

var pluginsInstallCmd = &Command{
	Topic:       "plugins",
	Command:     "install",
	Args:        []Arg{{Name: "name"}},
	Description: "Installs a plugin into the CLI",
	Help: `Install a Heroku plugin

  Example:
  $ heroku plugins:install dickeyxxx/heroku-production-status`,

	Run: func(ctx *Context) {
		name := ctx.Args.(map[string]string)["name"]
		if len(name) == 0 {
			Errln("Must specify a plugin name")
			return
		}
		Errf("Installing plugin %s... ", name)
		if err := node.InstallPackage(name); err != nil {
			panic(err)
		}
		plugin := getPlugin(name)
		if plugin == nil || len(plugin.Commands) == 0 {
			Err("This does not appear to be a Heroku plugin, uninstalling... ")
			if err := (node.RemovePackage(name)); err != nil {
				panic(err)
			}
		}
		Errln("done")
	},
}

var pluginsUninstallCmd = &Command{
	Topic:       "plugins",
	Command:     "uninstall",
	Args:        []Arg{{Name: "name"}},
	Description: "Uninstalls a plugin from the CLI",
	Help: `Uninstalls a Heroku plugin

  Example:
  $ heroku plugins:uninstall heroku-production-status`,

	Run: func(ctx *Context) {
		name := ctx.Args.(map[string]string)["name"]
		Errf("Uninstalling plugin %s... ", name)
		if err := node.RemovePackage(name); err != nil {
			panic(err)
		}
		Errln("done")
	},
}

var pluginsListCmd = &Command{
	Topic:       "plugins",
	Description: "Lists the installed plugins",
	Help: `Lists installed plugins

  Example:
  $ heroku plugins`,

	Run: func(ctx *Context) {
		packages, err := node.Packages()
		if err != nil {
			panic(err)
		}
		for _, pkg := range packages {
			Println(pkg.Name, pkg.Version)
		}
	},
}

func runFn(module, topic, command string) func(ctx *Context) {
	return func(ctx *Context) {
		ctxJSON, err := json.Marshal(ctx)
		if err != nil {
			panic(err)
		}
		script := fmt.Sprintf(`
		var topic = '%s';
		var command = '%s';
		if (command === '') { command = null }
		require('%s')
		.commands.filter(function (c) {
			return c.topic === topic && c.command == command;
		})[0]
		.run(%s)`, topic, command, module, ctxJSON)

		// swallow sigint since the plugin will handle it
		swallowSignal(os.Interrupt)

		cmd := node.RunScript(script)
		cmd.Stdout = Stdout
		cmd.Stdin = os.Stdin
		cmd.Stderr = os.Stderr
		if err := cmd.Run(); err != nil {
			Exit(getExitCode(err))
		}
	}
}

func swallowSignal(s os.Signal) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, s)
	go func() {
		<-c
	}()
}

func getExitCode(err error) int {
	exitErr, ok := err.(*exec.ExitError)
	if !ok {
		panic(err)
	}
	status, ok := exitErr.Sys().(syscall.WaitStatus)
	if !ok {
		panic(err)
	}
	return status.ExitStatus()
}

func getPlugin(name string) *Plugin {
	script := `console.log(JSON.stringify(require('` + name + `')))`
	cmd := node.RunScript(script)
	cmd.Stderr = Stderr
	output, err := cmd.StdoutPipe()
	if err != nil {
		panic(err)
	}
	if err := cmd.Start(); err != nil {
		panic(err)
	}
	var plugin Plugin
	err = json.NewDecoder(output).Decode(&plugin)
	if err != nil {
		Errf("Error reading plugin: %s. See %s for more information.\n", name, ErrLogPath)
		Logln(err)
		return nil
	}
	if err := cmd.Wait(); err != nil {
		panic(err)
	}
	for _, command := range plugin.Commands {
		command.Plugin = name
		command.Run = runFn(name, command.Topic, command.Command)
	}
	return &plugin
}

// GetPlugins goes through all the node plugins and returns them in Go stucts
func GetPlugins() []Plugin {
	names := PluginNames()
	plugins := make([]Plugin, 0, len(names))
	for _, name := range names {
		plugin := getPlugin(name)
		if plugin != nil {
			plugins = append(plugins, *plugin)
		}
	}
	return plugins
}

// PluginNames just lists the files in ~/.heroku/node_modules
func PluginNames() []string {
	files, _ := ioutil.ReadDir(filepath.Join(AppDir, "node_modules"))
	names := make([]string, 0, len(files))
	for _, f := range files {
		names = append(names, f.Name())
	}
	return names
}
<commit_msg>upgraded iojs to 1.4.3<commit_after>package main

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

	"github.com/dickeyxxx/gode"
)

// Plugin represents a javascript plugin
type Plugin struct {
	Topics   TopicSet   `json:"topics"`
	Commands CommandSet `json:"commands"`
}

var node = gode.NewClient(AppDir)

func init() {
	node.Registry = "http://54.173.158.18"
	node.NodeVersion = "1.4.3"
	node.NpmVersion = "2.6.1"
}

// SetupNode sets up node and npm in ~/.heroku
func SetupNode() {
	if !node.IsSetup() {
		Log("setting up plugins... ")
		if err := node.Setup(); err != nil {
			panic(err)
		}
		Logln("done")
	}
}

// LoadPlugins loads the topics and commands from the JavaScript plugins into the CLI
func (cli *Cli) LoadPlugins(plugins []Plugin) {
	for _, plugin := range plugins {
		for _, topic := range plugin.Topics {
			cli.AddTopic(topic)
		}
		for _, command := range plugin.Commands {
			if !cli.AddCommand(command) {
				Errln("WARNING: command %s has already been defined", command)
			}
		}
	}
}

var pluginsTopic = &Topic{
	Name:        "plugins",
	Description: "manage plugins",
}

var pluginsInstallCmd = &Command{
	Topic:       "plugins",
	Command:     "install",
	Args:        []Arg{{Name: "name"}},
	Description: "Installs a plugin into the CLI",
	Help: `Install a Heroku plugin

  Example:
  $ heroku plugins:install dickeyxxx/heroku-production-status`,

	Run: func(ctx *Context) {
		name := ctx.Args.(map[string]string)["name"]
		if len(name) == 0 {
			Errln("Must specify a plugin name")
			return
		}
		Errf("Installing plugin %s... ", name)
		if err := node.InstallPackage(name); err != nil {
			panic(err)
		}
		plugin := getPlugin(name)
		if plugin == nil || len(plugin.Commands) == 0 {
			Err("This does not appear to be a Heroku plugin, uninstalling... ")
			if err := (node.RemovePackage(name)); err != nil {
				panic(err)
			}
		}
		Errln("done")
	},
}

var pluginsUninstallCmd = &Command{
	Topic:       "plugins",
	Command:     "uninstall",
	Args:        []Arg{{Name: "name"}},
	Description: "Uninstalls a plugin from the CLI",
	Help: `Uninstalls a Heroku plugin

  Example:
  $ heroku plugins:uninstall heroku-production-status`,

	Run: func(ctx *Context) {
		name := ctx.Args.(map[string]string)["name"]
		Errf("Uninstalling plugin %s... ", name)
		if err := node.RemovePackage(name); err != nil {
			panic(err)
		}
		Errln("done")
	},
}

var pluginsListCmd = &Command{
	Topic:       "plugins",
	Description: "Lists the installed plugins",
	Help: `Lists installed plugins

  Example:
  $ heroku plugins`,

	Run: func(ctx *Context) {
		packages, err := node.Packages()
		if err != nil {
			panic(err)
		}
		for _, pkg := range packages {
			Println(pkg.Name, pkg.Version)
		}
	},
}

func runFn(module, topic, command string) func(ctx *Context) {
	return func(ctx *Context) {
		ctxJSON, err := json.Marshal(ctx)
		if err != nil {
			panic(err)
		}
		script := fmt.Sprintf(`
		var topic = '%s';
		var command = '%s';
		if (command === '') { command = null }
		require('%s')
		.commands.filter(function (c) {
			return c.topic === topic && c.command == command;
		})[0]
		.run(%s)`, topic, command, module, ctxJSON)

		// swallow sigint since the plugin will handle it
		swallowSignal(os.Interrupt)

		cmd := node.RunScript(script)
		cmd.Stdout = Stdout
		cmd.Stdin = os.Stdin
		cmd.Stderr = os.Stderr
		if err := cmd.Run(); err != nil {
			Exit(getExitCode(err))
		}
	}
}

func swallowSignal(s os.Signal) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, s)
	go func() {
		<-c
	}()
}

func getExitCode(err error) int {
	exitErr, ok := err.(*exec.ExitError)
	if !ok {
		panic(err)
	}
	status, ok := exitErr.Sys().(syscall.WaitStatus)
	if !ok {
		panic(err)
	}
	return status.ExitStatus()
}

func getPlugin(name string) *Plugin {
	script := `console.log(JSON.stringify(require('` + name + `')))`
	cmd := node.RunScript(script)
	cmd.Stderr = Stderr
	output, err := cmd.StdoutPipe()
	if err != nil {
		panic(err)
	}
	if err := cmd.Start(); err != nil {
		panic(err)
	}
	var plugin Plugin
	err = json.NewDecoder(output).Decode(&plugin)
	if err != nil {
		Errf("Error reading plugin: %s. See %s for more information.\n", name, ErrLogPath)
		Logln(err)
		return nil
	}
	if err := cmd.Wait(); err != nil {
		panic(err)
	}
	for _, command := range plugin.Commands {
		command.Plugin = name
		command.Run = runFn(name, command.Topic, command.Command)
	}
	return &plugin
}

// GetPlugins goes through all the node plugins and returns them in Go stucts
func GetPlugins() []Plugin {
	names := PluginNames()
	plugins := make([]Plugin, 0, len(names))
	for _, name := range names {
		plugin := getPlugin(name)
		if plugin != nil {
			plugins = append(plugins, *plugin)
		}
	}
	return plugins
}

// PluginNames just lists the files in ~/.heroku/node_modules
func PluginNames() []string {
	files, _ := ioutil.ReadDir(filepath.Join(AppDir, "node_modules"))
	names := make([]string, 0, len(files))
	for _, f := range files {
		names = append(names, f.Name())
	}
	return names
}
<|endoftext|>


<commit_before>package pwr

import (
	"bytes"
	"errors"
	"io"
	"io/ioutil"

	"github.com/itchio/wharf/state"
	"github.com/itchio/wharf/wire"
)

func swap(a []int, i, j int) { a[i], a[j] = a[j], a[i] }

// Ternary-Split Quicksort, cf. http://www.larsson.dogma.net/ssrev-tr.pdf
func split(I, V []int, start, length, h int) {
	var i, j, k, x, jj, kk int

	if length < 16 {
		for k = start; k < start+length; k += j {
			j = 1
			x = V[I[k]+h]
			for i = 1; k+i < start+length; i++ {
				if V[I[k+i]+h] < x {
					x = V[I[k+i]+h]
					j = 0
				}
				if V[I[k+i]+h] == x {
					swap(I, k+i, k+j)
					j++
				}
			}
			for i = 0; i < j; i++ {
				V[I[k+i]] = k + j - 1
			}
			if j == 1 {
				I[k] = -1
			}
		}
		return
	}

	x = V[I[start+length/2]+h]
	jj = 0
	kk = 0
	for i = start; i < start+length; i++ {
		if V[I[i]+h] < x {
			jj++
		}
		if V[I[i]+h] == x {
			kk++
		}
	}
	jj += start
	kk += jj

	i = start
	j = 0
	k = 0
	for i < jj {
		if V[I[i]+h] < x {
			i++
		} else if V[I[i]+h] == x {
			swap(I, i, jj+j)
			j++
		} else {
			swap(I, i, kk+k)
			k++
		}
	}

	for jj+j < kk {
		if V[I[jj+j]+h] == x {
			j++
		} else {
			swap(I, jj+j, kk+k)
			k++
		}
	}

	if jj > start {
		split(I, V, start, jj-start, h)
	}

	for i = 0; i < kk-jj; i++ {
		V[I[jj+i]] = kk - 1
	}
	if jj == kk-1 {
		I[jj] = -1
	}

	if start+length > kk {
		split(I, V, kk, start+length-kk, h)
	}
}

// Faster Suffix Sorting, see: http://www.larsson.dogma.net/ssrev-tr.pdf
// Output `I` is a sorted suffix array.
func qsufsort(obuf []byte) []int {
	var buckets [256]int
	var i, h int
	I := make([]int, len(obuf)+1)
	V := make([]int, len(obuf)+1)

	for _, c := range obuf {
		buckets[c]++
	}
	for i = 1; i < 256; i++ {
		buckets[i] += buckets[i-1]
	}
	copy(buckets[1:], buckets[:])
	buckets[0] = 0

	for i, c := range obuf {
		buckets[c]++
		I[buckets[c]] = i
	}

	I[0] = len(obuf)
	for i, c := range obuf {
		V[i] = buckets[c]
	}

	V[len(obuf)] = 0
	for i = 1; i < 256; i++ {
		if buckets[i] == buckets[i-1]+1 {
			I[buckets[i]] = -1
		}
	}
	I[0] = -1

	for h = 1; I[0] != -(len(obuf) + 1); h += h {
		var n int
		for i = 0; i < len(obuf)+1; {
			if I[i] < 0 {
				n -= I[i]
				i -= I[i]
			} else {
				if n != 0 {
					I[i-n] = -n
				}
				n = V[I[i]] + 1 - i
				split(I, V, i, n, h)
				i += n
				n = 0
			}
		}
		if n != 0 {
			I[i-n] = -n
		}
	}

	for i = 0; i < len(obuf)+1; i++ {
		I[V[i]] = i
	}
	return I
}

// Returns the number of bytes common to a and b
func matchlen(a, b []byte) (i int) {
	for i < len(a) && i < len(b) && a[i] == b[i] {
		i++
	}
	return i
}

func search(I []int, obuf, nbuf []byte, st, en int) (pos, n int) {
	if en-st < 2 {
		x := matchlen(obuf[I[st]:], nbuf)
		y := matchlen(obuf[I[en]:], nbuf)

		if x > y {
			return I[st], x
		}
		return I[en], y
	}

	x := st + (en-st)/2
	if bytes.Compare(obuf[I[x]:], nbuf) < 0 {
		return search(I, obuf, nbuf, x, en)
	}
	return search(I, obuf, nbuf, st, x)
}

// BSDiff computes the difference between old and new, according to the bsdiff
// algorithm, and writes the result to patch.
func BSDiff(old, new io.Reader, patch *wire.WriteContext, consumer *state.Consumer) error {
	obuf, err := ioutil.ReadAll(old)
	if err != nil {
		return err
	}

	nbuf, err := ioutil.ReadAll(new)
	if err != nil {
		return err
	}

	consumer.ProgressLabel("Suffix sorting...")

	var lenf int
	I := qsufsort(obuf)
	db := make([]byte, len(nbuf))
	eb := make([]byte, len(nbuf))

	bsdc := &BsdiffControl{}

	consumer.ProgressLabel("Scanning...")

	// Compute the differences, writing ctrl as we go
	var scan, pos, length int
	var lastscan, lastpos, lastoffset int
	for scan < len(nbuf) {
		var oldscore int
		scan += length

		progress := float64(scan) / float64(len(nbuf))
		consumer.Progress(progress)

		for scsc := scan; scan < len(nbuf); scan++ {
			pos, length = search(I, obuf, nbuf[scan:], 0, len(obuf))

			for ; scsc < scan+length; scsc++ {
				if scsc+lastoffset < len(obuf) &&
					obuf[scsc+lastoffset] == nbuf[scsc] {
					oldscore++
				}
			}

			if (length == oldscore && length != 0) || length > oldscore+8 {
				break
			}

			if scan+lastoffset < len(obuf) && obuf[scan+lastoffset] == nbuf[scan] {
				oldscore--
			}
		}

		if length != oldscore || scan == len(nbuf) {
			var s, Sf int
			lenf = 0
			for i := 0; lastscan+i < scan && lastpos+i < len(obuf); {
				if obuf[lastpos+i] == nbuf[lastscan+i] {
					s++
				}
				i++
				if s*2-i > Sf*2-lenf {
					Sf = s
					lenf = i
				}
			}

			lenb := 0
			if scan < len(nbuf) {
				var s, Sb int
				for i := 1; (scan >= lastscan+i) && (pos >= i); i++ {
					if obuf[pos-i] == nbuf[scan-i] {
						s++
					}
					if s*2-i > Sb*2-lenb {
						Sb = s
						lenb = i
					}
				}
			}

			if lastscan+lenf > scan-lenb {
				overlap := (lastscan + lenf) - (scan - lenb)
				s := 0
				Ss := 0
				lens := 0
				for i := 0; i < overlap; i++ {
					if nbuf[lastscan+lenf-overlap+i] == obuf[lastpos+lenf-overlap+i] {
						s++
					}
					if nbuf[scan-lenb+i] == obuf[pos-lenb+i] {
						s--
					}
					if s > Ss {
						Ss = s
						lens = i + 1
					}
				}

				lenf += lens - overlap
				lenb -= lens
			}

			for i := 0; i < lenf; i++ {
				db[i] = nbuf[lastscan+i] - obuf[lastpos+i]
			}
			for i := 0; i < (scan-lenb)-(lastscan+lenf); i++ {
				eb[i] = nbuf[lastscan+lenf+i]
			}

			bsdc.Add = db[:lenf]
			bsdc.Copy = eb[:(scan-lenb)-(lastscan+lenf)]
			bsdc.Seek = int64((pos - lenb) - (lastpos + lenf))

			err := patch.WriteMessage(bsdc)
			if err != nil {
				return err
			}

			lastscan = scan - lenb
			lastpos = pos - lenb
			lastoffset = pos - scan
		}
	}

	// Write sentinel control message
	bsdc.Reset()
	bsdc.Seek = -1
	err = patch.WriteMessage(bsdc)
	if err != nil {
		return err
	}

	return nil
}

// ErrCorrupt indicates that a patch is corrupted, most often that it would produce a longer file
// than specified
var ErrCorrupt = errors.New("corrupt patch")

// BSPatch applies patch to old, according to the bspatch algorithm,
// and writes the result to new.
func BSPatch(old io.Reader, new io.Writer, newSize int64, patch *wire.ReadContext) error {
	obuf, err := ioutil.ReadAll(old)
	if err != nil {
		return err
	}

	nbuf := make([]byte, newSize)

	var oldpos, newpos int64

	ctrl := &BsdiffControl{}

	for {
		ctrl.Reset()

		err = patch.ReadMessage(ctrl)
		if err != nil {
			return err
		}

		if ctrl.Seek == -1 {
			break
		}

		// Sanity-check
		if newpos+int64(len(ctrl.Add)) > newSize {
			return ErrCorrupt
		}

		// Add old data to diff string
		for i := int64(0); i < int64(len(ctrl.Add)); i++ {
			nbuf[newpos+i] = ctrl.Add[i] + obuf[oldpos+i]
		}

		// Adjust pointers
		newpos += int64(len(ctrl.Add))
		oldpos += int64(len(ctrl.Add))

		// Sanity-check
		if newpos+int64(len(ctrl.Copy)) > newSize {
			return ErrCorrupt
		}

		// Read extra string
		copy(nbuf[newpos:], ctrl.Copy)

		// Adjust pointers
		newpos += int64(len(ctrl.Copy))
		oldpos += ctrl.Seek
	}

	// Write the new file
	for len(nbuf) > 0 {
		n, err := new.Write(nbuf)
		if err != nil {
			return err
		}
		nbuf = nbuf[n:]
	}

	return nil
}
<commit_msg>Add progress indicator for suffix sorting<commit_after>package pwr

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"

	"github.com/itchio/wharf/state"
	"github.com/itchio/wharf/wire"
)

func swap(a []int, i, j int) { a[i], a[j] = a[j], a[i] }

// Ternary-Split Quicksort, cf. http://www.larsson.dogma.net/ssrev-tr.pdf
func split(I, V []int, start, length, h int) {
	var i, j, k, x, jj, kk int

	if length < 16 {
		for k = start; k < start+length; k += j {
			j = 1
			x = V[I[k]+h]
			for i = 1; k+i < start+length; i++ {
				if V[I[k+i]+h] < x {
					x = V[I[k+i]+h]
					j = 0
				}
				if V[I[k+i]+h] == x {
					swap(I, k+i, k+j)
					j++
				}
			}
			for i = 0; i < j; i++ {
				V[I[k+i]] = k + j - 1
			}
			if j == 1 {
				I[k] = -1
			}
		}
		return
	}

	x = V[I[start+length/2]+h]
	jj = 0
	kk = 0
	for i = start; i < start+length; i++ {
		if V[I[i]+h] < x {
			jj++
		}
		if V[I[i]+h] == x {
			kk++
		}
	}
	jj += start
	kk += jj

	i = start
	j = 0
	k = 0
	for i < jj {
		if V[I[i]+h] < x {
			i++
		} else if V[I[i]+h] == x {
			swap(I, i, jj+j)
			j++
		} else {
			swap(I, i, kk+k)
			k++
		}
	}

	for jj+j < kk {
		if V[I[jj+j]+h] == x {
			j++
		} else {
			swap(I, jj+j, kk+k)
			k++
		}
	}

	if jj > start {
		split(I, V, start, jj-start, h)
	}

	for i = 0; i < kk-jj; i++ {
		V[I[jj+i]] = kk - 1
	}
	if jj == kk-1 {
		I[jj] = -1
	}

	if start+length > kk {
		split(I, V, kk, start+length-kk, h)
	}
}

// Faster Suffix Sorting, see: http://www.larsson.dogma.net/ssrev-tr.pdf
// Output `I` is a sorted suffix array.
func qsufsort(obuf []byte, consumer *state.Consumer) []int {
	var buckets [256]int
	var i, h int
	I := make([]int, len(obuf)+1)
	V := make([]int, len(obuf)+1)

	for _, c := range obuf {
		buckets[c]++
	}
	for i = 1; i < 256; i++ {
		buckets[i] += buckets[i-1]
	}
	copy(buckets[1:], buckets[:])
	buckets[0] = 0

	for i, c := range obuf {
		buckets[c]++
		I[buckets[c]] = i
	}

	I[0] = len(obuf)
	for i, c := range obuf {
		V[i] = buckets[c]
	}

	V[len(obuf)] = 0
	for i = 1; i < 256; i++ {
		if buckets[i] == buckets[i-1]+1 {
			I[buckets[i]] = -1
		}
	}
	I[0] = -1

	const progressInterval = 64 * 1024

	for h = 1; I[0] != -(len(obuf) + 1); h += h {
		consumer.ProgressLabel(fmt.Sprintf("Suffix sorting (%d-order)", h))

		lastI := 0

		var n int
		for i = 0; i < len(obuf)+1; {
			if i-lastI > progressInterval {
				progress := float64(i) / float64(len(obuf))
				consumer.Progress(progress)
				lastI = i
			}

			if I[i] < 0 {
				n -= I[i]
				i -= I[i]
			} else {
				if n != 0 {
					I[i-n] = -n
				}
				n = V[I[i]] + 1 - i
				split(I, V, i, n, h)
				i += n
				n = 0
			}
		}
		if n != 0 {
			I[i-n] = -n
		}
	}

	for i = 0; i < len(obuf)+1; i++ {
		I[V[i]] = i
	}
	return I
}

// Returns the number of bytes common to a and b
func matchlen(a, b []byte) (i int) {
	for i < len(a) && i < len(b) && a[i] == b[i] {
		i++
	}
	return i
}

func search(I []int, obuf, nbuf []byte, st, en int) (pos, n int) {
	if en-st < 2 {
		x := matchlen(obuf[I[st]:], nbuf)
		y := matchlen(obuf[I[en]:], nbuf)

		if x > y {
			return I[st], x
		}
		return I[en], y
	}

	x := st + (en-st)/2
	if bytes.Compare(obuf[I[x]:], nbuf) < 0 {
		return search(I, obuf, nbuf, x, en)
	}
	return search(I, obuf, nbuf, st, x)
}

// BSDiff computes the difference between old and new, according to the bsdiff
// algorithm, and writes the result to patch.
func BSDiff(old, new io.Reader, patch *wire.WriteContext, consumer *state.Consumer) error {
	obuf, err := ioutil.ReadAll(old)
	if err != nil {
		return err
	}

	nbuf, err := ioutil.ReadAll(new)
	if err != nil {
		return err
	}

	var lenf int
	I := qsufsort(obuf, consumer)
	db := make([]byte, len(nbuf))
	eb := make([]byte, len(nbuf))

	bsdc := &BsdiffControl{}

	consumer.ProgressLabel("Scanning...")

	// Compute the differences, writing ctrl as we go
	var scan, pos, length int
	var lastscan, lastpos, lastoffset int
	for scan < len(nbuf) {
		var oldscore int
		scan += length

		progress := float64(scan) / float64(len(nbuf))
		consumer.Progress(progress)

		for scsc := scan; scan < len(nbuf); scan++ {
			pos, length = search(I, obuf, nbuf[scan:], 0, len(obuf))

			for ; scsc < scan+length; scsc++ {
				if scsc+lastoffset < len(obuf) &&
					obuf[scsc+lastoffset] == nbuf[scsc] {
					oldscore++
				}
			}

			if (length == oldscore && length != 0) || length > oldscore+8 {
				break
			}

			if scan+lastoffset < len(obuf) && obuf[scan+lastoffset] == nbuf[scan] {
				oldscore--
			}
		}

		if length != oldscore || scan == len(nbuf) {
			var s, Sf int
			lenf = 0
			for i := 0; lastscan+i < scan && lastpos+i < len(obuf); {
				if obuf[lastpos+i] == nbuf[lastscan+i] {
					s++
				}
				i++
				if s*2-i > Sf*2-lenf {
					Sf = s
					lenf = i
				}
			}

			lenb := 0
			if scan < len(nbuf) {
				var s, Sb int
				for i := 1; (scan >= lastscan+i) && (pos >= i); i++ {
					if obuf[pos-i] == nbuf[scan-i] {
						s++
					}
					if s*2-i > Sb*2-lenb {
						Sb = s
						lenb = i
					}
				}
			}

			if lastscan+lenf > scan-lenb {
				overlap := (lastscan + lenf) - (scan - lenb)
				s := 0
				Ss := 0
				lens := 0
				for i := 0; i < overlap; i++ {
					if nbuf[lastscan+lenf-overlap+i] == obuf[lastpos+lenf-overlap+i] {
						s++
					}
					if nbuf[scan-lenb+i] == obuf[pos-lenb+i] {
						s--
					}
					if s > Ss {
						Ss = s
						lens = i + 1
					}
				}

				lenf += lens - overlap
				lenb -= lens
			}

			for i := 0; i < lenf; i++ {
				db[i] = nbuf[lastscan+i] - obuf[lastpos+i]
			}
			for i := 0; i < (scan-lenb)-(lastscan+lenf); i++ {
				eb[i] = nbuf[lastscan+lenf+i]
			}

			bsdc.Add = db[:lenf]
			bsdc.Copy = eb[:(scan-lenb)-(lastscan+lenf)]
			bsdc.Seek = int64((pos - lenb) - (lastpos + lenf))

			err := patch.WriteMessage(bsdc)
			if err != nil {
				return err
			}

			lastscan = scan - lenb
			lastpos = pos - lenb
			lastoffset = pos - scan
		}
	}

	// Write sentinel control message
	bsdc.Reset()
	bsdc.Seek = -1
	err = patch.WriteMessage(bsdc)
	if err != nil {
		return err
	}

	return nil
}

// ErrCorrupt indicates that a patch is corrupted, most often that it would produce a longer file
// than specified
var ErrCorrupt = errors.New("corrupt patch")

// BSPatch applies patch to old, according to the bspatch algorithm,
// and writes the result to new.
func BSPatch(old io.Reader, new io.Writer, newSize int64, patch *wire.ReadContext) error {
	obuf, err := ioutil.ReadAll(old)
	if err != nil {
		return err
	}

	nbuf := make([]byte, newSize)

	var oldpos, newpos int64

	ctrl := &BsdiffControl{}

	for {
		ctrl.Reset()

		err = patch.ReadMessage(ctrl)
		if err != nil {
			return err
		}

		if ctrl.Seek == -1 {
			break
		}

		// Sanity-check
		if newpos+int64(len(ctrl.Add)) > newSize {
			return ErrCorrupt
		}

		// Add old data to diff string
		for i := int64(0); i < int64(len(ctrl.Add)); i++ {
			nbuf[newpos+i] = ctrl.Add[i] + obuf[oldpos+i]
		}

		// Adjust pointers
		newpos += int64(len(ctrl.Add))
		oldpos += int64(len(ctrl.Add))

		// Sanity-check
		if newpos+int64(len(ctrl.Copy)) > newSize {
			return ErrCorrupt
		}

		// Read extra string
		copy(nbuf[newpos:], ctrl.Copy)

		// Adjust pointers
		newpos += int64(len(ctrl.Copy))
		oldpos += ctrl.Seek
	}

	// Write the new file
	for len(nbuf) > 0 {
		n, err := new.Write(nbuf)
		if err != nil {
			return err
		}
		nbuf = nbuf[n:]
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2016-2017 Olivier Mengué. All rights reserved.
// Use of this source code is governed by the Apache 2.0 license that
// can be found in the LICENSE file.

package jsonptr

import (
	"bytes"
	"encoding/json"
	"strconv"
	"strings"
)

// Pointer represents a mutable parsed JSON Pointer.
//
// The Go representation is a array of non-encoded path elements. This
// allows to use type conversion from/to a []string.
type Pointer []string

// Parse parses a JSON pointer from its text representation.
func Parse(pointer string) (Pointer, error) {
	if pointer == "" {
		return nil, nil
	}
	if pointer[0] != '/' {
		return nil, ErrSyntax
	}
	ptr := strings.Split(pointer[1:], "/")
	// Optimize for the common case
	if strings.IndexByte(pointer, '~') == -1 {
		return ptr, nil
	}
	for i, part := range ptr {
		var err error
		if ptr[i], err = UnescapeString(part); err != nil {
			// TODO return the full prefix
			return nil, err
		}
	}
	return ptr, nil
}

// MarshalText() implements encoding.TextUnmarshaler
func (ptr *Pointer) UnmarshalText(text []byte) error {
	if len(text) == 0 {
		*ptr = nil
		return nil
	}
	if text[0] != '/' {
		return ErrSyntax
	}

	var p Pointer
	t := text[1:]
	for {
		i := bytes.IndexByte(t, '/')
		if i < 0 {
			break
		}
		part, err := Unescape(t[:i])
		if err != nil {
			return syntaxError(string(text[:len(text)-len(t)-i-1]))
		}
		p = append(p, string(part))
		t = t[i+1:]
	}
	part, err := Unescape(t)
	if err != nil {
		return syntaxError(string(text))
	}
	*ptr = append(p, string(part))
	return nil
}

// String returns a JSON Pointer string, escaping components when necessary:
// '~' is replaced by "~0", '/' by "~1"
func (ptr Pointer) String() string {
	if len(ptr) == 0 {
		return ""
	}

	dst := make([]byte, 0, 8*len(ptr))
	for _, part := range ptr {
		dst = AppendEscape(append(dst, '/'), part)
	}
	return string(dst)
}

// MarshalText() implements encoding.TextMarshaler
func (ptr Pointer) MarshalText() (text []byte, err error) {
	if len(ptr) == 0 {
		return nil, nil
	}
	dst := make([]byte, 0, 8*len(ptr))
	for _, part := range ptr {
		dst = AppendEscape(append(dst, '/'), part)
	}
	return dst, nil
}

// Grow allows to prepare space for growth (before use of Property/Index).
func (ptr *Pointer) Grow(n int) {
	if cap(*ptr) >= len(*ptr)+n {
		return
	}
	*ptr = append(make(Pointer, 0, len(*ptr)+n), *ptr...)
}

// Copy returns a new, independant, copy of the pointer.
func (ptr Pointer) Copy() Pointer {
	return append(Pointer(nil), ptr...)
}

// IsRoot returns true if the pointer is at root (empty).
func (ptr Pointer) IsRoot() bool {
	return len(ptr) == 0
}

// Up removes the last element of the pointer.
// The pointer is returned for chaining.
//
// Panics if already at root.
func (ptr *Pointer) Up() *Pointer {
	if ptr.IsRoot() {
		panic(ErrRoot)
	}
	*ptr = (*ptr)[:len(*ptr)-1]
	return ptr
}

// Pop removes the last element of the pointer and returns it.
//
// Panics if already at root.
func (ptr *Pointer) Pop() string {
	last := len(*ptr) - 1
	if last < 0 {
		panic(ErrRoot)
	}
	prop := (*ptr)[last]
	*ptr = (*ptr)[:last]
	return prop
}

// Property moves the pointer deeper, following a property name.
// The pointer is returned for chaining.
func (ptr *Pointer) Property(name string) *Pointer {
	*ptr = append(*ptr, name)
	return ptr
}

// Index moves the pointer deeper, following an array index.
// The pointer is returned for chaining.
func (ptr *Pointer) Index(index int) *Pointer {
	var prop string
	if index < 0 {
		prop = "-"
	} else {
		prop = strconv.Itoa(index)
	}
	return ptr.Property(prop)
}

// LeafName returns the name of the last part of the pointer.
func (ptr Pointer) LeafName() string {
	return ptr[len(ptr)-1]
}

// LeafIndex returns the last part of the pointer as an array index.
// -1 is returned for "-".
func (ptr Pointer) LeafIndex() (int, error) {
	return arrayIndex(ptr.LeafName())
}

// In returns the value from doc pointed by ptr.
//
// doc may be a deserialized document, or a json.RawMessage.
func (ptr Pointer) In(doc interface{}) (interface{}, error) {
	for i, key := range ptr {
		switch here := (doc).(type) {
		case map[string]interface{}:
			var ok bool
			if doc, ok = here[key]; !ok {
				return nil, propertyError(ptr[:i].String())
			}
		case []interface{}:
			n, err := arrayIndex(key)
			if err != nil {
				return nil, &PtrError{ptr[:i].String(), err}
			}
			if n < 0 || n >= len(here) {
				return nil, indexError(ptr[:i].String())
			}
			doc = here[n]
		case JSONDecoder:
			v, err := getJSON(here, ptr[i:].String())
			if err != nil {
				err.rebase(ptr[:i].String())
			}
			return v, err
		case json.RawMessage:
			v, err := getRaw(here, ptr[i:].String())
			if err != nil {
				err.rebase(ptr[:i].String())
			}
			return v, err
		default:
			// We report the error at the upper level
			return nil, docError(ptr[:i-1].String(), doc)
		}
	}

	doc, err := getLeaf(doc)
	if err != nil {
		err.rebase(ptr.String())
	}
	return doc, err
}

// Set changes a value in document pdoc at location pointed by ptr.
func (ptr Pointer) Set(pdoc *interface{}, value interface{}) error {
	// TODO Make an optimised implementation
	return Set(pdoc, ptr.String(), value)
}
<commit_msg>Fix error location in Pointer.In<commit_after>// Copyright 2016-2017 Olivier Mengué. All rights reserved.
// Use of this source code is governed by the Apache 2.0 license that
// can be found in the LICENSE file.

package jsonptr

import (
	"bytes"
	"encoding/json"
	"strconv"
	"strings"
)

// Pointer represents a mutable parsed JSON Pointer.
//
// The Go representation is a array of non-encoded path elements. This
// allows to use type conversion from/to a []string.
type Pointer []string

// Parse parses a JSON pointer from its text representation.
func Parse(pointer string) (Pointer, error) {
	if pointer == "" {
		return nil, nil
	}
	if pointer[0] != '/' {
		return nil, ErrSyntax
	}
	ptr := strings.Split(pointer[1:], "/")
	// Optimize for the common case
	if strings.IndexByte(pointer, '~') == -1 {
		return ptr, nil
	}
	for i, part := range ptr {
		var err error
		if ptr[i], err = UnescapeString(part); err != nil {
			// TODO return the full prefix
			return nil, err
		}
	}
	return ptr, nil
}

// MarshalText() implements encoding.TextUnmarshaler
func (ptr *Pointer) UnmarshalText(text []byte) error {
	if len(text) == 0 {
		*ptr = nil
		return nil
	}
	if text[0] != '/' {
		return ErrSyntax
	}

	var p Pointer
	t := text[1:]
	for {
		i := bytes.IndexByte(t, '/')
		if i < 0 {
			break
		}
		part, err := Unescape(t[:i])
		if err != nil {
			return syntaxError(string(text[:len(text)-len(t)-i-1]))
		}
		p = append(p, string(part))
		t = t[i+1:]
	}
	part, err := Unescape(t)
	if err != nil {
		return syntaxError(string(text))
	}
	*ptr = append(p, string(part))
	return nil
}

// String returns a JSON Pointer string, escaping components when necessary:
// '~' is replaced by "~0", '/' by "~1"
func (ptr Pointer) String() string {
	if len(ptr) == 0 {
		return ""
	}

	dst := make([]byte, 0, 8*len(ptr))
	for _, part := range ptr {
		dst = AppendEscape(append(dst, '/'), part)
	}
	return string(dst)
}

// MarshalText() implements encoding.TextMarshaler
func (ptr Pointer) MarshalText() (text []byte, err error) {
	if len(ptr) == 0 {
		return nil, nil
	}
	dst := make([]byte, 0, 8*len(ptr))
	for _, part := range ptr {
		dst = AppendEscape(append(dst, '/'), part)
	}
	return dst, nil
}

// Grow allows to prepare space for growth (before use of Property/Index).
func (ptr *Pointer) Grow(n int) {
	if cap(*ptr) >= len(*ptr)+n {
		return
	}
	*ptr = append(make(Pointer, 0, len(*ptr)+n), *ptr...)
}

// Copy returns a new, independant, copy of the pointer.
func (ptr Pointer) Copy() Pointer {
	return append(Pointer(nil), ptr...)
}

// IsRoot returns true if the pointer is at root (empty).
func (ptr Pointer) IsRoot() bool {
	return len(ptr) == 0
}

// Up removes the last element of the pointer.
// The pointer is returned for chaining.
//
// Panics if already at root.
func (ptr *Pointer) Up() *Pointer {
	if ptr.IsRoot() {
		panic(ErrRoot)
	}
	*ptr = (*ptr)[:len(*ptr)-1]
	return ptr
}

// Pop removes the last element of the pointer and returns it.
//
// Panics if already at root.
func (ptr *Pointer) Pop() string {
	last := len(*ptr) - 1
	if last < 0 {
		panic(ErrRoot)
	}
	prop := (*ptr)[last]
	*ptr = (*ptr)[:last]
	return prop
}

// Property moves the pointer deeper, following a property name.
// The pointer is returned for chaining.
func (ptr *Pointer) Property(name string) *Pointer {
	*ptr = append(*ptr, name)
	return ptr
}

// Index moves the pointer deeper, following an array index.
// The pointer is returned for chaining.
func (ptr *Pointer) Index(index int) *Pointer {
	var prop string
	if index < 0 {
		prop = "-"
	} else {
		prop = strconv.Itoa(index)
	}
	return ptr.Property(prop)
}

// LeafName returns the name of the last part of the pointer.
func (ptr Pointer) LeafName() string {
	return ptr[len(ptr)-1]
}

// LeafIndex returns the last part of the pointer as an array index.
// -1 is returned for "-".
func (ptr Pointer) LeafIndex() (int, error) {
	return arrayIndex(ptr.LeafName())
}

// In returns the value from doc pointed by ptr.
//
// doc may be a deserialized document, or a json.RawMessage.
func (ptr Pointer) In(doc interface{}) (interface{}, error) {
	for i, key := range ptr {
		switch here := (doc).(type) {
		case map[string]interface{}:
			var ok bool
			if doc, ok = here[key]; !ok {
				return nil, propertyError(ptr[:i+1].String())
			}
		case []interface{}:
			n, err := arrayIndex(key)
			if err != nil || n < 0 || n >= len(here) {
				return nil, indexError(ptr[:i+1].String())
			}
			doc = here[n]
		case JSONDecoder:
			v, err := getJSON(here, ptr[i:].String())
			if err != nil {
				err.rebase(ptr[:i].String())
			}
			return v, err
		case json.RawMessage:
			v, err := getRaw(here, ptr[i:].String())
			if err != nil {
				err.rebase(ptr[:i].String())
			}
			return v, err
		default:
			// We report the error at the upper level
			return nil, docError(ptr[:i-1].String(), doc)
		}
	}

	doc, err := getLeaf(doc)
	if err != nil {
		err.rebase(ptr.String())
	}
	return doc, err
}

// Set changes a value in document pdoc at location pointed by ptr.
func (ptr Pointer) Set(pdoc *interface{}, value interface{}) error {
	// TODO Make an optimised implementation
	return Set(pdoc, ptr.String(), value)
}
<|endoftext|>


<commit_before>package commands

import "testing"

func noop(req Request) (interface{}, error) {
	return nil, nil
}

func TestOptionValidation(t *testing.T) {
	cmd := Command{
		Options: []Option{
			Option{[]string{"b", "beep"}, Int, "enables beeper"},
			Option{[]string{"B", "boop"}, String, "password for booper"},
		},
		Run: noop,
	}

	opts, _ := cmd.GetOptions(nil)

	req, _ := NewRequest(nil, nil, nil, nil, nil, opts)
	req.SetOption("beep", true)
	res := cmd.Call(req)
	if res.Error() == nil {
		t.Error("Should have failed (incorrect type)")
	}

	req, _ = NewRequest(nil, nil, nil, nil, nil, opts)
	req.SetOption("beep", 5)
	res = cmd.Call(req)
	if res.Error() != nil {
		t.Error(res.Error(), "Should have passed")
	}

	req, _ = NewRequest(nil, nil, nil, nil, nil, opts)
	req.SetOption("beep", 5)
	req.SetOption("boop", "test")
	res = cmd.Call(req)
	if res.Error() != nil {
		t.Error("Should have passed")
	}

	req, _ = NewRequest(nil, nil, nil, nil, nil, opts)
	req.SetOption("b", 5)
	req.SetOption("B", "test")
	res = cmd.Call(req)
	if res.Error() != nil {
		t.Error("Should have passed")
	}

	req, _ = NewRequest(nil, nil, nil, nil, nil, opts)
	req.SetOption("foo", 5)
	res = cmd.Call(req)
	if res.Error() != nil {
		t.Error("Should have passed")
	}

	req, _ = NewRequest(nil, nil, nil, nil, nil, opts)
	req.SetOption(EncShort, "json")
	res = cmd.Call(req)
	if res.Error() != nil {
		t.Error("Should have passed")
	}

	req, _ = NewRequest(nil, nil, nil, nil, nil, opts)
	req.SetOption("b", "100")
	res = cmd.Call(req)
	if res.Error() != nil {
		t.Error("Should have passed")
	}

	req, _ = NewRequest(nil, nil, nil, nil, nil, opts)
	req.SetOption("b", ":)")
	res = cmd.Call(req)
	if res.Error() == nil {
		t.Error("Should have failed (string value not convertible to int)")
	}
}

func TestRegistration(t *testing.T) {
	cmdA := &Command{
		Options: []Option{
			Option{[]string{"beep"}, Int, "number of beeps"},
		},
		Run: noop,
	}

	cmdB := &Command{
		Options: []Option{
			Option{[]string{"beep"}, Int, "number of beeps"},
		},
		Run: noop,
		Subcommands: map[string]*Command{
			"a": cmdA,
		},
	}

	cmdC := &Command{
		Options: []Option{
			Option{[]string{"encoding"}, String, "data encoding type"},
		},
		Run: noop,
	}

	path := []string{"a"}
	_, err := cmdB.GetOptions(path)
	if err == nil {
		t.Error("Should have failed (option name collision)")
	}

	_, err = cmdC.GetOptions(nil)
	if err == nil {
		t.Error("Should have failed (option name collision with global options)")
	}
}

func TestResolving(t *testing.T) {
	cmdC := &Command{}
	cmdB := &Command{
		Subcommands: map[string]*Command{
			"c": cmdC,
		},
	}
	cmdB2 := &Command{}
	cmdA := &Command{
		Subcommands: map[string]*Command{
			"b": cmdB,
			"B": cmdB2,
		},
	}
	cmd := &Command{
		Subcommands: map[string]*Command{
			"a": cmdA,
		},
	}

	cmds, err := cmd.Resolve([]string{"a", "b", "c"})
	if err != nil {
		t.Error(err)
	}
	if len(cmds) != 4 || cmds[0] != cmd || cmds[1] != cmdA || cmds[2] != cmdB || cmds[3] != cmdC {
		t.Error("Returned command path is different than expected", cmds)
	}
}
<commit_msg>commands: Added tests for Request#SetOptions<commit_after>package commands

import "testing"

func noop(req Request) (interface{}, error) {
	return nil, nil
}

func TestOptionValidation(t *testing.T) {
	cmd := Command{
		Options: []Option{
			Option{[]string{"b", "beep"}, Int, "enables beeper"},
			Option{[]string{"B", "boop"}, String, "password for booper"},
		},
		Run: noop,
	}

	opts, _ := cmd.GetOptions(nil)

	req, _ := NewRequest(nil, nil, nil, nil, nil, opts)
	req.SetOption("beep", true)
	res := cmd.Call(req)
	if res.Error() == nil {
		t.Error("Should have failed (incorrect type)")
	}

	req, _ = NewRequest(nil, nil, nil, nil, nil, opts)
	req.SetOption("beep", 5)
	res = cmd.Call(req)
	if res.Error() != nil {
		t.Error(res.Error(), "Should have passed")
	}

	req, _ = NewRequest(nil, nil, nil, nil, nil, opts)
	req.SetOption("beep", 5)
	req.SetOption("boop", "test")
	res = cmd.Call(req)
	if res.Error() != nil {
		t.Error("Should have passed")
	}

	req, _ = NewRequest(nil, nil, nil, nil, nil, opts)
	req.SetOption("b", 5)
	req.SetOption("B", "test")
	res = cmd.Call(req)
	if res.Error() != nil {
		t.Error("Should have passed")
	}

	req, _ = NewRequest(nil, nil, nil, nil, nil, opts)
	req.SetOption("foo", 5)
	res = cmd.Call(req)
	if res.Error() != nil {
		t.Error("Should have passed")
	}

	req, _ = NewRequest(nil, nil, nil, nil, nil, opts)
	req.SetOption(EncShort, "json")
	res = cmd.Call(req)
	if res.Error() != nil {
		t.Error("Should have passed")
	}

	req, _ = NewRequest(nil, nil, nil, nil, nil, opts)
	req.SetOption("b", "100")
	res = cmd.Call(req)
	if res.Error() != nil {
		t.Error("Should have passed")
	}

	req, _ = NewRequest(nil, nil, nil, nil, &cmd, opts)
	req.SetOption("b", ":)")
	res = cmd.Call(req)
	if res.Error() == nil {
		t.Error("Should have failed (string value not convertible to int)")
	}

	err := req.SetOptions(map[string]interface{}{
		"b": 100,
	})
	if err != nil {
		t.Error("Should have passed")
	}

	err = req.SetOptions(map[string]interface{}{
		"b": ":)",
	})
	if err == nil {
		t.Error("Should have failed (string value not convertible to int)")
	}
}

func TestRegistration(t *testing.T) {
	cmdA := &Command{
		Options: []Option{
			Option{[]string{"beep"}, Int, "number of beeps"},
		},
		Run: noop,
	}

	cmdB := &Command{
		Options: []Option{
			Option{[]string{"beep"}, Int, "number of beeps"},
		},
		Run: noop,
		Subcommands: map[string]*Command{
			"a": cmdA,
		},
	}

	cmdC := &Command{
		Options: []Option{
			Option{[]string{"encoding"}, String, "data encoding type"},
		},
		Run: noop,
	}

	path := []string{"a"}
	_, err := cmdB.GetOptions(path)
	if err == nil {
		t.Error("Should have failed (option name collision)")
	}

	_, err = cmdC.GetOptions(nil)
	if err == nil {
		t.Error("Should have failed (option name collision with global options)")
	}
}

func TestResolving(t *testing.T) {
	cmdC := &Command{}
	cmdB := &Command{
		Subcommands: map[string]*Command{
			"c": cmdC,
		},
	}
	cmdB2 := &Command{}
	cmdA := &Command{
		Subcommands: map[string]*Command{
			"b": cmdB,
			"B": cmdB2,
		},
	}
	cmd := &Command{
		Subcommands: map[string]*Command{
			"a": cmdA,
		},
	}

	cmds, err := cmd.Resolve([]string{"a", "b", "c"})
	if err != nil {
		t.Error(err)
	}
	if len(cmds) != 4 || cmds[0] != cmd || cmds[1] != cmdA || cmds[2] != cmdB || cmds[3] != cmdC {
		t.Error("Returned command path is different than expected", cmds)
	}
}
<|endoftext|>


<commit_before>package commands

import "github.com/spf13/cobra"

func (l *Logical) AddReadSub(c *cobra.Command) {
	cmd := &cobra.Command{
		Use:   "read",
		Short: "Reads the value of the key at the given path.",
		Long:  "Reads the value of the key at the given path.",
		RunE: func(cmd *cobra.Command, args []string) error {
			return l.Read(args)
		},
	}

	l.AddCommand(cmd)
}

func (l *Logical) Read(args []string) error {
	if err := l.CheckArgs(args); err != nil {
		return err
	}

	logical, err := l.Logical()
	if err != nil {
		return err
	}

	result, err := logical.Read(args[0])
	if err != nil {
		return err
	}

	return l.Output(result.Data["value"])
}
<commit_msg>avoid panic when there is no value for the given key<commit_after>package commands

import (
	"fmt"

	"github.com/spf13/cobra"
)

func (l *Logical) AddReadSub(c *cobra.Command) {
	cmd := &cobra.Command{
		Use:   "read",
		Short: "Reads the value of the key at the given path.",
		Long:  "Reads the value of the key at the given path.",
		RunE: func(cmd *cobra.Command, args []string) error {
			return l.Read(args)
		},
	}

	l.AddCommand(cmd)
}

func (l *Logical) Read(args []string) error {
	if err := l.CheckArgs(args); err != nil {
		return err
	}

	logical, err := l.Logical()
	if err != nil {
		return err
	}

	result, err := logical.Read(args[0])
	if err != nil {
		return err
	}

	if result == nil {
		fmt.Printf("No value found at %s\n", args[0])
		return nil
	} else {
		return l.Output(result.Data["value"])
	}
}
<|endoftext|>


<commit_before>package phrase

import "math/rand"

const (
	DefaultRandChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 -./~"
)

type Rand struct {
	Chars  string
	Length int
}

func (r *Rand) Phrase() string {
	if r.Chars == "" {
		r.Chars = DefaultRandChars
	}
	nChars := len(r.Chars)
	var b []byte
	for i := 0; i < r.Length; i++ {
		b = append(b, r.Chars[rand.Intn(nChars)])
	}
	return string(b)
}
<commit_msg>s/nChars/n/ -- more concise<commit_after>package phrase

import "math/rand"

const (
	DefaultRandChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 -./~"
)

type Rand struct {
	Chars  string
	Length int
}

func (r *Rand) Phrase() string {
	if r.Chars == "" {
		r.Chars = DefaultRandChars
	}
	n := len(r.Chars)
	var b []byte
	for i := 0; i < r.Length; i++ {
		b = append(b, r.Chars[rand.Intn(n)])
	}
	return string(b)
}
<|endoftext|>


<commit_before>package psdock

import (
	"bufio"
	"bytes"
	"code.google.com/p/go.crypto/ssh/terminal"
	"github.com/kr/pty"
	"log"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"syscall"
	"time"
)

type Process struct {
	Cmd           *exec.Cmd
	Conf          *Config
	Notif         Notifier
	Pty           *os.File
	Term          *terminal.Terminal
	stdinStruct   *stdin
	StatusChannel chan ProcessStatus
}

//NewProcess creates a new struct of type *Process and returns its address
func NewProcess(conf *Config) *Process {
	var cmd *exec.Cmd
	if len(conf.Args) > 0 {
		cmd = exec.Command(conf.Command, strings.Split(conf.Args, " ")...)
	} else {
		cmd = exec.Command(conf.Command)
	}
	newStatusChannel := make(chan ProcessStatus, 1)

	return &Process{Cmd: cmd, Conf: conf, StatusChannel: newStatusChannel, Notif: Notifier{webHook: conf.WebHook}}
}

//SetEnvVars sets the environment variables for the launched process
//If p.Conf.EnvVars is empty, we pass all the current env vars to the child
func (p *Process) SetEnvVars() {
	if len(p.Conf.EnvVars) == 0 {
		return
	}
	for _, envVar := range strings.Split(p.Conf.EnvVars, ",") {
		p.Cmd.Env = append(p.Cmd.Env, envVar)
	}
}

func (p *Process) Terminate(nbSec int) error {
	syscall.Kill(p.Cmd.Process.Pid, syscall.SIGTERM)
	time.Sleep(time.Duration(nbSec) * time.Second)
	if !p.isRunning() {
		return nil
	}
	return syscall.Kill(p.Cmd.Process.Pid, syscall.SIGKILL)
}

func (p *Process) isStarted() bool {
	return p.Cmd.Process != nil
}

func (p *Process) isRunning() bool {
	if p.Conf.BindPort == 0 {
		return p.isStarted()
	} else {
		return p.isStarted() && p.hasBoundPort()
	}
}

func (p *Process) hasBoundPort() bool {
	//We execute lsof -i :bindPort to find if bindPort is open
	//For the moment, we only verified that bindPort is used by some process
	lsofCmd := exec.Command("lsof", "-i", ":"+strconv.Itoa(p.Conf.BindPort))

	lsofBytes, _ := lsofCmd.Output()
	lsofScanner := bufio.NewScanner(bytes.NewBuffer(lsofBytes))
	lsofScanner.Scan()
	lsofScanner.Text()
	lsofScanner.Scan()
	lsofResult := lsofScanner.Text()

	return len(lsofResult) > 0
}

func (p *Process) Start() error {
	//We start the process
	var startErr error
	p.Pty, startErr = pty.Start(p.Cmd)
	if startErr != nil {
		return startErr
	}

	go func() {
		var err error
		eofChannel := make(chan bool, 1)
		p.stdinStruct, err = setTerminalAndRedirectStdin(os.Stdin, p.Pty)
		if err != nil {
			p.StatusChannel <- ProcessStatus{Status: -1, Err: err}
		}
		defer p.stdinStruct.restoreStdin()

		if err = p.redirectStdout(eofChannel); err != nil {
			p.StatusChannel <- ProcessStatus{Status: -1, Err: err}
		}
		for !p.isStarted() {
			time.Sleep(100 * time.Millisecond)
		}

		if err = p.Notif.Notify(PROCESS_STARTED); err != nil {
			log.Println(err)
		}
		p.StatusChannel <- ProcessStatus{Status: PROCESS_STARTED, Err: nil}

		for p.isRunning() == false {
			time.Sleep(100 * time.Millisecond)
		}

		if err = p.Notif.Notify(PROCESS_RUNNING); err != nil {
			log.Println(err)
		}
		p.StatusChannel <- ProcessStatus{Status: PROCESS_RUNNING, Err: nil}

		err = p.Cmd.Wait()
		if err != nil {
			p.stdinStruct.restoreStdin()
			p.Notif.Notify(PROCESS_STOPPED)
			log.Fatal(err)
		}
		_ = <-eofChannel

		//p has stopped and stdout has been written
		p.stdinStruct.restoreStdin()
		if err = p.Notif.Notify(PROCESS_STOPPED); err != nil {
			log.Println(err)
		}
		p.StatusChannel <- ProcessStatus{Status: PROCESS_STOPPED, Err: nil}
	}()

	return nil
}
<commit_msg>Removed useless field of Process<commit_after>package psdock

import (
	"bufio"
	"bytes"
	"github.com/kr/pty"
	"log"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"syscall"
	"time"
)

type Process struct {
	Cmd           *exec.Cmd
	Conf          *Config
	Notif         Notifier
	Pty           *os.File
	stdinStruct   *stdin
	StatusChannel chan ProcessStatus
}

//NewProcess creates a new struct of type *Process and returns its address
func NewProcess(conf *Config) *Process {
	var cmd *exec.Cmd
	if len(conf.Args) > 0 {
		cmd = exec.Command(conf.Command, strings.Split(conf.Args, " ")...)
	} else {
		cmd = exec.Command(conf.Command)
	}
	newStatusChannel := make(chan ProcessStatus, 1)

	return &Process{Cmd: cmd, Conf: conf, StatusChannel: newStatusChannel, Notif: Notifier{webHook: conf.WebHook}}
}

//SetEnvVars sets the environment variables for the launched process
//If p.Conf.EnvVars is empty, we pass all the current env vars to the child
func (p *Process) SetEnvVars() {
	if len(p.Conf.EnvVars) == 0 {
		return
	}
	for _, envVar := range strings.Split(p.Conf.EnvVars, ",") {
		p.Cmd.Env = append(p.Cmd.Env, envVar)
	}
}

func (p *Process) Terminate(nbSec int) error {
	syscall.Kill(p.Cmd.Process.Pid, syscall.SIGTERM)
	time.Sleep(time.Duration(nbSec) * time.Second)
	if !p.isRunning() {
		return nil
	}
	return syscall.Kill(p.Cmd.Process.Pid, syscall.SIGKILL)
}

func (p *Process) isStarted() bool {
	return p.Cmd.Process != nil
}

func (p *Process) isRunning() bool {
	if p.Conf.BindPort == 0 {
		return p.isStarted()
	} else {
		return p.isStarted() && p.hasBoundPort()
	}
}

func (p *Process) hasBoundPort() bool {
	//We execute lsof -i :bindPort to find if bindPort is open
	//For the moment, we only verified that bindPort is used by some process
	lsofCmd := exec.Command("lsof", "-i", ":"+strconv.Itoa(p.Conf.BindPort))

	lsofBytes, _ := lsofCmd.Output()
	lsofScanner := bufio.NewScanner(bytes.NewBuffer(lsofBytes))
	lsofScanner.Scan()
	lsofScanner.Text()
	lsofScanner.Scan()
	lsofResult := lsofScanner.Text()

	return len(lsofResult) > 0
}

func (p *Process) Start() error {
	//We start the process
	var startErr error
	p.Pty, startErr = pty.Start(p.Cmd)
	if startErr != nil {
		return startErr
	}

	go func() {
		var err error
		eofChannel := make(chan bool, 1)
		p.stdinStruct, err = setTerminalAndRedirectStdin(os.Stdin, p.Pty)
		if err != nil {
			p.StatusChannel <- ProcessStatus{Status: -1, Err: err}
		}
		defer p.stdinStruct.restoreStdin()

		if err = p.redirectStdout(eofChannel); err != nil {
			p.StatusChannel <- ProcessStatus{Status: -1, Err: err}
		}
		for !p.isStarted() {
			time.Sleep(100 * time.Millisecond)
		}

		if err = p.Notif.Notify(PROCESS_STARTED); err != nil {
			log.Println(err)
		}
		p.StatusChannel <- ProcessStatus{Status: PROCESS_STARTED, Err: nil}

		for p.isRunning() == false {
			time.Sleep(100 * time.Millisecond)
		}

		if err = p.Notif.Notify(PROCESS_RUNNING); err != nil {
			log.Println(err)
		}
		p.StatusChannel <- ProcessStatus{Status: PROCESS_RUNNING, Err: nil}

		err = p.Cmd.Wait()
		if err != nil {
			p.stdinStruct.restoreStdin()
			p.Notif.Notify(PROCESS_STOPPED)
			log.Fatal(err)
		}
		_ = <-eofChannel

		//p has stopped and stdout has been written
		p.stdinStruct.restoreStdin()
		if err = p.Notif.Notify(PROCESS_STOPPED); err != nil {
			log.Println(err)
		}
		p.StatusChannel <- ProcessStatus{Status: PROCESS_STOPPED, Err: nil}
	}()

	return nil
}
<|endoftext|>


<commit_before>package main

type Productor struct {
	items   [][]string
	indexes []int
	ch      chan []int
}

func NewProductor(items [][]string, ch chan []int) *Productor {
	return &Productor{
		items:   items,
		indexes: make([]int, len(items)),
		ch:      ch,
	}
}

func (p *Productor) FindNext(index_i int) {
	if index_i == len(p.items) {
		indexes := make([]int, len(p.indexes))
		copy(indexes, p.indexes)
		p.ch <- indexes
		return
	}

	for i := 0; i < len(p.items[index_i]); i++ {
		p.indexes[index_i] = i
		p.FindNext(index_i + 1)
	}
}

func Product(items [][]string) chan []int {
	ch := make(chan []int, 16)
	go func() {
		p := NewProductor(items, ch)
		p.FindNext(0)
		close(p.ch)
	}()
	return ch
}
<commit_msg>s/Productor.FindNext/Productor.FindProduct/<commit_after>package main

type Productor struct {
	items   [][]string
	indexes []int
	ch      chan []int
}

func NewProductor(items [][]string, ch chan []int) *Productor {
	return &Productor{
		items:   items,
		indexes: make([]int, len(items)),
		ch:      ch,
	}
}

func (p *Productor) FindProduct(index_i int) {
	if index_i == len(p.items) {
		indexes := make([]int, len(p.indexes))
		copy(indexes, p.indexes)
		p.ch <- indexes
		return
	}

	for i := 0; i < len(p.items[index_i]); i++ {
		p.indexes[index_i] = i
		p.FindProduct(index_i + 1)
	}
}

func Product(items [][]string) chan []int {
	ch := make(chan []int, 16)
	go func() {
		p := NewProductor(items, ch)
		p.FindProduct(0)
		close(p.ch)
	}()
	return ch
}
<|endoftext|>


<commit_before>package flect

var pluralRules = []rule{}

// AddPlural adds a rule that will replace the given suffix with the replacement suffix.
func AddPlural(suffix string, repl string) {
	pluralMoot.Lock()
	defer pluralMoot.Unlock()
	pluralRules = append(pluralRules, rule{
		suffix: suffix,
		fn: func(s string) string {
			s = s[:len(s)-len(suffix)]
			return s + repl
		},
	})

	pluralRules = append(pluralRules, rule{
		suffix: repl,
		fn:     noop,
	})
}

var singleToPlural = map[string]string{
	"aircraft":    "aircraft",
	"alias":       "aliases",
	"alumna":      "alumnae",
	"alumnus":     "alumni",
	"analysis":    "analyses",
	"antenna":     "antennas",
	"antithesis":  "antitheses",
	"apex":        "apexes",
	"appendix":    "appendices",
	"axis":        "axes",
	"bacillus":    "bacilli",
	"bacterium":   "bacteria",
	"basis":       "bases",
	"beau":        "beaus",
	"bison":       "bison",
	"bureau":      "bureaus",
	"bus":         "buses",
	"campus":      "campuses",
	"caucus":      "caucuses",
	"château":     "châteaux",
	"circus":      "circuses",
	"codex":       "codices",
	"concerto":    "concertos",
	"corpus":      "corpora",
	"crisis":      "crises",
	"curriculum":  "curriculums",
	"datum":       "data",
	"deer":        "deer",
	"diagnosis":   "diagnoses",
	"die":         "dice",
	"dwarf":       "dwarves",
	"ellipsis":    "ellipses",
	"equipment":   "equipment",
	"erratum":     "errata",
	"faux pas":    "faux pas",
	"fez":         "fezzes",
	"fish":        "fish",
	"focus":       "foci",
	"foo":         "foos",
	"foot":        "feet",
	"formula":     "formulas",
	"fungus":      "fungi",
	"genus":       "genera",
	"goose":       "geese",
	"graffito":    "graffiti",
	"grouse":      "grouse",
	"half":        "halves",
	"halo":        "halos",
	"hoof":        "hooves",
	"human":       "humans",
	"hypothesis":  "hypotheses",
	"index":       "indices",
	"information": "information",
	"jeans":       "jeans",
	"larva":       "larvae",
	"libretto":    "librettos",
	"loaf":        "loaves",
	"locus":       "loci",
	"louse":       "lice",
	"matrix":      "matrices",
	"minutia":     "minutiae",
	"money":       "money",
	"moose":       "moose",
	"mouse":       "mice",
	"nebula":      "nebulae",
	"news":        "news",
	"nucleus":     "nuclei",
	"oasis":       "oases",
	"octopus":     "octopi",
	"offspring":   "offspring",
	"opus":        "opera",
	"ovum":        "ova",
	"ox":          "oxen",
	"parenthesis": "parentheses",
	"phenomenon":  "phenomena",
	"photo":       "photos",
	"phylum":      "phyla",
	"piano":       "pianos",
	"plus":        "pluses",
	"police":      "police",
	"prognosis":   "prognoses",
	"prometheus":  "prometheuses",
	"quiz":        "quizzes",
	"radius":      "radiuses",
	"referendum":  "referendums",
	"ress":        "resses",
	"rice":        "rice",
	"salmon":      "salmon",
	"series":      "series",
	"sheep":       "sheep",
	"shoe":        "shoes",
	"shrimp":      "shrimp",
	"species":     "species",
	"stimulus":    "stimuli",
	"stratum":     "strata",
	"swine":       "swine",
	"syllabus":    "syllabi",
	"symposium":   "symposiums",
	"synopsis":    "synopses",
	"tableau":     "tableaus",
	"testis":      "testes",
	"thesis":      "theses",
	"thief":       "thieves",
	"tooth":       "teeth",
	"trout":       "trout",
	"tuna":        "tuna",
	"vertebra":    "vertebrae",
	"vertix":      "vertices",
	"vita":        "vitae",
	"vortex":      "vortices",
	"wharf":       "wharves",
	"wife":        "wives",
	"wolf":        "wolves",
	"you":         "you",
}

var pluralToSingle = map[string]string{}

func init() {
	for k, v := range singleToPlural {
		pluralToSingle[v] = k
	}
}

type singularToPluralSuffix struct {
	singular string
	plural   string
}

var singularToPluralSuffixList = []singularToPluralSuffix{
	{"iterion", "iteria"},
	{"campus", "campuses"},
	{"genera", "genus"},
	{"person", "people"},
	{"phylum", "phyla"},
	{"randum", "randa"},
	{"actus", "acti"},
	{"adium", "adia"},
	{"alias", "aliases"},
	{"basis", "basis"},
	{"child", "children"},
	{"chive", "chives"},
	{"focus", "foci"},
	{"hello", "hellos"},
	{"jeans", "jeans"},
	{"louse", "lice"},
	{"mouse", "mice"},
	{"movie", "movies"},
	{"oasis", "oasis"},
	{"atum", "ata"},
	{"atus", "atuses"},
	{"base", "bases"},
	{"cess", "cesses"},
	{"dium", "diums"},
	{"eses", "esis"},
	{"half", "halves"},
	{"hive", "hives"},
	{"iano", "ianos"},
	{"irus", "iri"},
	{"isis", "ises"},
	{"leus", "li"},
	{"mnus", "mni"},
	{"move", "moves"},
	{"news", "news"},
	{"odex", "odice"},
	{"oose", "eese"},
	{"ouse", "ouses"},
	{"ovum", "ova"},
	{"rion", "ria"},
	{"shoe", "shoes"},
	{"stis", "stes"},
	{"tive", "tives"},
	{"wife", "wives"},
	{"afe", "aves"},
	{"bfe", "bves"},
	{"box", "boxes"},
	{"cfe", "cves"},
	{"dfe", "dves"},
	{"dge", "dges"},
	{"efe", "eves"},
	{"gfe", "gves"},
	{"hfe", "hves"},
	{"ife", "ives"},
	{"itz", "itzes"},
	{"ium", "ia"},
	{"ize", "izes"},
	{"jfe", "jves"},
	{"kfe", "kves"},
	{"man", "men"},
	{"mfe", "mves"},
	{"nfe", "nves"},
	{"nna", "nnas"},
	{"oaf", "oaves"},
	{"oci", "ocus"},
	{"ode", "odes"},
	{"ofe", "oves"},
	{"oot", "eet"},
	{"pfe", "pves"},
	{"pse", "psis"},
	{"qfe", "qves"},
	{"quy", "quies"},
	{"rfe", "rves"},
	{"sfe", "sves"},
	{"tfe", "tves"},
	{"tum", "ta"},
	{"tus", "tuses"},
	{"ufe", "uves"},
	{"ula", "ulae"},
	{"ula", "ulas"},
	{"uli", "ulus"},
	{"use", "uses"},
	{"uss", "usses"},
	{"vfe", "vves"},
	{"wfe", "wves"},
	{"xfe", "xves"},
	{"yfe", "yves"},
	{"you", "you"},
	{"zfe", "zves"},
	{"by", "bies"},
	{"ch", "ches"},
	{"cy", "cies"},
	{"dy", "dies"},
	{"ex", "ices"},
	{"fy", "fies"},
	{"gy", "gies"},
	{"hy", "hies"},
	{"io", "ios"},
	{"jy", "jies"},
	{"ky", "kies"},
	{"ld", "ldren"},
	{"lf", "lves"},
	{"ly", "lies"},
	{"my", "mies"},
	{"ny", "nies"},
	{"py", "pies"},
	{"qy", "qies"},
	{"rf", "rves"},
	{"ry", "ries"},
	{"sh", "shes"},
	{"ss", "sses"},
	{"sy", "sies"},
	{"ty", "ties"},
	{"tz", "tzes"},
	{"va", "vae"},
	{"vy", "vies"},
	{"wy", "wies"},
	{"xy", "xies"},
	{"zy", "zies"},
	{"zz", "zzes"},
	{"o", "oes"},
	{"x", "xes"},
}

func init() {
	for _, suffix := range singularToPluralSuffixList {
		AddPlural(suffix.singular, suffix.plural)
		AddSingular(suffix.plural, suffix.singular)
	}
}
<commit_msg>remove redundant rule for alias<commit_after>package flect

var pluralRules = []rule{}

// AddPlural adds a rule that will replace the given suffix with the replacement suffix.
func AddPlural(suffix string, repl string) {
	pluralMoot.Lock()
	defer pluralMoot.Unlock()
	pluralRules = append(pluralRules, rule{
		suffix: suffix,
		fn: func(s string) string {
			s = s[:len(s)-len(suffix)]
			return s + repl
		},
	})

	pluralRules = append(pluralRules, rule{
		suffix: repl,
		fn:     noop,
	})
}

var singleToPlural = map[string]string{
	"aircraft":    "aircraft",
	"alias":       "aliases",
	"alumna":      "alumnae",
	"alumnus":     "alumni",
	"analysis":    "analyses",
	"antenna":     "antennas",
	"antithesis":  "antitheses",
	"apex":        "apexes",
	"appendix":    "appendices",
	"axis":        "axes",
	"bacillus":    "bacilli",
	"bacterium":   "bacteria",
	"basis":       "bases",
	"beau":        "beaus",
	"bison":       "bison",
	"bureau":      "bureaus",
	"bus":         "buses",
	"campus":      "campuses",
	"caucus":      "caucuses",
	"château":     "châteaux",
	"circus":      "circuses",
	"codex":       "codices",
	"concerto":    "concertos",
	"corpus":      "corpora",
	"crisis":      "crises",
	"curriculum":  "curriculums",
	"datum":       "data",
	"deer":        "deer",
	"diagnosis":   "diagnoses",
	"die":         "dice",
	"dwarf":       "dwarves",
	"ellipsis":    "ellipses",
	"equipment":   "equipment",
	"erratum":     "errata",
	"faux pas":    "faux pas",
	"fez":         "fezzes",
	"fish":        "fish",
	"focus":       "foci",
	"foo":         "foos",
	"foot":        "feet",
	"formula":     "formulas",
	"fungus":      "fungi",
	"genus":       "genera",
	"goose":       "geese",
	"graffito":    "graffiti",
	"grouse":      "grouse",
	"half":        "halves",
	"halo":        "halos",
	"hoof":        "hooves",
	"human":       "humans",
	"hypothesis":  "hypotheses",
	"index":       "indices",
	"information": "information",
	"jeans":       "jeans",
	"larva":       "larvae",
	"libretto":    "librettos",
	"loaf":        "loaves",
	"locus":       "loci",
	"louse":       "lice",
	"matrix":      "matrices",
	"minutia":     "minutiae",
	"money":       "money",
	"moose":       "moose",
	"mouse":       "mice",
	"nebula":      "nebulae",
	"news":        "news",
	"nucleus":     "nuclei",
	"oasis":       "oases",
	"octopus":     "octopi",
	"offspring":   "offspring",
	"opus":        "opera",
	"ovum":        "ova",
	"ox":          "oxen",
	"parenthesis": "parentheses",
	"phenomenon":  "phenomena",
	"photo":       "photos",
	"phylum":      "phyla",
	"piano":       "pianos",
	"plus":        "pluses",
	"police":      "police",
	"prognosis":   "prognoses",
	"prometheus":  "prometheuses",
	"quiz":        "quizzes",
	"radius":      "radiuses",
	"referendum":  "referendums",
	"ress":        "resses",
	"rice":        "rice",
	"salmon":      "salmon",
	"series":      "series",
	"sheep":       "sheep",
	"shoe":        "shoes",
	"shrimp":      "shrimp",
	"species":     "species",
	"stimulus":    "stimuli",
	"stratum":     "strata",
	"swine":       "swine",
	"syllabus":    "syllabi",
	"symposium":   "symposiums",
	"synopsis":    "synopses",
	"tableau":     "tableaus",
	"testis":      "testes",
	"thesis":      "theses",
	"thief":       "thieves",
	"tooth":       "teeth",
	"trout":       "trout",
	"tuna":        "tuna",
	"vertebra":    "vertebrae",
	"vertix":      "vertices",
	"vita":        "vitae",
	"vortex":      "vortices",
	"wharf":       "wharves",
	"wife":        "wives",
	"wolf":        "wolves",
	"you":         "you",
}

var pluralToSingle = map[string]string{}

func init() {
	for k, v := range singleToPlural {
		pluralToSingle[v] = k
	}
}

type singularToPluralSuffix struct {
	singular string
	plural   string
}

var singularToPluralSuffixList = []singularToPluralSuffix{
	{"iterion", "iteria"},
	{"campus", "campuses"},
	{"genera", "genus"},
	{"person", "people"},
	{"phylum", "phyla"},
	{"randum", "randa"},
	{"actus", "acti"},
	{"adium", "adia"},
	{"basis", "basis"},
	{"child", "children"},
	{"chive", "chives"},
	{"focus", "foci"},
	{"hello", "hellos"},
	{"jeans", "jeans"},
	{"louse", "lice"},
	{"mouse", "mice"},
	{"movie", "movies"},
	{"oasis", "oasis"},
	{"atum", "ata"},
	{"atus", "atuses"},
	{"base", "bases"},
	{"cess", "cesses"},
	{"dium", "diums"},
	{"eses", "esis"},
	{"half", "halves"},
	{"hive", "hives"},
	{"iano", "ianos"},
	{"irus", "iri"},
	{"isis", "ises"},
	{"leus", "li"},
	{"mnus", "mni"},
	{"move", "moves"},
	{"news", "news"},
	{"odex", "odice"},
	{"oose", "eese"},
	{"ouse", "ouses"},
	{"ovum", "ova"},
	{"rion", "ria"},
	{"shoe", "shoes"},
	{"stis", "stes"},
	{"tive", "tives"},
	{"wife", "wives"},
	{"afe", "aves"},
	{"bfe", "bves"},
	{"box", "boxes"},
	{"cfe", "cves"},
	{"dfe", "dves"},
	{"dge", "dges"},
	{"efe", "eves"},
	{"gfe", "gves"},
	{"hfe", "hves"},
	{"ife", "ives"},
	{"itz", "itzes"},
	{"ium", "ia"},
	{"ize", "izes"},
	{"jfe", "jves"},
	{"kfe", "kves"},
	{"man", "men"},
	{"mfe", "mves"},
	{"nfe", "nves"},
	{"nna", "nnas"},
	{"oaf", "oaves"},
	{"oci", "ocus"},
	{"ode", "odes"},
	{"ofe", "oves"},
	{"oot", "eet"},
	{"pfe", "pves"},
	{"pse", "psis"},
	{"qfe", "qves"},
	{"quy", "quies"},
	{"rfe", "rves"},
	{"sfe", "sves"},
	{"tfe", "tves"},
	{"tum", "ta"},
	{"tus", "tuses"},
	{"ufe", "uves"},
	{"ula", "ulae"},
	{"ula", "ulas"},
	{"uli", "ulus"},
	{"use", "uses"},
	{"uss", "usses"},
	{"vfe", "vves"},
	{"wfe", "wves"},
	{"xfe", "xves"},
	{"yfe", "yves"},
	{"you", "you"},
	{"zfe", "zves"},
	{"by", "bies"},
	{"ch", "ches"},
	{"cy", "cies"},
	{"dy", "dies"},
	{"ex", "ices"},
	{"fy", "fies"},
	{"gy", "gies"},
	{"hy", "hies"},
	{"io", "ios"},
	{"jy", "jies"},
	{"ky", "kies"},
	{"ld", "ldren"},
	{"lf", "lves"},
	{"ly", "lies"},
	{"my", "mies"},
	{"ny", "nies"},
	{"py", "pies"},
	{"qy", "qies"},
	{"rf", "rves"},
	{"ry", "ries"},
	{"sh", "shes"},
	{"ss", "sses"},
	{"sy", "sies"},
	{"ty", "ties"},
	{"tz", "tzes"},
	{"va", "vae"},
	{"vy", "vies"},
	{"wy", "wies"},
	{"xy", "xies"},
	{"zy", "zies"},
	{"zz", "zzes"},
	{"o", "oes"},
	{"x", "xes"},
}

func init() {
	for _, suffix := range singularToPluralSuffixList {
		AddPlural(suffix.singular, suffix.plural)
		AddSingular(suffix.plural, suffix.singular)
	}
}
<|endoftext|>


<commit_before>package promise

import (
	"fmt"
	"reflect"
)

type ParamFuture chan []reflect.Value
type ErrorFuture chan error

type Promise struct {
	pf ParamFuture
	ef ErrorFuture
}

///////////////////////////////////////////////////////////////////////////////////////
// makePromise
///////////////////////////////////////////////////////////////////////////////////////
func makePromise() *Promise {
	pr := &Promise{}
	pr.pf = make(ParamFuture)
	pr.ef = make(ErrorFuture)
	return pr
}

///////////////////////////////////////////////////////////////////////////////////////
// send
///////////////////////////////////////////////////////////////////////////////////////
func (p *Promise) send(out []reflect.Value, err error) {
	p.pf <- out
	p.ef <- err
}

///////////////////////////////////////////////////////////////////////////////////////
// receive
///////////////////////////////////////////////////////////////////////////////////////
func (p *Promise) receive() (out []reflect.Value, err error) {

	outR := false
	errR := false

	for !errR || !outR {
		select {
		case err = <-p.ef:
			errR = true
		case out = <-p.pf:
			outR = true
		}
	}
	return
}

///////////////////////////////////////////////////////////////////////////////////////
// invoke
///////////////////////////////////////////////////////////////////////////////////////
func (p *Promise) invoke(fn interface{}, in []reflect.Value) {
	v := reflect.ValueOf(fn)
	t := v.Type()

	//check arguments count equal
	if len(in) != t.NumIn() {
		// internal error, send the prev output and return internal error.
		p.send(in, fmt.Errorf("Function argument count mismatch."))
		return
	}
	//check arguments types equal
	for idx, inVal := range in {
		if inVal.Type() != t.In(idx) {
			// internal error, send the prev output and return internal error.
			p.send(in, fmt.Errorf("Function argument type mismatch."))
			return
		}
	}

	p.send(v.Call(in), nil)
}

///////////////////////////////////////////////////////////////////////////////////////
// Q
///////////////////////////////////////////////////////////////////////////////////////
func Q(init interface{}) *Promise {
	pr := makePromise()
	t := reflect.TypeOf(init)

	if t.Kind() == reflect.Func {
		go pr.invoke(init, []reflect.Value{})
	}

	return pr
}

///////////////////////////////////////////////////////////////////////////////////////
// Then
///////////////////////////////////////////////////////////////////////////////////////
func (p *Promise) Then(fns ...interface{}) *Promise {
	newP := makePromise()

	go func() {
		// wait on result and error from prev promise
		out, err := p.receive()

		// if we have an internal error, bubble it through, send the prev output and return.
		if err != nil {
			newP.send(out, err)
			return
		}

		// if we have only one Then func, map prev promise outputs to input
		if len(fns) == 1 {
			newP.invoke(fns[0], out)
			return
		}
	}()

	return newP
}

///////////////////////////////////////////////////////////////////////////////////////
// Done
///////////////////////////////////////////////////////////////////////////////////////
func (p *Promise) Done() ([]interface{}, error) {

	out, err := p.receive()
	res := make([]interface{}, len(out))

	for idx, val := range out {
		res[idx] = val.Interface()
	}

	return res, err
}
<commit_msg>introduced deferred<commit_after>package promise

import (
	"fmt"
	"reflect"
)

type PromiseKind uint

type ParamFuture chan []reflect.Value
type ErrorFuture chan error

type Promise struct {
	pf ParamFuture
	ef ErrorFuture
}

type Deferred struct {
	pr Promise
}

///////////////////////////////////////////////////////////////////////////////////////
// makePromise
///////////////////////////////////////////////////////////////////////////////////////
func makePromise() *Promise {
	pr := new(Promise)
	pr.pf = make(ParamFuture)
	pr.ef = make(ErrorFuture)
	return pr
}

///////////////////////////////////////////////////////////////////////////////////////
// send
///////////////////////////////////////////////////////////////////////////////////////
func (p *Promise) send(out []reflect.Value, err error) {
	p.pf <- out
	p.ef <- err
}

///////////////////////////////////////////////////////////////////////////////////////
// receive
///////////////////////////////////////////////////////////////////////////////////////
func (p *Promise) receive() (out []reflect.Value, err error) {

	outR := false
	errR := false

	for !errR || !outR {
		select {
		case err = <-p.ef:
			errR = true
		case out = <-p.pf:
			outR = true
		}
	}
	return
}

///////////////////////////////////////////////////////////////////////////////////////
// invoke
///////////////////////////////////////////////////////////////////////////////////////
func (p *Promise) invoke(fn interface{}, in []reflect.Value) {
	v := reflect.ValueOf(fn)
	t := v.Type()

	//check arguments count equal
	if len(in) != t.NumIn() {
		// internal error, send the prev output and return internal error.
		p.send(in, fmt.Errorf("Function argument count mismatch."))
		return
	}
	//check arguments types equal
	for idx, inVal := range in {
		if inVal.Type() != t.In(idx) {
			// internal error, send the prev output and return internal error.
			p.send(in, fmt.Errorf("Function argument type mismatch."))
			return
		}
	}

	p.send(v.Call(in), nil)
}

///////////////////////////////////////////////////////////////////////////////////////
// Q
///////////////////////////////////////////////////////////////////////////////////////
func Q(init ...interface{}) *Promise {

	pr := makePromise()

	if len(init) == 1 {
		t := reflect.TypeOf(init[0])

		if t.Kind() == reflect.Func {
			//input is init func, invoke it
			go pr.invoke(init[0], []reflect.Value{})
		} else {
			//input is init value, send it directly
			v := reflect.ValueOf(init[0])
			go pr.send([]reflect.Value{v}, nil)
		}
	}

	return pr
}

///////////////////////////////////////////////////////////////////////////////////////
// Defer creates a Deferred datatype. A Deferred can be resolved by value or a promise.
///////////////////////////////////////////////////////////////////////////////////////
func (p *Promise) Defer() *Deferred {
	df := &Deferred{pr: *p}
	return df
}

///////////////////////////////////////////////////////////////////////////////////////
// Resolve |
///////////////////////////////////////////////////////////////////////////////////////
func (d *Deferred) Resolve(val interface{}) {

}

///////////////////////////////////////////////////////////////////////////////////////
// Reject
///////////////////////////////////////////////////////////////////////////////////////
func (d *Deferred) Reject(val interface{}) {

}

///////////////////////////////////////////////////////////////////////////////////////
// Then
///////////////////////////////////////////////////////////////////////////////////////
func (p *Promise) Then(fns ...interface{}) *Promise {
	newP := makePromise()

	go func() {
		// wait on result and error from prev promise
		out, err := p.receive()

		// if we have an internal error, bubble it through, send the prev output and return.
		if err != nil {
			newP.send(out, err)
			return
		}

		// if we have only one Then func, map prev promise outputs to input
		if len(fns) == 1 {
			newP.invoke(fns[0], out)
			return
		}
	}()

	return newP
}

///////////////////////////////////////////////////////////////////////////////////////
// Done
///////////////////////////////////////////////////////////////////////////////////////
func (p *Promise) Done() ([]interface{}, error) {

	out, err := p.receive()
	res := make([]interface{}, len(out))

	for idx, val := range out {
		res[idx] = val.Interface()
	}

	return res, err
}
<|endoftext|>


<commit_before>package juju_test

import (
	"io/ioutil"
	. "launchpad.net/gocheck"
	"launchpad.net/juju-core/environs/dummy"
	"launchpad.net/juju-core/juju"
	"launchpad.net/juju-core/state/testing"
	coretesting "launchpad.net/juju-core/testing"
	"os"
	"path/filepath"
	stdtesting "testing"
)

func Test(t *stdtesting.T) {
	coretesting.ZkTestPackage(t)
}

type ConnSuite struct {
	coretesting.LoggingSuite
	testing.StateSuite
}

var _ = Suite(&ConnSuite{})

func (cs *ConnSuite) SetUpTest(c *C) {
	cs.LoggingSuite.SetUpTest(c)
	cs.StateSuite.SetUpTest(c)
}

func (cs *ConnSuite) TearDownTest(c *C) {
	dummy.Reset()
	cs.StateSuite.TearDownTest(c)
	cs.LoggingSuite.TearDownTest(c)
}

func (*ConnSuite) TestNewConn(c *C) {
	home := c.MkDir()
	defer os.Setenv("HOME", os.Getenv("HOME"))
	os.Setenv("HOME", home)
	conn, err := juju.NewConn("")
	c.Assert(conn, IsNil)
	c.Assert(err, ErrorMatches, ".*: no such file or directory")

	if err := os.Mkdir(filepath.Join(home, ".juju"), 0755); err != nil {
		c.Log("Could not create directory structure")
		c.Fail()
	}
	envs := filepath.Join(home, ".juju", "environments.yaml")
	err = ioutil.WriteFile(envs, []byte(`
default:
    erewhemos
environments:
    erewhemos:
        type: dummy
        zookeeper: true
        authorized-keys: i-am-a-key
`), 0644)
	if err != nil {
		c.Log("Could not create environments.yaml")
		c.Fail()
	}

	// Just run through a few operations on the dummy provider and verify that
	// they behave as expected.
	conn, err = juju.NewConn("")
	c.Assert(err, IsNil)
	defer conn.Close()
	st, err := conn.State()
	c.Assert(st, IsNil)
	c.Assert(err, ErrorMatches, "dummy environment not bootstrapped")
	err = conn.Bootstrap(false)
	c.Assert(err, IsNil)
	st, err = conn.State()
	c.Check(err, IsNil)
	c.Check(st, NotNil)
	err = conn.Destroy()
	c.Assert(err, IsNil)

	// Close the conn (thereby closing its state) a couple of times to
	// verify that multiple closes are safe.
	c.Assert(conn.Close(), IsNil)
	c.Assert(conn.Close(), IsNil)
}

func (*ConnSuite) TestNewConnFromAttrs(c *C) {
	attrs := map[string]interface{}{
		"name":            "erewhemos",
		"type":            "dummy",
		"zookeeper":       true,
		"authorized-keys": "i-am-a-key",
	}
	conn, err := juju.NewConnFromAttrs(attrs)
	c.Assert(err, IsNil)
	defer conn.Close()
	st, err := conn.State()
	c.Assert(st, IsNil)
	c.Assert(err, ErrorMatches, "dummy environment not bootstrapped")
}

func (cs *ConnSuite) TestConnStateSecretsSideEffect(c *C) {
	env, err := cs.State.EnvironConfig()
	c.Assert(err, IsNil)
	// verify we have no secret in the environ config
	_, ok := env.Get("secret")
	c.Assert(ok, Equals, false)
	attrs := map[string]interface{}{
		"name":            "erewhemos",
		"type":            "dummy",
		"zookeeper":       true,
		"authorized-keys": "i-am-a-key",
	}
	conn, err := juju.NewConnFromAttrs(attrs)
	c.Assert(err, IsNil)
	defer conn.Close()
	err = conn.Bootstrap(false)
	c.Assert(err, IsNil)
	// fetch a state connection via the conn, which will
	// push the secrets.
	_, err = conn.State()
	c.Assert(err, IsNil)
	err = env.Read()
	c.Assert(err, IsNil)
	// check that the secret has been populated
	secret, ok := env.Get("secret")
	c.Assert(ok, Equals, true)
	c.Assert(secret, Equals, "pork")
}

func (*ConnSuite) TestValidRegexps(c *C) {
	assertService := func(s string, expect bool) {
		c.Assert(juju.ValidService.MatchString(s), Equals, expect)
		c.Assert(juju.ValidUnit.MatchString(s+"/0"), Equals, expect)
		c.Assert(juju.ValidUnit.MatchString(s+"/99"), Equals, expect)
		c.Assert(juju.ValidUnit.MatchString(s+"/-1"), Equals, false)
		c.Assert(juju.ValidUnit.MatchString(s+"/blah"), Equals, false)
	}
	assertService("", false)
	assertService("33", false)
	assertService("wordpress", true)
	assertService("w0rd-pre55", true)
	assertService("foo2", true)
	assertService("foo-2", false)
	assertService("foo-2foo", true)
}
<commit_msg>juju: avoid use of StateSuite or JujuConnSuite<commit_after>package juju_test

import (
	"io/ioutil"
	. "launchpad.net/gocheck"
	"launchpad.net/juju-core/environs/dummy"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/juju"
	coretesting "launchpad.net/juju-core/testing"
	"os"
	"path/filepath"
	stdtesting "testing"
)

func Test(t *stdtesting.T) {
	coretesting.ZkTestPackage(t)
}

type ConnSuite struct {
	coretesting.LoggingSuite
}

var _ = Suite(&ConnSuite{})

func (cs *ConnSuite) SetUpTest(c *C) {
	cs.LoggingSuite.SetUpTest(c)
}

func (cs *ConnSuite) TearDownTest(c *C) {
	dummy.Reset()
	cs.LoggingSuite.TearDownTest(c)
}

func (*ConnSuite) TestNewConn(c *C) {
	home := c.MkDir()
	defer os.Setenv("HOME", os.Getenv("HOME"))
	os.Setenv("HOME", home)
	conn, err := juju.NewConn("")
	c.Assert(conn, IsNil)
	c.Assert(err, ErrorMatches, ".*: no such file or directory")

	if err := os.Mkdir(filepath.Join(home, ".juju"), 0755); err != nil {
		c.Log("Could not create directory structure")
		c.Fail()
	}
	envs := filepath.Join(home, ".juju", "environments.yaml")
	err = ioutil.WriteFile(envs, []byte(`
default:
    erewhemos
environments:
    erewhemos:
        type: dummy
        zookeeper: true
        authorized-keys: i-am-a-key
`), 0644)
	if err != nil {
		c.Log("Could not create environments.yaml")
		c.Fail()
	}

	// Just run through a few operations on the dummy provider and verify that
	// they behave as expected.
	conn, err = juju.NewConn("")
	c.Assert(err, IsNil)
	defer conn.Close()
	st, err := conn.State()
	c.Assert(st, IsNil)
	c.Assert(err, ErrorMatches, "dummy environment not bootstrapped")
	err = conn.Bootstrap(false)
	c.Assert(err, IsNil)
	st, err = conn.State()
	c.Check(err, IsNil)
	c.Check(st, NotNil)
	err = conn.Destroy()
	c.Assert(err, IsNil)

	// Close the conn (thereby closing its state) a couple of times to
	// verify that multiple closes are safe.
	c.Assert(conn.Close(), IsNil)
	c.Assert(conn.Close(), IsNil)
}

func (*ConnSuite) TestNewConnFromAttrs(c *C) {
	attrs := map[string]interface{}{
		"name":            "erewhemos",
		"type":            "dummy",
		"zookeeper":       true,
		"authorized-keys": "i-am-a-key",
	}
	conn, err := juju.NewConnFromAttrs(attrs)
	c.Assert(err, IsNil)
	defer conn.Close()
	st, err := conn.State()
	c.Assert(st, IsNil)
	c.Assert(err, ErrorMatches, "dummy environment not bootstrapped")
}

func (cs *ConnSuite) TestConnStateSecretsSideEffect(c *C) {
	env, err := environs.NewFromAttrs(map[string]interface{}{
		"name":            "erewhemos",
		"type":            "dummy",
		"zookeeper":       true,
		"authorized-keys": "i-am-a-key",
	})
	c.Assert(err, IsNil)
	err = env.Bootstrap(false)
	c.Assert(err, IsNil)
	info, err := env.StateInfo()
	c.Assert(err, IsNil)
	st, err := state.Open(info)
	c.Assert(err, IsNil)

	// verify we have no secret in the environ config
	cfg, err := st.EnvironConfig()
	c.Assert(err, IsNil)
	_, ok := cfg.Get("secret")
	c.Assert(ok, Equals, false)
	conn, err := juju.NewConnFromAttrs(map[string]interface{}{
		"name":            "erewhemos",
		"type":            "dummy",
		"zookeeper":       true,
		"authorized-keys": "i-am-a-key",
	})
	c.Assert(err, IsNil)
	defer conn.Close()
	// fetch a state connection via the conn, which will
	// push the secrets.
	_, err = conn.State()
	c.Assert(err, IsNil)
	err = cfg.Read()
	c.Assert(err, IsNil)
	// check that the secret has been populated
	secret, ok := cfg.Get("secret")
	c.Assert(ok, Equals, true)
	c.Assert(secret, Equals, "pork")
}

func (*ConnSuite) TestValidRegexps(c *C) {
	assertService := func(s string, expect bool) {
		c.Assert(juju.ValidService.MatchString(s), Equals, expect)
		c.Assert(juju.ValidUnit.MatchString(s+"/0"), Equals, expect)
		c.Assert(juju.ValidUnit.MatchString(s+"/99"), Equals, expect)
		c.Assert(juju.ValidUnit.MatchString(s+"/-1"), Equals, false)
		c.Assert(juju.ValidUnit.MatchString(s+"/blah"), Equals, false)
	}
	assertService("", false)
	assertService("33", false)
	assertService("wordpress", true)
	assertService("w0rd-pre55", true)
	assertService("foo2", true)
	assertService("foo-2", false)
	assertService("foo-2foo", true)
}
<|endoftext|>