<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"sort"
	"strings"
	"syscall"

	"github.com/dickeyxxx/golock"
)

func init() {
	Topics = append(Topics, &Topic{
		Name:        "plugins",
		Description: "manage plugins",
		Commands: CommandSet{
			{
				Topic:            "plugins",
				Hidden:           true,
				Description:      "Lists installed plugins",
				DisableAnalytics: true,
				Flags: []Flag{
					{Name: "core", Description: "show core plugins"},
				},
				Help: `
Example:
  $ heroku plugins`,

				Run: pluginsList,
			},
			{
				Topic:        "plugins",
				Command:      "install",
				Hidden:       true,
				VariableArgs: true,
				Description:  "Installs a plugin into the CLI",
				Help: `Install a Heroku plugin

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

				Run: pluginsInstall,
			},
			{
				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 the plugins directory
	and parses the plugin.

	You will need to run it again if you change any of the plugin metadata.

  Example:
	$ heroku plugins:link .`,

				Run: pluginsLink,
			},
			{
				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: pluginsUninstall,
			},
		},
	})
}

func pluginsList(ctx *Context) {
	var names []string
	for _, plugin := range userPlugins.Plugins() {
		symlinked := ""
		if userPlugins.isPluginSymlinked(plugin.Name) {
			symlinked = " (symlinked)"
		}
		names = append(names, fmt.Sprintf("%s %s%s", plugin.Name, plugin.Version, symlinked))
	}
	if ctx.Flags["core"] != nil {
		userPluginNames := userPlugins.PluginNames()
		for _, plugin := range corePlugins.Plugins() {
			if contains(userPluginNames, plugin.Name) {
				continue
			}
			names = append(names, fmt.Sprintf("%s %s (core)", plugin.Name, plugin.Version))
		}
	}
	sort.Strings(names)
	for _, plugin := range names {
		Println(plugin)
	}
}
func pluginsInstall(ctx *Context) {
	plugins := ctx.Args.([]string)
	if len(plugins) == 0 {
		ExitWithMessage("Must specify a plugin name.\nUSAGE: heroku plugins:install heroku-debug")
	}
	toinstall := make([]string, 0, len(plugins))
	core := corePlugins.PluginNames()
	for _, plugin := range plugins {
		if contains(core, strings.Split(plugin, "@")[0]) {
			Warn("Not installing " + plugin + " because it is already installed as a core plugin.")
			continue
		}
		toinstall = append(toinstall, plugin)
	}
	if len(toinstall) == 0 {
		Exit(1)
	}
	action("Installing "+plural("plugin", len(toinstall))+" "+strings.Join(toinstall, " "), "done", func() {
		err := userPlugins.InstallPlugins(toinstall...)
		if err != nil {
			if strings.Contains(err.Error(), "no such package available") {
				ExitWithMessage("Plugin not found")
			}
			must(err)
		}
	})
}

func pluginsLink(ctx *Context) {
	pluginInstallRetry = false
	path := ctx.Args.(map[string]string)["path"]
	if path == "" {
		path = "."
	}
	path, err := filepath.Abs(path)
	must(err)
	_, err = os.Stat(path)
	must(err)
	name := filepath.Base(path)
	action("Symlinking "+name, "done", func() {
		newPath := userPlugins.pluginPath(name)
		os.Remove(newPath)
		os.RemoveAll(newPath)
		os.MkdirAll(filepath.Dir(newPath), 0755)
		err = os.Symlink(path, newPath)
		must(err)
		plugin, err := userPlugins.ParsePlugin(name)
		must(err)
		if name != plugin.Name {
			path = newPath
			newPath = userPlugins.pluginPath(plugin.Name)
			os.Remove(newPath)
			os.RemoveAll(newPath)
			os.Rename(path, newPath)
		}
		userPlugins.addToCache(plugin)
	})
}

func pluginsUninstall(ctx *Context) {
	name := ctx.Args.(map[string]string)["name"]
	if !contains(userPlugins.PluginNames(), name) {
		must(errors.New(name + " is not installed"))
	}
	Errf("Uninstalling plugin %s...", name)
	must(userPlugins.RemovePackages(name))
	userPlugins.removeFromCache(name)
	Errln(" done")
}

// Plugins represents either core or user plugins
type Plugins struct {
	Path    string
	plugins []*Plugin
}

var corePlugins = &Plugins{Path: filepath.Join(AppDir, "lib")}
var userPlugins = &Plugins{Path: filepath.Join(DataHome, "plugins")}

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

// Commands lists all the commands of the plugins
func (p *Plugins) Commands() (commands CommandSet) {
	for _, plugin := range p.Plugins() {
		for _, command := range plugin.Commands {
			command.Run = p.runFn(plugin, command.Topic, command.Command)
			commands = append(commands, command)
		}
	}
	return
}

// Topics gets all the plugin's topics
func (p *Plugins) Topics() (topics TopicSet) {
	for _, plugin := range p.Plugins() {
		if plugin.Topic != nil {
			topics = append(topics, plugin.Topic)
		}
		topics = append(topics, plugin.Topics...)
	}
	return
}

func (p *Plugins) runFn(plugin *Plugin, topic, command string) func(ctx *Context) {
	return func(ctx *Context) {
		p.readLockPlugin(plugin.Name)
		ctx.Dev = p.isPluginSymlinked(plugin.Name)
		ctxJSON, err := json.Marshal(ctx)
		must(err)
		title, _ := json.Marshal("heroku " + strings.Join(os.Args[1:], " "))

		script := fmt.Sprintf(`'use strict'
let pluginName = '%s'
let pluginVersion = '%s'
let topic = '%s'
let command = '%s'
process.title = %s
let ctx = %s
ctx.version = ctx.version + ' ' + pluginName + '/' + pluginVersion + ' node-' + process.version
process.chdir(ctx.cwd)
if (command === '') { command = null }
let plugin = require(pluginName)
let cmd = plugin.commands.filter((c) => c.topic === topic && c.command == command)[0]
cmd.run(ctx)
`, plugin.Name, plugin.Version, topic, command, string(title), ctxJSON)

		// swallow sigint since the plugin will handle it
		swallowSigint = true

		currentAnalyticsCommand.Plugin = plugin.Name
		currentAnalyticsCommand.Version = plugin.Version
		currentAnalyticsCommand.Language = fmt.Sprintf("node/" + NodeVersion)

		cmd, done := p.RunScript(script)
		cmd.Stdin = os.Stdin
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		err = cmd.Run()
		done()
		Exit(getExitCode(err))
	}
}

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

var pluginInstallRetry = true

// ParsePlugin requires the plugin's node module
// to get the commands and metadata
func (p *Plugins) ParsePlugin(name string) (*Plugin, error) {
	script := `
	var plugin = require('` + name + `');
	var pjson  = require('` + name + `/package.json');

	plugin.name    = pjson.name;
	plugin.version = pjson.version;

	console.log(JSON.stringify(plugin))`
	cmd, done := p.RunScript(script)
	cmd.Stderr = Stderr
	output, err := cmd.Output()
	done()

	if err != nil {
		// try again but this time grab stdout and stderr
		cmd, done := p.RunScript(script)
		output, err = cmd.CombinedOutput() // sometimes this actually works the second time
		if err != nil {
			done()
			if pluginInstallRetry && strings.Contains(string(output), "Error: Cannot find module") {
				pluginInstallRetry = false
				Warn("Failed to install " + name + ". Retrying...")
				WarnIfError(p.RemovePackages(name))
				WarnIfError(p.ClearCache())
				if err := p.installPackages(name); err != nil {
					return nil, err
				}
				return p.ParsePlugin(name)
			}
			return nil, fmt.Errorf("Error reading plugin: %s\n%s\n%s", name, err, output)
		}
	}
	var plugin Plugin
	err = json.Unmarshal(output, &plugin)
	if err != nil {
		return nil, fmt.Errorf("Error parsing plugin: %s\n%s\n%s", name, err, string(output))
	}
	if len(plugin.Commands) == 0 {
		return nil, fmt.Errorf("Invalid plugin. No commands found.")
	}
	for _, command := range plugin.Commands {
		if command == nil {
			continue
		}
		command.Plugin = plugin.Name
		command.Help = strings.TrimSpace(command.Help)
	}
	return &plugin, nil
}

// PluginNames lists all the plugin names
func (p *Plugins) PluginNames() []string {
	plugins := p.Plugins()
	names := make([]string, 0, len(plugins))
	for _, plugin := range plugins {
		names = append(names, plugin.Name)
	}
	return names
}

// PluginNamesNotSymlinked lists all the plugin names that are not symlinked
func (p *Plugins) PluginNamesNotSymlinked() []string {
	plugins := p.PluginNames()
	names := make([]string, 0, len(plugins))
	for _, plugin := range plugins {
		if !p.isPluginSymlinked(plugin) {
			names = append(names, plugin)
		}
	}
	return names
}

func (p *Plugins) isPluginSymlinked(plugin string) bool {
	path := filepath.Join(p.modulesPath(), plugin)
	fi, err := os.Lstat(path)
	if err != nil {
		return false
	}
	return fi.Mode()&os.ModeSymlink != 0
}

func contains(arr []string, s string) bool {
	for _, a := range arr {
		if a == s {
			return true
		}
	}
	return false
}

// InstallPlugins installs plugins
func (p *Plugins) InstallPlugins(names ...string) error {
	for _, name := range names {
		p.lockPlugin(name)
	}
	defer func() {
		for _, name := range names {
			p.unlockPlugin(name)
		}
	}()
	err := p.installPackages(names...)
	if err != nil {
		return err
	}
	plugins := make([]*Plugin, len(names))
	for i, name := range names {
		plugin, err := p.ParsePlugin(name)
		if err != nil {
			return err
		}
		plugins[i] = plugin
	}
	p.addToCache(plugins...)
	return nil
}

// directory location of plugin
func (p *Plugins) pluginPath(plugin string) string {
	return filepath.Join(p.Path, "node_modules", plugin)
}

// name of lockfile
func (p *Plugins) lockfile(name string) string {
	return filepath.Join(p.Path, name+".updating")
}

// lock a plugin for reading
func (p *Plugins) readLockPlugin(name string) {
	locked, err := golock.IsLocked(p.lockfile(name))
	LogIfError(err)
	if locked {
		p.lockPlugin(name)
		p.unlockPlugin(name)
	}
}

// lock a plugin for writing
func (p *Plugins) lockPlugin(name string) {
	LogIfError(golock.Lock(p.lockfile(name)))
}

// unlock a plugin
func (p *Plugins) unlockPlugin(name string) {
	LogIfError(golock.Unlock(p.lockfile(name)))
}

// Update updates the plugins
func (p *Plugins) Update() {
	plugins := p.PluginNamesNotSymlinked()
	if len(plugins) == 0 {
		return
	}
	packages, err := p.OutdatedPackages(plugins...)
	WarnIfError(err)
	if len(packages) > 0 {
		action("heroku-cli: Updating plugins", "", func() {
			for name, version := range packages {
				p.lockPlugin(name)
				WarnIfError(p.installPackages(name + "@" + version))
				plugin, err := p.ParsePlugin(name)
				WarnIfError(err)
				p.addToCache(plugin)
				p.unlockPlugin(name)
			}
		})
		Errf(" done. Updated %d %s.\n", len(packages), plural("package", len(packages)))
	}
}

func (p *Plugins) addToCache(plugins ...*Plugin) {
	contains := func(name string) int {
		for i, plugin := range p.plugins {
			if plugin.Name == name {
				return i
			}
		}
		return -1
	}
	for _, plugin := range plugins {
		// find or replace
		i := contains(plugin.Name)
		if i == -1 {
			p.plugins = append(p.plugins, plugin)
		} else {
			p.plugins[i] = plugin
		}
	}
	p.saveCache()
}

func (p *Plugins) removeFromCache(name string) {
	for i, plugin := range p.plugins {
		if plugin.Name == name {
			p.plugins = append(p.plugins[:i], p.plugins[i+1:]...)
		}
	}
	p.saveCache()
}

func (p *Plugins) saveCache() {
	if err := saveJSON(p.plugins, p.cachePath()); err != nil {
		must(err)
	}
}

// Plugins reads the cache file into the struct
func (p *Plugins) Plugins() []*Plugin {
	if p.plugins == nil {
		p.plugins = []*Plugin{}
		if exists, _ := fileExists(p.cachePath()); !exists {
			return p.plugins
		}
		f, err := os.Open(p.cachePath())
		if err != nil {
			LogIfError(err)
			return p.plugins
		}
		err = json.NewDecoder(f).Decode(&p.plugins)
		WarnIfError(err)
	}
	return p.plugins
}

func (p *Plugins) cachePath() string {
	return filepath.Join(p.Path, "plugins.json")
}
<commit_msg>take out retry logic<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"sort"
	"strings"
	"syscall"

	"github.com/ansel1/merry"
	"github.com/dickeyxxx/golock"
)

func init() {
	Topics = append(Topics, &Topic{
		Name:        "plugins",
		Description: "manage plugins",
		Commands: CommandSet{
			{
				Topic:            "plugins",
				Hidden:           true,
				Description:      "Lists installed plugins",
				DisableAnalytics: true,
				Flags: []Flag{
					{Name: "core", Description: "show core plugins"},
				},
				Help: `
Example:
  $ heroku plugins`,

				Run: pluginsList,
			},
			{
				Topic:        "plugins",
				Command:      "install",
				Hidden:       true,
				VariableArgs: true,
				Description:  "Installs a plugin into the CLI",
				Help: `Install a Heroku plugin

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

				Run: pluginsInstall,
			},
			{
				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 the plugins directory
	and parses the plugin.

	You will need to run it again if you change any of the plugin metadata.

  Example:
	$ heroku plugins:link .`,

				Run: pluginsLink,
			},
			{
				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: pluginsUninstall,
			},
		},
	})
}

func pluginsList(ctx *Context) {
	var names []string
	for _, plugin := range userPlugins.Plugins() {
		symlinked := ""
		if userPlugins.isPluginSymlinked(plugin.Name) {
			symlinked = " (symlinked)"
		}
		names = append(names, fmt.Sprintf("%s %s%s", plugin.Name, plugin.Version, symlinked))
	}
	if ctx.Flags["core"] != nil {
		userPluginNames := userPlugins.PluginNames()
		for _, plugin := range corePlugins.Plugins() {
			if contains(userPluginNames, plugin.Name) {
				continue
			}
			names = append(names, fmt.Sprintf("%s %s (core)", plugin.Name, plugin.Version))
		}
	}
	sort.Strings(names)
	for _, plugin := range names {
		Println(plugin)
	}
}
func pluginsInstall(ctx *Context) {
	plugins := ctx.Args.([]string)
	if len(plugins) == 0 {
		ExitWithMessage("Must specify a plugin name.\nUSAGE: heroku plugins:install heroku-debug")
	}
	toinstall := make([]string, 0, len(plugins))
	core := corePlugins.PluginNames()
	for _, plugin := range plugins {
		if contains(core, strings.Split(plugin, "@")[0]) {
			Warn("Not installing " + plugin + " because it is already installed as a core plugin.")
			continue
		}
		toinstall = append(toinstall, plugin)
	}
	if len(toinstall) == 0 {
		Exit(1)
	}
	action("Installing "+plural("plugin", len(toinstall))+" "+strings.Join(toinstall, " "), "done", func() {
		err := userPlugins.InstallPlugins(toinstall...)
		if err != nil {
			if strings.Contains(err.Error(), "no such package available") {
				ExitWithMessage("Plugin not found")
			}
			must(err)
		}
	})
}

func pluginsLink(ctx *Context) {
	path := ctx.Args.(map[string]string)["path"]
	if path == "" {
		path = "."
	}
	path, err := filepath.Abs(path)
	must(err)
	_, err = os.Stat(path)
	must(err)
	name := filepath.Base(path)
	action("Symlinking "+name, "done", func() {
		newPath := userPlugins.pluginPath(name)
		os.Remove(newPath)
		os.RemoveAll(newPath)
		os.MkdirAll(filepath.Dir(newPath), 0755)
		err = os.Symlink(path, newPath)
		must(err)
		plugin, err := userPlugins.ParsePlugin(name)
		must(err)
		if name != plugin.Name {
			path = newPath
			newPath = userPlugins.pluginPath(plugin.Name)
			os.Remove(newPath)
			os.RemoveAll(newPath)
			os.Rename(path, newPath)
		}
		userPlugins.addToCache(plugin)
	})
}

func pluginsUninstall(ctx *Context) {
	name := ctx.Args.(map[string]string)["name"]
	if !contains(userPlugins.PluginNames(), name) {
		must(errors.New(name + " is not installed"))
	}
	Errf("Uninstalling plugin %s...", name)
	must(userPlugins.RemovePackages(name))
	userPlugins.removeFromCache(name)
	Errln(" done")
}

// Plugins represents either core or user plugins
type Plugins struct {
	Path    string
	plugins []*Plugin
}

var corePlugins = &Plugins{Path: filepath.Join(AppDir, "lib")}
var userPlugins = &Plugins{Path: filepath.Join(DataHome, "plugins")}

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

// Commands lists all the commands of the plugins
func (p *Plugins) Commands() (commands CommandSet) {
	for _, plugin := range p.Plugins() {
		for _, command := range plugin.Commands {
			command.Run = p.runFn(plugin, command.Topic, command.Command)
			commands = append(commands, command)
		}
	}
	return
}

// Topics gets all the plugin's topics
func (p *Plugins) Topics() (topics TopicSet) {
	for _, plugin := range p.Plugins() {
		if plugin.Topic != nil {
			topics = append(topics, plugin.Topic)
		}
		topics = append(topics, plugin.Topics...)
	}
	return
}

func (p *Plugins) runFn(plugin *Plugin, topic, command string) func(ctx *Context) {
	return func(ctx *Context) {
		p.readLockPlugin(plugin.Name)
		ctx.Dev = p.isPluginSymlinked(plugin.Name)
		ctxJSON, err := json.Marshal(ctx)
		must(err)
		title, _ := json.Marshal("heroku " + strings.Join(os.Args[1:], " "))

		script := fmt.Sprintf(`'use strict'
let pluginName = '%s'
let pluginVersion = '%s'
let topic = '%s'
let command = '%s'
process.title = %s
let ctx = %s
ctx.version = ctx.version + ' ' + pluginName + '/' + pluginVersion + ' node-' + process.version
process.chdir(ctx.cwd)
if (command === '') { command = null }
let plugin = require(pluginName)
let cmd = plugin.commands.filter((c) => c.topic === topic && c.command == command)[0]
cmd.run(ctx)
`, plugin.Name, plugin.Version, topic, command, string(title), ctxJSON)

		// swallow sigint since the plugin will handle it
		swallowSigint = true

		currentAnalyticsCommand.Plugin = plugin.Name
		currentAnalyticsCommand.Version = plugin.Version
		currentAnalyticsCommand.Language = fmt.Sprintf("node/" + NodeVersion)

		cmd, done := p.RunScript(script)
		cmd.Stdin = os.Stdin
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		err = cmd.Run()
		done()
		Exit(getExitCode(err))
	}
}

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

// ParsePlugin requires the plugin's node module
// to get the commands and metadata
func (p *Plugins) ParsePlugin(name string) (*Plugin, error) {
	script := `
	var plugin = require('` + name + `');
	var pjson  = require('` + name + `/package.json');

	plugin.name    = pjson.name;
	plugin.version = pjson.version;

	console.log(JSON.stringify(plugin))`
	cmd, done := p.RunScript(script)
	cmd.Stderr = Stderr
	output, err := cmd.Output()
	done()

	if err != nil {
		return nil, merry.Errorf("Error installing plugin %s", name)
	}
	var plugin Plugin
	err = json.Unmarshal(output, &plugin)
	if err != nil {
		return nil, fmt.Errorf("Error parsing plugin: %s\n%s\n%s", name, err, string(output))
	}
	if len(plugin.Commands) == 0 {
		return nil, fmt.Errorf("Invalid plugin. No commands found.")
	}
	for _, command := range plugin.Commands {
		if command == nil {
			continue
		}
		command.Plugin = plugin.Name
		command.Help = strings.TrimSpace(command.Help)
	}
	return &plugin, nil
}

// PluginNames lists all the plugin names
func (p *Plugins) PluginNames() []string {
	plugins := p.Plugins()
	names := make([]string, 0, len(plugins))
	for _, plugin := range plugins {
		names = append(names, plugin.Name)
	}
	return names
}

// PluginNamesNotSymlinked lists all the plugin names that are not symlinked
func (p *Plugins) PluginNamesNotSymlinked() []string {
	plugins := p.PluginNames()
	names := make([]string, 0, len(plugins))
	for _, plugin := range plugins {
		if !p.isPluginSymlinked(plugin) {
			names = append(names, plugin)
		}
	}
	return names
}

func (p *Plugins) isPluginSymlinked(plugin string) bool {
	path := filepath.Join(p.modulesPath(), plugin)
	fi, err := os.Lstat(path)
	if err != nil {
		return false
	}
	return fi.Mode()&os.ModeSymlink != 0
}

func contains(arr []string, s string) bool {
	for _, a := range arr {
		if a == s {
			return true
		}
	}
	return false
}

// InstallPlugins installs plugins
func (p *Plugins) InstallPlugins(names ...string) error {
	for _, name := range names {
		p.lockPlugin(name)
	}
	defer func() {
		for _, name := range names {
			p.unlockPlugin(name)
		}
	}()
	err := p.installPackages(names...)
	if err != nil {
		return err
	}
	plugins := make([]*Plugin, len(names))
	for i, name := range names {
		plugin, err := p.ParsePlugin(name)
		if err != nil {
			return err
		}
		plugins[i] = plugin
	}
	p.addToCache(plugins...)
	return nil
}

// directory location of plugin
func (p *Plugins) pluginPath(plugin string) string {
	return filepath.Join(p.Path, "node_modules", plugin)
}

// name of lockfile
func (p *Plugins) lockfile(name string) string {
	return filepath.Join(p.Path, name+".updating")
}

// lock a plugin for reading
func (p *Plugins) readLockPlugin(name string) {
	locked, err := golock.IsLocked(p.lockfile(name))
	LogIfError(err)
	if locked {
		p.lockPlugin(name)
		p.unlockPlugin(name)
	}
}

// lock a plugin for writing
func (p *Plugins) lockPlugin(name string) {
	LogIfError(golock.Lock(p.lockfile(name)))
}

// unlock a plugin
func (p *Plugins) unlockPlugin(name string) {
	LogIfError(golock.Unlock(p.lockfile(name)))
}

// Update updates the plugins
func (p *Plugins) Update() {
	plugins := p.PluginNamesNotSymlinked()
	if len(plugins) == 0 {
		return
	}
	packages, err := p.OutdatedPackages(plugins...)
	WarnIfError(err)
	if len(packages) > 0 {
		action("heroku-cli: Updating plugins", "", func() {
			for name, version := range packages {
				p.lockPlugin(name)
				WarnIfError(p.installPackages(name + "@" + version))
				plugin, err := p.ParsePlugin(name)
				WarnIfError(err)
				p.addToCache(plugin)
				p.unlockPlugin(name)
			}
		})
		Errf(" done. Updated %d %s.\n", len(packages), plural("package", len(packages)))
	}
}

func (p *Plugins) addToCache(plugins ...*Plugin) {
	contains := func(name string) int {
		for i, plugin := range p.plugins {
			if plugin.Name == name {
				return i
			}
		}
		return -1
	}
	for _, plugin := range plugins {
		// find or replace
		i := contains(plugin.Name)
		if i == -1 {
			p.plugins = append(p.plugins, plugin)
		} else {
			p.plugins[i] = plugin
		}
	}
	p.saveCache()
}

func (p *Plugins) removeFromCache(name string) {
	for i, plugin := range p.plugins {
		if plugin.Name == name {
			p.plugins = append(p.plugins[:i], p.plugins[i+1:]...)
		}
	}
	p.saveCache()
}

func (p *Plugins) saveCache() {
	if err := saveJSON(p.plugins, p.cachePath()); err != nil {
		must(err)
	}
}

// Plugins reads the cache file into the struct
func (p *Plugins) Plugins() []*Plugin {
	if p.plugins == nil {
		p.plugins = []*Plugin{}
		if exists, _ := fileExists(p.cachePath()); !exists {
			return p.plugins
		}
		f, err := os.Open(p.cachePath())
		if err != nil {
			LogIfError(err)
			return p.plugins
		}
		err = json.NewDecoder(f).Decode(&p.plugins)
		WarnIfError(err)
	}
	return p.plugins
}

func (p *Plugins) cachePath() string {
	return filepath.Join(p.Path, "plugins.json")
}
<|endoftext|>


<commit_before>package main

import (
    "net/http"
    "fmt"
    "io/ioutil"
    "os"
    "os/exec"
    "log"
//    "time"
    "path/filepath"
    "io"
    "archive/zip"
    "container/list"
    "strings"
)

type Unzip struct {
    zipfile string
    prefix string
    artifacts *list.List
}

type ZipArtifact struct {
  name string
  path string
  file *zip.File
}

func (u *Unzip) PrintListing() error {
    file_handler := func (meta *ZipMeta) error {
        log.Println(meta.current_file.path + meta.current_file.name)
        return nil
    }

    folder_handler := func(meta *ZipMeta) error {
        return nil
    }
    meta := ZipMeta { file_handler, folder_handler, make(map[string]bool), "", nil, nil} //list.New(), 1,true}
    if err := meta.walk(u.zipfile); err != nil {
        return err
    } else {
        u.artifacts = meta.artifacts
    }
    return nil
}

func (u *Unzip) GenerateListing() error {
    file_handler := func (meta *ZipMeta) error {
        if meta.artifacts == nil {
            meta.artifacts = list.New()
        }
        meta.artifacts.PushBack(meta.current_file)
        return nil
    }

    folder_handler := func(meta *ZipMeta) error {
        return nil
    }
    meta := ZipMeta { file_handler, folder_handler, make(map[string]bool), "", nil, nil}
    if err := meta.walk(u.zipfile); err != nil {
        return err
    } else {
        u.artifacts = meta.artifacts
    }
    return nil
}

func (u *Unzip) Expand() error {
    file_handler := func (meta *ZipMeta) error {

        if meta.artifacts == nil {
            meta.artifacts = list.New()
        }
        zipfile := meta.current_file.file
        meta.artifacts.PushBack(meta.current_file)

        var (
            err error
            file *os.File
            rc io.ReadCloser
        )
        if rc, err = zipfile.Open(); err != nil {
            return err
        }

        if file, err = os.Create(zipfile.Name); err != nil {
            return err
        }

        if _, err = io.Copy(file, rc); err != nil {
            return err
        }

        if err = file.Chmod(zipfile.Mode().Perm()); err != nil {
            //log.Println(err) // Windows WTF?
        }
        file.Close()
        rc.Close()
        return nil
    }

    folder_handler := func(meta *ZipMeta) error {
        return os.MkdirAll(meta.last_folder, 0755)
    }
    meta := ZipMeta {file_handler, folder_handler, make(map[string]bool), "", nil, nil}
    if err := meta.walk(u.zipfile); err != nil {
        return err
    } else {
        u.artifacts = meta.artifacts
    }
    return nil
}

type ZipMeta struct {
    file_handler func(*ZipMeta) error
    folder_handler func(*ZipMeta) error
    folders map[string]bool
    last_folder string
    current_file *ZipArtifact
    artifacts *list.List
}

func (w *ZipMeta) isNewFolder(folder_name string) bool {
    _, found := w.folders[folder_name]
    return !found
}

func (w *ZipMeta) handleFile(path string, file_name string, file *zip.File) error {
    w.current_file = &ZipArtifact{file_name, path, file}
    return w.file_handler(w)
}

func (w *ZipMeta) handleFolder(folder_name string) error {
    w.folders[folder_name] = true
    w.last_folder = folder_name
    return w.folder_handler(w)
}

func (w *ZipMeta) walk(zipfile string) error {
    var err error
    var r *zip.ReadCloser
    if r, err = zip.OpenReader(zipfile); err != nil {
      log.Fatalln(err)
      return err
    }

    for _, f := range r.File {

      if f.Mode().IsDir() {
        w.handleFolder(f.Name)
        continue
      }

      file_name := f.Name
      folder_name := ""
      folder_index := strings.LastIndex(f.Name, "/")
      if folder_index != -1 {
        folder_name += file_name[:folder_index] // 4.4.17
        if w.isNewFolder(folder_name) {
            if err = w.handleFolder(folder_name); err != nil {
                return err
            }
        }
        file_name = file_name[folder_index+1:] // strings.Join(dirlist[:len(dirlist)-1]
      }

      if err = w.handleFile(folder_name, file_name, f); err != nil {
          return err
      }
    }
    r.Close()
    return nil
}

/////////////////////////////////////////////////////////////////////////

var base_url = "http://jpercent.org/"

func downloadAndWrite(url_name string, file_name string) {
    resp, err := http.Get(url_name)
    if err != nil {
        log.Fatalln(err)
    }
    defer resp.Body.Close()
    body, err1 := ioutil.ReadAll(resp.Body)
    if err1 = ioutil.WriteFile(file_name, body, 0744); err1 != nil {
        log.Fatalln(err1)
    }
}

func getPath() string {
    path, err := filepath.Abs("")
    fmt.Println("path = ", path)
    if err != nil {
        log.Fatalln(err)
    }
    return path
}

func checkForPython() error {
    log.Println("Checking for Python...")
    cmd := exec.Command("cmd", "/C C:\\Python27\\python.exe")
    return cmd.Run()
}

func installExe(exe_name string, package_name string, post_fn func()) {
    log.Println("Downloading "+package_name+"...")
    downloadAndWrite(base_url+exe_file, exe_file)
    log.Println("Installing "+package_name+"...")
    path := getPath()
    cmd3 := exec.Command("cmd", "/C "+path+"\\"+exe_name)
    if err := cmd3.Run(); err != nil {
        log.Fatalln(err)
    }
    fmt.Println("Successfully installed "+package_name)
}

func installZippedPythonPackage(file_name string, package_name string, local_dir string, post_fn func()) {
    log.Println("Downloading "+package_name+"... ")
    downloadAndWrite(base_url+file_name, file_name)
    log.Println("Installing "+package_name+"... ")
    u := &Unzip{file_name, "", nil}
    if err := u.Expand(); err != nil {
        log.Fatalln("Failed to expand "+file_name, err)
    }

    if err := os.Chdir(local_dir); err != nil {
        log.Fatalln("Downloading and/or installing "+package_name+" failed ", err)
    }
    cmd2 := exec.Command("cmd", "/C C:\\Python27\\python.exe setup.py install")
    if err := cmd2.Run(); err != nil {
        log.Fatalln("Failed to install "+package_name, err)
    }
    post_fn()
    if err := os.Chdir(".."); err != nil {
        // ...
    }
    log.Println("Successfully installed "+package_name)
}

func installPython27() {
    if err := checkForPython(); err != nil {
        exe_name := "python-2.7.5.msi",
        package_name := "Python-2.7.5"
        post_fn := func() {}
        installExe(exe_name, package_name, post_fn)
    } else {
        log.Println("Python is already installed")
    }
}

func installPyglet12alpha() {
    post_fn := func() {}
    file_name := "pyglet-1.2alpha.zip"
    package_name := "pyglet-1.2alpha"
    local_dir := "pyglet-1.2alpha1"
    installZippedPythonPackage(file_name, package_name, local_dir, post_fn)
}

func installNumPy() {
    exe_name := "numpy-MKL-1.7.1.win32-py2.7.exe"
    package_name := "NumPy-1.7.1"
    post_fn := func() {}
    installExe(exe_name, package_name, post_fn)
}

func installPySerial26() {
    post_fn := func() {}
    file_name = "pyserial-2.6.zip"
    package_name = "pyserial-2.6"
    installZippedPythonPackage(file_name, package_name, package_name, post_fn)
}

func installUnlock() {
    post_processing_fn := func() {
        if err := os.MkdirAll("C:\\Unlock", 0755); err != nil {
            log.Fatalln("Failed to make unlock directory", err)
        }
        if err := os.Rename("collector.py", "C:\\Unlock\\collector.py"); err != nil {
            log.Fatalln("Failed to install unlock collector", err)
        }

        if err := os.Rename("collector.bat", "C:\\Unlock\\collector.bat"); err != nil {
            log.Fatalln("Failed to install unlock collector", err)
        }

        if err := os.Rename("pygtec.py", "C:\\Unlock\\pygtec.py"); err != nil {
            log.Fatalln("Failed to install unlock collector", err)
        }

        if err := os.Rename("targets.png", "C:\\Unlock\\targets.png"); err != nil {
            log.Fatalln("Failed to install unlock collector", err)
        }
    }
    installZippedPythonPackage("unlock.zip", "unlock", "unlock-npl", post_processing_fn)
}

func main() {
    logf, err := os.OpenFile("unlock-install.log", os.O_WRONLY|os.O_CREATE,0640)
    if err != nil {
        log.Fatalln(err)
    }
    log.SetOutput(io.MultiWriter(logf, os.Stdout))
    installPython27()
    installPyglet12alpha()
    installNumpy()
    installPySerial26()
    installUnlock()
}
<commit_msg>More refactoring of install.go<commit_after>package main

import (
    "net/http"
    "fmt"
    "io/ioutil"
    "os"
    "os/exec"
    "log"
    "path/filepath"
    "io"
    "archive/zip"
    "container/list"
    "strings"
)

type Unzip struct {
    zipfile string
    prefix string
    artifacts *list.List
}

type ZipArtifact struct {
  name string
  path string
  file *zip.File
}

func (u *Unzip) PrintListing() error {
    file_handler := func (meta *ZipMeta) error {
        log.Println(meta.current_file.path + meta.current_file.name)
        return nil
    }

    folder_handler := func(meta *ZipMeta) error {
        return nil
    }
    meta := ZipMeta { file_handler, folder_handler, make(map[string]bool), "", nil, nil} //list.New(), 1,true}
    if err := meta.walk(u.zipfile); err != nil {
        return err
    } else {
        u.artifacts = meta.artifacts
    }
    return nil
}

func (u *Unzip) GenerateListing() error {
    file_handler := func (meta *ZipMeta) error {
        if meta.artifacts == nil {
            meta.artifacts = list.New()
        }
        meta.artifacts.PushBack(meta.current_file)
        return nil
    }

    folder_handler := func(meta *ZipMeta) error {
        return nil
    }
    meta := ZipMeta { file_handler, folder_handler, make(map[string]bool), "", nil, nil}
    if err := meta.walk(u.zipfile); err != nil {
        return err
    } else {
        u.artifacts = meta.artifacts
    }
    return nil
}

func (u *Unzip) Expand() error {
    file_handler := func (meta *ZipMeta) error {

        if meta.artifacts == nil {
            meta.artifacts = list.New()
        }
        zipfile := meta.current_file.file
        meta.artifacts.PushBack(meta.current_file)

        var (
            err error
            file *os.File
            rc io.ReadCloser
        )
        if rc, err = zipfile.Open(); err != nil {
            return err
        }

        if file, err = os.Create(zipfile.Name); err != nil {
            return err
        }

        if _, err = io.Copy(file, rc); err != nil {
            return err
        }

        if err = file.Chmod(zipfile.Mode().Perm()); err != nil {
            //log.Println(err) // Windows WTF?
        }
        file.Close()
        rc.Close()
        return nil
    }

    folder_handler := func(meta *ZipMeta) error {
        return os.MkdirAll(meta.last_folder, 0755)
    }
    meta := ZipMeta {file_handler, folder_handler, make(map[string]bool), "", nil, nil}
    if err := meta.walk(u.zipfile); err != nil {
        return err
    } else {
        u.artifacts = meta.artifacts
    }
    return nil
}

type ZipMeta struct {
    file_handler func(*ZipMeta) error
    folder_handler func(*ZipMeta) error
    folders map[string]bool
    last_folder string
    current_file *ZipArtifact
    artifacts *list.List
}

func (w *ZipMeta) isNewFolder(folder_name string) bool {
    _, found := w.folders[folder_name]
    return !found
}

func (w *ZipMeta) handleFile(path string, file_name string, file *zip.File) error {
    w.current_file = &ZipArtifact{file_name, path, file}
    return w.file_handler(w)
}

func (w *ZipMeta) handleFolder(folder_name string) error {
    w.folders[folder_name] = true
    w.last_folder = folder_name
    return w.folder_handler(w)
}

func (w *ZipMeta) walk(zipfile string) error {
    var err error
    var r *zip.ReadCloser
    if r, err = zip.OpenReader(zipfile); err != nil {
      log.Fatalln(err)
      return err
    }

    for _, f := range r.File {

      if f.Mode().IsDir() {
        w.handleFolder(f.Name)
        continue
      }

      file_name := f.Name
      folder_name := ""
      folder_index := strings.LastIndex(f.Name, "/")
      if folder_index != -1 {
        folder_name += file_name[:folder_index] // 4.4.17
        if w.isNewFolder(folder_name) {
            if err = w.handleFolder(folder_name); err != nil {
                return err
            }
        }
        file_name = file_name[folder_index+1:] // strings.Join(dirlist[:len(dirlist)-1]
      }

      if err = w.handleFile(folder_name, file_name, f); err != nil {
          return err
      }
    }
    r.Close()
    return nil
}

/////////////////////////////////////////////////////////////////////////

var base_url = "http://jpercent.org/"

func downloadAndWrite(url_name string, file_name string) {
    resp, err := http.Get(url_name)
    if err != nil {
        log.Fatalln(err)
    }
    defer resp.Body.Close()
    body, err1 := ioutil.ReadAll(resp.Body)
    if err1 = ioutil.WriteFile(file_name, body, 0744); err1 != nil {
        log.Fatalln(err1)
    }
}

func cwdAbs() string {
    cwd, err := filepath.Abs("")
    log.Println("Current working directory = ", cwd)
    if err != nil {
        log.Fatalln(err)
    }
    return cwd
}

func checkForPython() error {
    log.Println("Checking for Python...")
    cmd := exec.Command("cmd", "/C C:\\Python27\\python.exe")
    return cmd.Run()
}

func installExe(exe_name string, package_name string, post_fn func()) {
    log.Println("Downloading "+package_name+"...")
    downloadAndWrite(base_url+exe_name, exe_name)
    log.Println("Installing "+package_name+"...")
    cwd := cwdAbs()
    cmd3 := exec.Command("cmd", "/C "+cwd+"\\"+exe_name)
    if err := cmd3.Run(); err != nil {
        log.Fatalln(err)
    }
    fmt.Println("Successfully installed "+package_name)
}

func installZippedPythonPackage(file_name string, package_name string, local_dir string, post_fn func()) {
    log.Println("Downloading "+package_name+"... ")
    downloadAndWrite(base_url+file_name, file_name)
    log.Println("Installing "+package_name+"... ")
    u := &Unzip{file_name, "", nil}
    if err := u.Expand(); err != nil {
        log.Fatalln("Failed to expand "+file_name, err)
    }

    if err := os.Chdir(local_dir); err != nil {
        log.Fatalln("Downloading and/or installing "+package_name+" failed ", err)
    }
    cmd2 := exec.Command("cmd", "/C C:\\Python27\\python.exe setup.py install")
    if err := cmd2.Run(); err != nil {
        log.Fatalln("Failed to install "+package_name, err)
    }
    post_fn()
    if err := os.Chdir(".."); err != nil {
        // ...
    }
    log.Println("Successfully installed "+package_name)
}

func installPython27() {
    if err := checkForPython(); err != nil {
        post_fn := func() {}
        installExe("python-2.7.5.msi", "Python-2.7.5", post_fn)
    } else {
        log.Println("Python is already installed")
    }
}

func installPyglet12alpha() {
    post_fn := func() {}
    installZippedPythonPackage("pyglet-1.2alpha.zip", "pyglet-1.2alpha", "pyglet-1.2alpha1", post_fn)
}

func installNumPy171() {
    post_fn := func() {}
    installExe("numpy-MKL-1.7.1.win32-py2.7.exe", "NumPy-1.7.1", post_fn)
}

func installPySerial26() {
    post_fn := func() {}
    installZippedPythonPackage("pyserial-2.6.zip", "pyserial-2.6", "pyserial-2.6", post_fn)
}

func installUnlock() {
    post_processing_fn := func() {
        if err := os.MkdirAll("C:\\Unlock", 0755); err != nil {
            log.Fatalln("Failed to make unlock directory", err)
        }
        if err := os.Rename("collector.py", "C:\\Unlock\\collector.py"); err != nil {
            log.Fatalln("Failed to install unlock collector", err)
        }

        if err := os.Rename("collector.bat", "C:\\Unlock\\collector.bat"); err != nil {
            log.Fatalln("Failed to install unlock collector", err)
        }

        if err := os.Rename("pygtec.py", "C:\\Unlock\\pygtec.py"); err != nil {
            log.Fatalln("Failed to install unlock collector", err)
        }

        if err := os.Rename("targets.png", "C:\\Unlock\\targets.png"); err != nil {
            log.Fatalln("Failed to install unlock collector", err)
        }
    }
    installZippedPythonPackage("unlock.zip", "unlock", "unlock-npl", post_processing_fn)
}

func main() {
    logf, err := os.OpenFile("unlock-install.log", os.O_WRONLY|os.O_CREATE,0640)
    if err != nil {
        log.Fatalln(err)
    }
    log.SetOutput(io.MultiWriter(logf, os.Stdout))
    installPython27()
    installPyglet12alpha()
    installNumPy171()
    installPySerial26()
    installUnlock()
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"io"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/gophergala/nut/vendor/_nuts/github.com/codegangsta/cli"
)

var installCmd = cli.Command{
	Name:   "install",
	Usage:  "install this project's dependencies",
	Action: runInstall,
}

func runInstall(c *cli.Context) {
	config := setting.Config()
	pl := &PkgLoader{
		Deps: config.Deps,
	}
	pkgs, err := pl.Load()
	check(err)

	l := pkgLister{
		Env: os.Environ(),
	}
	currentPkg, err := l.List(".")
	check(err)

	err = rewrite(pkgs, currentPkg[0].ImportPath)
	check(err)

	err = os.RemoveAll(setting.VendorDir())
	check(err)

	err = copyPkgs(pkgs)
	check(err)
}

func copyPkgs(pkgs []*Pkg) error {
	return copyDir(filepath.Join(setting.WorkDir(), "src"), setting.VendorDir())
}

func copyDir(source string, dest string) (err error) {
	sourceinfo, err := os.Stat(source)
	if err != nil {
		return err
	}

	err = os.MkdirAll(dest, sourceinfo.Mode())
	if err != nil {
		return err
	}

	directory, _ := os.Open(source)
	objects, err := directory.Readdir(-1)

	for _, obj := range objects {
		sourcefilepointer := source + "/" + obj.Name()
		destinationfilepointer := dest + "/" + obj.Name()

		// ignore dir starting with . or _
		c := obj.Name()[0]
		if obj.IsDir() && (c == '.' || c == '_') {
			continue
		}

		if obj.IsDir() {
			err = copyDir(sourcefilepointer, destinationfilepointer)
			if err != nil {
				return err
			}
		} else {
			err = copyFile(sourcefilepointer, destinationfilepointer)
			if err != nil {
				return err
			}
		}

	}

	return
}

func copyFile(source string, dest string) (err error) {
	sourcefile, err := os.Open(source)
	if err != nil {
		return err
	}

	defer sourcefile.Close()

	destfile, err := os.Create(dest)
	if err != nil {
		return err
	}

	defer destfile.Close()

	if strings.HasSuffix(dest, ".go") {
		err = copyWithoutImportComment(destfile, sourcefile)
	} else {
		_, err = io.Copy(destfile, sourcefile)
	}

	if err == nil {
		sourceinfo, err := os.Stat(source)
		if err != nil {
			err = os.Chmod(dest, sourceinfo.Mode())
		}

	}

	return
}

func copyWithoutImportComment(w io.Writer, r io.Reader) error {
	sc := bufio.NewScanner(r)
	for sc.Scan() {
		_, err := w.Write(append(stripImportComment(sc.Bytes()), '\n'))
		if err != nil {
			return err
		}
	}
	return nil
}

const (
	importAnnotation = `import\s+(?:"[^"]*"|` + "`[^`]*`" + `)`
	importComment    = `(?://\s*` + importAnnotation + `\s*$|/\*\s*` + importAnnotation + `\s*\*/)`
)

var (
	importCommentRE = regexp.MustCompile(`^\s*(package\s+\w+)\s+` + importComment + `(.*)`)
	pkgPrefix       = []byte("package ")
)

// stripImportComment returns line with its import comment removed.
// If s is not a package statement containing an import comment,
// it is returned unaltered.
// See also http://golang.org/s/go14customimport.
func stripImportComment(line []byte) []byte {
	if !bytes.HasPrefix(line, pkgPrefix) {
		// Fast path; this will skip all but one line in the file.
		// This assumes there is no whitespace before the keyword.
		return line
	}
	if m := importCommentRE.FindSubmatch(line); m != nil {
		return append(m[1], m[2]...)
	}
	return line
}
<commit_msg>Return if there’s no dependencies to install<commit_after>package main

import (
	"bufio"
	"bytes"
	"io"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/gophergala/nut/vendor/_nuts/github.com/codegangsta/cli"
)

var installCmd = cli.Command{
	Name:   "install",
	Usage:  "install this project's dependencies",
	Action: runInstall,
}

func runInstall(c *cli.Context) {
	config := setting.Config()
	if len(config.Deps) == 0 {
		return
	}

	pl := &PkgLoader{
		Deps: config.Deps,
	}
	pkgs, err := pl.Load()
	check(err)

	l := pkgLister{
		Env: os.Environ(),
	}
	currentPkg, err := l.List(".")
	check(err)

	err = rewrite(pkgs, currentPkg[0].ImportPath)
	check(err)

	err = os.RemoveAll(setting.VendorDir())
	check(err)

	err = copyPkgs(pkgs)
	check(err)
}

func copyPkgs(pkgs []*Pkg) error {
	return copyDir(filepath.Join(setting.WorkDir(), "src"), setting.VendorDir())
}

func copyDir(source string, dest string) (err error) {
	sourceinfo, err := os.Stat(source)
	if err != nil {
		return err
	}

	err = os.MkdirAll(dest, sourceinfo.Mode())
	if err != nil {
		return err
	}

	directory, _ := os.Open(source)
	objects, err := directory.Readdir(-1)

	for _, obj := range objects {
		sourcefilepointer := source + "/" + obj.Name()
		destinationfilepointer := dest + "/" + obj.Name()

		// ignore dir starting with . or _
		c := obj.Name()[0]
		if obj.IsDir() && (c == '.' || c == '_') {
			continue
		}

		if obj.IsDir() {
			err = copyDir(sourcefilepointer, destinationfilepointer)
			if err != nil {
				return err
			}
		} else {
			err = copyFile(sourcefilepointer, destinationfilepointer)
			if err != nil {
				return err
			}
		}

	}

	return
}

func copyFile(source string, dest string) (err error) {
	sourcefile, err := os.Open(source)
	if err != nil {
		return err
	}

	defer sourcefile.Close()

	destfile, err := os.Create(dest)
	if err != nil {
		return err
	}

	defer destfile.Close()

	if strings.HasSuffix(dest, ".go") {
		err = copyWithoutImportComment(destfile, sourcefile)
	} else {
		_, err = io.Copy(destfile, sourcefile)
	}

	if err == nil {
		sourceinfo, err := os.Stat(source)
		if err != nil {
			err = os.Chmod(dest, sourceinfo.Mode())
		}

	}

	return
}

func copyWithoutImportComment(w io.Writer, r io.Reader) error {
	sc := bufio.NewScanner(r)
	for sc.Scan() {
		_, err := w.Write(append(stripImportComment(sc.Bytes()), '\n'))
		if err != nil {
			return err
		}
	}
	return nil
}

const (
	importAnnotation = `import\s+(?:"[^"]*"|` + "`[^`]*`" + `)`
	importComment    = `(?://\s*` + importAnnotation + `\s*$|/\*\s*` + importAnnotation + `\s*\*/)`
)

var (
	importCommentRE = regexp.MustCompile(`^\s*(package\s+\w+)\s+` + importComment + `(.*)`)
	pkgPrefix       = []byte("package ")
)

// stripImportComment returns line with its import comment removed.
// If s is not a package statement containing an import comment,
// it is returned unaltered.
// See also http://golang.org/s/go14customimport.
func stripImportComment(line []byte) []byte {
	if !bytes.HasPrefix(line, pkgPrefix) {
		// Fast path; this will skip all but one line in the file.
		// This assumes there is no whitespace before the keyword.
		return line
	}
	if m := importCommentRE.FindSubmatch(line); m != nil {
		return append(m[1], m[2]...)
	}
	return line
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package irc

import (
	"strings"
	"time"

	"github.com/fluffle/goirc/client"
	log_glog "github.com/fluffle/goirc/logging/glog"
	"github.com/fluffle/goirc/state"
)

const (
	name    = "gibot"
	version = name + " v0.0 github.com/mvdan/gibot"
	quit    = name + " exited"

	wait    = 2 * time.Second
	timeout = 20 * time.Second
	ping    = 2 * time.Minute
	split   = 100

	server = "irc.freenode.net:7000"
	ssl    = true
)

type Event struct {
	Cmd  string
	Args []string
}

func EventFromLine(line *client.Line) Event {
	return Event{
		Cmd:  strings.ToUpper(line.Cmd),
		Args: line.Args,
	}
}

type Notice struct {
	Channel string
	Message string
}

type Client struct {
	conn *client.Conn

	chans map[string]struct{}

	In  chan Event
	Out chan Notice
}

func toSet(list []string) map[string]struct{} {
	m := make(map[string]struct{})
	for _, s := range list {
		m[s] = struct{}{}
	}
	return m
}

func Connect(nick string, chans []string) (*Client, error) {
	c := &Client{
		chans: toSet(chans),
		In:    make(chan Event),
		Out:   make(chan Notice),
	}

	c.conn = client.Client(&client.Config{
		Me: &state.Nick{
			Nick:  nick,
			Ident: name,
			Name:  name,
		},
		PingFreq:    ping,
		NewNick:     func(s string) string { return s + "_" },
		Recover:     (*client.Conn).LogPanic,
		SplitLen:    split,
		Timeout:     timeout,
		Server:      server,
		SSL:         ssl,
		Version:     version,
		QuitMessage: quit,
	})

	log_glog.Init()

	c.conn.HandleFunc(client.CONNECTED, func(conn *client.Conn, line *client.Line) {
		c.In <- EventFromLine(line)
		for channel := range c.chans {
			conn.Join(channel)
		}
	})
	c.conn.HandleFunc(client.DISCONNECTED, func(_ *client.Conn, line *client.Line) {
		c.In <- EventFromLine(line)
	})
	c.conn.HandleFunc(client.PRIVMSG, func(_ *client.Conn, line *client.Line) {
		channel := line.Args[0]
		if _, e := c.chans[channel]; !e {
			return
		}
		c.In <- EventFromLine(line)
	})
	if err := c.conn.Connect(); err != nil {
		return nil, err
	}
	go c.Work()
	return c, nil
}

func (c *Client) Work() {
	for {
		not := <-c.Out
		c.conn.Notice(not.Channel, not.Message)
		time.Sleep(wait)
	}
}

func (c *Client) Quit() {
	c.conn.Quit()
}
<commit_msg>Remove glog dependency<commit_after>// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package irc

import (
	"strings"
	"time"

	"github.com/fluffle/goirc/client"
	"github.com/fluffle/goirc/state"
)

const (
	name    = "gibot"
	version = name + " v0.0 github.com/mvdan/gibot"
	quit    = name + " exited"

	wait    = 2 * time.Second
	timeout = 20 * time.Second
	ping    = 2 * time.Minute
	split   = 100

	server = "irc.freenode.net:7000"
	ssl    = true
)

type Event struct {
	Cmd  string
	Args []string
}

func EventFromLine(line *client.Line) Event {
	return Event{
		Cmd:  strings.ToUpper(line.Cmd),
		Args: line.Args,
	}
}

type Notice struct {
	Channel string
	Message string
}

type Client struct {
	conn *client.Conn

	chans map[string]struct{}

	In  chan Event
	Out chan Notice
}

func toSet(list []string) map[string]struct{} {
	m := make(map[string]struct{})
	for _, s := range list {
		m[s] = struct{}{}
	}
	return m
}

func Connect(nick string, chans []string) (*Client, error) {
	c := &Client{
		chans: toSet(chans),
		In:    make(chan Event),
		Out:   make(chan Notice),
	}

	c.conn = client.Client(&client.Config{
		Me: &state.Nick{
			Nick:  nick,
			Ident: name,
			Name:  name,
		},
		PingFreq:    ping,
		NewNick:     func(s string) string { return s + "_" },
		Recover:     func(*client.Conn, *client.Line) {},
		SplitLen:    split,
		Timeout:     timeout,
		Server:      server,
		SSL:         ssl,
		Version:     version,
		QuitMessage: quit,
	})

	c.conn.HandleFunc(client.CONNECTED, func(conn *client.Conn, line *client.Line) {
		c.In <- EventFromLine(line)
		for channel := range c.chans {
			conn.Join(channel)
		}
	})
	c.conn.HandleFunc(client.DISCONNECTED, func(_ *client.Conn, line *client.Line) {
		c.In <- EventFromLine(line)
	})
	c.conn.HandleFunc(client.PRIVMSG, func(_ *client.Conn, line *client.Line) {
		channel := line.Args[0]
		if _, e := c.chans[channel]; !e {
			return
		}
		c.In <- EventFromLine(line)
	})
	if err := c.conn.Connect(); err != nil {
		return nil, err
	}
	go c.Work()
	return c, nil
}

func (c *Client) Work() {
	for {
		not := <-c.Out
		c.conn.Notice(not.Channel, not.Message)
		time.Sleep(wait)
	}
}

func (c *Client) Quit() {
	c.conn.Quit()
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"time"

	"fmt"
	"github.com/BurntSushi/toml"
	"github.com/dchest/uniuri"
	"github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
	"github.com/raggaer/castro/app/database"
	"github.com/raggaer/castro/app/lua"
	"github.com/raggaer/castro/app/util"
	"io/ioutil"
	"path/filepath"
	"strings"
)

const (
	// configFileName the name of the application configuration file
	configFileName = "config.toml"

	// znoteTableName name of the znote table
	znoteTableName = "znote"
)

type znoteTable struct {
	Version   int
	Installed int64
}

// isInstalled check if application is installed
func isInstalled() bool {
	// Check if file exists
	_, err := os.Stat(configFileName)

	return err == nil
}

// isZnoteInstalled checks if znote_aac is already installed
func isZnoteInstalled(db *sqlx.DB) (bool, error) {
	// Check if table exists
	if _, err := db.Exec("DESCRIBE " + znoteTableName); err != nil {

		// Convert error to MySQL error type
		mErr, ok := err.(*mysql.MySQLError)

		// Check if table is installed
		if ok && mErr.Number == 1146 {

			return false, nil
		}

		return false, err
	}

	return true, nil
}

// installApplication runs the installation process
func installApplication() error {

	// Ask user for server directory location
	fmt.Print("Insert your server location: ")

	// Location holder
	var location string

	// Get user response
	_, err := fmt.Scanln(&location)

	if err != nil {
		return err
	}

	// Load config.lua file
	if err := lua.LoadConfig(
		filepath.Join(location),
	); err != nil {
		return err
	}

	// Connect to database
	db, err := database.Open(lua.Config.GetGlobal("mysqlUser").String(), lua.Config.GetGlobal("mysqlPass").String(), lua.Config.GetGlobal("mysqlDatabase").String())

	if err != nil {
		return err
	}

	// Ping database
	if err := db.Ping(); err != nil {
		return err
	}

	// Close database handle
	defer db.Close()

	// Get all sql files
	tables, err := ioutil.ReadDir(filepath.Join("install"))

	if err != nil {
		return err
	}

	// Loop files
	for _, table := range tables {

		// Check if table exists
		if _, err := db.Exec("DESCRIBE " + strings.TrimSuffix(table.Name(), ".sql")); err != nil {

			// Convert error to MySQL error type
			mErr, ok := err.(*mysql.MySQLError)

			// Check if table is installed
			if ok && mErr.Number == 1146 {

				// Read file
				buff, err := ioutil.ReadFile(filepath.Join("install", table.Name()))

				if err != nil {
					return err
				}

				// Execute query
				if _, err := db.Exec(string(buff)); err != nil {
					return err
				}

				continue
			}

			return err
		}
	}

	fmt.Println("Missing tables created")

	// Create configuration file
	return createConfigFile(configFileName, location)
}

// createConfigFile encodes a configuration file with the given name and location
func createConfigFile(name, location string) error {
	// Create configuration file handle
	configFile, err := os.Create(name)
	if err != nil {
		return err
	}

	// Close file handle
	defer configFile.Close()

	// Encode the given configuration struct into the file
	return toml.NewEncoder(configFile).Encode(util.Configuration{
		Mode:     "dev",
		Port:     8080,
		URL:      "localhost",
		Datapack: location,
		Captcha: util.CaptchaConfig{
			Enabled: false,
		},
		Cookies: util.CookieConfig{
			Name:     "castro",
			MaxAge:   1000000,
			HashKey:  uniuri.NewLen(32),
			BlockKey: uniuri.NewLen(32),
		},
		Cache: util.CacheConfig{
			Default: time.Minute * 5,
			Purge:   time.Minute,
		},
		SSL: util.SSLConfig{
			Enabled: false,
		},
		RateLimit: util.RateLimiterConfig{
			Number: 100,
			Time:   time.Minute,
		},
		PayPal: util.PayPalConfig{
			Enabled: false,
		},
		Custom: make(map[string]interface{}),
	})
}
<commit_msg>Fix installation<commit_after>package main

import (
	"os"
	"time"

	"fmt"
	"github.com/BurntSushi/toml"
	"github.com/dchest/uniuri"
	"github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
	"github.com/raggaer/castro/app/database"
	"github.com/raggaer/castro/app/lua"
	"github.com/raggaer/castro/app/util"
	"io/ioutil"
	"path/filepath"
	"strings"
)

const (
	// configFileName the name of the application configuration file
	configFileName = "config.toml"

	// znoteTableName name of the znote table
	znoteTableName = "znote"
)

type znoteTable struct {
	Version   int
	Installed int64
}

// isInstalled check if application is installed
func isInstalled() bool {
	// Check if file exists
	_, err := os.Stat(configFileName)

	return err == nil
}

// isZnoteInstalled checks if znote_aac is already installed
func isZnoteInstalled(db *sqlx.DB) (bool, error) {
	// Check if table exists
	if _, err := db.Exec("DESCRIBE " + znoteTableName); err != nil {

		// Convert error to MySQL error type
		mErr, ok := err.(*mysql.MySQLError)

		// Check if table is installed
		if ok && mErr.Number == 1146 {

			return false, nil
		}

		return false, err
	}

	return true, nil
}

// installApplication runs the installation process
func installApplication() error {

	// Ask user for server directory location
	fmt.Print("Insert your server location: ")

	// Location holder
	var location string

	// Get user response
	_, err := fmt.Scanln(&location)

	if err != nil {
		return err
	}

	// Load config.lua file
	if err := lua.LoadConfig(
		filepath.Join(filepath.Join(location, "config.lua")),
	); err != nil {
		return err
	}

	// Connect to database
	db, err := database.Open(lua.Config.GetGlobal("mysqlUser").String(), lua.Config.GetGlobal("mysqlPass").String(), lua.Config.GetGlobal("mysqlDatabase").String())

	if err != nil {
		return err
	}

	// Ping database
	if err := db.Ping(); err != nil {
		return err
	}

	// Close database handle
	defer db.Close()

	// Get all sql files
	tables, err := ioutil.ReadDir(filepath.Join("install"))

	if err != nil {
		return err
	}

	// Loop files
	for _, table := range tables {

		// Check if table exists
		if _, err := db.Exec("DESCRIBE " + strings.TrimSuffix(table.Name(), ".sql")); err != nil {

			// Convert error to MySQL error type
			mErr, ok := err.(*mysql.MySQLError)

			// Check if table is installed
			if ok && mErr.Number == 1146 {

				// Read file
				buff, err := ioutil.ReadFile(filepath.Join("install", table.Name()))

				if err != nil {
					return err
				}

				// Execute query
				if _, err := db.Exec(string(buff)); err != nil {
					return err
				}

				continue
			}

			return err
		}
	}

	fmt.Println("Missing tables created")

	// Create configuration file
	return createConfigFile(configFileName, location)
}

// createConfigFile encodes a configuration file with the given name and location
func createConfigFile(name, location string) error {
	// Create configuration file handle
	configFile, err := os.Create(name)
	if err != nil {
		return err
	}

	// Close file handle
	defer configFile.Close()

	// Encode the given configuration struct into the file
	return toml.NewEncoder(configFile).Encode(util.Configuration{
		Mode:     "dev",
		Port:     8080,
		URL:      "localhost",
		Datapack: location,
		Captcha: util.CaptchaConfig{
			Enabled: false,
		},
		Cookies: util.CookieConfig{
			Name:     "castro",
			MaxAge:   1000000,
			HashKey:  uniuri.NewLen(32),
			BlockKey: uniuri.NewLen(32),
		},
		Cache: util.CacheConfig{
			Default: time.Minute * 5,
			Purge:   time.Minute,
		},
		SSL: util.SSLConfig{
			Enabled: false,
		},
		RateLimit: util.RateLimiterConfig{
			Number: 100,
			Time:   time.Minute,
		},
		PayPal: util.PayPalConfig{
			Enabled: false,
		},
		Custom: make(map[string]interface{}),
	})
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"image"
	"image/color"
	"image/png"
	"io"
	"os"
	"strconv"
)

var encodeMap map[string]string = map[string]string{
	"0": "11000",
	"1": "00011",
	"2": "00101",
	"3": "00110",
	"4": "01001",
	"5": "01010",
	"6": "01100",
	"7": "10001",
	"8": "10010",
	"9": "10100",
}

type Postnet struct {
	msg                 string
	BarHeight, BarWidth int
	DebugPrint          bool
}

func NewPostnet(msg string) *Postnet {
	b := new(Postnet)
	b.msg = msg

	b.BarWidth = 2
	b.BarHeight = 25
	b.DebugPrint = false

	return b
}

func (this *Postnet) EncodeToPNG(w io.Writer) {
	encoded := this.getEncodedForPrint()

	pos := 0
	barH := this.BarHeight
	barW := this.BarWidth

	imgH := barH * 4
	imgW := len(encoded) * barW * 2

	size := image.Rect(0, 0, imgW, imgH)
	img := image.NewRGBA(size)

	for _, c := range encoded {

		switch string(c) {
		case "1":
			for x := 0; x <= barW; x++ {
				for y := barH * 2; y > 0; y-- {
					img.Set(x+pos, y, color.Black)
				}
			}
			pos += barW
		case "0":
			for x := 0; x <= barW; x++ {
				for y := barH; y <= barH*2; y++ {
					img.Set(x+pos, y, color.Black)
				}
			}
			pos += barW
		case "_":
			pos -= barW
			for x := 0; x <= barW; x++ {
				for y := 0; y <= barH; y++ {
					img.Set(x+pos, y, color.RGBA{255, 0, 0, 255})
				}
			}
		}
		pos += barW
	}

	png.Encode(w, img)
}

func (this *Postnet) getEncodedForPrint() string {
	var interCharSymb string

	if this.DebugPrint {
		interCharSymb = "_"
	} else {
		interCharSymb = ""
	}

	checkDigit := this.checksum()

	encoded := "1"
	encoded += interCharSymb
	for _, c := range this.msg {
		ch := string(c)
		encoded += encodeMap[ch]
		encoded += interCharSymb
	}
	encoded += encodeMap[checkDigit]
	encoded += interCharSymb
	encoded += "1"
	encoded += interCharSymb

	return encoded
}

func (this *Postnet) checksum() string {
	var sum int64 = 0
	var r int = 0

	for _, v := range this.msg {
		rV, _ := strconv.ParseInt(string(v), 10, 32)

		sum += rV
	}

	for (sum % 10) != 0 {
		sum += 1
		r += 1
	}

	return fmt.Sprint(r)
}

func main() {
	msg := "0123456789"
	f, _ := os.Create(msg + ".png")

	postnet := NewPostnet(msg)
	postnet.DebugPrint = true
	postnet.EncodeToPNG(f)

	f.Close()
}
<commit_msg>postnet<commit_after>package gobarcode

import (
	"fmt"
	"image"
	"image/color"
	"image/png"
	"io"
	"strconv"
)

var postnetEncodeMap map[string]string = map[string]string{
	"0": "11000",
	"1": "00011",
	"2": "00101",
	"3": "00110",
	"4": "01001",
	"5": "01010",
	"6": "01100",
	"7": "10001",
	"8": "10010",
	"9": "10100",
}

type Postnet struct {
	msg                 string
	BarHeight, BarWidth int
	DebugPrint          bool
}

func NewPostnet(msg string) *Postnet {
	b := new(Postnet)
	b.msg = msg

	b.BarWidth = 4
	b.BarHeight = 50
	b.DebugPrint = false

	return b
}

// Example
// 	msg := "555551237"
// 	f, _ := os.Create(msg + ".png")
// 	postnet := NewPostnet(msg)
// 	postnet.DebugPrint = true
// 	postnet.EncodeToPNG(f)
// 	f.Close()
func (this *Postnet) EncodeToPNG(w io.Writer) {
	encoded := this.getEncodedForPrint()

	pos := 0
	barH := this.BarHeight
	barW := this.BarWidth
	barWWide := barW * 2

	imgH := barH * 2
	imgW := len(encoded) * barWWide * 2

	size := image.Rect(0, 0, imgW, imgH)
	img := image.NewRGBA(size)

	for _, c := range encoded {

		switch string(c) {
		case "1":
			for x := 0; x <= barW; x++ {
				for y := barH * 2; y >= 0; y-- {
					img.Set(x+pos, y, color.Black)
				}
			}
			pos += barW
		case "0":
			for x := 0; x <= barW; x++ {
				for y := barH; y <= barH*2; y++ {
					img.Set(x+pos, y, color.Black)
				}
			}
			pos += barW
		case "_":
			pos -= barWWide
			for x := 0; x <= barW; x++ {
				for y := barH * 2; y >= 0; y-- {
					img.Set(x+pos, y, color.RGBA{255, 0, 0, 255})
				}
			}
		}
		pos += barWWide
	}

	png.Encode(w, img)
}

func (this *Postnet) getEncodedForPrint() string {
	var interCharSymb string

	if this.DebugPrint {
		interCharSymb = "_"
	} else {
		interCharSymb = ""
	}

	checkDigit := this.checksum()

	encoded := "1"
	encoded += interCharSymb
	for _, c := range this.msg {
		ch := string(c)
		encoded += postnetEncodeMap[ch]
		encoded += interCharSymb
	}
	encoded += postnetEncodeMap[checkDigit]
	encoded += interCharSymb
	encoded += "1"
	encoded += interCharSymb

	return encoded
}

func (this *Postnet) checksum() string {
	var sum int64 = 0
	var r int = 0

	for _, v := range this.msg {
		rV, _ := strconv.ParseInt(string(v), 10, 32)

		sum += rV
	}

	r = 10 - (int(sum) % 10)

	return fmt.Sprint(r)
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	"github.com/coopernurse/gorp"
	. "gopkg.in/check.v1"
)

func createTestDatabase() *gorp.DbMap {
	db, err := sql.Open("sqlite3", ":memory:")
	checkErr(err, "sql.Open failed")

	// construct a gorp DbMap
	dbmap := &gorp.DbMap{Db: db, Dialect: gorp.SqliteDialect{}}

	return dbmap
}

func Test(t *testing.T) { TestingT(t) }

type PRSuite struct {
	dbmap     *gorp.DbMap
	app       Application
	createURL string
	tableName string
}

func (s *PRSuite) SetUpSuite(c *C) {
	s.dbmap = createTestDatabase()
	s.app = CreateApplication(s.dbmap)
}

func (s *PRSuite) SetUpTest(c *C) {
	err := s.dbmap.TruncateTables()
	if err != nil {
		c.Error(err)
	}
}

func (s *PRSuite) TearDownSuite(c *C) {
	s.dbmap.Db.Close()
}

func (s *PRSuite) PerformRequest(method string, relativePath string, body string) *httptest.ResponseRecorder {
	path := fmt.Sprintf("http://test.example.com%s", relativePath)
	w := httptest.NewRecorder()
	r, err := http.NewRequest(method, path, strings.NewReader(body))
	checkErr(err, "Request creation failed")

	s.app.handler.ServeHTTP(w, r)
	return w
}

func (s *PRSuite) TestAddReturns201(c *C) {
	recorder := s.PerformRequest("POST", s.createURL, `{"name": "Test Name"}`)

	c.Check(recorder.Code, Equals, 201)
}

func (s *PRSuite) TestAddCreatesOneEntity(c *C) {
	s.PerformRequest("POST", s.createURL, `{"name": "Test Name"}`)

	query := fmt.Sprintf("SELECT count(*) FROM %s", s.tableName)
	count, err := s.dbmap.SelectInt(query)
	checkErr(err, "Getting count failed")
	c.Assert(count, Equals, int64(1))
}

func (s *PRSuite) TestAddCreatesEntityWithCorrectName(c *C) {
	type nameHolder struct {
		Name string
	}
	s.PerformRequest("POST", s.createURL, `{"name": "Test Name"}`)

	var createdEntity nameHolder
	query := fmt.Sprintf("select Name from %s", s.tableName)
	err := s.dbmap.SelectOne(&createdEntity, query)
	if err != nil {
		c.Error(err)
	}
	c.Assert(createdEntity.Name, Matches, "Test Name")
}

type ElectionSuite struct {
	PRSuite
}

func (s *ElectionSuite) SetUpSuite(c *C) {
	s.PRSuite.SetUpSuite(c)
	s.createURL = "/elections"
	s.tableName = "elections"
}

var _ = Suite(&ElectionSuite{})

func (s *ElectionSuite) TestAddElectionRejectsZeroLengthName(c *C) {
	recorder := s.PerformRequest("POST", "/elections", `{"name": ""}`)

	c.Check(recorder.Code, Equals, 400)
	c.Check(recorder.Body.String(), Matches, "Empty name forbidden.\n?")

	count, err := s.dbmap.SelectInt("select count(*) from elections")
	checkErr(err, "Getting count failed")
	c.Check(count, Equals, int64(0))
}

func (s *ElectionSuite) TestAddElectionRejectsDuplicateNames(c *C) {
	s.PerformRequest("POST", "/elections", `{"name": "Duplicate"}`)
	recorder := s.PerformRequest("POST", "/elections", `{"name": "Duplicate"}`)

	c.Check(recorder.Code, Equals, 400)
	c.Check(recorder.Body.String(), Matches, "Name taken.\n?")

	count, err := s.dbmap.SelectInt("select count(*) from elections")
	checkErr(err, "Getting count failed")
	c.Check(count, Equals, int64(1))
}

func (s *ElectionSuite) TestGetElectionReturns200(c *C) {
	election := Election{Name: "my test name"}
	s.dbmap.Insert(&election)

	recorder := s.PerformRequest("GET", fmt.Sprintf("/elections/%d", election.Id), "")

	c.Check(recorder.Code, Equals, 200)
}

func (s *ElectionSuite) TestGetElectionReturnsElectionName(c *C) {
	election := Election{Name: "my test name"}
	s.dbmap.Insert(&election)

	recorder := s.PerformRequest("GET", fmt.Sprintf("/elections/%d", election.Id), "")
	returnedElection := Election{}
	json.Unmarshal(recorder.Body.Bytes(), &returnedElection)
	c.Assert(returnedElection.Name, Matches, "my test name")
}

func (s *ElectionSuite) TestGetElection404sForUnknownElection(c *C) {
	recorder := s.PerformRequest("GET", "/elections/1", "")

	c.Check(recorder.Code, Equals, 404)
}

func (s *ElectionSuite) TestListElectionsReturnsEmptyList(c *C) {
	recorder := s.PerformRequest("GET", "/elections", "")

	c.Check(recorder.Code, Equals, 200)
	c.Check(recorder.Body.String(), Equals, "[]")
}

func (s *ElectionSuite) TestListElectionsReturnsListOfCorrectLength(c *C) {
	election := Election{Name: "my test name"}
	other_election := Election{Name: "my other name"}
	third_election := Election{Name: "my third name"}
	s.dbmap.Insert(&election, &other_election, &third_election)

	recorder := s.PerformRequest("GET", "/elections", "")

	var electionList []Election
	json.Unmarshal(recorder.Body.Bytes(), &electionList)
	c.Check(len(electionList), Equals, 3)
}

func (s *ElectionSuite) TestListElectionReturnsExistingElections(c *C) {
	election := Election{Name: "my test name"}
	other_election := Election{Name: "my other name"}
	s.dbmap.Insert(&election, &other_election)

	recorder := s.PerformRequest("GET", "/elections", "")

	expectedElectionNames := map[string]int{
		"my test name":  0,
		"my other name": 0,
	}
	var electionList []Election
	json.Unmarshal(recorder.Body.Bytes(), &electionList)
	actualElectionNames := make(map[string]int)
	for _, election := range electionList {
		actualElectionNames[election.Name] = 0
	}
	c.Check(actualElectionNames, DeepEquals, expectedElectionNames)
}

type CandidatesSuite struct {
	PRSuite
}

func (s *CandidatesSuite) SetUpTest(c *C) {
	s.PRSuite.SetUpTest(c)

	// Set up test election
	election := Election{Name: "my test name"}
	err := s.dbmap.Insert(&election)
	if err != nil {
		c.Error(err)
	}

	s.createURL = fmt.Sprintf("/elections/%d/candidates", election.Id)
	s.tableName = "candidates"
}

var _ = Suite(&CandidatesSuite{})

func (s *CandidatesSuite) TestAddCandidateReturns404ForMissingElection(c *C) {
	recorder := s.PerformRequest("POST", "/elections/1234/candidates", `{"name": "Test Candidate"}`)

	c.Check(recorder.Code, Equals, 404)
}
<commit_msg>Use SelectStr to avoid need for custom type.<commit_after>package main

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	"github.com/coopernurse/gorp"
	. "gopkg.in/check.v1"
)

func createTestDatabase() *gorp.DbMap {
	db, err := sql.Open("sqlite3", ":memory:")
	checkErr(err, "sql.Open failed")

	// construct a gorp DbMap
	dbmap := &gorp.DbMap{Db: db, Dialect: gorp.SqliteDialect{}}

	return dbmap
}

func Test(t *testing.T) { TestingT(t) }

type PRSuite struct {
	dbmap     *gorp.DbMap
	app       Application
	createURL string
	tableName string
}

func (s *PRSuite) SetUpSuite(c *C) {
	s.dbmap = createTestDatabase()
	s.app = CreateApplication(s.dbmap)
}

func (s *PRSuite) SetUpTest(c *C) {
	err := s.dbmap.TruncateTables()
	if err != nil {
		c.Error(err)
	}
}

func (s *PRSuite) TearDownSuite(c *C) {
	s.dbmap.Db.Close()
}

func (s *PRSuite) PerformRequest(method string, relativePath string, body string) *httptest.ResponseRecorder {
	path := fmt.Sprintf("http://test.example.com%s", relativePath)
	w := httptest.NewRecorder()
	r, err := http.NewRequest(method, path, strings.NewReader(body))
	checkErr(err, "Request creation failed")

	s.app.handler.ServeHTTP(w, r)
	return w
}

func (s *PRSuite) TestAddReturns201(c *C) {
	recorder := s.PerformRequest("POST", s.createURL, `{"name": "Test Name"}`)

	c.Check(recorder.Code, Equals, 201)
}

func (s *PRSuite) TestAddCreatesOneEntity(c *C) {
	s.PerformRequest("POST", s.createURL, `{"name": "Test Name"}`)

	query := fmt.Sprintf("SELECT count(*) FROM %s", s.tableName)
	count, err := s.dbmap.SelectInt(query)
	checkErr(err, "Getting count failed")
	c.Assert(count, Equals, int64(1))
}

func (s *PRSuite) TestAddCreatesEntityWithCorrectName(c *C) {
	s.PerformRequest("POST", s.createURL, `{"name": "Test Name"}`)

	query := fmt.Sprintf("select Name from %s", s.tableName)
	name, err := s.dbmap.SelectStr(query)
	if err != nil {
		c.Error(err)
	}
	c.Assert(name, Matches, "Test Name")
}

type ElectionSuite struct {
	PRSuite
}

func (s *ElectionSuite) SetUpSuite(c *C) {
	s.PRSuite.SetUpSuite(c)
	s.createURL = "/elections"
	s.tableName = "elections"
}

var _ = Suite(&ElectionSuite{})

func (s *ElectionSuite) TestAddElectionRejectsZeroLengthName(c *C) {
	recorder := s.PerformRequest("POST", "/elections", `{"name": ""}`)

	c.Check(recorder.Code, Equals, 400)
	c.Check(recorder.Body.String(), Matches, "Empty name forbidden.\n?")

	count, err := s.dbmap.SelectInt("select count(*) from elections")
	checkErr(err, "Getting count failed")
	c.Check(count, Equals, int64(0))
}

func (s *ElectionSuite) TestAddElectionRejectsDuplicateNames(c *C) {
	s.PerformRequest("POST", "/elections", `{"name": "Duplicate"}`)
	recorder := s.PerformRequest("POST", "/elections", `{"name": "Duplicate"}`)

	c.Check(recorder.Code, Equals, 400)
	c.Check(recorder.Body.String(), Matches, "Name taken.\n?")

	count, err := s.dbmap.SelectInt("select count(*) from elections")
	checkErr(err, "Getting count failed")
	c.Check(count, Equals, int64(1))
}

func (s *ElectionSuite) TestGetElectionReturns200(c *C) {
	election := Election{Name: "my test name"}
	s.dbmap.Insert(&election)

	recorder := s.PerformRequest("GET", fmt.Sprintf("/elections/%d", election.Id), "")

	c.Check(recorder.Code, Equals, 200)
}

func (s *ElectionSuite) TestGetElectionReturnsElectionName(c *C) {
	election := Election{Name: "my test name"}
	s.dbmap.Insert(&election)

	recorder := s.PerformRequest("GET", fmt.Sprintf("/elections/%d", election.Id), "")
	returnedElection := Election{}
	json.Unmarshal(recorder.Body.Bytes(), &returnedElection)
	c.Assert(returnedElection.Name, Matches, "my test name")
}

func (s *ElectionSuite) TestGetElection404sForUnknownElection(c *C) {
	recorder := s.PerformRequest("GET", "/elections/1", "")

	c.Check(recorder.Code, Equals, 404)
}

func (s *ElectionSuite) TestListElectionsReturnsEmptyList(c *C) {
	recorder := s.PerformRequest("GET", "/elections", "")

	c.Check(recorder.Code, Equals, 200)
	c.Check(recorder.Body.String(), Equals, "[]")
}

func (s *ElectionSuite) TestListElectionsReturnsListOfCorrectLength(c *C) {
	election := Election{Name: "my test name"}
	other_election := Election{Name: "my other name"}
	third_election := Election{Name: "my third name"}
	s.dbmap.Insert(&election, &other_election, &third_election)

	recorder := s.PerformRequest("GET", "/elections", "")

	var electionList []Election
	json.Unmarshal(recorder.Body.Bytes(), &electionList)
	c.Check(len(electionList), Equals, 3)
}

func (s *ElectionSuite) TestListElectionReturnsExistingElections(c *C) {
	election := Election{Name: "my test name"}
	other_election := Election{Name: "my other name"}
	s.dbmap.Insert(&election, &other_election)

	recorder := s.PerformRequest("GET", "/elections", "")

	expectedElectionNames := map[string]int{
		"my test name":  0,
		"my other name": 0,
	}
	var electionList []Election
	json.Unmarshal(recorder.Body.Bytes(), &electionList)
	actualElectionNames := make(map[string]int)
	for _, election := range electionList {
		actualElectionNames[election.Name] = 0
	}
	c.Check(actualElectionNames, DeepEquals, expectedElectionNames)
}

type CandidatesSuite struct {
	PRSuite
}

func (s *CandidatesSuite) SetUpTest(c *C) {
	s.PRSuite.SetUpTest(c)

	// Set up test election
	election := Election{Name: "my test name"}
	err := s.dbmap.Insert(&election)
	if err != nil {
		c.Error(err)
	}

	s.createURL = fmt.Sprintf("/elections/%d/candidates", election.Id)
	s.tableName = "candidates"
}

var _ = Suite(&CandidatesSuite{})

func (s *CandidatesSuite) TestAddCandidateReturns404ForMissingElection(c *C) {
	recorder := s.PerformRequest("POST", "/elections/1234/candidates", `{"name": "Test Candidate"}`)

	c.Check(recorder.Code, Equals, 404)
}
<|endoftext|>


<commit_before>package httpexpect

import (
	"bytes"
	"fmt"
	"net/http"
	"net/http/httputil"
	"strings"
	"time"

	"github.com/gorilla/websocket"
	"moul.io/http2curl/v2"
)

// Printer is used to print requests and responses.
// CompactPrinter, DebugPrinter, and CurlPrinter implement this interface.
type Printer interface {
	// Request is called before request is sent.
	Request(*http.Request)

	// Response is called after response is received.
	Response(*http.Response, time.Duration)
}

// WebsocketPrinter is used to print writes and reads of WebSocket connection.
//
// If WebSocket connection is used, all Printers that also implement WebsocketPrinter
// are invoked on every WebSocket message read or written.
//
// DebugPrinter implements this interface.
type WebsocketPrinter interface {
	Printer

	// WebsocketWrite is called before writes to WebSocket connection.
	WebsocketWrite(typ int, content []byte, closeCode int)

	// WebsocketRead is called after reads from WebSocket connection.
	WebsocketRead(typ int, content []byte, closeCode int)
}

// CompactPrinter implements Printer.
// Prints requests in compact form. Does not print responses.
type CompactPrinter struct {
	logger Logger
}

// NewCompactPrinter returns a new CompactPrinter given a logger.
func NewCompactPrinter(logger Logger) CompactPrinter {
	return CompactPrinter{logger}
}

// Request implements Printer.Request.
func (p CompactPrinter) Request(req *http.Request) {
	if req != nil {
		p.logger.Logf("%s %s", req.Method, req.URL)
	}
}

// Response implements Printer.Response.
func (CompactPrinter) Response(*http.Response, time.Duration) {
}

// CurlPrinter implements Printer.
// Uses http2curl to dump requests as curl commands that can be inserted
// into terminal.
type CurlPrinter struct {
	logger Logger
}

// NewCurlPrinter returns a new CurlPrinter given a logger.
func NewCurlPrinter(logger Logger) CurlPrinter {
	return CurlPrinter{logger}
}

// Request implements Printer.Request.
func (p CurlPrinter) Request(req *http.Request) {
	if req != nil {
		cmd, err := http2curl.GetCurlCommand(req)
		if err != nil {
			panic(err)
		}
		p.logger.Logf("%s", cmd.String())
	}
}

// Response implements Printer.Response.
func (CurlPrinter) Response(*http.Response, time.Duration) {
}

// DebugPrinter implements Printer and WebsocketPrinter.
// Uses net/http/httputil to dump both requests and responses.
// Also prints all websocket messages.
type DebugPrinter struct {
	logger Logger
	body   bool
}

// NewDebugPrinter returns a new DebugPrinter given a logger and body
// flag. If body is true, request and response body is also printed.
func NewDebugPrinter(logger Logger, body bool) DebugPrinter {
	return DebugPrinter{logger, body}
}

// Request implements Printer.Request.
func (p DebugPrinter) Request(req *http.Request) {
	if req == nil {
		return
	}

	dump, err := httputil.DumpRequest(req, p.body)
	if err != nil {
		panic(err)
	}
	p.logger.Logf("%s", dump)
}

// Response implements Printer.Response.
func (p DebugPrinter) Response(resp *http.Response, duration time.Duration) {
	if resp == nil {
		return
	}

	dump, err := httputil.DumpResponse(resp, p.body)
	if err != nil {
		panic(err)
	}

	text := strings.Replace(string(dump), "\r\n", "\n", -1)
	lines := strings.SplitN(text, "\n", 2)

	p.logger.Logf("%s %s\n%s", lines[0], duration, lines[1])
}

// WebsocketWrite implements WebsocketPrinter.WebsocketWrite.
func (p DebugPrinter) WebsocketWrite(typ int, content []byte, closeCode int) {
	b := &bytes.Buffer{}
	fmt.Fprintf(b, "-> Sent: %s", wsMessageType(typ))
	if typ == websocket.CloseMessage {
		fmt.Fprintf(b, " %s", wsCloseCode(closeCode))
	}
	fmt.Fprint(b, "\n")
	if len(content) > 0 {
		if typ == websocket.BinaryMessage {
			fmt.Fprintf(b, "%v\n", content)
		} else {
			fmt.Fprintf(b, "%s\n", content)
		}
	}
	fmt.Fprintf(b, "\n")
	p.logger.Logf(b.String())
}

// WebsocketRead implements WebsocketPrinter.WebsocketRead.
func (p DebugPrinter) WebsocketRead(typ int, content []byte, closeCode int) {
	b := &bytes.Buffer{}
	fmt.Fprintf(b, "<- Received: %s", wsMessageType(typ))
	if typ == websocket.CloseMessage {
		fmt.Fprintf(b, " %s", wsCloseCode(closeCode))
	}
	fmt.Fprint(b, "\n")
	if len(content) > 0 {
		if typ == websocket.BinaryMessage {
			fmt.Fprintf(b, "%v\n", content)
		} else {
			fmt.Fprintf(b, "%s\n", content)
		}
	}
	fmt.Fprintf(b, "\n")
	p.logger.Logf(b.String())
}
<commit_msg>Add comment<commit_after>package httpexpect

import (
	"bytes"
	"fmt"
	"net/http"
	"net/http/httputil"
	"strings"
	"time"

	"github.com/gorilla/websocket"
	"moul.io/http2curl/v2"
)

// Printer is used to print requests and responses.
// CompactPrinter, DebugPrinter, and CurlPrinter implement this interface.
type Printer interface {
	// Request is called before request is sent.
	// It is allowed to read and close request body, or ignore it.
	Request(*http.Request)

	// Response is called after response is received.
	// It is allowed to read and close response body, or ignore it.
	Response(*http.Response, time.Duration)
}

// WebsocketPrinter is used to print writes and reads of WebSocket connection.
//
// If WebSocket connection is used, all Printers that also implement WebsocketPrinter
// are invoked on every WebSocket message read or written.
//
// DebugPrinter implements this interface.
type WebsocketPrinter interface {
	Printer

	// WebsocketWrite is called before writes to WebSocket connection.
	WebsocketWrite(typ int, content []byte, closeCode int)

	// WebsocketRead is called after reads from WebSocket connection.
	WebsocketRead(typ int, content []byte, closeCode int)
}

// CompactPrinter implements Printer.
// Prints requests in compact form. Does not print responses.
type CompactPrinter struct {
	logger Logger
}

// NewCompactPrinter returns a new CompactPrinter given a logger.
func NewCompactPrinter(logger Logger) CompactPrinter {
	return CompactPrinter{logger}
}

// Request implements Printer.Request.
func (p CompactPrinter) Request(req *http.Request) {
	if req != nil {
		p.logger.Logf("%s %s", req.Method, req.URL)
	}
}

// Response implements Printer.Response.
func (CompactPrinter) Response(*http.Response, time.Duration) {
}

// CurlPrinter implements Printer.
// Uses http2curl to dump requests as curl commands that can be inserted
// into terminal.
type CurlPrinter struct {
	logger Logger
}

// NewCurlPrinter returns a new CurlPrinter given a logger.
func NewCurlPrinter(logger Logger) CurlPrinter {
	return CurlPrinter{logger}
}

// Request implements Printer.Request.
func (p CurlPrinter) Request(req *http.Request) {
	if req != nil {
		cmd, err := http2curl.GetCurlCommand(req)
		if err != nil {
			panic(err)
		}
		p.logger.Logf("%s", cmd.String())
	}
}

// Response implements Printer.Response.
func (CurlPrinter) Response(*http.Response, time.Duration) {
}

// DebugPrinter implements Printer and WebsocketPrinter.
// Uses net/http/httputil to dump both requests and responses.
// Also prints all websocket messages.
type DebugPrinter struct {
	logger Logger
	body   bool
}

// NewDebugPrinter returns a new DebugPrinter given a logger and body
// flag. If body is true, request and response body is also printed.
func NewDebugPrinter(logger Logger, body bool) DebugPrinter {
	return DebugPrinter{logger, body}
}

// Request implements Printer.Request.
func (p DebugPrinter) Request(req *http.Request) {
	if req == nil {
		return
	}

	dump, err := httputil.DumpRequest(req, p.body)
	if err != nil {
		panic(err)
	}
	p.logger.Logf("%s", dump)
}

// Response implements Printer.Response.
func (p DebugPrinter) Response(resp *http.Response, duration time.Duration) {
	if resp == nil {
		return
	}

	dump, err := httputil.DumpResponse(resp, p.body)
	if err != nil {
		panic(err)
	}

	text := strings.Replace(string(dump), "\r\n", "\n", -1)
	lines := strings.SplitN(text, "\n", 2)

	p.logger.Logf("%s %s\n%s", lines[0], duration, lines[1])
}

// WebsocketWrite implements WebsocketPrinter.WebsocketWrite.
func (p DebugPrinter) WebsocketWrite(typ int, content []byte, closeCode int) {
	b := &bytes.Buffer{}
	fmt.Fprintf(b, "-> Sent: %s", wsMessageType(typ))
	if typ == websocket.CloseMessage {
		fmt.Fprintf(b, " %s", wsCloseCode(closeCode))
	}
	fmt.Fprint(b, "\n")
	if len(content) > 0 {
		if typ == websocket.BinaryMessage {
			fmt.Fprintf(b, "%v\n", content)
		} else {
			fmt.Fprintf(b, "%s\n", content)
		}
	}
	fmt.Fprintf(b, "\n")
	p.logger.Logf(b.String())
}

// WebsocketRead implements WebsocketPrinter.WebsocketRead.
func (p DebugPrinter) WebsocketRead(typ int, content []byte, closeCode int) {
	b := &bytes.Buffer{}
	fmt.Fprintf(b, "<- Received: %s", wsMessageType(typ))
	if typ == websocket.CloseMessage {
		fmt.Fprintf(b, " %s", wsCloseCode(closeCode))
	}
	fmt.Fprint(b, "\n")
	if len(content) > 0 {
		if typ == websocket.BinaryMessage {
			fmt.Fprintf(b, "%v\n", content)
		} else {
			fmt.Fprintf(b, "%s\n", content)
		}
	}
	fmt.Fprintf(b, "\n")
	p.logger.Logf(b.String())
}
<|endoftext|>


<commit_before>package main

import (
	"ircconn"
	"ircmsg"
	//	"fmt"
)

var server_lines= []string{
	":fu-berlin.de 020 * :Please wait while we process your connection.",
	":fu-berlin.de 001 osntauohe :Welcome to the Internet Relay Network osntauohe!~osntauohe@176.99.114.122",
	":fu-berlin.de 002 osntauohe :Your host is fu-berlin.de, running version 2.11.2p2",
	":fu-berlin.de 003 osntauohe :This server was created Wed Dec 8 2010 at 17:45:14 CET",
	":fu-berlin.de 004 osntauohe fu-berlin.de 2.11.2p2 aoOirw abeiIklmnoOpqrRstv",
	":fu-berlin.de 005 osntauohe RFC2812 PREFIX=(ov)@+ CHANTYPES=#&!+ MODES=3 CHANLIMIT=#&!+:21 NICKLEN=15 TOPICLEN=255 KICKLEN=255 MAXLIST=beIR:64 CHANNELLEN=50 IDCHAN=!:5 CHANMODES=beIR,k,l,imnpstaqr :are supported by this server",
	":fu-berlin.de 005 osntauohe PENALTY FNC EXCEPTS=e INVEX=I CASEMAPPING=ascii NETWORK=IRCnet :are supported by this server",
	":fu-berlin.de 042 osntauohe 276BAY2UY :your unique ID",
	":fu-berlin.de 251 osntauohe :There are 61364 users and 7 services on 30 servers",
	":fu-berlin.de 252 osntauohe 109 :operators online",
	":fu-berlin.de 254 osntauohe 34263 :channels formed",
	":fu-berlin.de 255 osntauohe :I have 1547 users, 1 services and 1 servers",
	":fu-berlin.de 265 osntauohe 1547 1864 :Current local users 1547, max 1864",
	":fu-berlin.de 266 osntauohe 61364 77287 :Current global users 61364, max 77287",
	":fu-berlin.de 375 osntauohe :- fu-berlin.de Message of the Day - ",
	":fu-berlin.de 372 osntauohe :- 8/12/2010 17:33",
	":fu-berlin.de 372 osntauohe :- ",
	":fu-berlin.de 372 osntauohe :- Willkommen auf dem IRCnet-Server der Freien Universitaet Berlin, ZEDAT",
	":fu-berlin.de 372 osntauohe :- ",
	":fu-berlin.de 372 osntauohe :-    Verbindliche Benutzungsregeln und weitere Informationen gibt es ",
	":fu-berlin.de 372 osntauohe :-    unter http://irc.fu-berlin.de",
	":fu-berlin.de 372 osntauohe :- ",
	":fu-berlin.de 372 osntauohe :-                                                                       ",
	":fu-berlin.de 372 osntauohe :- ",
	":fu-berlin.de 372 osntauohe :- Viel Spass wuenschen",
	":fu-berlin.de 372 osntauohe :- ",
	":fu-berlin.de 372 osntauohe :- Oliver 'ob' Brandmueller, Timo 'fuechsle' Fuchs, Tanja 'tawi' Wittke",
	":fu-berlin.de 372 osntauohe :- ",
	":fu-berlin.de 376 osntauohe :End of MOTD command.",
}

func main() {
	for _, line := range server_lines {
		ircmsg.ParseServerLine(line)
	}
	s := ircconn.NewIRCConn()
	s.Connect("localhost:6667")
	s.Output <- "Hello, world\n"
	s.Output <- "Asdf!\n"
	s.Quit()
	//	go output_channel(serverData)
	//	for {
	//		fmt.Scanln(st)
	//		clientInput <- st
	//	}
}

func output_channel(c <-chan string) {
	//	for {
	//		s := <- c
	//		fmt.Println("-> " + s)
	//	}
}
<commit_msg>Fix new main<commit_after>package main

import (
	"ircclient"
)

var server_lines= []string{
	":fu-berlin.de 020 * :Please wait while we process your connection.",
	":fu-berlin.de 001 osntauohe :Welcome to the Internet Relay Network osntauohe!~osntauohe@176.99.114.122",
	":fu-berlin.de 002 osntauohe :Your host is fu-berlin.de, running version 2.11.2p2",
	":fu-berlin.de 003 osntauohe :This server was created Wed Dec 8 2010 at 17:45:14 CET",
	":fu-berlin.de 004 osntauohe fu-berlin.de 2.11.2p2 aoOirw abeiIklmnoOpqrRstv",
	":fu-berlin.de 005 osntauohe RFC2812 PREFIX=(ov)@+ CHANTYPES=#&!+ MODES=3 CHANLIMIT=#&!+:21 NICKLEN=15 TOPICLEN=255 KICKLEN=255 MAXLIST=beIR:64 CHANNELLEN=50 IDCHAN=!:5 CHANMODES=beIR,k,l,imnpstaqr :are supported by this server",
	":fu-berlin.de 005 osntauohe PENALTY FNC EXCEPTS=e INVEX=I CASEMAPPING=ascii NETWORK=IRCnet :are supported by this server",
	":fu-berlin.de 042 osntauohe 276BAY2UY :your unique ID",
	":fu-berlin.de 251 osntauohe :There are 61364 users and 7 services on 30 servers",
	":fu-berlin.de 252 osntauohe 109 :operators online",
	":fu-berlin.de 254 osntauohe 34263 :channels formed",
	":fu-berlin.de 255 osntauohe :I have 1547 users, 1 services and 1 servers",
	":fu-berlin.de 265 osntauohe 1547 1864 :Current local users 1547, max 1864",
	":fu-berlin.de 266 osntauohe 61364 77287 :Current global users 61364, max 77287",
	":fu-berlin.de 375 osntauohe :- fu-berlin.de Message of the Day - ",
	":fu-berlin.de 372 osntauohe :- 8/12/2010 17:33",
	":fu-berlin.de 372 osntauohe :- ",
	":fu-berlin.de 372 osntauohe :- Willkommen auf dem IRCnet-Server der Freien Universitaet Berlin, ZEDAT",
	":fu-berlin.de 372 osntauohe :- ",
	":fu-berlin.de 372 osntauohe :-    Verbindliche Benutzungsregeln und weitere Informationen gibt es ",
	":fu-berlin.de 372 osntauohe :-    unter http://irc.fu-berlin.de",
	":fu-berlin.de 372 osntauohe :- ",
	":fu-berlin.de 372 osntauohe :-                                                                       ",
	":fu-berlin.de 372 osntauohe :- ",
	":fu-berlin.de 372 osntauohe :- Viel Spass wuenschen",
	":fu-berlin.de 372 osntauohe :- ",
	":fu-berlin.de 372 osntauohe :- Oliver 'ob' Brandmueller, Timo 'fuechsle' Fuchs, Tanja 'tawi' Wittke",
	":fu-berlin.de 372 osntauohe :- ",
	":fu-berlin.de 376 osntauohe :End of MOTD command.",
}

func main() {
	for _, line := range server_lines {
		ircclient.ParseServerLine(line)
	}
	s := ircclient.NewIRCConn()
	s.Connect("localhost:6667")
	s.Output <- "Hello, world\n"
	s.Output <- "Asdf!\n"
	s.Quit()
	//	go output_channel(serverData)
	//	for {
	//		fmt.Scanln(st)
	//		clientInput <- st
	//	}
}

func output_channel(c <-chan string) {
	//	for {
	//		s := <- c
	//		fmt.Println("-> " + s)
	//	}
}
<|endoftext|>