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

package docker

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/globocom/config"
	"github.com/globocom/tsuru/fs"
	"github.com/globocom/tsuru/log"
	"github.com/globocom/tsuru/provision"
	"github.com/globocom/tsuru/repository"
	"io"
	"io/ioutil"
	"labix.org/v2/mgo/bson"
	"os"
	"os/user"
	"path"
	"strings"
)

var fsystem fs.Fs

func filesystem() fs.Fs {
	if fsystem == nil {
		fsystem = fs.OsFs{}
	}
	return fsystem
}

// runCmd executes commands and log the given stdout and stderror.
func runCmd(cmd string, args ...string) (string, error) {
	out := bytes.Buffer{}
	err := executor().Execute(cmd, args, nil, &out, &out)
	log.Printf("running the cmd: %s with the args: %s", cmd, args)
	return out.String(), err
}

func getSSHCommands() ([]string, error) {
	addKeyCommand, err := config.GetString("docker:ssh:add-key-cmd")
	if err != nil {
		return nil, err
	}
	keyFile, err := config.GetString("docker:ssh:public-key")
	if err != nil {
		if u, err := user.Current(); err == nil {
			keyFile = path.Join(u.HomeDir, ".ssh", "id_rsa.pub")
		} else {
			keyFile = os.ExpandEnv("${HOME}/.ssh/id_rsa.pub")
		}
	}
	f, err := filesystem().Open(keyFile)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	keyContent, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}
	sshdPath, err := config.GetString("docker:ssh:sshd-path")
	if err != nil {
		sshdPath = "/usr/sbin/sshd"
	}
	return []string{
		fmt.Sprintf("%s %s", addKeyCommand, bytes.TrimSpace(keyContent)),
		sshdPath,
	}, nil
}

func commandToRun(app provision.App) ([]string, error) {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		return nil, err
	}
	repoNamespace, err := config.GetString("docker:repository-namespace")
	if err != nil {
		return nil, err
	}
	port, err := config.GetString("docker:run-cmd:port")
	if err != nil {
		return nil, err
	}
	commands, err := getSSHCommands()
	if err != nil {
		return nil, err
	}
	imageName := fmt.Sprintf("%s/%s", repoNamespace, app.GetPlatform()) // TODO (flaviamissi): should use same algorithm as image.repositoryName
	containerCmd := strings.Join(commands, " && ")
	wholeCmd := []string{docker, "run", "-d", "-t", "-p", port, imageName, "/bin/bash", "-c", containerCmd}
	return wholeCmd, nil
}

func getPort() (string, error) {
	return config.GetString("docker:run-cmd:port")
}

type container struct {
	Id      string `bson:"_id"`
	AppName string
	Type    string
	Ip      string
	Port    string
}

// newContainer creates a new container in Docker and stores it in the database.
//
// TODO (flaviamissi): make it atomic
func newContainer(app provision.App) (*container, error) {
	appName := app.GetName()
	c := container{
		AppName: appName,
		Type:    app.GetPlatform(),
	}
	err := c.create(app)
	if err != nil {
		log.Printf("Error creating container %s", appName)
		log.Printf("Error was: %s", err.Error())
		return nil, err
	}
	return &c, nil
}

func (c *container) inspect() (map[string]interface{}, error) {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		return nil, err
	}
	out, err := runCmd(docker, "inspect", c.Id)
	if err != nil {
		return nil, err
	}
	var r map[string]interface{}
	err = json.Unmarshal([]byte(out), &r)
	if err != nil {
		return nil, err
	}
	return r, nil
}

// hostPort returns the host port mapped for the container.
func (c *container) hostPort() (string, error) {
	if c.Port == "" {
		return "", errors.New("Container does not contain any mapped port")
	}
	data, err := c.inspect()
	if err != nil {
		return "", err
	}
	mappedPorts := data["NetworkSettings"].(map[string]interface{})["PortMapping"].(map[string]interface{})
	if port, ok := mappedPorts[c.Port]; ok {
		return port.(string), nil
	}
	return "", fmt.Errorf("Container port %s is not mapped to any host port", c.Port)
}

// ip returns the ip for the container.
func (c *container) ip() (string, error) {
	result, err := c.inspect()
	if err != nil {
		msg := fmt.Sprintf("error(%s) parsing json from docker when trying to get ipaddress", err)
		log.Print(msg)
		return "", errors.New(msg)
	}
	if ns, ok := result["NetworkSettings"]; !ok || ns == nil {
		msg := "Error when getting container information. NetworkSettings is missing."
		log.Print(msg)
		return "", errors.New(msg)
	}
	networkSettings := result["NetworkSettings"].(map[string]interface{})
	instanceIp := networkSettings["IpAddress"].(string)
	if instanceIp == "" {
		msg := "error: Can't get ipaddress..."
		log.Print(msg)
		return "", errors.New(msg)
	}
	log.Printf("Instance IpAddress: %s", instanceIp)
	return instanceIp, nil
}

// create creates a docker container, stores it on the database and adds a route to it.
//
// It receives the related application in order to choose the correct
// docker image and the repository to pass to the script that will take
// care of the deploy, and a function to generate the correct command ran by
// docker, which might be to deploy a container or to run and expose a
// container for an application.
func (c *container) create(app provision.App) error {
	hostAddr, err := config.Get("docker:host-address")
	if err != nil {
		return err
	}
	cmd, err := commandToRun(app)
	if err != nil {
		return err
	}
	port, err := getPort()
	if err != nil {
		return err
	}
	id, err := runCmd(cmd[0], cmd[1:]...)
	if err != nil {
		return err
	}
	id = strings.TrimSpace(id)
	log.Printf("docker id=%s", id)
	c.Id = strings.TrimSpace(id)
	c.Port = port
	ip, err := c.ip()
	if err != nil {
		return err
	}
	c.Ip = ip
	coll := collection()
	defer coll.Database.Session.Close()
	if err := coll.Insert(c); err != nil {
		log.Print(err)
		return err
	}
	r, err := getRouter()
	if err != nil {
		return err
	}
	hostPort, err := c.hostPort()
	if err != nil {
		hostPort = c.Port
	}
	return r.AddRoute(app.GetName(), fmt.Sprintf("http://%s:%s", hostAddr, hostPort))
}

func (c *container) deploy(w io.Writer) error {
	deployCmd, err := config.GetString("docker:deploy-cmd")
	if err != nil {
		return err
	}
	runBin, err := config.GetString("docker:run-cmd:bin")
	if err != nil {
		return err
	}
	runArgs, err := config.GetString("docker:run-cmd:args")
	if err != nil {
		return err
	}
	err = c.ssh(w, w, deployCmd, repository.GetReadOnlyUrl(c.AppName))
	if err != nil {
		return err
	}
	return c.ssh(w, w, runBin, strings.Fields(runArgs)...)
}

// start starts a docker container.
func (c *container) start() error {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		return err
	}
	log.Printf("Stating container %s", c.Id)
	out, err := runCmd(docker, "start", c.Id)
	log.Printf("docker start output: %s", out)
	return err
}

// stop stops a docker container.
func (c *container) stop() error {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		return err
	}
	//TODO: better error handling
	log.Printf("Stopping container %s", c.Id)
	output, err := runCmd(docker, "stop", c.Id)
	log.Printf("docker stop output: %s", output)
	return err
}

// remove removes a docker container.
func (c *container) remove() error {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		return err
	}
	log.Printf("Removing container %s from docker", c.Id)
	out, err := runCmd(docker, "rm", c.Id)
	if err != nil {
		log.Printf("Failed to remove container from docker: %s", err.Error())
		log.Printf("Command output: %s", out)
		return err
	}
	log.Printf("Removing container %s from database", c.Id)
	coll := collection()
	defer coll.Database.Session.Close()
	if err := coll.RemoveId(c.Id); err != nil {
		log.Printf("Failed to remove container from database: %s", err.Error())
		return err
	}
	r, err := getRouter()
	if err != nil {
		log.Printf("Failed to obtain router: %s", err.Error())
		return err
	}
	if err := r.RemoveRoute(c.AppName); err != nil {
		log.Printf("Failed to remove route: %s", err.Error())
		return err
	}
	return nil
}

func (c *container) ssh(stdout, stderr io.Writer, cmd string, args ...string) error {
	user, err := config.GetString("docker:ssh:user")
	if err != nil {
		return err
	}
	sshArgs := []string{c.Ip, "-l", user, "-o", "StrictHostKeyChecking no"}
	if keyFile, err := config.GetString("docker:ssh:private-key"); err == nil {
		sshArgs = append(sshArgs, "-i", keyFile)
	}
	sshArgs = append(sshArgs, "--", cmd)
	sshArgs = append(sshArgs, args...)
	return executor().Execute("ssh", sshArgs, nil, stdout, stderr)
}

// image represents a docker image.
type image struct {
	Name string
	Id   string
}

// repositoryName returns the image repository name for a given image.
//
// Repository is a docker concept, the image actually does not have a name,
// it has a repository, that is a composed name, e.g.: tsuru/base.
// Tsuru will always use a namespace, defined in tsuru.conf.
// Additionally, tsuru will use the application's name to do that composition.
func (img *image) repositoryName() string {
	repoNamespace, err := config.GetString("docker:repository-namespace")
	if err != nil {
		log.Printf("Tsuru is misconfigured. docker:repository-namespace config is missing.")
		return ""
	}
	return fmt.Sprintf("%s/%s", repoNamespace, img.Name)
}

// commit commits an image in docker
//
// This is another docker concept, in order to generate an image from a container
// one must commit it.
func (img *image) commit(cId string) (string, error) {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		log.Printf("Tsuru is misconfigured. docker:binary config is missing.")
		return "", err
	}
	log.Printf("attempting to commit image from container %s", cId)
	rName := img.repositoryName()
	id, err := runCmd(docker, "commit", cId, rName)
	if err != nil {
		log.Printf("Could not commit docker image: %s", err.Error())
		return "", err
	}
	img.Id = strings.Replace(id, "\n", "", -1)
	if err := imagesCollection().Insert(&img); err != nil {
		log.Printf("Could not store image information %s", err.Error())
		return "", err
	}
	return img.Id, nil
}

// remove removes an image from docker registry
func (img *image) remove() error {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		log.Printf("Tsuru is misconfigured. docker:binary config is missing.")
		return err
	}
	log.Printf("attempting to remove image %s from docker", img.repositoryName())
	_, err = runCmd(docker, "rmi", img.Id)
	if err != nil {
		log.Printf("Could not remove image %s from docker: %s", img.Id, err.Error())
		return err
	}
	err = imagesCollection().Remove(bson.M{"name": img.Name})
	if err != nil {
		log.Printf("Could not remove image %s from mongo: %s", img.Id, err.Error())
		return err
	}
	return nil
}

func getContainer(id string) (*container, error) {
	var c container
	coll := collection()
	defer coll.Database.Session.Close()
	err := coll.Find(bson.M{"_id": id}).One(&c)
	if err != nil {
		return nil, err
	}
	return &c, nil
}

func getContainers(appName string) ([]container, error) {
	var containers []container
	err := collection().Find(bson.M{"appname": appName}).All(&containers)
	return containers, err
}
<commit_msg>provision/docker: don't require docker:run-cmd:args on container.deploy<commit_after>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package docker

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/globocom/config"
	"github.com/globocom/tsuru/fs"
	"github.com/globocom/tsuru/log"
	"github.com/globocom/tsuru/provision"
	"github.com/globocom/tsuru/repository"
	"io"
	"io/ioutil"
	"labix.org/v2/mgo/bson"
	"os"
	"os/user"
	"path"
	"strings"
)

var fsystem fs.Fs

func filesystem() fs.Fs {
	if fsystem == nil {
		fsystem = fs.OsFs{}
	}
	return fsystem
}

// runCmd executes commands and log the given stdout and stderror.
func runCmd(cmd string, args ...string) (string, error) {
	out := bytes.Buffer{}
	err := executor().Execute(cmd, args, nil, &out, &out)
	log.Printf("running the cmd: %s with the args: %s", cmd, args)
	return out.String(), err
}

func getSSHCommands() ([]string, error) {
	addKeyCommand, err := config.GetString("docker:ssh:add-key-cmd")
	if err != nil {
		return nil, err
	}
	keyFile, err := config.GetString("docker:ssh:public-key")
	if err != nil {
		if u, err := user.Current(); err == nil {
			keyFile = path.Join(u.HomeDir, ".ssh", "id_rsa.pub")
		} else {
			keyFile = os.ExpandEnv("${HOME}/.ssh/id_rsa.pub")
		}
	}
	f, err := filesystem().Open(keyFile)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	keyContent, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}
	sshdPath, err := config.GetString("docker:ssh:sshd-path")
	if err != nil {
		sshdPath = "/usr/sbin/sshd"
	}
	return []string{
		fmt.Sprintf("%s %s", addKeyCommand, bytes.TrimSpace(keyContent)),
		sshdPath,
	}, nil
}

func commandToRun(app provision.App) ([]string, error) {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		return nil, err
	}
	repoNamespace, err := config.GetString("docker:repository-namespace")
	if err != nil {
		return nil, err
	}
	port, err := config.GetString("docker:run-cmd:port")
	if err != nil {
		return nil, err
	}
	commands, err := getSSHCommands()
	if err != nil {
		return nil, err
	}
	imageName := fmt.Sprintf("%s/%s", repoNamespace, app.GetPlatform()) // TODO (flaviamissi): should use same algorithm as image.repositoryName
	containerCmd := strings.Join(commands, " && ")
	wholeCmd := []string{docker, "run", "-d", "-t", "-p", port, imageName, "/bin/bash", "-c", containerCmd}
	return wholeCmd, nil
}

func getPort() (string, error) {
	return config.GetString("docker:run-cmd:port")
}

type container struct {
	Id      string `bson:"_id"`
	AppName string
	Type    string
	Ip      string
	Port    string
}

// newContainer creates a new container in Docker and stores it in the database.
//
// TODO (flaviamissi): make it atomic
func newContainer(app provision.App) (*container, error) {
	appName := app.GetName()
	c := container{
		AppName: appName,
		Type:    app.GetPlatform(),
	}
	err := c.create(app)
	if err != nil {
		log.Printf("Error creating container %s", appName)
		log.Printf("Error was: %s", err.Error())
		return nil, err
	}
	return &c, nil
}

func (c *container) inspect() (map[string]interface{}, error) {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		return nil, err
	}
	out, err := runCmd(docker, "inspect", c.Id)
	if err != nil {
		return nil, err
	}
	var r map[string]interface{}
	err = json.Unmarshal([]byte(out), &r)
	if err != nil {
		return nil, err
	}
	return r, nil
}

// hostPort returns the host port mapped for the container.
func (c *container) hostPort() (string, error) {
	if c.Port == "" {
		return "", errors.New("Container does not contain any mapped port")
	}
	data, err := c.inspect()
	if err != nil {
		return "", err
	}
	mappedPorts := data["NetworkSettings"].(map[string]interface{})["PortMapping"].(map[string]interface{})
	if port, ok := mappedPorts[c.Port]; ok {
		return port.(string), nil
	}
	return "", fmt.Errorf("Container port %s is not mapped to any host port", c.Port)
}

// ip returns the ip for the container.
func (c *container) ip() (string, error) {
	result, err := c.inspect()
	if err != nil {
		msg := fmt.Sprintf("error(%s) parsing json from docker when trying to get ipaddress", err)
		log.Print(msg)
		return "", errors.New(msg)
	}
	if ns, ok := result["NetworkSettings"]; !ok || ns == nil {
		msg := "Error when getting container information. NetworkSettings is missing."
		log.Print(msg)
		return "", errors.New(msg)
	}
	networkSettings := result["NetworkSettings"].(map[string]interface{})
	instanceIp := networkSettings["IpAddress"].(string)
	if instanceIp == "" {
		msg := "error: Can't get ipaddress..."
		log.Print(msg)
		return "", errors.New(msg)
	}
	log.Printf("Instance IpAddress: %s", instanceIp)
	return instanceIp, nil
}

// create creates a docker container, stores it on the database and adds a route to it.
//
// It receives the related application in order to choose the correct
// docker image and the repository to pass to the script that will take
// care of the deploy, and a function to generate the correct command ran by
// docker, which might be to deploy a container or to run and expose a
// container for an application.
func (c *container) create(app provision.App) error {
	hostAddr, err := config.Get("docker:host-address")
	if err != nil {
		return err
	}
	cmd, err := commandToRun(app)
	if err != nil {
		return err
	}
	port, err := getPort()
	if err != nil {
		return err
	}
	id, err := runCmd(cmd[0], cmd[1:]...)
	if err != nil {
		return err
	}
	id = strings.TrimSpace(id)
	log.Printf("docker id=%s", id)
	c.Id = strings.TrimSpace(id)
	c.Port = port
	ip, err := c.ip()
	if err != nil {
		return err
	}
	c.Ip = ip
	coll := collection()
	defer coll.Database.Session.Close()
	if err := coll.Insert(c); err != nil {
		log.Print(err)
		return err
	}
	r, err := getRouter()
	if err != nil {
		return err
	}
	hostPort, err := c.hostPort()
	if err != nil {
		hostPort = c.Port
	}
	return r.AddRoute(app.GetName(), fmt.Sprintf("http://%s:%s", hostAddr, hostPort))
}

func (c *container) deploy(w io.Writer) error {
	deployCmd, err := config.GetString("docker:deploy-cmd")
	if err != nil {
		return err
	}
	runBin, err := config.GetString("docker:run-cmd:bin")
	if err != nil {
		return err
	}
	runArgs, _ := config.GetString("docker:run-cmd:args")
	err = c.ssh(w, w, deployCmd, repository.GetReadOnlyUrl(c.AppName))
	if err != nil {
		return err
	}
	return c.ssh(w, w, runBin, strings.Fields(runArgs)...)
}

// start starts a docker container.
func (c *container) start() error {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		return err
	}
	log.Printf("Stating container %s", c.Id)
	out, err := runCmd(docker, "start", c.Id)
	log.Printf("docker start output: %s", out)
	return err
}

// stop stops a docker container.
func (c *container) stop() error {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		return err
	}
	//TODO: better error handling
	log.Printf("Stopping container %s", c.Id)
	output, err := runCmd(docker, "stop", c.Id)
	log.Printf("docker stop output: %s", output)
	return err
}

// remove removes a docker container.
func (c *container) remove() error {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		return err
	}
	log.Printf("Removing container %s from docker", c.Id)
	out, err := runCmd(docker, "rm", c.Id)
	if err != nil {
		log.Printf("Failed to remove container from docker: %s", err.Error())
		log.Printf("Command output: %s", out)
		return err
	}
	log.Printf("Removing container %s from database", c.Id)
	coll := collection()
	defer coll.Database.Session.Close()
	if err := coll.RemoveId(c.Id); err != nil {
		log.Printf("Failed to remove container from database: %s", err.Error())
		return err
	}
	r, err := getRouter()
	if err != nil {
		log.Printf("Failed to obtain router: %s", err.Error())
		return err
	}
	if err := r.RemoveRoute(c.AppName); err != nil {
		log.Printf("Failed to remove route: %s", err.Error())
		return err
	}
	return nil
}

func (c *container) ssh(stdout, stderr io.Writer, cmd string, args ...string) error {
	user, err := config.GetString("docker:ssh:user")
	if err != nil {
		return err
	}
	sshArgs := []string{c.Ip, "-l", user, "-o", "StrictHostKeyChecking no"}
	if keyFile, err := config.GetString("docker:ssh:private-key"); err == nil {
		sshArgs = append(sshArgs, "-i", keyFile)
	}
	sshArgs = append(sshArgs, "--", cmd)
	sshArgs = append(sshArgs, args...)
	return executor().Execute("ssh", sshArgs, nil, stdout, stderr)
}

// image represents a docker image.
type image struct {
	Name string
	Id   string
}

// repositoryName returns the image repository name for a given image.
//
// Repository is a docker concept, the image actually does not have a name,
// it has a repository, that is a composed name, e.g.: tsuru/base.
// Tsuru will always use a namespace, defined in tsuru.conf.
// Additionally, tsuru will use the application's name to do that composition.
func (img *image) repositoryName() string {
	repoNamespace, err := config.GetString("docker:repository-namespace")
	if err != nil {
		log.Printf("Tsuru is misconfigured. docker:repository-namespace config is missing.")
		return ""
	}
	return fmt.Sprintf("%s/%s", repoNamespace, img.Name)
}

// commit commits an image in docker
//
// This is another docker concept, in order to generate an image from a container
// one must commit it.
func (img *image) commit(cId string) (string, error) {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		log.Printf("Tsuru is misconfigured. docker:binary config is missing.")
		return "", err
	}
	log.Printf("attempting to commit image from container %s", cId)
	rName := img.repositoryName()
	id, err := runCmd(docker, "commit", cId, rName)
	if err != nil {
		log.Printf("Could not commit docker image: %s", err.Error())
		return "", err
	}
	img.Id = strings.Replace(id, "\n", "", -1)
	if err := imagesCollection().Insert(&img); err != nil {
		log.Printf("Could not store image information %s", err.Error())
		return "", err
	}
	return img.Id, nil
}

// remove removes an image from docker registry
func (img *image) remove() error {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		log.Printf("Tsuru is misconfigured. docker:binary config is missing.")
		return err
	}
	log.Printf("attempting to remove image %s from docker", img.repositoryName())
	_, err = runCmd(docker, "rmi", img.Id)
	if err != nil {
		log.Printf("Could not remove image %s from docker: %s", img.Id, err.Error())
		return err
	}
	err = imagesCollection().Remove(bson.M{"name": img.Name})
	if err != nil {
		log.Printf("Could not remove image %s from mongo: %s", img.Id, err.Error())
		return err
	}
	return nil
}

func getContainer(id string) (*container, error) {
	var c container
	coll := collection()
	defer coll.Database.Session.Close()
	err := coll.Find(bson.M{"_id": id}).One(&c)
	if err != nil {
		return nil, err
	}
	return &c, nil
}

func getContainers(appName string) ([]container, error) {
	var containers []container
	err := collection().Find(bson.M{"appname": appName}).All(&containers)
	return containers, err
}
<|endoftext|>


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

package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"strings"
)

/*
canyon is a tool for making big splits. This assumes that you have a very large
changelist prepared in a single branch. canyon will then split up the large
change into multiple branches, by OWNERS file, and then will prepare a changelist
description.
*/

var (
	maxDepth = flag.Int("depth", 0, "The maximum subdirectory depth for which split branches should be created.")

	upstreamBranch = flag.String("upstream", "origin/master", "The upstream branch against which diffs are taken and new branches created.")

	splitByType = flag.String("split-by", "[dir|file]", "The method by which the branch is split.")

	splitByFile = flag.String("split-by-file", "", "If using -split-by=file, this the common file name by which split directories are found.")
)

func main() {
	flag.Parse()

	if err := validateDescription(); err != nil {
		fmt.Println("Please provide a valid -message for your branches. Error:", err)
		flag.Usage()
		os.Exit(1)
	}

	if *splitByType != "dir" || *splitByType != "file" {
		fmt.Println("Invalid -split-by type:", *splitByType)
		flag.Usage()
		os.Exit(1)
	}
	if *splitByType == "file" && *splitByFile == "" {
		fmt.Println("Whe using -split-by=file, a -split-by-file is needed.")
		flag.Usage()
		os.Exit(1)
	}

	branch := strings.TrimSpace(gitOrDie("symbolic-ref", "--short", "HEAD"))

	fmt.Printf("Split changelist on branch %q into sub-changelists? [y/N] ", branch)
	buf := make([]byte, 1)
	os.Stdin.Read(buf)
	if buf[0] != 'y' {
		fmt.Println("Exiting")
		return
	}

	log.Print("Gathering changed files")
	files := strings.Split(gitOrDie("diff", "--name-only", *upstreamBranch), "\n")

	log.Print("Splitting changed files into groups for changelists")
	cs := prepareChangeSet(branch, files)

	log.Print("Creating branches for splits")
	createBranches(cs)

	git("checkout", branch)
}

// git runs the specified git commands and returns the output as a string,
// blocking to completion.
func git(args ...string) (string, error) {
	cmd := exec.Command("git", args...)
	stdout, err := cmd.Output()
	if err != nil {
		return "", err
	}

	return string(stdout), nil
}

// gitOrDie runs the git command and panics on failure.
func gitOrDie(args ...string) string {
	r, e := git(args...)
	if e != nil {
		panic(e.Error())
	}
	return r
}

// prepareChangeSet creates a new changeset on |branch| and splits the |files|.
func prepareChangeSet(branch string, files []string) *changeSet {
	cs := newChangeSet(branch)
	for _, file := range files {
		if file == "" {
			continue
		}
		if *splitByType == "dir" {
			cs.splitByDir(file)
		} else if *splitByType == "file" {
			cs.splitByFile(*splitByFile, file)
		}
	}
	return cs
}

// createBranches creates branches as specified by the changeSet.
func createBranches(cs *changeSet) {
	for _, cl := range cs.splits {
		splitBranch := cl.branchName(cs.branch)
		log.Printf("Preparing branch %s", splitBranch)

		_, err := git("checkout", "-b", splitBranch, *upstreamBranch)
		if err != nil {
			log.Printf("Failed to create new branch %q: %v", splitBranch, err)
			continue
		}

		_, err = git("checkout", cs.branch, cl.base)
		if err != nil {
			log.Print("Failed to check out subdirectory from root branch")
			gitOrDie("reset", "--hard", *upstreamBranch)
			continue
		}

		_, err = git("commit", "-a", "-m", formatDescription(cl))
		if err != nil {
			log.Print("Failed to create subchangelist")
			gitOrDie("reset", "--hard", *upstreamBranch)
			continue
		}
	}
}
<commit_msg>Fix some typos and documentation.<commit_after>// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"strings"
)

/*
canyon is a tool for making big splits. This assumes that you have a very large
changelist prepared in a single branch. canyon will then split up the large
change into multiple branches and then will prepare a changelist description.
*/

var (
	maxDepth = flag.Int("depth", 0, "The maximum subdirectory depth for which split branches should be created. 0 is no depth limit.")

	upstreamBranch = flag.String("upstream", "origin/master", "The upstream branch against which diffs are taken and new branches created.")

	splitByType = flag.String("split-by", "[dir|file]", "The method by which the branch is split.")

	splitByFile = flag.String("split-by-file", "", "If using -split-by=file, this the common file name by which split directories are found.")
)

func main() {
	flag.Parse()

	if err := validateDescription(); err != nil {
		fmt.Println("Please provide a valid -message for your branches. Error:", err)
		flag.Usage()
		os.Exit(1)
	}

	if *splitByType != "dir" || *splitByType != "file" {
		fmt.Println("Invalid -split-by type:", *splitByType)
		flag.Usage()
		os.Exit(1)
	}
	if *splitByType == "file" && *splitByFile == "" {
		fmt.Println("When using -split-by=file, a -split-by-file is needed.")
		flag.Usage()
		os.Exit(1)
	}

	branch := strings.TrimSpace(gitOrDie("symbolic-ref", "--short", "HEAD"))

	fmt.Printf("Split changelist on branch %q into sub-changelists? [y/N] ", branch)
	buf := make([]byte, 1)
	os.Stdin.Read(buf)
	if buf[0] != 'y' {
		fmt.Println("Exiting")
		return
	}

	log.Print("Gathering changed files")
	files := strings.Split(gitOrDie("diff", "--name-only", *upstreamBranch), "\n")

	log.Print("Splitting changed files into groups for changelists")
	cs := prepareChangeSet(branch, files)

	log.Print("Creating branches for splits")
	createBranches(cs)

	git("checkout", branch)
}

// git runs the specified git commands and returns the output as a string,
// blocking to completion.
func git(args ...string) (string, error) {
	cmd := exec.Command("git", args...)
	stdout, err := cmd.Output()
	if err != nil {
		return "", err
	}

	return string(stdout), nil
}

// gitOrDie runs the git command and panics on failure.
func gitOrDie(args ...string) string {
	r, e := git(args...)
	if e != nil {
		panic(e.Error())
	}
	return r
}

// prepareChangeSet creates a new changeset on |branch| and splits the |files|.
func prepareChangeSet(branch string, files []string) *changeSet {
	cs := newChangeSet(branch)
	for _, file := range files {
		if file == "" {
			continue
		}
		if *splitByType == "dir" {
			cs.splitByDir(file)
		} else if *splitByType == "file" {
			cs.splitByFile(*splitByFile, file)
		}
	}
	return cs
}

// createBranches creates branches as specified by the changeSet.
func createBranches(cs *changeSet) {
	for _, cl := range cs.splits {
		splitBranch := cl.branchName(cs.branch)
		log.Printf("Preparing branch %s", splitBranch)

		_, err := git("checkout", "-b", splitBranch, *upstreamBranch)
		if err != nil {
			log.Printf("Failed to create new branch %q: %v", splitBranch, err)
			continue
		}

		_, err = git("checkout", cs.branch, cl.base)
		if err != nil {
			log.Print("Failed to check out subdirectory from root branch")
			gitOrDie("reset", "--hard", *upstreamBranch)
			continue
		}

		_, err = git("commit", "-a", "-m", formatDescription(cl))
		if err != nil {
			log.Print("Failed to create subchangelist")
			gitOrDie("reset", "--hard", *upstreamBranch)
			continue
		}
	}
}
<|endoftext|>


<commit_before>package operators

import (
	"errors"
	"fmt"

	"github.com/aurelien-rainone/evolve/number"
)

// Option is the interface implemented by objects configuring a
// particular option of a genetic operator.
type Option interface {
	Apply(interface{}) error
}

// ConstantProbability configures a constant probability that a genetic operator
// applies.
func ConstantProbability(prob number.Probability) probabilityGeneratorOption {
	return probabilityGeneratorOption{
		gen: number.NewConstantProbabilityGenerator(prob),
	}
}

// VariableProbability configures, via a number.ProbabilityGenerator, the
// probability that a genetic operator applies to an individual.
func VariableProbability(gen number.ProbabilityGenerator) probabilityGeneratorOption {
	return probabilityGeneratorOption{
		gen: gen,
	}
}

type probabilityGeneratorOption struct {
	gen number.ProbabilityGenerator
	err error
}

func (opt probabilityGeneratorOption) Apply(ope interface{}) error {
	switch ope.(type) {
	case *AbstractCrossover:
		if opt.err == nil {
			crossover := ope.(*AbstractCrossover)
			crossover.crossoverProbabilityVariable = opt.gen
		}
		return opt.err
	case *AbstractMutation:
		if opt.err == nil {
			mutation := ope.(*AbstractMutation)
			mutation.mutationProbability = opt.gen
		}
		return opt.err
	}
	return fmt.Errorf("can't apply option to object of type %T", ope)
}

// ConstantCrossoverPoints configures a constant number of crossover points.
//
// This option only applies to crossover operators.
func ConstantCrossoverPoints(points int64) integerGeneratorOption {
	var err error
	if points <= 0 {
		err = errors.New("number of crossover points must be positive")
	} else {
		err = nil
	}
	return integerGeneratorOption{
		gen: number.NewConstantIntegerGenerator(points),
		err: err,
	}
}

// VariableCrossoverPoints configures, via a number.IntegerGenerator, a
// crossover such as the number of crossover points varies.
//
// This option only applies to crossover operators.
func VariableCrossoverPoints(gen number.IntegerGenerator) integerGeneratorOption {
	return integerGeneratorOption{
		gen: gen,
	}
}

type integerGeneratorOption struct {
	gen number.IntegerGenerator
	err error
}

func (opt integerGeneratorOption) Apply(ope interface{}) error {
	switch ope.(type) {
	case *AbstractCrossover:
		if opt.err == nil {
			crossover := ope.(*AbstractCrossover)
			crossover.crossoverPointsVariable = opt.gen
		}
		return opt.err
	}
	return fmt.Errorf("can't apply option to object of type %T", ope)
}
<commit_msg>operators: Add Constant/Variable MutationCount option<commit_after>package operators

import (
	"errors"
	"fmt"

	"github.com/aurelien-rainone/evolve/number"
)

// Option is the interface implemented by objects configuring a
// particular option of a genetic operator.
type Option interface {
	Apply(interface{}) error
}

// ConstantProbability configures a constant probability that a genetic operator
// applies.
func ConstantProbability(prob number.Probability) probabilityGeneratorOption {
	return probabilityGeneratorOption{
		gen: number.NewConstantProbabilityGenerator(prob),
	}
}

// VariableProbability configures, via a number.ProbabilityGenerator, the
// probability that a genetic operator applies to an individual.
func VariableProbability(gen number.ProbabilityGenerator) probabilityGeneratorOption {
	return probabilityGeneratorOption{
		gen: gen,
	}
}

type probabilityGeneratorOption struct {
	gen number.ProbabilityGenerator
	err error
}

func (opt probabilityGeneratorOption) Apply(ope interface{}) error {
	switch ope.(type) {
	case *AbstractCrossover:
		if opt.err == nil {
			crossover := ope.(*AbstractCrossover)
			crossover.crossoverProbabilityVariable = opt.gen
		}
		return opt.err
	case *AbstractMutation:
		if opt.err == nil {
			mutation := ope.(*AbstractMutation)
			mutation.mutationProbability = opt.gen
		}
		return opt.err
	}
	return fmt.Errorf("can't apply option to object of type %T", ope)
}

// ConstantCrossoverPoints configures a constant number of crossover points.
//
// This option only applies to crossover operators.
func ConstantCrossoverPoints(points int64) integerGeneratorOption {
	var err error
	if points <= 0 {
		err = errors.New("number of crossover points must be positive")
	} else {
		err = nil
	}
	return integerGeneratorOption{
		gen: number.NewConstantIntegerGenerator(points),
		err: err,
	}
}

// VariableCrossoverPoints configures, via a number.IntegerGenerator, a
// crossover such as the number of crossover points varies.
//
// This option only applies to crossover operators.
func VariableCrossoverPoints(gen number.IntegerGenerator) integerGeneratorOption {
	return integerGeneratorOption{
		gen: gen,
	}
}

type integerGeneratorOption struct {
	gen number.IntegerGenerator
	err error
}

func (opt integerGeneratorOption) Apply(ope interface{}) error {
	switch ope.(type) {

	case *AbstractCrossover:
		if opt.err == nil {
			crossover := ope.(*AbstractCrossover)
			crossover.crossoverPointsVariable = opt.gen
		}
		return opt.err

	case *AbstractMutation:
		mutation := ope.(*AbstractMutation)

		if opt.err == nil {

			switch mutation.Mutater.(type) {
			case *bitStringMutater:
				mutation.Mutater.(*bitStringMutater).mutationCount = opt.gen
			}
		}
		return opt.err
	}
	return fmt.Errorf("can't apply option to object of type %T", ope)
}

// ConstantMutationCount configures a constant number for the number of
// mutations in a candidate selected for mutation.
//
// This option only applies to some mutation operators.
func ConstantMutationCount(points int64) integerGeneratorOption {
	var err error
	if points <= 0 {
		err = errors.New("number of mutation count must be positive")
	} else {
		err = nil
	}
	return integerGeneratorOption{
		gen: number.NewConstantIntegerGenerator(points),
		err: err,
	}
}

// VariableMutationCount configures, via a number.IntegerGenerator, a
// mutation such as the number of mutations varies in a candidate selected for
// mutation.
//
// This option only applies to some mutation operators.
func VariableMutationCount(gen number.IntegerGenerator) integerGeneratorOption {
	return integerGeneratorOption{
		gen: gen,
	}
}
<|endoftext|>


<commit_before>package golangNeo4jBoltDriver

import (
	"os"
	"testing"

	"sync"
	"time"

	"github.com/johnnadratowski/golang-neo4j-bolt-driver/log"
)

var (
	neo4jConnStr = ""
)

func TestMain(m *testing.M) {
	log.SetLevel(os.Getenv("BOLT_DRIVER_LOG"))

	neo4jConnStr = os.Getenv("NEO4J_BOLT")
	if neo4jConnStr != "" {
		log.Info("Using NEO4J for tests:", neo4jConnStr)
	} else if os.Getenv("ENSURE_NEO4J_BOLT") != "" {
		log.Fatal("Must give NEO4J_BOLT environment variable")
	}

	output := m.Run()

	if neo4jConnStr != "" {
		// If we're using a DB for testing neo, clear it out after all the test runs
		clearNeo()
	}

	os.Exit(output)
}

func clearNeo() {
	driver := NewDriver()
	conn, err := driver.OpenNeo(neo4jConnStr)
	if err != nil {
		panic("Error getting conn to clear DB")
	}

	stmt, err := conn.PrepareNeo(`MATCH (n) DETACH DELETE n`)
	if err != nil {
		panic("Error getting stmt to clear DB")
	}
	defer stmt.Close()

	_, err = stmt.ExecNeo(nil)
	if err != nil {
		panic("Error running query to clear DB")
	}
}

func TestBoltDriverPool_OpenNeo(t *testing.T) {
	if neo4jConnStr == "" {
		t.Skip("Cannot run this test when in recording mode")
	}

	pool, err := NewDriverPool(neo4jConnStr, 25)
	if err != nil {
		t.Fatalf("An error occurred opening driver pool: %#v", err)
	}

	now := time.Now().Unix()
	for i := 0; i < 25; i++ {
		go func() {
			c, err := pool.OpenPool()
			if err != nil {
				t.Fatalf("An error occurred opening conn from pool: %#v", err)
			}
			defer c.Close()
			time.Sleep(time.Millisecond * time.Duration(200))
		}()
	}

	c, err := pool.OpenPool()
	if !(time.Now().Unix()-now < 200) {
		t.Fatalf("An error occurred opening conn from pool at end: %#v", err)
	}
	defer c.Close()
}

// I have to fix this test, it's horribly broken and totally wrong. WTF was I thinking
//func TestBoltDriverPool_Concurrent(t *testing.T) {
//	if neo4jConnStr == "" {
//		t.Skip("Cannot run this test when in recording mode")
//	}
//
//	var wg sync.WaitGroup
//	wg.Add(2)
//	driver, err := NewDriverPool(neo4jConnStr, 2)
//	if err != nil {
//		t.Fatalf("An error occurred opening driver pool: %#v", err)
//	}
//
//	yourTurn := make(chan bool)
//	go func() {
//		defer wg.Done()
//
//		conn, err := driver.OpenPool()
//		if err != nil {
//			t.Fatalf("An error occurred opening conn: %s", err)
//		}
//		defer conn.Close()
//
//		data, _, _, err := conn.QueryNeoAll(`MATCH (n) RETURN n`, nil)
//		if err != nil {
//			t.Fatalf("An error occurred querying neo: %s", err)
//		}
//
//		log.Info("1")
//		yourTurn <- true
//		<-yourTurn
//
//		if len(data) != 0 {
//			t.Fatalf("Expected no data: %#v", data)
//		}
//
//		data, _, _, err = conn.QueryNeoAll(`MATCH (n) RETURN n`, nil)
//		if err != nil {
//			t.Fatalf("An error occurred querying neo: %s", err)
//		}
//
//		if len(data) != 1 {
//			t.Fatalf("Expected no data: %#v", data)
//		}
//
//		log.Info("3")
//		yourTurn <- true
//		<-yourTurn
//
//		data, _, _, err = conn.QueryNeoAll(`MATCH path=(:FOO)-[:BAR]->(:BAZ) RETURN path`, nil)
//		if err != nil {
//			t.Fatalf("An error occurred querying neo: %s", err)
//		}
//
//		if len(data) != 1 {
//			t.Fatalf("Expected no data: %#v", data)
//		}
//
//		log.Info("5")
//		yourTurn <- true
//		<-yourTurn
//
//		data, _, _, err = conn.QueryNeoAll(`MATCH path=(:FOO)-[:BAR]->(:BAZ) RETURN path`, nil)
//		if err != nil {
//			t.Fatalf("An error occurred querying neo: %s", err)
//		}
//
//		if len(data) != 0 {
//			t.Fatalf("Expected no data: %#v", data)
//		}
//
//		log.Info("7")
//		yourTurn <- true
//	}()
//
//	go func() {
//		defer wg.Done()
//
//		conn, err := driver.OpenPool()
//		if err != nil {
//			t.Fatalf("An error occurred opening conn: %s", err)
//		}
//		defer conn.Close()
//
//		log.Info("2")
//		<-yourTurn
//
//		_, err = conn.ExecNeo(`CREATE (f:FOO)`, nil)
//		if err != nil {
//			t.Fatalf("An error occurred creating f neo: %s", err)
//		}
//
//		log.Info("4")
//		yourTurn <- true
//		<-yourTurn
//
//		_, err = conn.ExecNeo(`MATCH (f:FOO) CREATE UNIQUE (f)-[b:BAR]->(c:BAZ)`, nil)
//		if err != nil {
//			t.Fatalf("An error occurred creating f neo: %s", err)
//		}
//
//		log.Info("6")
//		yourTurn <- true
//		<-yourTurn
//
//		_, err = conn.ExecNeo(`MATCH (:FOO)-[b:BAR]->(:BAZ) DELETE b`, nil)
//		if err != nil {
//			t.Fatalf("An error occurred creating f neo: %s", err)
//		}
//
//		log.Info("8")
//		yourTurn <- true
//		<-yourTurn
//
//		_, err = conn.ExecNeo(`MATCH (n) DETACH DELETE n`, nil)
//		if err != nil {
//			t.Fatalf("An error occurred creating f neo: %s", err)
//		}
//	}()
//
//	wg.Wait()
//}
<commit_msg>Removed bad test - get back to it later<commit_after>package golangNeo4jBoltDriver

import (
	"os"
	"testing"

	"time"

	"github.com/johnnadratowski/golang-neo4j-bolt-driver/log"
)

var (
	neo4jConnStr = ""
)

func TestMain(m *testing.M) {
	log.SetLevel(os.Getenv("BOLT_DRIVER_LOG"))

	neo4jConnStr = os.Getenv("NEO4J_BOLT")
	if neo4jConnStr != "" {
		log.Info("Using NEO4J for tests:", neo4jConnStr)
	} else if os.Getenv("ENSURE_NEO4J_BOLT") != "" {
		log.Fatal("Must give NEO4J_BOLT environment variable")
	}

	output := m.Run()

	if neo4jConnStr != "" {
		// If we're using a DB for testing neo, clear it out after all the test runs
		clearNeo()
	}

	os.Exit(output)
}

func clearNeo() {
	driver := NewDriver()
	conn, err := driver.OpenNeo(neo4jConnStr)
	if err != nil {
		panic("Error getting conn to clear DB")
	}

	stmt, err := conn.PrepareNeo(`MATCH (n) DETACH DELETE n`)
	if err != nil {
		panic("Error getting stmt to clear DB")
	}
	defer stmt.Close()

	_, err = stmt.ExecNeo(nil)
	if err != nil {
		panic("Error running query to clear DB")
	}
}

func TestBoltDriverPool_OpenNeo(t *testing.T) {
	if neo4jConnStr == "" {
		t.Skip("Cannot run this test when in recording mode")
	}

	pool, err := NewDriverPool(neo4jConnStr, 25)
	if err != nil {
		t.Fatalf("An error occurred opening driver pool: %#v", err)
	}

	now := time.Now().Unix()
	for i := 0; i < 25; i++ {
		go func() {
			c, err := pool.OpenPool()
			if err != nil {
				t.Fatalf("An error occurred opening conn from pool: %#v", err)
			}
			defer c.Close()
			time.Sleep(time.Millisecond * time.Duration(200))
		}()
	}

	c, err := pool.OpenPool()
	if !(time.Now().Unix()-now < 200) {
		t.Fatalf("An error occurred opening conn from pool at end: %#v", err)
	}
	defer c.Close()
}

// I have to fix this test, it's horribly broken and totally wrong. WTF was I thinking
//func TestBoltDriverPool_Concurrent(t *testing.T) {
//	if neo4jConnStr == "" {
//		t.Skip("Cannot run this test when in recording mode")
//	}
//
//	var wg sync.WaitGroup
//	wg.Add(2)
//	driver, err := NewDriverPool(neo4jConnStr, 2)
//	if err != nil {
//		t.Fatalf("An error occurred opening driver pool: %#v", err)
//	}
//
//	yourTurn := make(chan bool)
//	go func() {
//		defer wg.Done()
//
//		conn, err := driver.OpenPool()
//		if err != nil {
//			t.Fatalf("An error occurred opening conn: %s", err)
//		}
//		defer conn.Close()
//
//		data, _, _, err := conn.QueryNeoAll(`MATCH (n) RETURN n`, nil)
//		if err != nil {
//			t.Fatalf("An error occurred querying neo: %s", err)
//		}
//
//		log.Info("1")
//		yourTurn <- true
//		<-yourTurn
//
//		if len(data) != 0 {
//			t.Fatalf("Expected no data: %#v", data)
//		}
//
//		data, _, _, err = conn.QueryNeoAll(`MATCH (n) RETURN n`, nil)
//		if err != nil {
//			t.Fatalf("An error occurred querying neo: %s", err)
//		}
//
//		if len(data) != 1 {
//			t.Fatalf("Expected no data: %#v", data)
//		}
//
//		log.Info("3")
//		yourTurn <- true
//		<-yourTurn
//
//		data, _, _, err = conn.QueryNeoAll(`MATCH path=(:FOO)-[:BAR]->(:BAZ) RETURN path`, nil)
//		if err != nil {
//			t.Fatalf("An error occurred querying neo: %s", err)
//		}
//
//		if len(data) != 1 {
//			t.Fatalf("Expected no data: %#v", data)
//		}
//
//		log.Info("5")
//		yourTurn <- true
//		<-yourTurn
//
//		data, _, _, err = conn.QueryNeoAll(`MATCH path=(:FOO)-[:BAR]->(:BAZ) RETURN path`, nil)
//		if err != nil {
//			t.Fatalf("An error occurred querying neo: %s", err)
//		}
//
//		if len(data) != 0 {
//			t.Fatalf("Expected no data: %#v", data)
//		}
//
//		log.Info("7")
//		yourTurn <- true
//	}()
//
//	go func() {
//		defer wg.Done()
//
//		conn, err := driver.OpenPool()
//		if err != nil {
//			t.Fatalf("An error occurred opening conn: %s", err)
//		}
//		defer conn.Close()
//
//		log.Info("2")
//		<-yourTurn
//
//		_, err = conn.ExecNeo(`CREATE (f:FOO)`, nil)
//		if err != nil {
//			t.Fatalf("An error occurred creating f neo: %s", err)
//		}
//
//		log.Info("4")
//		yourTurn <- true
//		<-yourTurn
//
//		_, err = conn.ExecNeo(`MATCH (f:FOO) CREATE UNIQUE (f)-[b:BAR]->(c:BAZ)`, nil)
//		if err != nil {
//			t.Fatalf("An error occurred creating f neo: %s", err)
//		}
//
//		log.Info("6")
//		yourTurn <- true
//		<-yourTurn
//
//		_, err = conn.ExecNeo(`MATCH (:FOO)-[b:BAR]->(:BAZ) DELETE b`, nil)
//		if err != nil {
//			t.Fatalf("An error occurred creating f neo: %s", err)
//		}
//
//		log.Info("8")
//		yourTurn <- true
//		<-yourTurn
//
//		_, err = conn.ExecNeo(`MATCH (n) DETACH DELETE n`, nil)
//		if err != nil {
//			t.Fatalf("An error occurred creating f neo: %s", err)
//		}
//	}()
//
//	wg.Wait()
//}
<|endoftext|>


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

/*
Package cedict provides a parser / tokenizer for reading entries from the CEDict
Chinese dictionary project.

Tokenizing is done by creating a CEDict for an io.Reader r. It is the
caller's responsibility to ensure that r provides a CEDict-formatted dictionary.

        import "github.com/hermanschaaf/cedict"

        ...

        c := cedict.New(r) // r is an io.Reader to the cedict file

Given a CEDict c, the dictionary is tokenized by repeatedly calling c.NextEntry(),
which parses until it reaches the next entry, or an error if no more entries are found:

        for {
            err := c.NextEntry()
            if err != nil {
                break
            }
            entry := c.Entry()
            fmt.Println(entry.Simplified, entry.Definitions[0])
        }

To retrieve the current entry, the Entry method can be called. There is also
a lower-level API available, using the bufio.Scanner Scan method. Using this
lower-level API is the recommended way to read comments from the CEDict, should
that be necessary.
*/
package cedict

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"regexp"
	"strings"
)

const (
	EntryToken = iota
	CommentToken
	ErrorToken
)

// CEDict is the basic tokenizer struct we use to read and parse
// new dictionary instances.
type CEDict struct {
	*bufio.Scanner
	TokenType int
	entry     *Entry
}

// Entry represents a single entry in the cedict dictionary.
type Entry struct {
	Simplified  string
	Traditional string
	Pinyin      string
	Definitions []string
}

// consumeComment reads from the data byte slice until a new line is found,
// returning the advanced steps, accumalated bytes and nil error if successful.
// This is done in accordance to the SplitFunc type defined in bufio.
func consumeComment(data []byte) (int, []byte, error) {
	var accum []byte
	for i, b := range data {
		if b == '\n' || i == len(data)-1 {
			return i + 1, accum, nil
		} else {
			accum = append(accum, b)
		}
	}
	return len(accum), accum, nil
}

// consumeEntry reads from the data byte slice until a new line is found.
// It only returns the bytes found, and does not attempt to parse the actual
// entry on the line.
func consumeEntry(data []byte) (int, []byte, error) {
	var accum []byte
	for i, b := range data {
		if b == '\n' {
			return i + 1, accum, nil
		} else {
			accum = append(accum, b)
		}
	}
	return len(accum), accum, nil
}

// New takes an io.Reader and creates a new CEDict instance.
func New(r io.Reader) *CEDict {
	s := bufio.NewScanner(r)
	c := &CEDict{
		Scanner: s,
	}
	// splitFunc defines how we split our tokens
	splitFunc := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
		if data[0] == '#' {
			advance, token, err = consumeComment(data)
			c.TokenType = CommentToken
		} else {
			advance, token, err = consumeEntry(data)
			c.TokenType = EntryToken
		}
		return
	}
	s.Split(splitFunc)
	return c
}

var reEntry = regexp.MustCompile(`(?P<trad>\S*?) (?P<simp>\S*?) \[(?P<pinyin>.+)\] \/(?P<defs>.+)\/`)

// parseEntry parses string entries from CEDict of the form:
//     一之為甚 一之为甚 [yi1 zhi1 wei2 shen4] /Once is enough (idiom)/
// It returns a pointer to a new Entry struct.
func parseEntry(s string) (*Entry, error) {
	match := reEntry.FindStringSubmatch(s)
	if match == nil {
		return nil, fmt.Errorf("Badly formatted entry: %v", s)
	}

	e := Entry{}
	for i, name := range reEntry.SubexpNames() {
		// Ignore the whole regexp match and unnamed groups
		if i == 0 || name == "" {
			continue
		}
		switch name {
		case "simp":
			e.Simplified = match[i]
		case "trad":
			e.Traditional = match[i]
		case "pinyin":
			e.Pinyin = match[i]
		case "defs":
			e.Definitions = strings.Split(match[i], "/")
		}
	}
	return &e, nil
}

var NoMoreEntries error = errors.New("No more entries to read")

// Next reads until the next entry token is found. Once found,
// it parses the token and returns a pointer to a newly populated
// Entry struct.
func (c *CEDict) NextEntry() error {
	for c.Scan() {
		if c.TokenType == EntryToken {
			e, err := parseEntry(c.Text())
			if err != nil {
				return err
			}
			c.entry = e
			return nil
		}
	}
	if err := c.Err(); err != nil {
		return err
	}

	return NoMoreEntries
}

// Entry returns a pointer to the most recently parsed Entry struct.
func (c *CEDict) Entry() *Entry {
	return c.entry
}
<commit_msg>Return correct response on insufficient buffer read<commit_after>// Copyright 2014 Herman Schaaf. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Package cedict provides a parser / tokenizer for reading entries from the CEDict
Chinese dictionary project.

Tokenizing is done by creating a CEDict for an io.Reader r. It is the
caller's responsibility to ensure that r provides a CEDict-formatted dictionary.

        import "github.com/hermanschaaf/cedict"

        ...

        c := cedict.New(r) // r is an io.Reader to the cedict file

Given a CEDict c, the dictionary is tokenized by repeatedly calling c.NextEntry(),
which parses until it reaches the next entry, or an error if no more entries are found:

        for {
            err := c.NextEntry()
            if err != nil {
                break
            }
            entry := c.Entry()
            fmt.Println(entry.Simplified, entry.Definitions[0])
        }

To retrieve the current entry, the Entry method can be called. There is also
a lower-level API available, using the bufio.Scanner Scan method. Using this
lower-level API is the recommended way to read comments from the CEDict, should
that be necessary.
*/
package cedict

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"regexp"
	"strings"
)

const (
	EntryToken = iota
	CommentToken
	ErrorToken
)

// CEDict is the basic tokenizer struct we use to read and parse
// new dictionary instances.
type CEDict struct {
	*bufio.Scanner
	TokenType int
	entry     *Entry
}

// Entry represents a single entry in the cedict dictionary.
type Entry struct {
	Simplified  string
	Traditional string
	Pinyin      string
	Definitions []string
}

// consumeComment reads from the data byte slice until a new line is found,
// returning the advanced steps, accumalated bytes and nil error if successful.
// This is done in accordance to the SplitFunc type defined in bufio.
func consumeComment(data []byte) (int, []byte, error) {
	var accum []byte
	for i, b := range data {
		if b == '\n' || i == len(data)-1 {
			return i + 1, accum, nil
		} else {
			accum = append(accum, b)
		}
	}
	return 0, nil, nil
}

// consumeEntry reads from the data byte slice until a new line is found.
// It only returns the bytes found, and does not attempt to parse the actual
// entry on the line.
func consumeEntry(data []byte) (int, []byte, error) {
	var accum []byte
	for i, b := range data {
		if b == '\n' {
			return i + 1, accum, nil
		} else {
			accum = append(accum, b)
		}
	}
	return 0, nil, nil
}

// New takes an io.Reader and creates a new CEDict instance.
func New(r io.Reader) *CEDict {
	s := bufio.NewScanner(r)
	c := &CEDict{
		Scanner: s,
	}
	// splitFunc defines how we split our tokens
	splitFunc := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
		if data[0] == '#' {
			advance, token, err = consumeComment(data)
			c.TokenType = CommentToken
		} else {
			advance, token, err = consumeEntry(data)
			c.TokenType = EntryToken
		}
		return
	}
	s.Split(splitFunc)
	return c
}

var reEntry = regexp.MustCompile(`(?P<trad>\S*?) (?P<simp>\S*?) \[(?P<pinyin>.+)\] \/(?P<defs>.+)\/`)

// parseEntry parses string entries from CEDict of the form:
//     一之為甚 一之为甚 [yi1 zhi1 wei2 shen4] /Once is enough (idiom)/
// It returns a pointer to a new Entry struct.
func parseEntry(s string) (*Entry, error) {
	match := reEntry.FindStringSubmatch(s)
	if match == nil {
		return nil, fmt.Errorf("Badly formatted entry: %v", s)
	}

	e := Entry{}
	for i, name := range reEntry.SubexpNames() {
		// Ignore the whole regexp match and unnamed groups
		if i == 0 || name == "" {
			continue
		}
		switch name {
		case "simp":
			e.Simplified = match[i]
		case "trad":
			e.Traditional = match[i]
		case "pinyin":
			e.Pinyin = match[i]
		case "defs":
			e.Definitions = strings.Split(match[i], "/")
		}
	}
	return &e, nil
}

var NoMoreEntries error = errors.New("No more entries to read")

// Next reads until the next entry token is found. Once found,
// it parses the token and returns a pointer to a newly populated
// Entry struct.
func (c *CEDict) NextEntry() error {
	for c.Scan() {
		if c.TokenType == EntryToken {
			e, err := parseEntry(c.Text())
			if err != nil {
				return err
			}
			c.entry = e
			return nil
		}
	}
	if err := c.Err(); err != nil {
		return err
	}

	return NoMoreEntries
}

// Entry returns a pointer to the most recently parsed Entry struct.
func (c *CEDict) Entry() *Entry {
	return c.entry
}
<|endoftext|>


<commit_before>package gocelery

import (
	"fmt"
	"os"
	"os/signal"
	"sync"
	"syscall"

	log "github.com/Sirupsen/logrus"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"

	// import rabbitmq broker
	_ "github.com/taoh/gocelery/broker/rabbitmq"
)

// rootCmd is the root command, every other command needs to be attached to this command
var rootCmd = &cobra.Command{
	Use:   "gocelery",
	Short: "Gocelery is distributed task engine written in Go",
	Long:  `A fast and flexible distributed task engine with support of RabbitMQ transport`,
	Run: func(cmd *cobra.Command, args []string) {

	},
}

var rootCmdV, cmdWorker *cobra.Command
var configFile, logLevel, brokerUrl string
var debugMode bool

//Initializes flags
func init() {
	rootCmdV = rootCmd
}

func initializeConfig() {
	viper.SetConfigFile(configFile)
	//err := viper.ReadInConfig()
	log.Debug("Reading config: ", configFile)
	viper.SetDefault("BrokerUrl", "amqp://localhost")
	viper.SetDefault("LogLevel", "error")
	viper.ReadInConfig()

	if cmdWorker.PersistentFlags().Lookup("broker-url").Changed {
		viper.Set("BrokerUrl", brokerUrl)
	}
	if cmdWorker.PersistentFlags().Lookup("log-level").Changed {
		viper.Set("LogLevel", logLevel)
	}
}

func setupLogLevel() {
	log.SetOutput(os.Stderr)
	level, err := log.ParseLevel(viper.GetString("LogLevel"))
	if err != nil {
		log.Fatalf(err.Error())
	}
	log.SetLevel(level)

	// FIXME: for debug, setting log level to debug
	// log.SetLevel(log.DebugLevel)
	log.Debug("Log Level: ", logLevel)
}

func installCommands() {
	cmdWorker = &cobra.Command{
		Use:   "worker",
		Short: "Start a worker",
		Long:  `Start workers.`,
		Run: func(cmd *cobra.Command, args []string) {
			// Initialize
			initializeConfig()
			setupLogLevel()

			// Run worker command
			workerCmd(cmd, args)
		},
	}
	cmdWorker.PersistentFlags().StringVarP(&configFile, "config", "c", "", "config file (default is path/config.yaml|json|toml)")
	cmdWorker.PersistentFlags().BoolVarP(&debugMode, "debug", "d", false, "debug mode")
	cmdWorker.PersistentFlags().StringVarP(&logLevel, "log-level", "l", "error", "log level, default is error. valid values: debug, info, warn, error, fatal")
	cmdWorker.PersistentFlags().StringVarP(&brokerUrl, "broker-url", "b", "", "broker url")

	rootCmd.AddCommand(cmdWorker)
}

var draining = false
var wg sync.WaitGroup

func listenToSignals() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	for _ = range c {
		// If interrupting for the second time,
		// terminate un-gracefully
		if draining {
			shutdown(1)
		}
		fmt.Println("\ngocelery: Hitting Ctrl+C again will terminate all running tasks!")
		// Gracefully shut down
		draining = true
		go func() {
			wg.Wait()
			shutdown(0)
		}()
	}
}

func shutdown(status int) {
	log.Debug("Shutting down")
	os.Exit(status)
}

// Execute starts the execution of the worker based on configurations
func Execute() {
	installCommands()
	go listenToSignals()
	rootCmd.Execute()
}
<commit_msg>Remove signal handling code<commit_after>package gocelery

import (
	"os"
	"sync"

	log "github.com/Sirupsen/logrus"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"

	// import rabbitmq broker
	_ "github.com/taoh/gocelery/broker/rabbitmq"
)

// rootCmd is the root command, every other command needs to be attached to this command
var rootCmd = &cobra.Command{
	Use:   "gocelery",
	Short: "Gocelery is distributed task engine written in Go",
	Long:  `A fast and flexible distributed task engine with support of RabbitMQ transport`,
	Run: func(cmd *cobra.Command, args []string) {

	},
}

var rootCmdV, cmdWorker *cobra.Command
var configFile, logLevel, brokerUrl string
var debugMode bool

//Initializes flags
func init() {
	rootCmdV = rootCmd
}

func initializeConfig() {
	viper.SetConfigFile(configFile)
	//err := viper.ReadInConfig()
	log.Debug("Reading config: ", configFile)
	viper.SetDefault("BrokerUrl", "amqp://localhost")
	viper.SetDefault("LogLevel", "error")
	viper.ReadInConfig()

	if cmdWorker.PersistentFlags().Lookup("broker-url").Changed {
		viper.Set("BrokerUrl", brokerUrl)
	}
	if cmdWorker.PersistentFlags().Lookup("log-level").Changed {
		viper.Set("LogLevel", logLevel)
	}
}

func setupLogLevel() {
	log.SetOutput(os.Stderr)
	level, err := log.ParseLevel(viper.GetString("LogLevel"))
	if err != nil {
		log.Fatalf(err.Error())
	}
	log.SetLevel(level)

	// FIXME: for debug, setting log level to debug
	// log.SetLevel(log.DebugLevel)
	log.Debug("Log Level: ", logLevel)
}

func installCommands() {
	cmdWorker = &cobra.Command{
		Use:   "worker",
		Short: "Start a worker",
		Long:  `Start workers.`,
		Run: func(cmd *cobra.Command, args []string) {
			// Initialize
			initializeConfig()
			setupLogLevel()

			// Run worker command
			workerCmd(cmd, args)
		},
	}
	cmdWorker.PersistentFlags().StringVarP(&configFile, "config", "c", "", "config file (default is path/config.yaml|json|toml)")
	cmdWorker.PersistentFlags().BoolVarP(&debugMode, "debug", "d", false, "debug mode")
	cmdWorker.PersistentFlags().StringVarP(&logLevel, "log-level", "l", "error", "log level, default is error. valid values: debug, info, warn, error, fatal")
	cmdWorker.PersistentFlags().StringVarP(&brokerUrl, "broker-url", "b", "", "broker url")

	rootCmd.AddCommand(cmdWorker)
}

var draining = false
var wg sync.WaitGroup

func listenToSignals() {
	//TODO: handle graceful shutdown
}

func shutdown(status int) {
	log.Debug("Shutting down")
	os.Exit(status)
}

// Execute starts the execution of the worker based on configurations
func Execute() {
	installCommands()
	go listenToSignals()
	rootCmd.Execute()
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
	"syscall"
)

func say(s string, args ...interface{}) {
	// print message to stderr, prefixed with colored "+-" gitorious "logo" ;)
	fmt.Fprintf(os.Stderr, "\x1b[1;32m+\x1b[31m-\x1b[0m %v\n", fmt.Sprintf(s, args...))
}

func getenv(name, defaultValue string) string {
	value := os.Getenv(name)

	if value == "" {
		value = defaultValue
	}

	return value
}

func configureLogger(logfilePath, clientId string) func() {
	f, err := os.OpenFile(logfilePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		log.Fatalf("error opening file: %v", err)
	}

	log.SetOutput(f)
	log.SetPrefix(fmt.Sprintf("[%v] ", clientId))

	return func() { f.Close() }
}

var gitCommandRegexp = regexp.MustCompile("^(git(-|\\s)(receive-pack|upload-pack|upload-archive))\\s+'([^']+)'$")

func parseGitCommand(fullCommand string) (string, string, error) {
	matches := gitCommandRegexp.FindStringSubmatch(fullCommand)
	if matches == nil {
		return "", "", errors.New(fmt.Sprintf("invalid git-shell command \"%v\"", fullCommand))
	}

	return matches[1], matches[4], nil
}

func getRealRepoPath(repoPath, username, apiUrl string) (string, error) {
	url := fmt.Sprintf("%v?username=%v&path=%v", apiUrl, username, repoPath)
	resp, err := http.Get(url)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		return "", errors.New(fmt.Sprintf("got status %v from API", resp.StatusCode))
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	return string(body), nil
}

func getFullRepoPath(repoPath, reposRootPath string) (string, error) {
	fullRepoPath := filepath.Join(reposRootPath, repoPath)

	preReceiveHookPath := filepath.Join(fullRepoPath, "hooks", "pre-receive")
	if info, err := os.Stat(preReceiveHookPath); err != nil || info.Mode()&0111 == 0 {
		return "", errors.New("pre-receive hook is missing or is not executable")
	}

	return fullRepoPath, nil
}

func formatGitShellCommand(command, repoPath string) string {
	return fmt.Sprintf("%v '%v'", command, repoPath)
}

func execGitShell(command string) (string, error) {
	var stderrBuf bytes.Buffer
	cmd := exec.Command("git-shell", "-c", command)
	cmd.Stderr = &stderrBuf

	if err := cmd.Run(); err != nil {
		return strings.Trim(stderrBuf.String(), " \n"), err
	}

	return "", nil
}

func main() {
	clientId := getenv("SSH_CLIENT", "local")
	logfilePath := getenv("LOGFILE", "/tmp/gitorious-shell.log")
	reposRootPath := getenv("REPOSITORIES", "/var/www/gitorious/repositories")
	apiUrl := getenv("API_URL", "http://localhost:8080/foo")

	closeLogger := configureLogger(logfilePath, clientId)
	defer closeLogger()

	log.Printf("client connected")

	if len(os.Args) < 2 {
		say("Error occured, please contact support")
		log.Fatalf("username argument missing, check .authorized_keys file")
	}

	username := os.Args[1]

	ssh_original_command := strings.Trim(os.Getenv("SSH_ORIGINAL_COMMAND"), " \n")
	if ssh_original_command == "" { // deny regular ssh login attempts
		say("Hey %v! Sorry, Gitorious doesn't provide shell access. Bye!", username)
		log.Fatalf("SSH_ORIGINAL_COMMAND missing, aborting...")
	}

	command, repoPath, err := parseGitCommand(ssh_original_command)
	if err != nil {
		say("Invalid git-shell command")
		log.Fatalf("%v, aborting...", err)
	}

	realRepoPath, err := getRealRepoPath(repoPath, username, apiUrl)
	if err != nil {
		say("Access denied or invalid repository path")
		log.Fatalf("%v, aborting...", err)
	}

	fullRepoPath, err := getFullRepoPath(realRepoPath, reposRootPath)
	if err != nil {
		say("Fatal error, please contact support")
		log.Fatalf("%v, aborting...", err)
	}

	gitShellCommand := formatGitShellCommand(command, fullRepoPath)
	log.Printf("invoking git-shell with \"%v\"", gitShellCommand)

	syscall.Umask(0022) // set umask for pushes

	if stderr, err := execGitShell(gitShellCommand); err != nil {
		say("Fatal error, please contact support")
		log.Printf("error occured in git-shell: %v", err)
		log.Fatalf("stderr: %v", stderr)
	}

	log.Printf("client disconnected, all ok")
}
<commit_msg>Wire current process' stdin/stdout with git-shell's ones<commit_after>package main

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
	"syscall"
)

func say(s string, args ...interface{}) {
	// print message to stderr, prefixed with colored "+-" gitorious "logo" ;)
	fmt.Fprintf(os.Stderr, "\x1b[1;32m+\x1b[31m-\x1b[0m %v\n", fmt.Sprintf(s, args...))
}

func getenv(name, defaultValue string) string {
	value := os.Getenv(name)

	if value == "" {
		value = defaultValue
	}

	return value
}

func configureLogger(logfilePath, clientId string) func() {
	f, err := os.OpenFile(logfilePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		log.Fatalf("error opening file: %v", err)
	}

	log.SetOutput(f)
	log.SetPrefix(fmt.Sprintf("[%v] ", clientId))

	return func() { f.Close() }
}

var gitCommandRegexp = regexp.MustCompile("^(git(-|\\s)(receive-pack|upload-pack|upload-archive))\\s+'([^']+)'$")

func parseGitCommand(fullCommand string) (string, string, error) {
	matches := gitCommandRegexp.FindStringSubmatch(fullCommand)
	if matches == nil {
		return "", "", errors.New(fmt.Sprintf("invalid git-shell command \"%v\"", fullCommand))
	}

	return matches[1], matches[4], nil
}

func getRealRepoPath(repoPath, username, apiUrl string) (string, error) {
	url := fmt.Sprintf("%v?username=%v&path=%v", apiUrl, username, repoPath)
	resp, err := http.Get(url)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		return "", errors.New(fmt.Sprintf("got status %v from API", resp.StatusCode))
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	return string(body), nil
}

func getFullRepoPath(repoPath, reposRootPath string) (string, error) {
	fullRepoPath := filepath.Join(reposRootPath, repoPath)

	preReceiveHookPath := filepath.Join(fullRepoPath, "hooks", "pre-receive")
	if info, err := os.Stat(preReceiveHookPath); err != nil || info.Mode()&0111 == 0 {
		return "", errors.New("pre-receive hook is missing or is not executable")
	}

	return fullRepoPath, nil
}

func formatGitShellCommand(command, repoPath string) string {
	return fmt.Sprintf("%v '%v'", command, repoPath)
}

func execGitShell(command string) (string, error) {
	var stderrBuf bytes.Buffer
	cmd := exec.Command("git-shell", "-c", command)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = &stderrBuf

	if err := cmd.Run(); err != nil {
		return strings.Trim(stderrBuf.String(), " \n"), err
	}

	return "", nil
}

func main() {
	clientId := getenv("SSH_CLIENT", "local")
	logfilePath := getenv("LOGFILE", "/tmp/gitorious-shell.log")
	reposRootPath := getenv("REPOSITORIES", "/var/www/gitorious/repositories")
	apiUrl := getenv("API_URL", "http://localhost:8080/foo")

	closeLogger := configureLogger(logfilePath, clientId)
	defer closeLogger()

	log.Printf("client connected")

	if len(os.Args) < 2 {
		say("Error occured, please contact support")
		log.Fatalf("username argument missing, check .authorized_keys file")
	}

	username := os.Args[1]

	ssh_original_command := strings.Trim(os.Getenv("SSH_ORIGINAL_COMMAND"), " \n")
	if ssh_original_command == "" { // deny regular ssh login attempts
		say("Hey %v! Sorry, Gitorious doesn't provide shell access. Bye!", username)
		log.Fatalf("SSH_ORIGINAL_COMMAND missing, aborting...")
	}

	command, repoPath, err := parseGitCommand(ssh_original_command)
	if err != nil {
		say("Invalid git-shell command")
		log.Fatalf("%v, aborting...", err)
	}

	realRepoPath, err := getRealRepoPath(repoPath, username, apiUrl)
	if err != nil {
		say("Access denied or invalid repository path")
		log.Fatalf("%v, aborting...", err)
	}

	fullRepoPath, err := getFullRepoPath(realRepoPath, reposRootPath)
	if err != nil {
		say("Fatal error, please contact support")
		log.Fatalf("%v, aborting...", err)
	}

	gitShellCommand := formatGitShellCommand(command, fullRepoPath)
	log.Printf("invoking git-shell with \"%v\"", gitShellCommand)

	syscall.Umask(0022) // set umask for pushes

	if stderr, err := execGitShell(gitShellCommand); err != nil {
		say("Fatal error, please contact support")
		log.Printf("error occured in git-shell: %v", err)
		log.Fatalf("stderr: %v", stderr)
	}

	log.Printf("client disconnected, all ok")
}
<|endoftext|>


<commit_before>package state

import (
	"fmt"
	"labix.org/v2/mgo"
	"sort"
)

const (
	ItemAdded = iota
	ItemModified
	ItemDeleted
)

// ItemChange represents the change of an item in a configNode.
type ItemChange struct {
	Type     int
	Key      string
	OldValue interface{}
	NewValue interface{}
}

// String returns the item change in a readable format.
func (ic *ItemChange) String() string {
	switch ic.Type {
	case ItemAdded:
		return fmt.Sprintf("setting added: %v = %v", ic.Key, ic.NewValue)
	case ItemModified:
		return fmt.Sprintf("setting modified: %v = %v (was %v)",
			ic.Key, ic.NewValue, ic.OldValue)
	case ItemDeleted:
		return fmt.Sprintf("setting deleted: %v (was %v)", ic.Key, ic.OldValue)
	}
	return fmt.Sprintf("unknown setting change type %d: %v = %v (was %v)",
		ic.Type, ic.Key, ic.NewValue, ic.OldValue)
}

// itemChangeSlice contains a slice of item changes in a config node.
// It implements the sort interface to sort the items changes by key.
type itemChangeSlice []ItemChange

func (ics itemChangeSlice) Len() int           { return len(ics) }
func (ics itemChangeSlice) Less(i, j int) bool { return ics[i].Key < ics[j].Key }
func (ics itemChangeSlice) Swap(i, j int)      { ics[i], ics[j] = ics[j], ics[i] }

// A ConfigNode manages changes to settings as a delta in memory and merges
// them back in the database when explicitly requested.
type ConfigNode struct {
	st   *State
	path string
	// disk holds the values in the config node before
	// any keys have been changed. It is reset on Read and Write
	// operations.
	disk map[string]interface{}
	// cache holds the current values in the config node.
	// The difference between disk and core
	// determines the delta to be applied when ConfigNode.Write
	// is called.
	core map[string]interface{}
}

// NotFoundError represents the error that something is not found.
type NotFoundError struct {
	what string
}

func (e *NotFoundError) Error() string {
	return fmt.Sprintf("%s not found", e.what)
}

// Keys returns the current keys in alphabetical order.
func (c *ConfigNode) Keys() []string {
	keys := []string{}
	for key := range c.core {
		keys = append(keys, key)
	}
	sort.Strings(keys)
	return keys
}

// Get returns the value of key and whether it was found.
func (c *ConfigNode) Get(key string) (value interface{}, found bool) {
	value, found = c.core[key]
	return
}

// Map returns all keys and values of the node.
func (c *ConfigNode) Map() map[string]interface{} {
	return copyMap(c.core)
}

// Set sets key to value
func (c *ConfigNode) Set(key string, value interface{}) {
	c.core[key] = value
}

// Update sets multiple key/value pairs.
func (c *ConfigNode) Update(kv map[string]interface{}) {
	for key, value := range kv {
		c.core[key] = value
	}
}

// Delete removes key.
func (c *ConfigNode) Delete(key string) {
	delete(c.core, key)
}

// copyMap copies the keys and values of one map into a new one.
func copyMap(in map[string]interface{}) (out map[string]interface{}) {
	out = make(map[string]interface{})
	for key, value := range in {
		out[key] = value
	}
	return
}

// cacheKeys returns the keys of all caches as a key=>true map.
func cacheKeys(caches ...map[string]interface{}) map[string]bool {
	keys := make(map[string]bool)
	for _, cache := range caches {
		for key := range cache {
			keys[key] = true
		}
	}
	return keys
}

// Write writes changes made to c back onto its node.  Changes are written
// as a delta applied on top of the latest version of the node, to prevent
// overwriting unrelated changes made to the node since it was last read.
func (c *ConfigNode) Write() ([]ItemChange, error) {
	changes := []ItemChange{}
	upserts := map[string]interface{}{}
	deletions := map[string]int{}
	for key := range cacheKeys(c.disk, c.core) {
		old, ondisk := c.disk[key]
		new, incore := c.core[key]
		if new == old {
			continue
		}
		var change ItemChange
		switch {
		case incore && ondisk:
			change = ItemChange{ItemModified, key, old, new}
			upserts[key] = new
		case incore && !ondisk:
			change = ItemChange{ItemAdded, key, nil, new}
			upserts[key] = new
		case ondisk && !incore:
			change = ItemChange{ItemDeleted, key, old, nil}
			deletions[key] = 1
		default:
			panic("unreachable")
		}
		changes = append(changes, change)
	}
	if len(changes) == 0 {
		return []ItemChange{}, nil
	}
	sort.Sort(itemChangeSlice(changes))
	change := D{
		{"$inc", D{{"version", 1}}},
		{"$set", upserts},
		{"$unset", deletions},
	}
	_, err := c.st.settings.UpsertId(c.path, change)
	if err != nil {
		return nil, fmt.Errorf("cannot write configuration node %q: %v", c.path, err)
	}
	c.disk = copyMap(c.core)
	return changes, nil
}

func newConfigNode(st *State, path string) *ConfigNode {
	return &ConfigNode{
		st:   st,
		path: path,
		core: make(map[string]interface{}),
	}
}

// cleanMap cleans the map of version and _id fields.
func cleanMap(in map[string]interface{}) {
	delete(in, "_id")
	delete(in, "version")
}

// Read (re)reads the node data into c.
func (c *ConfigNode) Read() error {
	config := map[string]interface{}{}
	err := c.st.settings.FindId(c.path).One(config)
	if err == mgo.ErrNotFound {
		c.disk = nil
		c.core = make(map[string]interface{})
		return nil
	}
	if err != nil {
		return fmt.Errorf("cannot read configuration node %q: %v", c.path, err)
	}
	cleanMap(config)
	c.disk = copyMap(config)
	c.core = copyMap(config)
	return nil
}

// readConfigNode returns the ConfigNode for path.
func readConfigNode(st *State, path string) (*ConfigNode, error) {
	c := newConfigNode(st, path)
	if err := c.Read(); err != nil {
		return nil, err
	}
	return c, nil
}

// createConfigNode writes an initial config node.
func createConfigNode(st *State, path string, values map[string]interface{}) (*ConfigNode, error) {
	c := newConfigNode(st, path)
	c.core = copyMap(values)
	_, err := c.Write()
	if err != nil {
		return nil, err
	}
	return c, nil
}
<commit_msg>state: convert config nodes to txn<commit_after>package state

import (
	"fmt"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/txn"
	"sort"
)

const (
	ItemAdded = iota
	ItemModified
	ItemDeleted
)

// ItemChange represents the change of an item in a configNode.
type ItemChange struct {
	Type     int
	Key      string
	OldValue interface{}
	NewValue interface{}
}

// String returns the item change in a readable format.
func (ic *ItemChange) String() string {
	switch ic.Type {
	case ItemAdded:
		return fmt.Sprintf("setting added: %v = %v", ic.Key, ic.NewValue)
	case ItemModified:
		return fmt.Sprintf("setting modified: %v = %v (was %v)",
			ic.Key, ic.NewValue, ic.OldValue)
	case ItemDeleted:
		return fmt.Sprintf("setting deleted: %v (was %v)", ic.Key, ic.OldValue)
	}
	return fmt.Sprintf("unknown setting change type %d: %v = %v (was %v)",
		ic.Type, ic.Key, ic.NewValue, ic.OldValue)
}

// itemChangeSlice contains a slice of item changes in a config node.
// It implements the sort interface to sort the items changes by key.
type itemChangeSlice []ItemChange

func (ics itemChangeSlice) Len() int           { return len(ics) }
func (ics itemChangeSlice) Less(i, j int) bool { return ics[i].Key < ics[j].Key }
func (ics itemChangeSlice) Swap(i, j int)      { ics[i], ics[j] = ics[j], ics[i] }

// A ConfigNode manages changes to settings as a delta in memory and merges
// them back in the database when explicitly requested.
type ConfigNode struct {
	st   *State
	path string
	// disk holds the values in the config node before
	// any keys have been changed. It is reset on Read and Write
	// operations.
	disk map[string]interface{}
	// cache holds the current values in the config node.
	// The difference between disk and core
	// determines the delta to be applied when ConfigNode.Write
	// is called.
	core map[string]interface{}
}

// NotFoundError represents the error that something is not found.
type NotFoundError struct {
	what string
}

func (e *NotFoundError) Error() string {
	return fmt.Sprintf("%s not found", e.what)
}

// Keys returns the current keys in alphabetical order.
func (c *ConfigNode) Keys() []string {
	keys := []string{}
	for key := range c.core {
		keys = append(keys, key)
	}
	sort.Strings(keys)
	return keys
}

// Get returns the value of key and whether it was found.
func (c *ConfigNode) Get(key string) (value interface{}, found bool) {
	value, found = c.core[key]
	return
}

// Map returns all keys and values of the node.
func (c *ConfigNode) Map() map[string]interface{} {
	return copyMap(c.core)
}

// Set sets key to value
func (c *ConfigNode) Set(key string, value interface{}) {
	c.core[key] = value
}

// Update sets multiple key/value pairs.
func (c *ConfigNode) Update(kv map[string]interface{}) {
	for key, value := range kv {
		c.core[key] = value
	}
}

// Delete removes key.
func (c *ConfigNode) Delete(key string) {
	delete(c.core, key)
}

// copyMap copies the keys and values of one map into a new one.
func copyMap(in map[string]interface{}) (out map[string]interface{}) {
	out = make(map[string]interface{})
	for key, value := range in {
		out[key] = value
	}
	return
}

// cacheKeys returns the keys of all caches as a key=>true map.
func cacheKeys(caches ...map[string]interface{}) map[string]bool {
	keys := make(map[string]bool)
	for _, cache := range caches {
		for key := range cache {
			keys[key] = true
		}
	}
	return keys
}

// Write writes changes made to c back onto its node.  Changes are written
// as a delta applied on top of the latest version of the node, to prevent
// overwriting unrelated changes made to the node since it was last read.
func (c *ConfigNode) Write() ([]ItemChange, error) {
	changes := []ItemChange{}
	upserts := map[string]interface{}{}
	deletions := map[string]int{}
	for key := range cacheKeys(c.disk, c.core) {
		old, ondisk := c.disk[key]
		new, incore := c.core[key]
		if new == old {
			continue
		}
		var change ItemChange
		switch {
		case incore && ondisk:
			change = ItemChange{ItemModified, key, old, new}
			upserts[key] = new
		case incore && !ondisk:
			change = ItemChange{ItemAdded, key, nil, new}
			upserts[key] = new
		case ondisk && !incore:
			change = ItemChange{ItemDeleted, key, old, nil}
			deletions[key] = 1
		default:
			panic("unreachable")
		}
		changes = append(changes, change)
	}
	if len(changes) == 0 {
		return []ItemChange{}, nil
	}
	sort.Sort(itemChangeSlice(changes))
	inserts := copyMap(upserts)
	inserts["version"] = 1
	ops := []txn.Op{{
		C:      c.st.settings.Name,
		Id:     c.path,
		Insert: inserts,
	}}
	if err := c.st.runner.Run(ops, "", nil); err != nil {
		return nil, fmt.Errorf("cannot write configuration node %q: %v", c.path, err)
	}
	ops = []txn.Op{{
		C:  c.st.settings.Name,
		Id: c.path,
		Update: D{
			{"$inc", D{{"version", 1}}},
			{"$set", upserts},
			{"$unset", deletions},
		},
	}}
	if err := c.st.runner.Run(ops, "", nil); err != nil {
		return nil, fmt.Errorf("cannot write configuration node %q: %v", c.path, err)
	}
	c.disk = copyMap(c.core)
	return changes, nil
}

func newConfigNode(st *State, path string) *ConfigNode {
	return &ConfigNode{
		st:   st,
		path: path,
		core: make(map[string]interface{}),
	}
}

// cleanMap cleans the map of version and _id fields.
func cleanMap(in map[string]interface{}) {
	delete(in, "_id")
	delete(in, "version")
	delete(in, "txn-revno")
	delete(in, "txn-queue")
}

// Read (re)reads the node data into c.
func (c *ConfigNode) Read() error {
	config := map[string]interface{}{}
	err := c.st.settings.FindId(c.path).One(config)
	if err == mgo.ErrNotFound {
		c.disk = nil
		c.core = make(map[string]interface{})
		return nil
	}
	if err != nil {
		return fmt.Errorf("cannot read configuration node %q: %v", c.path, err)
	}
	cleanMap(config)
	c.disk = copyMap(config)
	c.core = copyMap(config)
	return nil
}

// readConfigNode returns the ConfigNode for path.
func readConfigNode(st *State, path string) (*ConfigNode, error) {
	c := newConfigNode(st, path)
	if err := c.Read(); err != nil {
		return nil, err
	}
	return c, nil
}

// createConfigNode writes an initial config node.
func createConfigNode(st *State, path string, values map[string]interface{}) (*ConfigNode, error) {
	c := newConfigNode(st, path)
	c.core = copyMap(values)
	_, err := c.Write()
	if err != nil {
		return nil, err
	}
	return c, nil
}
<|endoftext|>


<commit_before>package drone

import (
	"errors"
	"fmt"
)

type RepoService struct {
	*Client
}

// GET /api/repos/{host}/{owner}/{name}
func (s *RepoService) Get(host, owner, name string) (*Repo, error) {
	var path string
	if s.isServer04 {
		path = fmt.Sprintf("/api/repos/%s/%s", owner, name)
	} else {
		path = fmt.Sprintf("/api/repos/%s/%s/%s", host, owner, name)
	}
	var repo = Repo{}
	var err = s.run("GET", path, nil, &repo)
	if err == nil {
		return &repo, nil
	} else {
		return nil, err
	}
}

// POST /api/repos/{owner}/{name}
func (s *RepoService) Create(owner, name string) (*Repo, error) {
	if !s.isServer04 {
		return nil, errors.New("No create repos method before Drone 0.4")
	}
	path := fmt.Sprintf("/api/repos/%s/%s", owner, name)
	var result = Repo{}
	var err = s.run("POST", path, nil, &result)
	if err == nil {
		return &result, nil
	} else {
		return nil, err
	}
}

// PUT /api/repos/{host}/{owner}/{name}
func (s *RepoService) Update(repo *Repo) (*Repo, error) {
	var path string
	if s.isServer04 {
		path = fmt.Sprintf("/api/repos/%s/%s", repo.Owner, repo.Name)
	} else {
		path = fmt.Sprintf("/api/repos/%s/%s/%s", repo.Host, repo.Owner, repo.Name)
	}
	var result = Repo{}
	var err = s.run("PUT", path, &repo, &result)
	return &result, err
}

// POST /api/repos/{host}/{owner}/{name}
func (s *RepoService) Enable(host, owner, name string) error {
	var path string
	if s.isServer04 {
		path = fmt.Sprintf("/api/repos/%s/%s", owner, name)
	} else {
		path = fmt.Sprintf("/api/repos/%s/%s/%s", host, owner, name)
	}
	return s.run("POST", path, nil, nil)
}

// POST /api/repos/{host}/{owner}/{name}/deactivate
func (s *RepoService) Disable(host, owner, name string) error {
	var path string
	if s.isServer04 {
		return errors.New("No disable function in Drone 0.4")
	} else {
		path = fmt.Sprintf("/api/repos/%s/%s/%s/deactivate", host, owner, name)
	}
	return s.run("POST", path, nil, nil)
}

// DELETE /api/repos/{host}/{owner}/{name}?remove=true
func (s *RepoService) Delete(host, owner, name string) error {
	var path string
	if s.isServer04 {
		path = fmt.Sprintf("/api/repos/%s/%s", owner, name)
	} else {
		path = fmt.Sprintf("/api/repos/%s/%s/%s", host, owner, name)
	}
	return s.run("DELETE", path, nil, nil)
}

// PUT /api/repos/{host}/{owner}/{name}
func (s *RepoService) SetKey(host, owner, name, pub, priv string) error {
	var path string
	if s.isServer04 {
		path = fmt.Sprintf("/api/repos/%s/%s", owner, name)
	} else {
		path = fmt.Sprintf("/api/repos/%s/%s/%s", host, owner, name)
	}
	var in = struct {
		PublicKey  string `json:"public_key"`
		PrivateKey string `json:"private_key"`
	}{pub, priv}
	return s.run("PUT", path, &in, nil)
}

// PUT /api/repos/{host}/{owner}/{name}
func (s *RepoService) SetParams(host, owner, name, params string) error {
	var path string
	if s.isServer04 {
		path = fmt.Sprintf("/api/repos/%s/%s", owner, name)
	} else {
		path = fmt.Sprintf("/api/repos/%s/%s/%s", host, owner, name)
	}
	var in = struct {
		Params string `json:"params"`
	}{params}
	return s.run("PUT", path, &in, nil)
}

// GET /api/user/repos
func (s *RepoService) List() ([]*Repo, error) {
	var repos []*Repo
	var err = s.run("GET", "/api/user/repos", nil, &repos)
	return repos, err
}
<commit_msg>Add no-activate option to prevent Drone 0.4 creating webhooks in Github<commit_after>package drone

import (
	"errors"
	"fmt"
)

type RepoService struct {
	*Client
}

// GET /api/repos/{host}/{owner}/{name}
func (s *RepoService) Get(host, owner, name string) (*Repo, error) {
	var path string
	if s.isServer04 {
		path = fmt.Sprintf("/api/repos/%s/%s", owner, name)
	} else {
		path = fmt.Sprintf("/api/repos/%s/%s/%s", host, owner, name)
	}
	var repo = Repo{}
	var err = s.run("GET", path, nil, &repo)
	if err == nil {
		return &repo, nil
	} else {
		return nil, err
	}
}

// POST /api/repos/{owner}/{name}
func (s *RepoService) Create(owner, name string) (*Repo, error) {
	if !s.isServer04 {
		return nil, errors.New("No create repos method before Drone 0.4")
	}
	path := fmt.Sprintf("/api/repos/%s/%s?no-activate=true", owner, name)
	var result = Repo{}
	var err = s.run("POST", path, nil, &result)
	if err == nil {
		return &result, nil
	} else {
		return nil, err
	}
}

// PUT /api/repos/{host}/{owner}/{name}
func (s *RepoService) Update(repo *Repo) (*Repo, error) {
	var path string
	if s.isServer04 {
		path = fmt.Sprintf("/api/repos/%s/%s", repo.Owner, repo.Name)
	} else {
		path = fmt.Sprintf("/api/repos/%s/%s/%s", repo.Host, repo.Owner, repo.Name)
	}
	var result = Repo{}
	var err = s.run("PUT", path, &repo, &result)
	return &result, err
}

// POST /api/repos/{host}/{owner}/{name}
func (s *RepoService) Enable(host, owner, name string) error {
	var path string
	if s.isServer04 {
		path = fmt.Sprintf("/api/repos/%s/%s", owner, name)
	} else {
		path = fmt.Sprintf("/api/repos/%s/%s/%s", host, owner, name)
	}
	return s.run("POST", path, nil, nil)
}

func (s *RepoService) EnableWithActivate(host, owner, name string, activate bool) error {
	var path string
	if s.isServer04 {
		path = fmt.Sprintf("/api/repos/%s/%s?no-activate=%v", owner, name, !activate)
	} else {
		path = fmt.Sprintf("/api/repos/%s/%s/%s", host, owner, name)
	}
	return s.run("POST", path, nil, nil)
}

// POST /api/repos/{host}/{owner}/{name}/deactivate
func (s *RepoService) Disable(host, owner, name string) error {
	var path string
	if s.isServer04 {
		return errors.New("No disable function in Drone 0.4")
	} else {
		path = fmt.Sprintf("/api/repos/%s/%s/%s/deactivate", host, owner, name)
	}
	return s.run("POST", path, nil, nil)
}

// DELETE /api/repos/{host}/{owner}/{name}?remove=true
func (s *RepoService) Delete(host, owner, name string) error {
	var path string
	if s.isServer04 {
		path = fmt.Sprintf("/api/repos/%s/%s", owner, name)
	} else {
		path = fmt.Sprintf("/api/repos/%s/%s/%s", host, owner, name)
	}
	return s.run("DELETE", path, nil, nil)
}

// PUT /api/repos/{host}/{owner}/{name}
func (s *RepoService) SetKey(host, owner, name, pub, priv string) error {
	var path string
	if s.isServer04 {
		path = fmt.Sprintf("/api/repos/%s/%s", owner, name)
	} else {
		path = fmt.Sprintf("/api/repos/%s/%s/%s", host, owner, name)
	}
	var in = struct {
		PublicKey  string `json:"public_key"`
		PrivateKey string `json:"private_key"`
	}{pub, priv}
	return s.run("PUT", path, &in, nil)
}

// PUT /api/repos/{host}/{owner}/{name}
func (s *RepoService) SetParams(host, owner, name, params string) error {
	var path string
	if s.isServer04 {
		path = fmt.Sprintf("/api/repos/%s/%s", owner, name)
	} else {
		path = fmt.Sprintf("/api/repos/%s/%s/%s", host, owner, name)
	}
	var in = struct {
		Params string `json:"params"`
	}{params}
	return s.run("PUT", path, &in, nil)
}

// GET /api/user/repos
func (s *RepoService) List() ([]*Repo, error) {
	var repos []*Repo
	var err = s.run("GET", "/api/user/repos", nil, &repos)
	return repos, err
}
<|endoftext|>


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

package net

import (
	"os"
	"reflect"
	"runtime"
	"syscall"
	"testing"
)

type listenerFile interface {
	Listener
	File() (f *os.File, err os.Error)
}

type packetConnFile interface {
	PacketConn
	File() (f *os.File, err os.Error)
}

type connFile interface {
	Conn
	File() (f *os.File, err os.Error)
}

func testFileListener(t *testing.T, net, laddr string) {
	if net == "tcp" {
		laddr += ":0" // any available port
	}
	l, err := Listen(net, laddr)
	if err != nil {
		t.Fatalf("Listen failed: %v", err)
	}
	defer l.Close()
	lf := l.(listenerFile)
	f, err := lf.File()
	if err != nil {
		t.Fatalf("File failed: %v", err)
	}
	c, err := FileListener(f)
	if err != nil {
		t.Fatalf("FileListener failed: %v", err)
	}
	if !reflect.DeepEqual(l.Addr(), c.Addr()) {
		t.Fatalf("Addrs not equal: %#v != %#v", l.Addr(), c.Addr())
	}
	if err := c.Close(); err != nil {
		t.Fatalf("Close failed: %v", err)
	}
	if err := f.Close(); err != nil {
		t.Fatalf("Close failed: %v", err)
	}
}

func TestFileListener(t *testing.T) {
	if runtime.GOOS == "windows" {
		return
	}
	testFileListener(t, "tcp", "127.0.0.1")
	testFileListener(t, "tcp", "127.0.0.1")
	if kernelSupportsIPv6() {
		testFileListener(t, "tcp", "[::ffff:127.0.0.1]")
		testFileListener(t, "tcp", "127.0.0.1")
		testFileListener(t, "tcp", "[::ffff:127.0.0.1]")
	}
	if syscall.OS == "linux" {
		testFileListener(t, "unix", "@gotest/net")
		testFileListener(t, "unixpacket", "@gotest/net")
	}
}

func testFilePacketConn(t *testing.T, pcf packetConnFile) {
	f, err := pcf.File()
	if err != nil {
		t.Fatalf("File failed: %v", err)
	}
	c, err := FilePacketConn(f)
	if err != nil {
		t.Fatalf("FilePacketConn failed: %v", err)
	}
	if !reflect.DeepEqual(pcf.LocalAddr(), c.LocalAddr()) {
		t.Fatalf("LocalAddrs not equal: %#v != %#v", pcf.LocalAddr(), c.LocalAddr())
	}
	if err := c.Close(); err != nil {
		t.Fatalf("Close failed: %v", err)
	}
	if err := f.Close(); err != nil {
		t.Fatalf("Close failed: %v", err)
	}
}

func testFilePacketConnListen(t *testing.T, net, laddr string) {
	l, err := ListenPacket(net, laddr)
	if err != nil {
		t.Fatalf("Listen failed: %v", err)
	}
	testFilePacketConn(t, l.(packetConnFile))
	if err := l.Close(); err != nil {
		t.Fatalf("Close failed: %v", err)
	}
}

func testFilePacketConnDial(t *testing.T, net, raddr string) {
	c, err := Dial(net, "", raddr)
	if err != nil {
		t.Fatalf("Dial failed: %v", err)
	}
	testFilePacketConn(t, c.(packetConnFile))
	if err := c.Close(); err != nil {
		t.Fatalf("Close failed: %v", err)
	}
}

func TestFilePacketConn(t *testing.T) {
	if runtime.GOOS == "windows" {
		return
	}
	testFilePacketConnListen(t, "udp", "127.0.0.1:0")
	testFilePacketConnDial(t, "udp", "127.0.0.1:12345")
	if kernelSupportsIPv6() {
		testFilePacketConnListen(t, "udp", "[::1]:0")
		testFilePacketConnDial(t, "udp", "[::ffff:127.0.0.1]:12345")
	}
	if syscall.OS == "linux" {
		testFilePacketConnListen(t, "unixgram", "@gotest1/net")
	}
}
<commit_msg>fix build<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package net

import (
	"os"
	"reflect"
	"runtime"
	"syscall"
	"testing"
)

type listenerFile interface {
	Listener
	File() (f *os.File, err os.Error)
}

type packetConnFile interface {
	PacketConn
	File() (f *os.File, err os.Error)
}

type connFile interface {
	Conn
	File() (f *os.File, err os.Error)
}

func testFileListener(t *testing.T, net, laddr string) {
	if net == "tcp" {
		laddr += ":0" // any available port
	}
	l, err := Listen(net, laddr)
	if err != nil {
		t.Fatalf("Listen failed: %v", err)
	}
	defer l.Close()
	lf := l.(listenerFile)
	f, err := lf.File()
	if err != nil {
		t.Fatalf("File failed: %v", err)
	}
	c, err := FileListener(f)
	if err != nil {
		t.Fatalf("FileListener failed: %v", err)
	}
	if !reflect.DeepEqual(l.Addr(), c.Addr()) {
		t.Fatalf("Addrs not equal: %#v != %#v", l.Addr(), c.Addr())
	}
	if err := c.Close(); err != nil {
		t.Fatalf("Close failed: %v", err)
	}
	if err := f.Close(); err != nil {
		t.Fatalf("Close failed: %v", err)
	}
}

func TestFileListener(t *testing.T) {
	if runtime.GOOS == "windows" {
		return
	}
	testFileListener(t, "tcp", "127.0.0.1")
	testFileListener(t, "tcp", "127.0.0.1")
	if kernelSupportsIPv6() {
		testFileListener(t, "tcp", "[::ffff:127.0.0.1]")
		testFileListener(t, "tcp", "127.0.0.1")
		testFileListener(t, "tcp", "[::ffff:127.0.0.1]")
	}
	if syscall.OS == "linux" {
		testFileListener(t, "unix", "@gotest/net")
		testFileListener(t, "unixpacket", "@gotest/net")
	}
}

func testFilePacketConn(t *testing.T, pcf packetConnFile) {
	f, err := pcf.File()
	if err != nil {
		t.Fatalf("File failed: %v", err)
	}
	c, err := FilePacketConn(f)
	if err != nil {
		t.Fatalf("FilePacketConn failed: %v", err)
	}
	if !reflect.DeepEqual(pcf.LocalAddr(), c.LocalAddr()) {
		t.Fatalf("LocalAddrs not equal: %#v != %#v", pcf.LocalAddr(), c.LocalAddr())
	}
	if err := c.Close(); err != nil {
		t.Fatalf("Close failed: %v", err)
	}
	if err := f.Close(); err != nil {
		t.Fatalf("Close failed: %v", err)
	}
}

func testFilePacketConnListen(t *testing.T, net, laddr string) {
	l, err := ListenPacket(net, laddr)
	if err != nil {
		t.Fatalf("Listen failed: %v", err)
	}
	testFilePacketConn(t, l.(packetConnFile))
	if err := l.Close(); err != nil {
		t.Fatalf("Close failed: %v", err)
	}
}

func testFilePacketConnDial(t *testing.T, net, raddr string) {
	c, err := Dial(net, raddr)
	if err != nil {
		t.Fatalf("Dial failed: %v", err)
	}
	testFilePacketConn(t, c.(packetConnFile))
	if err := c.Close(); err != nil {
		t.Fatalf("Close failed: %v", err)
	}
}

func TestFilePacketConn(t *testing.T) {
	if runtime.GOOS == "windows" {
		return
	}
	testFilePacketConnListen(t, "udp", "127.0.0.1:0")
	testFilePacketConnDial(t, "udp", "127.0.0.1:12345")
	if kernelSupportsIPv6() {
		testFilePacketConnListen(t, "udp", "[::1]:0")
		testFilePacketConnDial(t, "udp", "[::ffff:127.0.0.1]:12345")
	}
	if syscall.OS == "linux" {
		testFilePacketConnListen(t, "unixgram", "@gotest1/net")
	}
}
<|endoftext|>