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

package main

import (
	"bytes"
	"container/list"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strconv"
	"strings"

	"github.com/codegangsta/cli"
	"github.com/gogits/gogs/modules/log"

	"github.com/gogits/git"
	"github.com/gogits/gogs/models"
	"github.com/gogits/gogs/modules/base"
)

var (
	COMMANDS_READONLY = map[string]int{
		"git-upload-pack":    models.AU_WRITABLE,
		"git upload-pack":    models.AU_WRITABLE,
		"git-upload-archive": models.AU_WRITABLE,
	}

	COMMANDS_WRITE = map[string]int{
		"git-receive-pack": models.AU_READABLE,
		"git receive-pack": models.AU_READABLE,
	}
)

var CmdServ = cli.Command{
	Name:  "serv",
	Usage: "This command just should be called by ssh shell",
	Description: `
gogs serv provide access auth for repositories`,
	Action: runServ,
	Flags:  []cli.Flag{},
}

func init() {
	os.MkdirAll("log", os.ModePerm)
	log.NewLogger(10000, "file", fmt.Sprintf(`{"filename":"%s"}`, "log/serv.log"))
}

func parseCmd(cmd string) (string, string) {
	ss := strings.SplitN(cmd, " ", 2)
	if len(ss) != 2 {
		return "", ""
	}

	verb, args := ss[0], ss[1]
	if verb == "git" {
		ss = strings.SplitN(args, " ", 2)
		args = ss[1]
		verb = fmt.Sprintf("%s %s", verb, ss[0])
	}
	return verb, args
}

func In(b string, sl map[string]int) bool {
	_, e := sl[b]
	return e
}

func runServ(k *cli.Context) {
	base.NewConfigContext()
	models.LoadModelsConfig()
	models.NewEngine()

	keys := strings.Split(os.Args[2], "-")
	if len(keys) != 2 {
		fmt.Println("auth file format error")
		return
	}

	keyId, err := strconv.ParseInt(keys[1], 10, 64)
	if err != nil {
		fmt.Println("auth file format error")
		return
	}
	user, err := models.GetUserByKeyId(keyId)
	if err != nil {
		fmt.Println("You have no right to access")
		return
	}

	cmd := os.Getenv("SSH_ORIGINAL_COMMAND")
	if cmd == "" {
		println("Hi", user.Name, "! You've successfully authenticated, but Gogs does not provide shell access.")
		return
	}

	verb, args := parseCmd(cmd)
	rRepo := strings.Trim(args, "'")
	rr := strings.SplitN(rRepo, "/", 2)
	if len(rr) != 2 {
		println("Unavilable repository", args)
		return
	}
	repoName := rr[1]
	if strings.HasSuffix(repoName, ".git") {
		repoName = repoName[:len(repoName)-4]
	}

	repo, err := models.GetRepositoryByName(user.Id, repoName)
	var isExist bool = true
	if err != nil {
		if err == models.ErrRepoNotExist {
			isExist = false
		} else {
			println("Unavilable repository", err)
			return
		}
	}

	isWrite := In(verb, COMMANDS_WRITE)
	isRead := In(verb, COMMANDS_READONLY)

	switch {
	case isWrite:
		has, err := models.HasAccess(user.Name, repoName, models.AU_WRITABLE)
		if err != nil {
			println("Inernel error:", err)
			return
		}
		if !has {
			println("You have no right to write this repository")
			return
		}
	case isRead:
		has, err := models.HasAccess(user.Name, repoName, models.AU_READABLE)
		if err != nil {
			println("Inernel error")
			return
		}
		if !has {
			has, err = models.HasAccess(user.Name, repoName, models.AU_WRITABLE)
			if err != nil {
				println("Inernel error")
				return
			}
		}
		if !has {
			println("You have no right to access this repository")
			return
		}
	default:
		println("Unknown command")
		return
	}

	if !isExist {
		if isRead {
			println("Repository", user.Name+"/"+repoName, "is not exist")
			return
		} else if isWrite {
			_, err := models.CreateRepository(user, repoName, "", "", "", false, true)
			if err != nil {
				println("Create repository failed")
				return
			}
		}
	}

	rep, err := git.OpenRepository(models.RepoPath(user.Name, repoName))
	if err != nil {
		println(err.Error())
		return
	}

	refs, err := rep.AllReferencesMap()
	if err != nil {
		println(err.Error())
		return
	}

	gitcmd := exec.Command(verb, rRepo)
	gitcmd.Dir = base.RepoRootPath

	var s string
	b := bytes.NewBufferString(s)

	gitcmd.Stdout = io.MultiWriter(os.Stdout, b)
	//gitcmd.Stdin = io.MultiReader(os.Stdin, b)
	gitcmd.Stdin = os.Stdin
	gitcmd.Stderr = os.Stderr

	if err = gitcmd.Run(); err != nil {
		println("execute command error:", err.Error())
	}

	if !strings.HasPrefix(cmd, "git-receive-pack") {
		return
	}

	// update
	//w, _ := os.Create("serve.log")
	//defer w.Close()
	//log.SetOutput(w)

	var t = "ok refs/heads/"
	var i int
	var refname string
	for {
		l, err := b.ReadString('\n')
		if err != nil {
			break
		}
		i = i + 1
		l = l[:len(l)-1]
		idx := strings.Index(l, t)
		if idx > 0 {
			refname = l[idx+len(t):]
		}
	}
	var ref *git.Reference
	var ok bool

	var l *list.List
	//log.Info("----", refname, "-----")
	if ref, ok = refs[refname]; !ok {
		refs, err = rep.AllReferencesMap()
		if err != nil {
			println(err.Error())
			return
		}
		if ref, ok = refs[refname]; !ok {
			log.Trace("unknow reference name -", refname, "-", b.String())
			return
		}
		l, err = ref.AllCommits()
		if err != nil {
			println(err.Error())
			return
		}
	} else {
		//log.Info("----", ref, "-----")
		var last *git.Commit
		//log.Info("00000", ref.Oid.String())
		last, err = ref.LastCommit()
		if err != nil {
			println(err.Error())
			return
		}

		ref2, err := rep.LookupReference(ref.Name)
		if err != nil {
			println(err.Error())
			return
		}

		//log.Info("11111", ref2.Oid.String())
		before, err := ref2.LastCommit()
		if err != nil {
			println(err.Error())
			return
		}
		//log.Info("----", before.Id(), "-----", last.Id())
		l = ref.CommitsBetween(before, last)
	}

	commits := make([][]string, 0)
	var maxCommits = 3
	for e := l.Front(); e != nil; e = e.Next() {
		commit := e.Value.(*git.Commit)
		commits = append(commits, []string{commit.Id().String(), commit.Message()})
		if len(commits) >= maxCommits {
			break
		}
	}

	if err = models.CommitRepoAction(user.Id, user.Name,
		repo.Id, repoName, refname, &base.PushCommits{l.Len(), commits}); err != nil {
		log.Error("runUpdate.models.CommitRepoAction: %v", err, commits)
	} else {
		//log.Info("refname", refname)
		//log.Info("Listen: %v", cmd)
		//fmt.Println("...", cmd)

		//runUpdate(k)
		c := exec.Command("git", "update-server-info")
		c.Dir = models.RepoPath(user.Name, repoName)
		err := c.Run()
		if err != nil {
			log.Error("update-server-info: %v", err)
		}
	}
}
<commit_msg>bug fixed<commit_after>// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"container/list"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strconv"
	"strings"

	"github.com/codegangsta/cli"
	"github.com/gogits/gogs/modules/log"

	"github.com/gogits/git"
	"github.com/gogits/gogs/models"
	"github.com/gogits/gogs/modules/base"
)

var (
	COMMANDS_READONLY = map[string]int{
		"git-upload-pack":    models.AU_WRITABLE,
		"git upload-pack":    models.AU_WRITABLE,
		"git-upload-archive": models.AU_WRITABLE,
	}

	COMMANDS_WRITE = map[string]int{
		"git-receive-pack": models.AU_READABLE,
		"git receive-pack": models.AU_READABLE,
	}
)

var CmdServ = cli.Command{
	Name:  "serv",
	Usage: "This command just should be called by ssh shell",
	Description: `
gogs serv provide access auth for repositories`,
	Action: runServ,
	Flags:  []cli.Flag{},
}

func init() {
	os.MkdirAll("log", os.ModePerm)
	log.NewLogger(10000, "file", fmt.Sprintf(`{"filename":"%s"}`, "log/serv.log"))
}

func parseCmd(cmd string) (string, string) {
	ss := strings.SplitN(cmd, " ", 2)
	if len(ss) != 2 {
		return "", ""
	}

	verb, args := ss[0], ss[1]
	if verb == "git" {
		ss = strings.SplitN(args, " ", 2)
		args = ss[1]
		verb = fmt.Sprintf("%s %s", verb, ss[0])
	}
	return verb, args
}

func In(b string, sl map[string]int) bool {
	_, e := sl[b]
	return e
}

func runServ(k *cli.Context) {
	base.NewConfigContext()
	models.LoadModelsConfig()
	models.NewEngine()

	keys := strings.Split(os.Args[2], "-")
	if len(keys) != 2 {
		fmt.Println("auth file format error")
		return
	}

	keyId, err := strconv.ParseInt(keys[1], 10, 64)
	if err != nil {
		fmt.Println("auth file format error")
		return
	}
	user, err := models.GetUserByKeyId(keyId)
	if err != nil {
		fmt.Println("You have no right to access")
		return
	}

	cmd := os.Getenv("SSH_ORIGINAL_COMMAND")
	if cmd == "" {
		println("Hi", user.Name, "! You've successfully authenticated, but Gogs does not provide shell access.")
		return
	}

	verb, args := parseCmd(cmd)
	rRepo := strings.Trim(args, "'")
	rr := strings.SplitN(rRepo, "/", 2)
	if len(rr) != 2 {
		println("Unavilable repository", args)
		return
	}
	repoName := rr[1]
	if strings.HasSuffix(repoName, ".git") {
		repoName = repoName[:len(repoName)-4]
	}

	isWrite := In(verb, COMMANDS_WRITE)
	isRead := In(verb, COMMANDS_READONLY)

	repo, err := models.GetRepositoryByName(user.Id, repoName)
	var isExist bool = true
	if err != nil {
		if err == models.ErrRepoNotExist {
			isExist = false
			if isRead {
				println("Repository", user.Name+"/"+repoName, "is not exist")
				return
			}
		} else {
			println("Get repository error:", err)
			return
		}
	}

	// access check
	switch {
	case isWrite:
		has, err := models.HasAccess(user.Name, repoName, models.AU_WRITABLE)
		if err != nil {
			println("Inernel error:", err)
			return
		}
		if !has {
			println("You have no right to write this repository")
			return
		}
	case isRead:
		has, err := models.HasAccess(user.Name, repoName, models.AU_READABLE)
		if err != nil {
			println("Inernel error")
			return
		}
		if !has {
			has, err = models.HasAccess(user.Name, repoName, models.AU_WRITABLE)
			if err != nil {
				println("Inernel error")
				return
			}
		}
		if !has {
			println("You have no right to access this repository")
			return
		}
	default:
		println("Unknown command")
		return
	}

	var rep *git.Repository
	repoPath := models.RepoPath(user.Name, repoName)
	if !isExist {
		if isWrite {
			_, err = models.CreateRepository(user, repoName, "", "", "", false, true)
			if err != nil {
				println("Create repository failed")
				return
			}
		}
	}

		rep, err = git.OpenRepository(repoPath)
		if err != nil {
			println(err.Error())
			return
		}

	refs, err := rep.AllReferencesMap()
	if err != nil {
		println(err.Error())
		return
	}

	gitcmd := exec.Command(verb, rRepo)
	gitcmd.Dir = base.RepoRootPath

	var s string
	b := bytes.NewBufferString(s)

	gitcmd.Stdout = io.MultiWriter(os.Stdout, b)
	//gitcmd.Stdin = io.MultiReader(os.Stdin, b)
	gitcmd.Stdin = os.Stdin
	gitcmd.Stderr = os.Stderr

	if err = gitcmd.Run(); err != nil {
		println("execute command error:", err.Error())
		return
	}

	if isRead {
		return
	}

	// find push reference name
	var t = "ok refs/heads/"
	var i int
	var refname string
	for {
		l, err := b.ReadString('\n')
		if err != nil {
			break
		}
		i = i + 1
		l = l[:len(l)-1]
		idx := strings.Index(l, t)
		if idx > 0 {
			refname = l[idx+len(t):]
		}
	}
	if refname == "" {
		println("No find any reference name:", b.String())
		return
	}

	var ref *git.Reference
	var ok bool
	var l *list.List
	//log.Info("----", refname, "-----")
	if ref, ok = refs[refname]; !ok {
		// for new branch
		refs, err = rep.AllReferencesMap()
		if err != nil {
			println(err.Error())
			return
		}
		if ref, ok = refs[refname]; !ok {
			log.Trace("unknow reference name -", refname, "-", b.String())
			return
		}
		l, err = ref.AllCommits()
		if err != nil {
			println(err.Error())
			return
		}
	} else {
		//log.Info("----", ref, "-----")
		var last *git.Commit
		//log.Info("00000", ref.Oid.String())
		last, err = ref.LastCommit()
		if err != nil {
			println(err.Error())
			return
		}

		ref2, err := rep.LookupReference(ref.Name)
		if err != nil {
			println(err.Error())
			return
		}

		//log.Info("11111", ref2.Oid.String())
		before, err := ref2.LastCommit()
		if err != nil {
			println(err.Error())
			return
		}
		//log.Info("----", before.Id(), "-----", last.Id())
		l = ref.CommitsBetween(before, last)
	}

	commits := make([][]string, 0)
	var maxCommits = 3
	for e := l.Front(); e != nil; e = e.Next() {
		commit := e.Value.(*git.Commit)
		commits = append(commits, []string{commit.Id().String(), commit.Message()})
		if len(commits) >= maxCommits {
			break
		}
	}

	if err = models.CommitRepoAction(user.Id, user.Name,
		repo.Id, repoName, refname, &base.PushCommits{l.Len(), commits}); err != nil {
		log.Error("runUpdate.models.CommitRepoAction: %v", err, commits)
	} else {
		c := exec.Command("git", "update-server-info")
		c.Dir = repoPath
		err := c.Run()
		if err != nil {
			log.Error("update-server-info: %v", err)
		}
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright 2019, EnMasse authors.
 * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
 */

package images

import (
	"fmt"
	"io/ioutil"
	"os"
	"strings"

	"gopkg.in/yaml.v2"
	corev1 "k8s.io/api/core/v1"
)

var (
	imageMap          map[string]string
	defaultPullPolicy corev1.PullPolicy
)

func loadImageMapFrom(fileName string) (map[string]string, error) {

	var data = make(map[string]string)

	file, err := os.Open(fileName)
	if err != nil {
		return nil, err
	}

	defer func() { _ = file.Close() }()

	byteValue, err := ioutil.ReadAll(file)
	if err != nil {
		return nil, err
	}

	if err := yaml.Unmarshal(byteValue, data); err != nil {
		return nil, err
	}

	return data, nil

}

func setIfEnvPresent(data map[string]string, key string, envVar string) {
	value, present := os.LookupEnv(key)
	if present {
		data[key] = value
	}
}

func overrideImageMapFromEnv(data map[string]string) {
	setIfEnvPresent(data, "iot-auth-service", "IOT_AUTH_SERVICE_IMAGE")
	setIfEnvPresent(data, "iot-device-registry-file", "IOT_DEVICE_REGISTRY_FILE_IMAGE")
	setIfEnvPresent(data, "iot-gc", "IOT_GC_IMAGE")
	setIfEnvPresent(data, "iot-http-adapter", "IOT_HTTP_ADAPTER_IMAGE")
	setIfEnvPresent(data, "iot-mqtt-adapter", "IOT_MQTT_ADAPTER_IMAGE")
	setIfEnvPresent(data, "iot-tenant-service", "IOT_TENANT_SERVICE_IMAGE_IMAGE")
	setIfEnvPresent(data, "iot-proxy-configurator", "IOT_PROXY_CONFIGURATOR_IMAGE")
	setIfEnvPresent(data, "qdrouterd-base", "QDROUTERD_BASE_IMAGE")
	setIfEnvPresent(data, "none-authservice", "NONE_AUTHSERVICE_IMAGE")
	setIfEnvPresent(data, "keycloak", "KEYCLOAK_IMAGE")
	setIfEnvPresent(data, "keycloak-plugin", "KEYCLOAK_PLUGIN_IMAGE")
}

const defaultImageMapFileName = "operatorImageMap.yaml"

func init() {
	defaultPullPolicy = corev1.PullPolicy(os.Getenv("IMAGE_PULL_POLICY"))
}

func lazyLoadImageMap() {
	if imageMap != nil {
		return
	}

	fileName := os.Getenv("ENMASSE_IMAGE_MAP_FILE")
	if fileName == "" {
		fileName = defaultImageMapFileName
	}

	var err error
	imageMap, err = loadImageMapFrom(fileName)
	if err != nil {
		panic(err)
	}

	overrideImageMapFromEnv(imageMap)
}

func GetImage(name string) (string, error) {
	lazyLoadImageMap()

	if imageMap == nil {
		return "", fmt.Errorf("'%s' not found or 'ENMASSE_IMAGE_MAP_FILE' not set to a readable file, unable to lookup image names", defaultImageMapFileName)
	}

	value, ok := imageMap[name]
	if !ok {
		return "", fmt.Errorf("image '%s' not found in the mapping table", name)
	}

	return value, nil
}

func PullPolicyFromImageName(imageName string) corev1.PullPolicy {

	if defaultPullPolicy != "" {
		return defaultPullPolicy
	}

	if strings.HasSuffix(imageName, "-SNAPSHOT") || strings.HasSuffix(imageName, ":latest") {
		return corev1.PullAlways
	} else {
		return corev1.PullIfNotPresent
	}

}
<commit_msg>Use correct variable<commit_after>/*
 * Copyright 2019, EnMasse authors.
 * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
 */

package images

import (
	"fmt"
	"io/ioutil"
	"os"
	"strings"

	"gopkg.in/yaml.v2"
	corev1 "k8s.io/api/core/v1"
)

var (
	imageMap          map[string]string
	defaultPullPolicy corev1.PullPolicy
)

func loadImageMapFrom(fileName string) (map[string]string, error) {

	var data = make(map[string]string)

	file, err := os.Open(fileName)
	if err != nil {
		return nil, err
	}

	defer func() { _ = file.Close() }()

	byteValue, err := ioutil.ReadAll(file)
	if err != nil {
		return nil, err
	}

	if err := yaml.Unmarshal(byteValue, data); err != nil {
		return nil, err
	}

	return data, nil

}

func setIfEnvPresent(data map[string]string, key string, envVar string) {
	value, present := os.LookupEnv(envVar)
	if present {
		data[key] = value
	}
}

func overrideImageMapFromEnv(data map[string]string) {
	setIfEnvPresent(data, "iot-auth-service", "IOT_AUTH_SERVICE_IMAGE")
	setIfEnvPresent(data, "iot-device-registry-file", "IOT_DEVICE_REGISTRY_FILE_IMAGE")
	setIfEnvPresent(data, "iot-gc", "IOT_GC_IMAGE")
	setIfEnvPresent(data, "iot-http-adapter", "IOT_HTTP_ADAPTER_IMAGE")
	setIfEnvPresent(data, "iot-mqtt-adapter", "IOT_MQTT_ADAPTER_IMAGE")
	setIfEnvPresent(data, "iot-tenant-service", "IOT_TENANT_SERVICE_IMAGE_IMAGE")
	setIfEnvPresent(data, "iot-proxy-configurator", "IOT_PROXY_CONFIGURATOR_IMAGE")
	setIfEnvPresent(data, "qdrouterd-base", "QDROUTERD_BASE_IMAGE")
	setIfEnvPresent(data, "none-authservice", "NONE_AUTHSERVICE_IMAGE")
	setIfEnvPresent(data, "keycloak", "KEYCLOAK_IMAGE")
	setIfEnvPresent(data, "keycloak-plugin", "KEYCLOAK_PLUGIN_IMAGE")
}

const defaultImageMapFileName = "operatorImageMap.yaml"

func init() {
	defaultPullPolicy = corev1.PullPolicy(os.Getenv("IMAGE_PULL_POLICY"))
}

func lazyLoadImageMap() {
	if imageMap != nil {
		return
	}

	fileName := os.Getenv("ENMASSE_IMAGE_MAP_FILE")
	if fileName == "" {
		fileName = defaultImageMapFileName
	}

	var err error
	imageMap, err = loadImageMapFrom(fileName)
	if err != nil {
		panic(err)
	}

	overrideImageMapFromEnv(imageMap)
}

func GetImage(name string) (string, error) {
	lazyLoadImageMap()

	if imageMap == nil {
		return "", fmt.Errorf("'%s' not found or 'ENMASSE_IMAGE_MAP_FILE' not set to a readable file, unable to lookup image names", defaultImageMapFileName)
	}

	value, ok := imageMap[name]
	if !ok {
		return "", fmt.Errorf("image '%s' not found in the mapping table", name)
	}

	return value, nil
}

func PullPolicyFromImageName(imageName string) corev1.PullPolicy {

	if defaultPullPolicy != "" {
		return defaultPullPolicy
	}

	if strings.HasSuffix(imageName, "-SNAPSHOT") || strings.HasSuffix(imageName, ":latest") {
		return corev1.PullAlways
	} else {
		return corev1.PullIfNotPresent
	}

}
<|endoftext|>


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

package k8sutil

import (
	"encoding/json"
	"fmt"
	"path"
	"time"

	backupenv "github.com/coreos/etcd-operator/pkg/backup/env"
	"github.com/coreos/etcd-operator/pkg/spec"
	"github.com/coreos/etcd-operator/pkg/util/constants"
	"github.com/coreos/etcd-operator/pkg/util/retryutil"

	"github.com/coreos/etcd-operator/pkg/backup/s3/s3config"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/meta/metatypes"
	"k8s.io/kubernetes/pkg/api/resource"
	unversionedAPI "k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/apis/extensions"
	"k8s.io/kubernetes/pkg/apis/storage"
	"k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/util/intstr"
	"k8s.io/kubernetes/pkg/watch"
)

const (
	storageClassPrefix        = "etcd-operator-backup"
	BackupPodSelectorAppField = "etcd_backup_tool"
	backupPVVolName           = "etcd-backup-storage"
	awsCredentialDir          = "/root/.aws/"
	awsConfigDir              = "/root/.aws/config/"
	awsSecretVolName          = "secret-aws"
	awsConfigVolName          = "config-aws"
	fromDirMountDir           = "/mnt/backup/from"
)

func CreateStorageClass(kubecli *unversioned.Client, pvProvisioner string) error {
	// We need to get rid of prefix because naming doesn't support "/".
	name := storageClassPrefix + "-" + path.Base(pvProvisioner)
	class := &storage.StorageClass{
		ObjectMeta: api.ObjectMeta{
			Name: name,
		},
		Provisioner: pvProvisioner,
	}
	_, err := kubecli.StorageClasses().Create(class)
	return err
}

func CreateAndWaitPVC(kubecli *unversioned.Client, clusterName, ns, pvProvisioner string, volumeSizeInMB int) error {
	name := makePVCName(clusterName)
	storageClassName := storageClassPrefix + "-" + path.Base(pvProvisioner)
	claim := &api.PersistentVolumeClaim{
		ObjectMeta: api.ObjectMeta{
			Name: name,
			Labels: map[string]string{
				"etcd_cluster": clusterName,
			},
			Annotations: map[string]string{
				"volume.beta.kubernetes.io/storage-class": storageClassName,
			},
		},
		Spec: api.PersistentVolumeClaimSpec{
			AccessModes: []api.PersistentVolumeAccessMode{
				api.ReadWriteOnce,
			},
			Resources: api.ResourceRequirements{
				Requests: api.ResourceList{
					api.ResourceStorage: resource.MustParse(fmt.Sprintf("%dMi", volumeSizeInMB)),
				},
			},
		},
	}
	_, err := kubecli.PersistentVolumeClaims(ns).Create(claim)
	if err != nil {
		return err
	}

	err = retryutil.Retry(4*time.Second, 5, func() (bool, error) {
		var err error
		claim, err = kubecli.PersistentVolumeClaims(ns).Get(name)
		if err != nil {
			return false, err
		}
		if claim.Status.Phase != api.ClaimBound {
			return false, nil
		}
		return true, nil
	})
	if err != nil {
		wErr := fmt.Errorf("fail to wait PVC (%s) '(%v)/Bound': %v", name, claim.Status.Phase, err)
		return wErr
	}

	return nil
}

var BackupImage = "quay.io/coreos/etcd-operator:latest"

func PodSpecWithPV(ps *api.PodSpec, clusterName string) *api.PodSpec {
	ps.Containers[0].VolumeMounts = []api.VolumeMount{{
		Name:      backupPVVolName,
		MountPath: constants.BackupDir,
	}}
	ps.Volumes = []api.Volume{{
		Name: backupPVVolName,
		VolumeSource: api.VolumeSource{
			PersistentVolumeClaim: &api.PersistentVolumeClaimVolumeSource{
				ClaimName: makePVCName(clusterName),
			},
		},
	}}
	return ps
}

func PodSpecWithS3(ps *api.PodSpec, s3Ctx s3config.S3Context) *api.PodSpec {
	ps.Containers[0].VolumeMounts = []api.VolumeMount{{
		Name:      awsSecretVolName,
		MountPath: awsCredentialDir,
	}, {
		Name:      awsConfigVolName,
		MountPath: awsConfigDir,
	}}
	ps.Volumes = []api.Volume{{
		Name: awsSecretVolName,
		VolumeSource: api.VolumeSource{
			Secret: &api.SecretVolumeSource{
				SecretName: s3Ctx.AWSSecret,
			},
		},
	}, {
		Name: awsConfigVolName,
		VolumeSource: api.VolumeSource{
			ConfigMap: &api.ConfigMapVolumeSource{
				LocalObjectReference: api.LocalObjectReference{
					Name: s3Ctx.AWSConfig,
				},
			},
		},
	}}
	ps.Containers[0].Env = append(ps.Containers[0].Env, api.EnvVar{
		Name:  backupenv.AWSConfig,
		Value: path.Join(awsConfigDir, "config"),
	}, api.EnvVar{
		Name:  backupenv.AWSS3Bucket,
		Value: s3Ctx.S3Bucket,
	})
	return ps
}

func MakeBackupPodSpec(clusterName string, policy *spec.BackupPolicy) (*api.PodSpec, error) {
	bp, err := json.Marshal(policy)
	if err != nil {
		return nil, err
	}

	ps := &api.PodSpec{
		Containers: []api.Container{
			{
				Name:  "backup",
				Image: BackupImage,
				Command: []string{
					"/bin/sh",
					"-c",
					"/usr/local/bin/etcd-backup --etcd-cluster=" + clusterName,
				},
				Env: []api.EnvVar{{
					Name:      "MY_POD_NAMESPACE",
					ValueFrom: &api.EnvVarSource{FieldRef: &api.ObjectFieldSelector{FieldPath: "metadata.namespace"}},
				}, {
					Name:  backupenv.BackupPolicy,
					Value: string(bp),
				}},
			},
		},
	}
	return ps, nil
}

func backupNameAndLabel(clusterName string) (string, map[string]string) {
	labels := map[string]string{
		"app":          BackupPodSelectorAppField,
		"etcd_cluster": clusterName,
	}
	name := MakeBackupName(clusterName)
	return name, labels
}

func MakeBackupReplicaSet(clusterName string, ps api.PodSpec, owner metatypes.OwnerReference) *extensions.ReplicaSet {
	name, labels := backupNameAndLabel(clusterName)
	rs := &extensions.ReplicaSet{
		ObjectMeta: api.ObjectMeta{
			Name: name,
			Labels: map[string]string{
				"etcd_cluster": clusterName,
			},
		},
		Spec: extensions.ReplicaSetSpec{
			Replicas: 1,
			Selector: &unversionedAPI.LabelSelector{MatchLabels: labels},
			Template: api.PodTemplateSpec{
				ObjectMeta: api.ObjectMeta{
					Labels: labels,
				},
				Spec: ps,
			},
		},
	}
	addOwnerRefToObject(rs.GetObjectMeta(), owner)
	return rs
}

func MakeBackupService(clusterName string, owner metatypes.OwnerReference) *api.Service {
	name, labels := backupNameAndLabel(clusterName)
	svc := &api.Service{
		ObjectMeta: api.ObjectMeta{
			Name:   name,
			Labels: labels,
		},
		Spec: api.ServiceSpec{
			Ports: []api.ServicePort{
				{
					Name:       "backup-service",
					Port:       constants.DefaultBackupPodHTTPPort,
					TargetPort: intstr.FromInt(constants.DefaultBackupPodHTTPPort),
					Protocol:   api.ProtocolTCP,
				},
			},
			Selector: labels,
		},
	}
	addOwnerRefToObject(svc.GetObjectMeta(), owner)
	return svc
}

func DeleteBackupReplicaSetAndService(kubecli *unversioned.Client, clusterName, ns string) error {
	name := MakeBackupName(clusterName)
	err := kubecli.Services(ns).Delete(name)
	if err != nil {
		return err
	}
	orphanOption := false
	gracePeriod := int64(0)
	err = kubecli.ReplicaSets(ns).Delete(name, &api.DeleteOptions{
		OrphanDependents:   &orphanOption,
		GracePeriodSeconds: &gracePeriod,
	})
	if err != nil {
		return err
	}
	return nil
}

func DeletePVC(kubecli *unversioned.Client, clusterName, ns string) error {
	return kubecli.PersistentVolumeClaims(ns).Delete(makePVCName(clusterName))
}

func CopyVolume(kubecli *unversioned.Client, fromClusterName, toClusterName, ns string) error {
	pod := &api.Pod{
		ObjectMeta: api.ObjectMeta{
			Name: copyVolumePodName(toClusterName),
			Labels: map[string]string{
				"etcd_cluster": toClusterName,
			},
		},
		Spec: api.PodSpec{
			Containers: []api.Container{
				{
					Name:  "copy-backup",
					Image: "alpine",
					Command: []string{
						"/bin/sh",
						"-c",
						fmt.Sprintf("cp -r %s/* %s/", fromDirMountDir, constants.BackupDir),
					},
					VolumeMounts: []api.VolumeMount{{
						Name:      "from-dir",
						MountPath: fromDirMountDir,
					}, {
						Name:      "to-dir",
						MountPath: constants.BackupDir,
					}},
				},
			},
			RestartPolicy: api.RestartPolicyNever,
			Volumes: []api.Volume{{
				Name: "from-dir",
				VolumeSource: api.VolumeSource{
					PersistentVolumeClaim: &api.PersistentVolumeClaimVolumeSource{
						ClaimName: makePVCName(fromClusterName),
						ReadOnly:  true,
					},
				},
			}, {
				Name: "to-dir",
				VolumeSource: api.VolumeSource{
					PersistentVolumeClaim: &api.PersistentVolumeClaimVolumeSource{
						ClaimName: makePVCName(toClusterName),
					},
				},
			}},
		},
	}
	if _, err := kubecli.Pods(ns).Create(pod); err != nil {
		return err
	}

	w, err := kubecli.Pods(ns).Watch(api.SingleObject(api.ObjectMeta{Name: pod.Name}))
	if err != nil {
		return err
	}
	// It could take long due to delay of k8s controller detaching the volume
	_, err = watch.Until(120*time.Second, w, unversioned.PodCompleted)
	if err != nil {
		return fmt.Errorf("fail to wait data copy job completed: %v", err)
	}
	// Delete the pod to detach the volume from the node
	return kubecli.Pods(ns).Delete(pod.Name, api.NewDeleteOptions(0))
}

func copyVolumePodName(clusterName string) string {
	return clusterName + "-copyvolume"
}

func makePVCName(clusterName string) string {
	return fmt.Sprintf("%s-pvc", clusterName)
}
<commit_msg>backup_RS: label should have app=etcd<commit_after>// Copyright 2016 The etcd-operator Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package k8sutil

import (
	"encoding/json"
	"fmt"
	"path"
	"time"

	backupenv "github.com/coreos/etcd-operator/pkg/backup/env"
	"github.com/coreos/etcd-operator/pkg/spec"
	"github.com/coreos/etcd-operator/pkg/util/constants"
	"github.com/coreos/etcd-operator/pkg/util/retryutil"

	"github.com/coreos/etcd-operator/pkg/backup/s3/s3config"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/meta/metatypes"
	"k8s.io/kubernetes/pkg/api/resource"
	unversionedAPI "k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/apis/extensions"
	"k8s.io/kubernetes/pkg/apis/storage"
	"k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/util/intstr"
	"k8s.io/kubernetes/pkg/watch"
)

const (
	storageClassPrefix        = "etcd-operator-backup"
	BackupPodSelectorAppField = "etcd_backup_tool"
	backupPVVolName           = "etcd-backup-storage"
	awsCredentialDir          = "/root/.aws/"
	awsConfigDir              = "/root/.aws/config/"
	awsSecretVolName          = "secret-aws"
	awsConfigVolName          = "config-aws"
	fromDirMountDir           = "/mnt/backup/from"
)

func CreateStorageClass(kubecli *unversioned.Client, pvProvisioner string) error {
	// We need to get rid of prefix because naming doesn't support "/".
	name := storageClassPrefix + "-" + path.Base(pvProvisioner)
	class := &storage.StorageClass{
		ObjectMeta: api.ObjectMeta{
			Name: name,
		},
		Provisioner: pvProvisioner,
	}
	_, err := kubecli.StorageClasses().Create(class)
	return err
}

func CreateAndWaitPVC(kubecli *unversioned.Client, clusterName, ns, pvProvisioner string, volumeSizeInMB int) error {
	name := makePVCName(clusterName)
	storageClassName := storageClassPrefix + "-" + path.Base(pvProvisioner)
	claim := &api.PersistentVolumeClaim{
		ObjectMeta: api.ObjectMeta{
			Name: name,
			Labels: map[string]string{
				"etcd_cluster": clusterName,
			},
			Annotations: map[string]string{
				"volume.beta.kubernetes.io/storage-class": storageClassName,
			},
		},
		Spec: api.PersistentVolumeClaimSpec{
			AccessModes: []api.PersistentVolumeAccessMode{
				api.ReadWriteOnce,
			},
			Resources: api.ResourceRequirements{
				Requests: api.ResourceList{
					api.ResourceStorage: resource.MustParse(fmt.Sprintf("%dMi", volumeSizeInMB)),
				},
			},
		},
	}
	_, err := kubecli.PersistentVolumeClaims(ns).Create(claim)
	if err != nil {
		return err
	}

	err = retryutil.Retry(4*time.Second, 5, func() (bool, error) {
		var err error
		claim, err = kubecli.PersistentVolumeClaims(ns).Get(name)
		if err != nil {
			return false, err
		}
		if claim.Status.Phase != api.ClaimBound {
			return false, nil
		}
		return true, nil
	})
	if err != nil {
		wErr := fmt.Errorf("fail to wait PVC (%s) '(%v)/Bound': %v", name, claim.Status.Phase, err)
		return wErr
	}

	return nil
}

var BackupImage = "quay.io/coreos/etcd-operator:latest"

func PodSpecWithPV(ps *api.PodSpec, clusterName string) *api.PodSpec {
	ps.Containers[0].VolumeMounts = []api.VolumeMount{{
		Name:      backupPVVolName,
		MountPath: constants.BackupDir,
	}}
	ps.Volumes = []api.Volume{{
		Name: backupPVVolName,
		VolumeSource: api.VolumeSource{
			PersistentVolumeClaim: &api.PersistentVolumeClaimVolumeSource{
				ClaimName: makePVCName(clusterName),
			},
		},
	}}
	return ps
}

func PodSpecWithS3(ps *api.PodSpec, s3Ctx s3config.S3Context) *api.PodSpec {
	ps.Containers[0].VolumeMounts = []api.VolumeMount{{
		Name:      awsSecretVolName,
		MountPath: awsCredentialDir,
	}, {
		Name:      awsConfigVolName,
		MountPath: awsConfigDir,
	}}
	ps.Volumes = []api.Volume{{
		Name: awsSecretVolName,
		VolumeSource: api.VolumeSource{
			Secret: &api.SecretVolumeSource{
				SecretName: s3Ctx.AWSSecret,
			},
		},
	}, {
		Name: awsConfigVolName,
		VolumeSource: api.VolumeSource{
			ConfigMap: &api.ConfigMapVolumeSource{
				LocalObjectReference: api.LocalObjectReference{
					Name: s3Ctx.AWSConfig,
				},
			},
		},
	}}
	ps.Containers[0].Env = append(ps.Containers[0].Env, api.EnvVar{
		Name:  backupenv.AWSConfig,
		Value: path.Join(awsConfigDir, "config"),
	}, api.EnvVar{
		Name:  backupenv.AWSS3Bucket,
		Value: s3Ctx.S3Bucket,
	})
	return ps
}

func MakeBackupPodSpec(clusterName string, policy *spec.BackupPolicy) (*api.PodSpec, error) {
	bp, err := json.Marshal(policy)
	if err != nil {
		return nil, err
	}

	ps := &api.PodSpec{
		Containers: []api.Container{
			{
				Name:  "backup",
				Image: BackupImage,
				Command: []string{
					"/bin/sh",
					"-c",
					"/usr/local/bin/etcd-backup --etcd-cluster=" + clusterName,
				},
				Env: []api.EnvVar{{
					Name:      "MY_POD_NAMESPACE",
					ValueFrom: &api.EnvVarSource{FieldRef: &api.ObjectFieldSelector{FieldPath: "metadata.namespace"}},
				}, {
					Name:  backupenv.BackupPolicy,
					Value: string(bp),
				}},
			},
		},
	}
	return ps, nil
}

func backupNameAndLabel(clusterName string) (string, map[string]string) {
	labels := map[string]string{
		"app":          BackupPodSelectorAppField,
		"etcd_cluster": clusterName,
	}
	name := MakeBackupName(clusterName)
	return name, labels
}

func MakeBackupReplicaSet(clusterName string, ps api.PodSpec, owner metatypes.OwnerReference) *extensions.ReplicaSet {
	name, labels := backupNameAndLabel(clusterName)
	rs := &extensions.ReplicaSet{
		ObjectMeta: api.ObjectMeta{
			Name: name,
			Labels: map[string]string{
				"etcd_cluster": clusterName,
				"app":          "etcd",
			},
		},
		Spec: extensions.ReplicaSetSpec{
			Replicas: 1,
			Selector: &unversionedAPI.LabelSelector{MatchLabels: labels},
			Template: api.PodTemplateSpec{
				ObjectMeta: api.ObjectMeta{
					Labels: labels,
				},
				Spec: ps,
			},
		},
	}
	addOwnerRefToObject(rs.GetObjectMeta(), owner)
	return rs
}

func MakeBackupService(clusterName string, owner metatypes.OwnerReference) *api.Service {
	name, labels := backupNameAndLabel(clusterName)
	svc := &api.Service{
		ObjectMeta: api.ObjectMeta{
			Name:   name,
			Labels: labels,
		},
		Spec: api.ServiceSpec{
			Ports: []api.ServicePort{
				{
					Name:       "backup-service",
					Port:       constants.DefaultBackupPodHTTPPort,
					TargetPort: intstr.FromInt(constants.DefaultBackupPodHTTPPort),
					Protocol:   api.ProtocolTCP,
				},
			},
			Selector: labels,
		},
	}
	addOwnerRefToObject(svc.GetObjectMeta(), owner)
	return svc
}

func DeleteBackupReplicaSetAndService(kubecli *unversioned.Client, clusterName, ns string) error {
	name := MakeBackupName(clusterName)
	err := kubecli.Services(ns).Delete(name)
	if err != nil {
		return err
	}
	orphanOption := false
	gracePeriod := int64(0)
	err = kubecli.ReplicaSets(ns).Delete(name, &api.DeleteOptions{
		OrphanDependents:   &orphanOption,
		GracePeriodSeconds: &gracePeriod,
	})
	if err != nil {
		return err
	}
	return nil
}

func DeletePVC(kubecli *unversioned.Client, clusterName, ns string) error {
	return kubecli.PersistentVolumeClaims(ns).Delete(makePVCName(clusterName))
}

func CopyVolume(kubecli *unversioned.Client, fromClusterName, toClusterName, ns string) error {
	pod := &api.Pod{
		ObjectMeta: api.ObjectMeta{
			Name: copyVolumePodName(toClusterName),
			Labels: map[string]string{
				"etcd_cluster": toClusterName,
			},
		},
		Spec: api.PodSpec{
			Containers: []api.Container{
				{
					Name:  "copy-backup",
					Image: "alpine",
					Command: []string{
						"/bin/sh",
						"-c",
						fmt.Sprintf("cp -r %s/* %s/", fromDirMountDir, constants.BackupDir),
					},
					VolumeMounts: []api.VolumeMount{{
						Name:      "from-dir",
						MountPath: fromDirMountDir,
					}, {
						Name:      "to-dir",
						MountPath: constants.BackupDir,
					}},
				},
			},
			RestartPolicy: api.RestartPolicyNever,
			Volumes: []api.Volume{{
				Name: "from-dir",
				VolumeSource: api.VolumeSource{
					PersistentVolumeClaim: &api.PersistentVolumeClaimVolumeSource{
						ClaimName: makePVCName(fromClusterName),
						ReadOnly:  true,
					},
				},
			}, {
				Name: "to-dir",
				VolumeSource: api.VolumeSource{
					PersistentVolumeClaim: &api.PersistentVolumeClaimVolumeSource{
						ClaimName: makePVCName(toClusterName),
					},
				},
			}},
		},
	}
	if _, err := kubecli.Pods(ns).Create(pod); err != nil {
		return err
	}

	w, err := kubecli.Pods(ns).Watch(api.SingleObject(api.ObjectMeta{Name: pod.Name}))
	if err != nil {
		return err
	}
	// It could take long due to delay of k8s controller detaching the volume
	_, err = watch.Until(120*time.Second, w, unversioned.PodCompleted)
	if err != nil {
		return fmt.Errorf("fail to wait data copy job completed: %v", err)
	}
	// Delete the pod to detach the volume from the node
	return kubecli.Pods(ns).Delete(pod.Name, api.NewDeleteOptions(0))
}

func copyVolumePodName(clusterName string) string {
	return clusterName + "-copyvolume"
}

func makePVCName(clusterName string) string {
	return fmt.Sprintf("%s-pvc", clusterName)
}
<|endoftext|>


<commit_before>package bf

import (
	"fmt"
	"os"
	"testing"
)

func TestCNF(t *testing.T) {
	f := And(Or(Var("a"), Var("b")), Var("i"), Or(Var("g"), Var("h"), And(Var("c"), Or(Var("d"), Var("e")), Var("f"))))
	model := Solve(f)
	if model == nil {
		t.Errorf("problem was declared UNSAT")
	}
}

func TestUnique(t *testing.T) {
	f := And(Var("a"), Unique("a", "b", "c", "d", "e"))
	model := Solve(f)
	if model == nil {
		t.Errorf("problem is declared unsat")
	} else if !model["a"] || model["b"] || model["c"] || model["d"] || model["e"] {
		t.Errorf("invalid model %v", model)
	}
	f = And(Var("a"), Or(Var("b"), Var("c")), Unique("a", "b", "c", "d", "e"))
	model = Solve(f)
	if model != nil {
		t.Errorf("problem is declared sat, model: %v", model)
	}
}

func TestString(t *testing.T) {
	f := And(Or(Var("a"), Not(Var("b"))), Not(Var("c")))
	const expected = "and(or(a, not(b)), not(c))"
	if f.String() != expected {
		t.Errorf("string representation of formula not as expected: wanted %q, got %q", expected, f.String())
	}
}

func ExampleSolve() {
	f := Not(Implies(
		And(Var("a"), Var("b")), And(Or(Var("c"), Not(Var("d"))),
			Not(And(Var("c"), Eq(Var("e"), Not(Var("c"))))), Not(Xor(Var("a"), Var("b"))))))
	model := Solve(f)
	if model != nil {
		fmt.Printf("Problem is satisfiable")
	} else {
		fmt.Printf("Problem is unsatisfiable")
	}
	// Output: Problem is satisfiable
}

func ExampleUnique() {
	f := And(Var("a"), Unique("a", "b", "c", "d", "e"))
	model := Solve(f)
	if model != nil {
		fmt.Printf("Problem is satisfiable: a=%t, b=%t, c=%t, d=%t", model["a"], model["b"], model["c"], model["d"])
	} else {
		fmt.Printf("Problem is unsatisfiable")
	}
	// Output: Problem is satisfiable: a=true, b=false, c=false, d=false
}

func ExampleDimacs() {
	f := Eq(And(Or(Var("a"), Not(Var("b"))), Not(Var("a"))), Var("b"))
	if err := Dimacs(f, os.Stdout); err != nil {
		fmt.Printf("Could not generate DIMACS file: %v", err)
	}
	// Output:
	// p cnf 4 6
	// c a=2
	// c b=3
	// -2 -1 0
	// 3 -1 0
	// 1 2 3 0
	// 2 -3 -4 0
	// -2 -4 0
	// 4 -3 0
}

func ExampleSolve_sudoku() {
	const varFmt = "line-%d-col-%d:%d" // Scheme for variable naming
	f := True
	// In each spot, exactly one number is written
	for line := 1; line <= 9; line++ {
		for col := 1; col <= 9; col++ {
			vars := make([]string, 9)
			for val := 1; val <= 9; val++ {
				vars[val-1] = fmt.Sprintf(varFmt, line, col, val)
			}
			f = And(f, Unique(vars...))
		}
	}
	// In each line, each number appears at least once.
	// Since there are 9 spots and 9 numbers, that means each number appears exactly once.
	for line := 1; line <= 9; line++ {
		for val := 1; val <= 9; val++ {
			var vars []Formula
			for col := 1; col <= 9; col++ {
				vars = append(vars, Var(fmt.Sprintf(varFmt, line, col, val)))
			}
			f = And(f, Or(vars...))
		}
	}
	// In each column, each number appears at least once.
	for col := 1; col <= 9; col++ {
		for val := 1; val <= 9; val++ {
			var vars []Formula
			for line := 1; line <= 9; line++ {
				vars = append(vars, Var(fmt.Sprintf(varFmt, line, col, val)))
			}
			f = And(f, Or(vars...))
		}
	}
	// In each 3x3 box, each number appears at least once.
	for lineB := 0; lineB < 3; lineB++ {
		for colB := 0; colB < 3; colB++ {
			for val := 1; val <= 9; val++ {
				var vars []Formula
				for lineOff := 1; lineOff <= 3; lineOff++ {
					line := lineB*3 + lineOff
					for colOff := 1; colOff <= 3; colOff++ {
						col := colB*3 + colOff
						vars = append(vars, Var(fmt.Sprintf(varFmt, line, col, val)))
					}
				}
				f = And(f, Or(vars...))
			}
		}
	}
	// Some spots already have a fixed value
	f = And(
		f,
		Var("line-1-col-1:5"),
		Var("line-1-col-2:3"),
		Var("line-1-col-5:7"),
		Var("line-2-col-1:6"),
		Var("line-2-col-4:1"),
		Var("line-2-col-5:9"),
		Var("line-2-col-6:5"),
		Var("line-3-col-2:9"),
		Var("line-3-col-3:8"),
		Var("line-3-col-8:6"),
		Var("line-4-col-1:8"),
		Var("line-4-col-5:6"),
		Var("line-4-col-9:3"),
		Var("line-5-col-1:4"),
		Var("line-5-col-4:8"),
		Var("line-5-col-6:3"),
		Var("line-5-col-9:1"),
		Var("line-6-col-1:7"),
		Var("line-6-col-5:2"),
		Var("line-6-col-9:6"),
		Var("line-7-col-2:6"),
		Var("line-7-col-7:2"),
		Var("line-7-col-8:8"),
		Var("line-8-col-4:4"),
		Var("line-8-col-5:1"),
		Var("line-8-col-6:9"),
		Var("line-8-col-9:5"),
		Var("line-9-col-5:8"),
		Var("line-9-col-8:7"),
		Var("line-9-col-9:9"),
	)
	model := Solve(f)
	if model == nil {
		fmt.Println("Error: solving grid was found unsat")
		return
	}
	fmt.Println("The grid has a solution")
	for line := 1; line <= 9; line++ {
		for col := 1; col <= 9; col++ {
			for val := 1; val <= 9; val++ {
				if model[fmt.Sprintf(varFmt, line, col, val)] {
					fmt.Printf("%d", val)
				}
			}
		}
		fmt.Println()
	}
	// Output:
	// The grid has a solution
	// 534678912
	// 672195348
	// 198342567
	// 859761423
	// 426853791
	// 713924856
	// 961537284
	// 287419635
	// 345286179
}

func benchmarkUnique(n int) {
	vars := make([]string, n)
	for i := range vars {
		vars[i] = fmt.Sprintf("var-%d", i)
	}
	f := Unique(vars...)
	_ = Solve(f)
}

func BenchmarkUnique100(b *testing.B) {
	for i := 0; i < b.N; i++ {
		benchmarkUnique(100)
	}
}

func BenchmarkUnique1000(b *testing.B) {
	for i := 0; i < b.N; i++ {
		benchmarkUnique(1000)
	}
}

func TestCnfFromNnf(t *testing.T) {
	f := And(Or(And(Var("a"), Var("c"), Var("b"), Var("d")),
		And(Or(Not(Var("a")), Not(Var("c"))), Or(Not(Var("b")),
			Not(Var("d")))), Var("p")), Or(And(Or(Not(Var("a")),
				Not(Var("c")), Not(Var("b")), Not(Var("d"))), Or(And(Var("a"),
					Var("c")), And(Var("b"), Var("d")))), Not(Var("p"))), Var("p"),
		Not(Var("c")), Var("d"))
	model := Solve(f)
	if model == nil {
		t.Errorf("Failed to solve; f:\n%s", f)
	}
	check := f.Eval(model)
	if !check {
		t.Errorf("Model check failed")
	}
}
<commit_msg>Add failing test for an apparent solver bug<commit_after>package bf

import (
	"fmt"
	"os"
	"testing"
)

func TestCNF(t *testing.T) {
	f := And(Or(Var("a"), Var("b")), Var("i"), Or(Var("g"), Var("h"), And(Var("c"), Or(Var("d"), Var("e")), Var("f"))))
	model := Solve(f)
	if model == nil {
		t.Errorf("problem was declared UNSAT")
	}
}

func TestUnique(t *testing.T) {
	f := And(Var("a"), Unique("a", "b", "c", "d", "e"))
	model := Solve(f)
	if model == nil {
		t.Errorf("problem is declared unsat")
	} else if !model["a"] || model["b"] || model["c"] || model["d"] || model["e"] {
		t.Errorf("invalid model %v", model)
	}
	f = And(Var("a"), Or(Var("b"), Var("c")), Unique("a", "b", "c", "d", "e"))
	model = Solve(f)
	if model != nil {
		t.Errorf("problem is declared sat, model: %v", model)
	}
}

func TestString(t *testing.T) {
	f := And(Or(Var("a"), Not(Var("b"))), Not(Var("c")))
	const expected = "and(or(a, not(b)), not(c))"
	if f.String() != expected {
		t.Errorf("string representation of formula not as expected: wanted %q, got %q", expected, f.String())
	}
}

func ExampleSolve() {
	f := Not(Implies(
		And(Var("a"), Var("b")), And(Or(Var("c"), Not(Var("d"))),
			Not(And(Var("c"), Eq(Var("e"), Not(Var("c"))))), Not(Xor(Var("a"), Var("b"))))))
	model := Solve(f)
	if model != nil {
		fmt.Printf("Problem is satisfiable")
	} else {
		fmt.Printf("Problem is unsatisfiable")
	}
	// Output: Problem is satisfiable
}

func ExampleUnique() {
	f := And(Var("a"), Unique("a", "b", "c", "d", "e"))
	model := Solve(f)
	if model != nil {
		fmt.Printf("Problem is satisfiable: a=%t, b=%t, c=%t, d=%t", model["a"], model["b"], model["c"], model["d"])
	} else {
		fmt.Printf("Problem is unsatisfiable")
	}
	// Output: Problem is satisfiable: a=true, b=false, c=false, d=false
}

func ExampleDimacs() {
	f := Eq(And(Or(Var("a"), Not(Var("b"))), Not(Var("a"))), Var("b"))
	if err := Dimacs(f, os.Stdout); err != nil {
		fmt.Printf("Could not generate DIMACS file: %v", err)
	}
	// Output:
	// p cnf 4 6
	// c a=2
	// c b=3
	// -2 -1 0
	// 3 -1 0
	// 1 2 3 0
	// 2 -3 -4 0
	// -2 -4 0
	// 4 -3 0
}

func ExampleSolve_sudoku() {
	const varFmt = "line-%d-col-%d:%d" // Scheme for variable naming
	f := True
	// In each spot, exactly one number is written
	for line := 1; line <= 9; line++ {
		for col := 1; col <= 9; col++ {
			vars := make([]string, 9)
			for val := 1; val <= 9; val++ {
				vars[val-1] = fmt.Sprintf(varFmt, line, col, val)
			}
			f = And(f, Unique(vars...))
		}
	}
	// In each line, each number appears at least once.
	// Since there are 9 spots and 9 numbers, that means each number appears exactly once.
	for line := 1; line <= 9; line++ {
		for val := 1; val <= 9; val++ {
			var vars []Formula
			for col := 1; col <= 9; col++ {
				vars = append(vars, Var(fmt.Sprintf(varFmt, line, col, val)))
			}
			f = And(f, Or(vars...))
		}
	}
	// In each column, each number appears at least once.
	for col := 1; col <= 9; col++ {
		for val := 1; val <= 9; val++ {
			var vars []Formula
			for line := 1; line <= 9; line++ {
				vars = append(vars, Var(fmt.Sprintf(varFmt, line, col, val)))
			}
			f = And(f, Or(vars...))
		}
	}
	// In each 3x3 box, each number appears at least once.
	for lineB := 0; lineB < 3; lineB++ {
		for colB := 0; colB < 3; colB++ {
			for val := 1; val <= 9; val++ {
				var vars []Formula
				for lineOff := 1; lineOff <= 3; lineOff++ {
					line := lineB*3 + lineOff
					for colOff := 1; colOff <= 3; colOff++ {
						col := colB*3 + colOff
						vars = append(vars, Var(fmt.Sprintf(varFmt, line, col, val)))
					}
				}
				f = And(f, Or(vars...))
			}
		}
	}
	// Some spots already have a fixed value
	f = And(
		f,
		Var("line-1-col-1:5"),
		Var("line-1-col-2:3"),
		Var("line-1-col-5:7"),
		Var("line-2-col-1:6"),
		Var("line-2-col-4:1"),
		Var("line-2-col-5:9"),
		Var("line-2-col-6:5"),
		Var("line-3-col-2:9"),
		Var("line-3-col-3:8"),
		Var("line-3-col-8:6"),
		Var("line-4-col-1:8"),
		Var("line-4-col-5:6"),
		Var("line-4-col-9:3"),
		Var("line-5-col-1:4"),
		Var("line-5-col-4:8"),
		Var("line-5-col-6:3"),
		Var("line-5-col-9:1"),
		Var("line-6-col-1:7"),
		Var("line-6-col-5:2"),
		Var("line-6-col-9:6"),
		Var("line-7-col-2:6"),
		Var("line-7-col-7:2"),
		Var("line-7-col-8:8"),
		Var("line-8-col-4:4"),
		Var("line-8-col-5:1"),
		Var("line-8-col-6:9"),
		Var("line-8-col-9:5"),
		Var("line-9-col-5:8"),
		Var("line-9-col-8:7"),
		Var("line-9-col-9:9"),
	)
	model := Solve(f)
	if model == nil {
		fmt.Println("Error: solving grid was found unsat")
		return
	}
	fmt.Println("The grid has a solution")
	for line := 1; line <= 9; line++ {
		for col := 1; col <= 9; col++ {
			for val := 1; val <= 9; val++ {
				if model[fmt.Sprintf(varFmt, line, col, val)] {
					fmt.Printf("%d", val)
				}
			}
		}
		fmt.Println()
	}
	// Output:
	// The grid has a solution
	// 534678912
	// 672195348
	// 198342567
	// 859761423
	// 426853791
	// 713924856
	// 961537284
	// 287419635
	// 345286179
}

func benchmarkUnique(n int) {
	vars := make([]string, n)
	for i := range vars {
		vars[i] = fmt.Sprintf("var-%d", i)
	}
	f := Unique(vars...)
	_ = Solve(f)
}

func BenchmarkUnique100(b *testing.B) {
	for i := 0; i < b.N; i++ {
		benchmarkUnique(100)
	}
}

func BenchmarkUnique1000(b *testing.B) {
	for i := 0; i < b.N; i++ {
		benchmarkUnique(1000)
	}
}

func TestCnfFromNnf(t *testing.T) {
	f := And(Or(And(Var("a"), Var("c"), Var("b"), Var("d")),
		And(Or(Not(Var("a")), Not(Var("c"))), Or(Not(Var("b")),
			Not(Var("d")))), Var("p")), Or(And(Or(Not(Var("a")),
				Not(Var("c")), Not(Var("b")), Not(Var("d"))), Or(And(Var("a"),
					Var("c")), And(Var("b"), Var("d")))), Not(Var("p"))), Var("p"),
		Not(Var("c")), Var("d"))
	model := Solve(f)
	if model == nil {
		t.Errorf("Failed to solve; f:\n%s", f)
	}
	check := f.Eval(model)
	if !check {
		t.Errorf("Model check failed")
	}
}

func TestReproduceInvalidSolutionBug2(t *testing.T) {
	f := And(And(And(Or(Not(And(Or(Not(And(Var("a"), Var("e"))),
		Not(And(Var("b"), Var("g")))), Or(And(Var("a"), Var("e")), And(Var("b"),
			Var("g"))))), Var("i")), Or(And(Or(Not(And(Var("a"), Var("e"))),
				Not(And(Var("b"), Var("g")))), Or(And(Var("a"), Var("e")), And(Var("b"),
					Var("g")))), Not(Var("i")))), And(Or(Not(And(Or(Not(And(Var("c"),
						Var("e"))), Not(And(Var("d"), Var("g")))), Or(And(Var("c"), Var("e")),
							And(Var("d"), Var("g"))))), Var("k")), Or(And(Or(Not(And(Var("c"),
								Var("e"))), Not(And(Var("d"), Var("g")))), Or(And(Var("c"), Var("e")),
									And(Var("d"), Var("g")))), Not(Var("k")))),
		And(Or(Not(And(Or(Not(And(Var("a"), Var("f"))), Not(And(Var("b"),
			Var("h")))), Or(And(Var("a"), Var("f")), And(Var("b"), Var("h"))))),
			Var("j")), Or(And(Or(Not(And(Var("a"), Var("f"))), Not(And(Var("b"),
				Var("h")))), Or(And(Var("a"), Var("f")), And(Var("b"), Var("h")))),
				Not(Var("j")))), And(Or(Not(And(Or(Not(And(Var("c"), Var("f"))),
					Not(And(Var("d"), Var("h")))), Or(And(Var("c"), Var("f")), And(Var("d"),
						Var("h"))))), Var("l")), Or(And(Or(Not(And(Var("c"), Var("f"))),
							Not(And(Var("d"), Var("h")))), Or(And(Var("c"), Var("f")), And(Var("d"),
								Var("h")))), Not(Var("l"))))), And(And(Not(Var("a")), Not(Var("b"))),
									And(Var("i"), Not(Var("j")), Not(Var("k")), Var("l"))))
	model := Solve(f)
	if model == nil {
		t.Errorf("Failed to solve; f:\n%s", f)
	}
	if !f.Eval(model) {
		t.Errorf("Model check failed")
	}
}
<|endoftext|>


<commit_before>package graval

import (
	"bufio"
	"fmt"
	"log"
	"net"
	"path/filepath"
	"strconv"
	"strings"
)

const (
	welcomeMessage = "Welcome to the Go FTP Server"
)

type ftpConn struct {
	conn          *net.TCPConn
	controlReader *bufio.Reader
	controlWriter *bufio.Writer
	dataConn      ftpDataSocket
	driver        FTPDriver
	namePrefix    string
	reqUser       string
	user          string
	renameFrom    string
}

// NewftpConn constructs a new object that will handle the FTP protocol over
// an active net.TCPConn. The TCP connection should already be open before
// it is handed to this functions. driver is an instance of FTPDrive that
// will handle all auth and persistence details.
func newftpConn(tcpConn *net.TCPConn, driver FTPDriver) *ftpConn {
	c := new(ftpConn)
	c.namePrefix = "/"
	c.conn = tcpConn
	c.controlReader = bufio.NewReader(tcpConn)
	c.controlWriter = bufio.NewWriter(tcpConn)
	c.driver = driver
	return c
}

// Serve starts an endless loop that reads FTP commands from the client and
// responds appropriately. terminated is a channel that will receive a true
// message when the connection closes. This loop will be running inside a
// goroutine, so use this channel to be notified when the connection can be
// cleaned up.
func (ftpConn *ftpConn) Serve() {
	log.Print("Connection Established")
	// send welcome
	ftpConn.writeMessage(220, welcomeMessage)
	// read commands
	for {
		line, err := ftpConn.controlReader.ReadString('\n')
		if err != nil {
			break
		}
		ftpConn.receiveLine(line)
	}
	log.Print("Connection Terminated")
}

// Close will manually close this connection, even if the client isn't ready.
func (ftpConn *ftpConn) Close() {
	ftpConn.conn.Close()
	if ftpConn.dataConn != nil {
		ftpConn.dataConn.Close()
	}
}

// receiveLine accepts a single line FTP command and co-ordinates an
// appropriate response.
func (ftpConn *ftpConn) receiveLine(line string) {
	log.Print(line)
	command, param := ftpConn.parseLine(line)
	cmdObj := commands[command]
	if cmdObj != nil {
		cmdObj.Execute(ftpConn, param)
		return
	}
	switch command {
	default:
		ftpConn.writeMessage(500, "Command not found")
	}
}

func (ftpConn *ftpConn) parseLine(line string) (string, string) {
	params := strings.SplitN(strings.Trim(line, "\r\n"), " ", 2)
	if len(params) == 1 {
		return params[0], ""
	}
	return params[0], params[1]
}

// writeMessage will send a standard FTP response back to the client.
func (ftpConn *ftpConn) writeMessage(code int, message string) (wrote int, err error) {
	line := fmt.Sprintf("%d %s\r\n", code, message)
	log.Print(line)
	wrote, err = ftpConn.controlWriter.WriteString(line)
	ftpConn.controlWriter.Flush()
	return
}

// buildPath takes a client supplied path or filename and generates a safe
// absolute path withing their account sandbox.
//
//    buildpath("/")
//    => "/"
//    buildpath("one.txt")
//    => "/one.txt"
//    buildpath("/files/two.txt")
//    => "/files/two.txt"
//    buildpath("files/two.txt")
//    => "files/two.txt"
//    buildpath("/../../../../etc/passwd")
//    => "/etc/passwd"
//
// The driver implementation is responsible for deciding how to treat this path.
// Obviously they MUST NOT just read the path off disk. The probably want to
// prefix the path with something to scope the users access to a sandbox.
func (ftpConn *ftpConn) buildPath(filename string) (fullPath string) {
	if len(filename) > 0 && filename[0:1] == "/" {
		fullPath = filepath.Clean(filename)
	} else if len(filename) > 0 && filename != "-a" {
		fullPath = filepath.Clean(ftpConn.namePrefix + "/" + filename)
	} else {
		fullPath = filepath.Clean(ftpConn.namePrefix)
	}
	fullPath = strings.Replace(fullPath, "//", "/", -1)
	return
}

// sendOutofbandData will send a string to the client via the currently open
// data socket. Assumes the socket is open and ready to be used.
func (ftpConn *ftpConn) sendOutofbandData(data string) {
	bytes := len(data)
	ftpConn.dataConn.Write([]byte(data))
	ftpConn.dataConn.Close()
	message := "Closing data connection, sent " + strconv.Itoa(bytes) + " bytes"
	ftpConn.writeMessage(226, message)
}
<commit_msg>return a 500 error when the client sends an unrecognised command<commit_after>package graval

import (
	"bufio"
	"fmt"
	"log"
	"net"
	"path/filepath"
	"strconv"
	"strings"
)

const (
	welcomeMessage = "Welcome to the Go FTP Server"
)

type ftpConn struct {
	conn          *net.TCPConn
	controlReader *bufio.Reader
	controlWriter *bufio.Writer
	dataConn      ftpDataSocket
	driver        FTPDriver
	namePrefix    string
	reqUser       string
	user          string
	renameFrom    string
}

// NewftpConn constructs a new object that will handle the FTP protocol over
// an active net.TCPConn. The TCP connection should already be open before
// it is handed to this functions. driver is an instance of FTPDrive that
// will handle all auth and persistence details.
func newftpConn(tcpConn *net.TCPConn, driver FTPDriver) *ftpConn {
	c := new(ftpConn)
	c.namePrefix = "/"
	c.conn = tcpConn
	c.controlReader = bufio.NewReader(tcpConn)
	c.controlWriter = bufio.NewWriter(tcpConn)
	c.driver = driver
	return c
}

// Serve starts an endless loop that reads FTP commands from the client and
// responds appropriately. terminated is a channel that will receive a true
// message when the connection closes. This loop will be running inside a
// goroutine, so use this channel to be notified when the connection can be
// cleaned up.
func (ftpConn *ftpConn) Serve() {
	log.Print("Connection Established")
	// send welcome
	ftpConn.writeMessage(220, welcomeMessage)
	// read commands
	for {
		line, err := ftpConn.controlReader.ReadString('\n')
		if err != nil {
			break
		}
		ftpConn.receiveLine(line)
	}
	log.Print("Connection Terminated")
}

// Close will manually close this connection, even if the client isn't ready.
func (ftpConn *ftpConn) Close() {
	ftpConn.conn.Close()
	if ftpConn.dataConn != nil {
		ftpConn.dataConn.Close()
	}
}

// receiveLine accepts a single line FTP command and co-ordinates an
// appropriate response.
func (ftpConn *ftpConn) receiveLine(line string) {
	log.Print(line)
	command, param := ftpConn.parseLine(line)
	cmdObj := commands[command]
	if cmdObj == nil {
		ftpConn.writeMessage(500, "Command not found")
		return
	}
	cmdObj.Execute(ftpConn, param)
}

func (ftpConn *ftpConn) parseLine(line string) (string, string) {
	params := strings.SplitN(strings.Trim(line, "\r\n"), " ", 2)
	if len(params) == 1 {
		return params[0], ""
	}
	return params[0], params[1]
}

// writeMessage will send a standard FTP response back to the client.
func (ftpConn *ftpConn) writeMessage(code int, message string) (wrote int, err error) {
	line := fmt.Sprintf("%d %s\r\n", code, message)
	log.Print(line)
	wrote, err = ftpConn.controlWriter.WriteString(line)
	ftpConn.controlWriter.Flush()
	return
}

// buildPath takes a client supplied path or filename and generates a safe
// absolute path withing their account sandbox.
//
//    buildpath("/")
//    => "/"
//    buildpath("one.txt")
//    => "/one.txt"
//    buildpath("/files/two.txt")
//    => "/files/two.txt"
//    buildpath("files/two.txt")
//    => "files/two.txt"
//    buildpath("/../../../../etc/passwd")
//    => "/etc/passwd"
//
// The driver implementation is responsible for deciding how to treat this path.
// Obviously they MUST NOT just read the path off disk. The probably want to
// prefix the path with something to scope the users access to a sandbox.
func (ftpConn *ftpConn) buildPath(filename string) (fullPath string) {
	if len(filename) > 0 && filename[0:1] == "/" {
		fullPath = filepath.Clean(filename)
	} else if len(filename) > 0 && filename != "-a" {
		fullPath = filepath.Clean(ftpConn.namePrefix + "/" + filename)
	} else {
		fullPath = filepath.Clean(ftpConn.namePrefix)
	}
	fullPath = strings.Replace(fullPath, "//", "/", -1)
	return
}

// sendOutofbandData will send a string to the client via the currently open
// data socket. Assumes the socket is open and ready to be used.
func (ftpConn *ftpConn) sendOutofbandData(data string) {
	bytes := len(data)
	ftpConn.dataConn.Write([]byte(data))
	ftpConn.dataConn.Close()
	message := "Closing data connection, sent " + strconv.Itoa(bytes) + " bytes"
	ftpConn.writeMessage(226, message)
}
<|endoftext|>


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

package hipchat

import (
	"encoding/json"
	"fmt"
	"github.com/mozilla-services/heka/message"
	. "github.com/mozilla-services/heka/pipeline"
	"net/http"
	"net/url"
)

type HipchatOutput struct {
	conf   *HipchatOutputConfig
	url    string
	format string
}

// Hipchat Output config struct
type HipchatOutputConfig struct {
	// Outputs the payload attribute in the HipChat message vs a full JSON message dump
	PayloadOnly bool `toml:"payload_only"`
	// Url for HttpInput to GET.
	AuthToken string `toml:"auth_token"`
	// Required. ID or name of the room.
	RoomId string `toml:"room_id"`
	// Required. Name the message will appear be sent. Must be less than 15
	// characters long. May contain letters, numbers, -, _, and spaces.
	From string
	// Whether or not this message should trigger a notification for people
	// in the room (change the tab color, play a sound, etc).
	// Each recipient's notification preferences are taken into account.
	// Default is false
	Notify bool
	// Background color for message.
	// One of "yellow", "red", "green", "purple", "gray", or "random".
	// Default is gray
	Color string
}

func (ho *HipchatOutput) ConfigStruct() interface{} {
	return &HipchatOutputConfig{
		PayloadOnly: true,
		From:        "Heka",
		Notify:      false,
		Color:       "gray",
	}
}

func (ho *HipchatOutput) sendMessage(mc string) error {
	messageUri := fmt.Sprintf("%s/rooms/message?auth_token=%s", ho.conf.url, url.QueryEscape(ho.conf.AuthToken))

	messagePayload := url.Values{
		"room_id":        {ho.conf.RoomId},
		"from":           {ho.conf.From},
		"message":        {mc},
		"color":          {ho.conf.Color},
		"message_format": {ho.format},
	}

	if ho.conf.Notify == true {
		messagePayload.Add("notify", "1")
	}

	resp, err := http.PostForm(messageUri, messagePayload)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	messageResponse := &struct{ Status string }{}
	if err := json.Unmarshal(body, messageResponse); err != nil {
		return err
	}
	if messageResponse.Status != "sent" {
		return errors.New("HipchatOutput: Status response was not sent.")
	}

	return nil
}

func (ho *HipchatOutput) Init(config interface{}) (err error) {
	ho.conf = config.(*HipchatOutputConfig)

	if ho.conf.RoomId == nil {
		return fmt.Errorf("room_id must contain a HipChat room ID or name")
	}

	ho.conf.url = "https://api.hipchat.com/v1"
	ho.conf.format = "text"
	return
}

func (ho *HipchatOutput) Run(or OutputRunner, h PluginHelper) (err error) {
	inChan := or.InChan()

	var (
		pack     *PipelinePack
		msg      *message.Message
		contents []byte
	)

	for pack = range inChan {
		msg = pack.Message
		if ho.conf.PayloadOnly {
			err = ho.sendMessage(msg.GetPayload())
		} else {
			if contents, err = json.Marshal(msg); err == nil {
				err = ho.sendMessage(string(contents))
			} else {
				or.LogError(err)
			}
		}
		if err != nil {
			or.LogError(err)
		}
		pack.Recycle()
	}
	return
}

func init() {
	RegisterPlugin("HipchatOutput", func() interface{} {
		return new(HipchatOutput)
	})
}
<commit_msg>Missing packages, incorrect struct syntax<commit_after>// Copyright 2013, Christian Vozar
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package hipchat

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/mozilla-services/heka/message"
	. "github.com/mozilla-services/heka/pipeline"
	"ioutil"
	"net/http"
	"net/url"
)

type HipchatOutput struct {
	conf   *HipchatOutputConfig
	url    string
	format string
}

// Hipchat Output config struct
type HipchatOutputConfig struct {
	// Outputs the payload attribute in the HipChat message vs a full JSON message dump
	PayloadOnly bool `toml:"payload_only"`
	// Url for HttpInput to GET.
	AuthToken string `toml:"auth_token"`
	// Required. ID or name of the room.
	RoomId string `toml:"room_id"`
	// Required. Name the message will appear be sent. Must be less than 15
	// characters long. May contain letters, numbers, -, _, and spaces.
	From string
	// Whether or not this message should trigger a notification for people
	// in the room (change the tab color, play a sound, etc).
	// Each recipient's notification preferences are taken into account.
	// Default is false
	Notify bool
	// Background color for message.
	// One of "yellow", "red", "green", "purple", "gray", or "random".
	// Default is gray
	Color string
}

func (ho *HipchatOutput) ConfigStruct() interface{} {
	return &HipchatOutputConfig{
		PayloadOnly: true,
		From:        "Heka",
		Notify:      false,
		Color:       "gray",
	}
}

func (ho *HipchatOutput) sendMessage(mc string) error {
	messageUri := fmt.Sprintf("%s/rooms/message?auth_token=%s", ho.url, url.QueryEscape(ho.conf.AuthToken))

	messagePayload := url.Values{
		"room_id":        {ho.conf.RoomId},
		"from":           {ho.conf.From},
		"message":        {mc},
		"color":          {ho.conf.Color},
		"message_format": {ho.format},
	}

	if ho.conf.Notify == true {
		messagePayload.Add("notify", "1")
	}

	resp, err := http.PostForm(messageUri, messagePayload)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	messageResponse := &struct{ Status string }{}
	if err := json.Unmarshal(body, messageResponse); err != nil {
		return err
	}
	if messageResponse.Status != "sent" {
		return errors.New("HipchatOutput: Status response was not sent.")
	}

	return nil
}

func (ho *HipchatOutput) Init(config interface{}) (err error) {
	ho.conf = config.(*HipchatOutputConfig)

	if ho.conf.RoomId == nil {
		return fmt.Errorf("room_id must contain a HipChat room ID or name")
	}

	ho.url = "https://api.hipchat.com/v1"
	ho.format = "text"
	return
}

func (ho *HipchatOutput) Run(or OutputRunner, h PluginHelper) (err error) {
	inChan := or.InChan()

	var (
		pack     *PipelinePack
		msg      *message.Message
		contents []byte
	)

	for pack = range inChan {
		msg = pack.Message
		if ho.conf.PayloadOnly {
			err = ho.sendMessage(msg.GetPayload())
		} else {
			if contents, err = json.Marshal(msg); err == nil {
				err = ho.sendMessage(string(contents))
			} else {
				or.LogError(err)
			}
		}
		if err != nil {
			or.LogError(err)
		}
		pack.Recycle()
	}
	return
}

func init() {
	RegisterPlugin("HipchatOutput", func() interface{} {
		return new(HipchatOutput)
	})
}
<|endoftext|>


<commit_before>package gen

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"go/format"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"text/template"
	"time"
)

// dirMetadata is the location of the problem-specifications repository on the filesystem.
// We're making the assumption that the problem-specifications repository has been cloned to
// the same parent directory as the Exercism Go track repository.
// E.g.
//
//     $ tree -L 1 .
//     .
//     ├── problem-specifications
//     └── go
//
var dirMetadata string

// dirExercise is the location that the test cases should be generated to.
// This assumes that the generator script lives in the .meta directory within
// the exercise directory. Falls back to the present working directory.
var dirExercise string

// genClient creates an http client with a 10 second timeout so we don't get
// stuck waiting for a response.
var genClient = &http.Client{Timeout: 10 * time.Second}

const (
	// canonicalDataURL is the URL for the raw canonical-data.json data,
	// requires exercise name.
	canonicalDataURL = "https://raw.githubusercontent.com/exercism/problem-specifications/master/exercises/%s/canonical-data.json"
	// commitsURL is the GitHub api endpoint for the canonical-data.json
	// file commit history, requires exercise name.
	commitsURL = "https://api.github.com/repos/exercism/problem-specifications/commits?path=exercises/%s/canonical-data.json"
)

// Header tells how the test data was generated, for display in the header of
// cases_test.go
type Header struct {
	Origin  string
	Commit  string
	Version string
}

func (h Header) String() string {
	s := fmt.Sprintf("// Source: %s\n", h.Origin)
	if h.Commit != "" {
		s += fmt.Sprintf("// Commit: %s\n", h.Commit)
	}
	if h.Version != "" {
		s += fmt.Sprintf("// Problem Specifications Version: %s\n", h.Version)
	}
	return s
}

func init() {
	if _, path, _, ok := runtime.Caller(0); ok {
		dirMetadata = filepath.Join(path, "..", "..", "..", "problem-specifications")
	}
	if _, path, _, ok := runtime.Caller(2); ok {
		dirExercise = filepath.Join(path, "..", "..")
	}
	if dirExercise == "" {
		dirExercise = "."
	}
}

// outputSource puts the src text into given fileName
// and outputs a log message with given [status].
func outputSource(status string, fileName string, src []byte) error {
	ioerr := ioutil.WriteFile(fileName, src, 0666)
	if ioerr != nil {
		log.Printf("[FAILED] %s\n", ioerr)
		return ioerr
	}
	log.Printf("[%s] output: %s\n", status, fileName)
	return nil
}

// Gen generates the exercise cases_test.go file from the relevant canonical-data.json
func Gen(exercise string, j interface{}, t *template.Template) error {
	if dirMetadata == "" {
		return errors.New("unable to determine current path")
	}
	jFile := filepath.Join("exercises", exercise, "canonical-data.json")
	// try to find and read the local json source file
	log.Printf("[LOCAL] fetching %s test data\n", exercise)
	jPath, jOrigin, jCommit := getLocal(jFile)
	jFilePath := filepath.Join(jPath, jFile)
	if jPath != "" {
		log.Printf("[LOCAL] source: %s\n", jFilePath)
	}
	jSrc, err := ioutil.ReadFile(jFilePath)
	if err != nil {
		// fetch json data remotely if there's no local file
		log.Println("[LOCAL] No test data found")
		log.Printf("[REMOTE] fetching %s test data\n", exercise)
		jSrc, jOrigin, jCommit, err = getRemote(exercise)
		if err != nil {
			return err
		}
	}

	// unmarshal the json source to a Go structure
	if err = json.Unmarshal(jSrc, j); err != nil {
		// This error message is usually enough if the problem is a wrong
		// data structure defined here. Sadly it doesn't locate the error well
		// in the case of invalid JSON.  Use a real validator tool if you can't
		// spot the problem right away.
		return fmt.Errorf(`unexpected data structure: %v`, err)
	}

	// These fields are guaranteed to be in every problem
	var commonMetadata struct {
		Version string
	}
	if err := json.Unmarshal(jSrc, &commonMetadata); err != nil {
		return fmt.Errorf(`didn't contain version: %v`, err)
	}

	if err := classifyByProperty(j); err != nil {
		return fmt.Errorf("couldn't auto-classify based on property: %v", err)
	}

	// package up a little meta data
	d := struct {
		Header
		J interface{}
	}{Header{
		Origin:  jOrigin,
		Commit:  jCommit,
		Version: commonMetadata.Version,
	}, j}

	casesFileName := filepath.Join(dirExercise, "cases_test.go")

	// render the Go test cases
	var b bytes.Buffer
	if err := t.Execute(&b, &d); err != nil {
		log.Print("[ERROR] template.Execute failed. The template has a semantic error.")
		return err
	}
	// clean it up
	srcBuf := b.Bytes()
	src, err := format.Source(srcBuf)
	if err != nil {
		log.Print("[ERROR] format.Source failed. The generated source has a syntax error.")
		b.Reset()
		_, _ = b.Write(srcBuf)
		_, _ = b.Write([]byte(
			"// !NOTE: Error during source formatting: Line:Column " + fmt.Sprint(err) + "\n"))
		src = b.Bytes()
		// Save the raw unformatted, error-containing source for purposes of debugging the generator.
		_ = outputSource("ERROR", casesFileName, src)
		return err
	}
	// write output file for the Go test cases.
	return outputSource("SUCCESS", casesFileName, src)
}

func getLocal(jFile string) (jPath, jOrigin, jCommit string) {
	// Ideally draw from a .json which is pulled from the official problem-specifications
	// repository.  For development however, accept a file in current directory
	// if there is no .json in source control.  Also allow an override in any
	// case by environment variable.
	if jPath := os.Getenv("EXTEST"); jPath > "" {
		return jPath, "local file", "" // override
	}
	c := exec.Command("git", "log", "-1", "--oneline", jFile)
	c.Dir = dirMetadata
	origin, err := c.Output()
	if err != nil {
		return "", "local file", "" // no source control
	}
	if _, err = os.Stat(filepath.Join(c.Dir, jFile)); err != nil {
		return "", "local file", "" // not in source control
	}
	// good.  return source control dir and commit.
	return c.Dir, "exercism/problem-specifications", string(bytes.TrimSpace(origin))
}

func getRemote(exercise string) (body []byte, jOrigin string, jCommit string, err error) {
	url := fmt.Sprintf(canonicalDataURL, exercise)
	resp, err := genClient.Get(url)
	if err != nil {
		return []byte{}, "", "", err
	}
	if resp.StatusCode != http.StatusOK {
		return []byte{}, "", "", fmt.Errorf("error fetching remote data: %s", resp.Status)
	}
	defer resp.Body.Close()
	body, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return []byte{}, "", "", err
	}
	c, err := getRemoteCommit(exercise)
	if err != nil {
		// we always expect to have the commit in the cases_test.go
		// file, so return the error if we can't fetch it
		return []byte{}, "", "", err
	}
	log.Printf("[REMOTE] source: %s\n", url)
	return body, "exercism/problem-specifications", c, nil
}

func getRemoteCommit(exercise string) (string, error) {
	type Commits struct {
		Sha    string
		Commit struct {
			Message string
		}
	}
	resp, err := genClient.Get(fmt.Sprintf(commitsURL, exercise))
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()
	var c []Commits
	err = json.NewDecoder(resp.Body).Decode(&c)
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("%s %s", c[0].Sha[0:7], c[0].Commit.Message), nil
}
<commit_msg>gen/gen.go: correct dirExercise determination (#850)<commit_after>package gen

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"go/format"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"text/template"
	"time"
)

// dirMetadata is the location of the problem-specifications repository on the filesystem.
// We're making the assumption that the problem-specifications repository has been cloned to
// the same parent directory as the Exercism Go track repository.
// E.g.
//
//     $ tree -L 1 .
//     .
//     ├── problem-specifications
//     └── go
//
var dirMetadata string

// dirExercise is the location that the test cases should be generated to.
// This assumes that the generator script lives in the .meta directory within
// the exercise directory. Falls back to the present working directory.
var dirExercise string

// genClient creates an http client with a 10 second timeout so we don't get
// stuck waiting for a response.
var genClient = &http.Client{Timeout: 10 * time.Second}

const (
	// canonicalDataURL is the URL for the raw canonical-data.json data,
	// requires exercise name.
	canonicalDataURL = "https://raw.githubusercontent.com/exercism/problem-specifications/master/exercises/%s/canonical-data.json"
	// commitsURL is the GitHub api endpoint for the canonical-data.json
	// file commit history, requires exercise name.
	commitsURL = "https://api.github.com/repos/exercism/problem-specifications/commits?path=exercises/%s/canonical-data.json"
)

// Header tells how the test data was generated, for display in the header of
// cases_test.go
type Header struct {
	Origin  string
	Commit  string
	Version string
}

func (h Header) String() string {
	s := fmt.Sprintf("// Source: %s\n", h.Origin)
	if h.Commit != "" {
		s += fmt.Sprintf("// Commit: %s\n", h.Commit)
	}
	if h.Version != "" {
		s += fmt.Sprintf("// Problem Specifications Version: %s\n", h.Version)
	}
	return s
}

func init() {
	if _, path, _, ok := runtime.Caller(0); ok {
		dirMetadata = filepath.Join(path, "..", "..", "..", "problem-specifications")
	}
}

// outputSource puts the src text into given fileName
// and outputs a log message with given [status].
func outputSource(status string, fileName string, src []byte) error {
	ioerr := ioutil.WriteFile(fileName, src, 0666)
	if ioerr != nil {
		log.Printf("[FAILED] %s\n", ioerr)
		return ioerr
	}
	log.Printf("[%s] output: %s\n", status, fileName)
	return nil
}

// Gen generates the exercise cases_test.go file from the relevant canonical-data.json
func Gen(exercise string, j interface{}, t *template.Template) error {
	if dirMetadata == "" {
		return errors.New("unable to determine current path")
	}
	// Determine the exercise directory.
	// Use runtime.Caller to determine path location of the generator main package.
	// Call frames: 0 is this frame, Gen().
	//              1 should be a func in <exercise-dir>/.meta/gen.go (generator main package)
	//                which is calling Gen().
	//                                  |
	//                                  V
	if _, path, _, ok := runtime.Caller(1); ok {
		// Construct a path 2 directories higher than the path for .meta/gen.go
		// and it should be exercise directory.
		dirExercise = filepath.Join(path, "..", "..")
	}
	if dirExercise == "" {
		dirExercise = "."
	}
	jFile := filepath.Join("exercises", exercise, "canonical-data.json")
	// try to find and read the local json source file
	log.Printf("[LOCAL] fetching %s test data\n", exercise)
	jPath, jOrigin, jCommit := getLocal(jFile)
	jFilePath := filepath.Join(jPath, jFile)
	if jPath != "" {
		log.Printf("[LOCAL] source: %s\n", jFilePath)
	}
	jSrc, err := ioutil.ReadFile(jFilePath)
	if err != nil {
		// fetch json data remotely if there's no local file
		log.Println("[LOCAL] No test data found")
		log.Printf("[REMOTE] fetching %s test data\n", exercise)
		jSrc, jOrigin, jCommit, err = getRemote(exercise)
		if err != nil {
			return err
		}
	}

	// unmarshal the json source to a Go structure
	if err = json.Unmarshal(jSrc, j); err != nil {
		// This error message is usually enough if the problem is a wrong
		// data structure defined here. Sadly it doesn't locate the error well
		// in the case of invalid JSON.  Use a real validator tool if you can't
		// spot the problem right away.
		return fmt.Errorf(`unexpected data structure: %v`, err)
	}

	// These fields are guaranteed to be in every problem
	var commonMetadata struct {
		Version string
	}
	if err := json.Unmarshal(jSrc, &commonMetadata); err != nil {
		return fmt.Errorf(`didn't contain version: %v`, err)
	}

	if err := classifyByProperty(j); err != nil {
		return fmt.Errorf("couldn't auto-classify based on property: %v", err)
	}

	// package up a little meta data
	d := struct {
		Header
		J interface{}
	}{Header{
		Origin:  jOrigin,
		Commit:  jCommit,
		Version: commonMetadata.Version,
	}, j}

	casesFileName := filepath.Join(dirExercise, "cases_test.go")

	// render the Go test cases
	var b bytes.Buffer
	if err := t.Execute(&b, &d); err != nil {
		log.Print("[ERROR] template.Execute failed. The template has a semantic error.")
		return err
	}
	// clean it up
	srcBuf := b.Bytes()
	src, err := format.Source(srcBuf)
	if err != nil {
		log.Print("[ERROR] format.Source failed. The generated source has a syntax error.")
		b.Reset()
		_, _ = b.Write(srcBuf)
		_, _ = b.Write([]byte(
			"// !NOTE: Error during source formatting: Line:Column " + fmt.Sprint(err) + "\n"))
		src = b.Bytes()
		// Save the raw unformatted, error-containing source for purposes of debugging the generator.
		_ = outputSource("ERROR", casesFileName, src)
		return err
	}
	// write output file for the Go test cases.
	return outputSource("SUCCESS", casesFileName, src)
}

func getLocal(jFile string) (jPath, jOrigin, jCommit string) {
	// Ideally draw from a .json which is pulled from the official problem-specifications
	// repository.  For development however, accept a file in current directory
	// if there is no .json in source control.  Also allow an override in any
	// case by environment variable.
	if jPath := os.Getenv("EXTEST"); jPath > "" {
		return jPath, "local file", "" // override
	}
	c := exec.Command("git", "log", "-1", "--oneline", jFile)
	c.Dir = dirMetadata
	origin, err := c.Output()
	if err != nil {
		return "", "local file", "" // no source control
	}
	if _, err = os.Stat(filepath.Join(c.Dir, jFile)); err != nil {
		return "", "local file", "" // not in source control
	}
	// good.  return source control dir and commit.
	return c.Dir, "exercism/problem-specifications", string(bytes.TrimSpace(origin))
}

func getRemote(exercise string) (body []byte, jOrigin string, jCommit string, err error) {
	url := fmt.Sprintf(canonicalDataURL, exercise)
	resp, err := genClient.Get(url)
	if err != nil {
		return []byte{}, "", "", err
	}
	if resp.StatusCode != http.StatusOK {
		return []byte{}, "", "", fmt.Errorf("error fetching remote data: %s", resp.Status)
	}
	defer resp.Body.Close()
	body, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return []byte{}, "", "", err
	}
	c, err := getRemoteCommit(exercise)
	if err != nil {
		// we always expect to have the commit in the cases_test.go
		// file, so return the error if we can't fetch it
		return []byte{}, "", "", err
	}
	log.Printf("[REMOTE] source: %s\n", url)
	return body, "exercism/problem-specifications", c, nil
}

func getRemoteCommit(exercise string) (string, error) {
	type Commits struct {
		Sha    string
		Commit struct {
			Message string
		}
	}
	resp, err := genClient.Get(fmt.Sprintf(commitsURL, exercise))
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()
	var c []Commits
	err = json.NewDecoder(resp.Body).Decode(&c)
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("%s %s", c[0].Sha[0:7], c[0].Commit.Message), nil
}
<|endoftext|>


<commit_before>package generic

import (
	"bytes"
	"reflect"
)

// GenericType
type GenericType interface {
	Valid() bool
	Value() interface{}
	Scan(interface{}) error
	Set(interface{}) error
	Reset()
}

// ErrInvalidGenericValue
type ErrInvalidGenericValue struct {
	Value interface{}
}

// ValidFlag
type ValidFlag bool

// Reset
func (v *ValidFlag) Reset() {
	*v = false
}

// Valid validates the specified value is nil or not.
func (v ValidFlag) Valid() bool {
	return bool(v)
}

// Error
func (e ErrInvalidGenericValue) Error() string {
	buf := bytes.Buffer{}
	buf.WriteString("invalid value: ")
	t := reflect.TypeOf(e.Value)
	switch t {
	case nil:
		buf.WriteString("(nil)")
	default:
		buf.WriteByte('(')
		buf.WriteString(t.String())
		buf.WriteByte(')')
	}

	return buf.String()
}
<commit_msg>add comments<commit_after>package generic

import (
	"bytes"
	"reflect"
)

// GenericType is the interface used as the basis for generic types
type GenericType interface {
	Valid() bool
	Value() interface{}
	Scan(interface{}) error
	Set(interface{}) error
	Reset()
}

// ErrInvalidGenericValue is used as error in generic types
type ErrInvalidGenericValue struct {
	Value interface{}
}

// ValidFlag
type ValidFlag bool

// Reset resets ValidFlag
func (v *ValidFlag) Reset() {
	*v = false
}

// Valid validates the specified value is nil or not.
func (v ValidFlag) Valid() bool {
	return bool(v)
}

// Error
func (e ErrInvalidGenericValue) Error() string {
	buf := bytes.Buffer{}
	buf.WriteString("invalid value: ")
	t := reflect.TypeOf(e.Value)
	switch t {
	case nil:
		buf.WriteString("(nil)")
	default:
		buf.WriteByte('(')
		buf.WriteString(t.String())
		buf.WriteByte(')')
	}

	return buf.String()
}
<|endoftext|>


<commit_before>package gramework

import (
	"runtime"
)

// HealthHandler serves info about memory usage
func (app *App) HealthHandler(ctx *Context) {
	var m *runtime.MemStats
	runtime.ReadMemStats(m)

	ctx.JSON(m)
}

// Health registers HealthHandler on /internal/health
func (app *App) Health() {
	app.GET("/internal/health", app.HealthHandler)
}
<commit_msg>Wrong declaration on healthcheck<commit_after>package gramework

import (
	"runtime"
)

// HealthHandler serves info about memory usage
func (app *App) HealthHandler(ctx *Context) {
	var m runtime.MemStats
	runtime.ReadMemStats(&m)

	ctx.JSON(m)
}

// Health registers HealthHandler on /internal/health
func (app *App) Health() {
	app.GET("/internal/health", app.HealthHandler)
}
<|endoftext|>


<commit_before>// +build !windows

package main

import "os"

func init() {
	os.Setenv("PATH", "/sbin:/usr/sbin:/bin:/usr/bin:"+os.Getenv("PATH"))
	// prevent changing outputs of some command, e.g. ifconfig.
	os.Setenv("LANG", "C")
	os.Setenv("LC_ALL", "C")
}
<commit_msg>make PATH not to end with `:`.<commit_after>// +build !windows

package main

import "os"

func init() {
	if path := os.Getenv("PATH"); path != "" {
		os.Setenv("PATH", "/sbin:/usr/sbin:/bin:/usr/bin:"+path)
	} else {
		os.Setenv("PATH", "/sbin:/usr/sbin:/bin:/usr/bin")
	}
	// prevent changing outputs of some command, e.g. ifconfig.
	os.Setenv("LANG", "C")
	os.Setenv("LC_ALL", "C")
}
<|endoftext|>


<commit_before>// Copyright 2017 ibelie, Chen Jie, Joungtao. All rights reserved.
// Use of this source code is governed by The MIT License
// that can be found in the LICENSE file.

package rpc

import (
	"bytes"
	"fmt"
	"path"
	"sort"
	"strings"

	"io/ioutil"
)

func injectJavascript(dir string, entities []*Entity) {
	var buffer bytes.Buffer
	requireMap := make(map[string]bool)
	methodsMap := make(map[string]bool)

	var methods []string
	for _, e := range entities {
		for _, c := range e.Components {
			for _, m := range c.Methods {
				if ok, exist := methodsMap[m.Name]; exist && ok {
					continue
				} else if len(m.Results) > 0 {
					continue
				}
				var params []string
				for i, _ := range m.Params {
					params = append(params, fmt.Sprintf("a%d", i))
				}
				methods = append(methods, fmt.Sprintf(`
Entity.prototype.Deserialize%s = function(data) {
	return ibelie.rpc.%s.Deserialize%s(data);
};

Entity.prototype.%s = function(%s) {
	if (!this.isAwake) {
		console.warn('[Entity] Not awake:', this);
		return;
	}
	var data = ibelie.rpc.%s.Serialize%s(%s);
	this.connection.send(this, ibelie.rpc.Symbols.%s, data);
};
`, m.Name, c.Name, m.Name, m.Name, strings.Join(params, ", "),
					c.Name, m.Name, strings.Join(params, ", "), m.Name))
				requireMap[fmt.Sprintf(`
goog.require('ibelie.rpc.%s');`, c.Name)] = true
				methodsMap[m.Name] = true
			}
		}
	}

	var requires []string
	for require, ok := range requireMap {
		if ok {
			requires = append(requires, require)
		}
	}
	sort.Strings(requires)

	buffer.Write([]byte(fmt.Sprintf(`// Generated by ibelie-rpc.  DO NOT EDIT!

goog.provide('Entity');

goog.require('tyts.String');
goog.require('tyts.ProtoBuf');
goog.require('tyts.SizeVarint');%s

Entity = function() {
	this.__class__ = 'Entity';
	this.isAwake = false;
	this.RUID = 0;
	this.Key  = 0;
	this.Type = 0;
};

Entity.prototype.ByteSize = function() {
	return tyts.SizeVarint(this.RUID) + tyts.SizeVarint(this.Key) + tyts.SizeVarint(this.Type);
};

Entity.prototype.Serialize = function() {
	var protobuf = new tyts.ProtoBuf(new Uint8Array(this.ByteSize()));
	protobuf.WriteVarint(this.RUID);
	protobuf.WriteVarint(this.Key);
	protobuf.WriteVarint(this.Type);
	return protobuf.buffer;
};

Entity.prototype.Deserialize = function(data) {
	this.RUID = protobuf.ReadVarint();
	this.Key  = protobuf.ReadVarint();
	this.Type = protobuf.ReadVarint();
};

var ibelie = {};
ibelie.rpc = {};
ibelie.rpc.Entity = Entity;

ibelie.rpc.Component = function(entity) {
	this.Entity = entity;
};

ibelie.rpc.Component.prototype.Awake = function(e) {
	if (e.isAwake) {
		console.warn('[Entity] Already awaked:', e);
		return e;
	}
	var conn = this.Entity.connection;
	var entity = conn.entities[e.RUID];
	if (entity) {
		return entity
	}
	entity = new entities[ibelie.rpc.Dictionary[e.Type]]();
	entity.RUID	= e.RUID;
	entity.Key	= e.Key;
	entity.Type	= e.Type;
	entity.connection = conn;
	conn.send(e, ibelie.rpc.Symbols.OBSERVE);
	conn.entities[entity.RUID] = entity;
	return entity;
};

ibelie.rpc.Component.prototype.Drop = function(e) {
	if (!e || !e.isAwake) {
		console.warn('[Entity] Not awaked:', e);
		return;
	}
	for (var k in e) {
		var v = e[k];
		v.onDrop && v.onDrop();
		if (v.Entity) {
			delete v.Entity;
		}
	}
	e.isAwake = false;
	conn.send(e, ibelie.rpc.Symbols.IGNORE);
	delete this.Entity.connection.entities[e.RUID];
	var entity = new Entity();
	entity.RUID	= e.RUID;
	entity.Key	= e.Key;
	entity.Type	= e.Type;
	return entity;
};

ibelie.rpc.Connection = function(url) {
	var conn = this;
	var socket = new WebSocket(url);
	socket.onopen = function (event) {
		socket.onmessage = function(event) {
			var entity;
			var protobuf = tyts.ProtoBuf.FromBase64(event.data);
			var id = protobuf.ReadVarint();
			if (!ibelie.rpc.Symbols) {
				ibelie.rpc.Symbols = {};
				ibelie.rpc.Dictionary = {};
				var buffer = new tyts.ProtoBuf(protobuf.ReadBuffer(protobuf.ReadVarint()));
				while (!buffer.End()) {
					var symbol = tyts.String.Deserialize(nil, buffer);
					var value = buffer.ReadVarint();
					ibelie.rpc.Symbols[symbol] = value;
					ibelie.rpc.Dictionary[value] = symbol;
				}
				entity = new entities.Session();
				entity.Deserialize(protobuf);
				entity.connection = conn;
				entity.Type = ibelie.rpc.Symbols['Session'];
				entity.Key  = 0;
				conn.entities[id] = entity;
			} else {
				entity = conn.entities[id];
				if (!entity) {
					console.error('[Connection] Cannot find entity:', id);
					return;
				}
			}
			while (!protobuf.End()) {
				var name = ibelie.rpc.Dictionary[protobuf.ReadVarint()];
				var data = protobuf.ReadBuffer(protobuf.ReadVarint());
				if (name == 'NOTIFY') {
					var component;
					var property;
					var buffer = new tyts.ProtoBuf(data);
					while (!buffer.End()) {
						var tag_cutoff = buffer.ReadTag(127);
						var i = (tag_cutoff[0] >> tyts.WireTypeBits) - 1;
						if (tag_cutoff[1] && (i == 1 || i == 2) &&
							(tag_cutoff[0] & tyts.WireTypeMask) == tyts.WireVarint) {
							if (i == 1) {
								component = ibelie.rpc.Dictionary[buffer.ReadVarint()];
							} else {
								property = ibelie.rpc.Dictionary[buffer.ReadVarint()];
							}
							continue;
						}
						if (!tag_cutoff[0]) {
							break;
						}
						buffer.SkipField(tag_cutoff[0]);
					}
					var newValue = ibelie.rpc[component]['Deserialize' + property](data)[2];
					var oldValue = entity[component][property];
					var handler = entity[component][property + 'Handler'];
					if (oldValue.concat) {
						entity[component][property] = oldValue.concat(newValue);
						handler && handler(oldValue, newValue);
					} else if ((newValue instanceof Object) && !newValue.__class__) {
						if (!entity[component][property]) {
							entity[component][property] = {};
						}
						for (var k in newValue) {
							var o = oldValue[k];
							var n = newValue[k];
							oldValue[k] = n;
							handler && handler(k, o, n);
						}
					} else {
						entity[component][property] = newValue;
						handler && handler(oldValue, newValue);
					}
				} else if (ibelie.rpc[name]) {
					ibelie.rpc[name].prototype.Deserialize.call(entity[name], data.subarray(1));
				} else {
					var args = entity['Deserialize' + name](data);
					for (var k in entity) {
						var v = entity[k];
						v[name] && v[name].apply(v, args);
					}
				}
			}
			if (entity && !entity.isAwake) {
				entity.isAwake = true;
				for (var k in entity) {
					var v = entity[k];
					v.onAwake && v.onAwake();
				}
			}
		};
		socket.onclose = function(event) {
			console.warn('[Connection] Socket has been closed:', event, conn);
		};
	};
	this.socket = socket;
	this.entities = {};
};

ibelie.rpc.Connection.prototype.send = function(entity, method, data) {
	var size = tyts.SizeVarint(entity.RUID) + tyts.SizeVarint(entity.Key) + tyts.SizeVarint(entity.Type) + tyts.SizeVarint(method);
	if data {
		size += data.length;
	}
	var protobuf = new tyts.ProtoBuf(new Uint8Array(size));
	protobuf.WriteVarint(entity.RUID);
	protobuf.WriteVarint(entity.Key);
	protobuf.WriteVarint(entity.Type);
	protobuf.WriteVarint(method);
	protobuf.WriteBytes(data);
	conn.socket.send(protobuf.Base64());
};

ibelie.rpc.Connection.prototype.disconnect = function() {
	this.socket.close();
};
%s`, strings.Join(requires, ""), strings.Join(methods, ""))))

	ioutil.WriteFile(path.Join(dir, "rpc.js"), buffer.Bytes(), 0666)
}
<commit_msg>change little<commit_after>// Copyright 2017 ibelie, Chen Jie, Joungtao. All rights reserved.
// Use of this source code is governed by The MIT License
// that can be found in the LICENSE file.

package rpc

import (
	"bytes"
	"fmt"
	"path"
	"sort"
	"strings"

	"io/ioutil"
)

func injectJavascript(dir string, entities []*Entity) {
	var buffer bytes.Buffer
	requireMap := make(map[string]bool)
	methodsMap := make(map[string]bool)

	var methods []string
	for _, e := range entities {
		for _, c := range e.Components {
			for _, m := range c.Methods {
				if ok, exist := methodsMap[m.Name]; exist && ok {
					continue
				} else if len(m.Results) > 0 {
					continue
				}
				var params []string
				for i, _ := range m.Params {
					params = append(params, fmt.Sprintf("a%d", i))
				}
				methods = append(methods, fmt.Sprintf(`
Entity.prototype.Deserialize%s = function(data) {
	return ibelie.rpc.%s.Deserialize%s(data);
};

Entity.prototype.%s = function(%s) {
	if (!this.isAwake) {
		console.warn('[Entity] Not awake:', this);
		return;
	}
	var data = ibelie.rpc.%s.Serialize%s(%s);
	this.connection.send(this, ibelie.rpc.Symbols.%s, data);
};
`, m.Name, c.Name, m.Name, m.Name, strings.Join(params, ", "),
					c.Name, m.Name, strings.Join(params, ", "), m.Name))
				requireMap[fmt.Sprintf(`
goog.require('ibelie.rpc.%s');`, c.Name)] = true
				methodsMap[m.Name] = true
			}
		}
	}

	var requires []string
	for require, ok := range requireMap {
		if ok {
			requires = append(requires, require)
		}
	}
	sort.Strings(requires)

	buffer.Write([]byte(fmt.Sprintf(`// Generated by ibelie-rpc.  DO NOT EDIT!

goog.provide('Entity');

goog.require('tyts.String');
goog.require('tyts.ProtoBuf');
goog.require('tyts.SizeVarint');%s

Entity = function() {
	this.__class__ = 'Entity';
	this.isAwake = false;
	this.RUID = 0;
	this.Key  = 0;
	this.Type = 0;
};

Entity.prototype.ByteSize = function() {
	return tyts.SizeVarint(this.RUID) + tyts.SizeVarint(this.Key) + tyts.SizeVarint(this.Type);
};

Entity.prototype.Serialize = function() {
	var protobuf = new tyts.ProtoBuf(new Uint8Array(this.ByteSize()));
	protobuf.WriteVarint(this.RUID);
	protobuf.WriteVarint(this.Key);
	protobuf.WriteVarint(this.Type);
	return protobuf.buffer;
};

Entity.prototype.Deserialize = function(data) {
	this.RUID = protobuf.ReadVarint();
	this.Key  = protobuf.ReadVarint();
	this.Type = protobuf.ReadVarint();
};

var ibelie = {};
ibelie.rpc = {};
ibelie.rpc.Entity = Entity;

ibelie.rpc.Component = function(entity) {
	this.Entity = entity;
};

ibelie.rpc.Component.prototype.Awake = function(e) {
	if (e.isAwake) {
		console.warn('[Entity] Already awaked:', e);
		return e;
	}
	var conn = this.Entity.connection;
	var entity = conn.entities[e.RUID];
	if (entity) {
		return entity
	}
	entity = new entities[ibelie.rpc.Dictionary[e.Type]]();
	entity.RUID	= e.RUID;
	entity.Key	= e.Key;
	entity.Type	= e.Type;
	entity.connection = conn;
	conn.send(e, ibelie.rpc.Symbols.OBSERVE);
	conn.entities[entity.RUID] = entity;
	return entity;
};

ibelie.rpc.Component.prototype.Drop = function(e) {
	if (!e || !e.isAwake) {
		console.warn('[Entity] Not awaked:', e);
		return;
	}
	for (var k in e) {
		var v = e[k];
		v.onDrop && v.onDrop();
		if (v.Entity) {
			delete v.Entity;
		}
	}
	e.isAwake = false;
	conn.send(e, ibelie.rpc.Symbols.IGNORE);
	delete this.Entity.connection.entities[e.RUID];
	var entity = new Entity();
	entity.RUID	= e.RUID;
	entity.Key	= e.Key;
	entity.Type	= e.Type;
	return entity;
};

ibelie.rpc.Connection = function(url) {
	var conn = this;
	var socket = new WebSocket(url);
	socket.onopen = function (event) {
		socket.onmessage = function(event) {
			var entity;
			var protobuf = tyts.ProtoBuf.FromBase64(event.data);
			var id = protobuf.ReadVarint();
			if (!ibelie.rpc.Symbols) {
				ibelie.rpc.Symbols = {};
				ibelie.rpc.Dictionary = {};
				var buffer = new tyts.ProtoBuf(protobuf.ReadBuffer(protobuf.ReadVarint()));
				while (!buffer.End()) {
					var symbol = tyts.String.Deserialize(nil, buffer);
					var value = buffer.ReadVarint();
					ibelie.rpc.Symbols[symbol] = value;
					ibelie.rpc.Dictionary[value] = symbol;
				}
				entity = new entities.Session();
				entity.Deserialize(protobuf);
				entity.connection = conn;
				entity.Type = ibelie.rpc.Symbols.Session;
				entity.Key  = 0;
				conn.entities[id] = entity;
			} else {
				entity = conn.entities[id];
				if (!entity) {
					console.error('[Connection] Cannot find entity:', id);
					return;
				}
			}
			while (!protobuf.End()) {
				var name = ibelie.rpc.Dictionary[protobuf.ReadVarint()];
				var data = protobuf.ReadBuffer(protobuf.ReadVarint());
				if (name == 'NOTIFY') {
					var component;
					var property;
					var buffer = new tyts.ProtoBuf(data);
					while (!buffer.End()) {
						var tag_cutoff = buffer.ReadTag(127);
						var i = (tag_cutoff[0] >> tyts.WireTypeBits) - 1;
						if (tag_cutoff[1] && (i == 1 || i == 2) &&
							(tag_cutoff[0] & tyts.WireTypeMask) == tyts.WireVarint) {
							if (i == 1) {
								component = ibelie.rpc.Dictionary[buffer.ReadVarint()];
							} else {
								property = ibelie.rpc.Dictionary[buffer.ReadVarint()];
							}
							continue;
						}
						if (!tag_cutoff[0]) {
							break;
						}
						buffer.SkipField(tag_cutoff[0]);
					}
					var newValue = ibelie.rpc[component]['Deserialize' + property](data)[2];
					var oldValue = entity[component][property];
					var handler = entity[component][property + 'Handler'];
					if (oldValue.concat) {
						entity[component][property] = oldValue.concat(newValue);
						handler && handler(oldValue, newValue);
					} else if ((newValue instanceof Object) && !newValue.__class__) {
						if (!entity[component][property]) {
							entity[component][property] = {};
						}
						for (var k in newValue) {
							var o = oldValue[k];
							var n = newValue[k];
							oldValue[k] = n;
							handler && handler(k, o, n);
						}
					} else {
						entity[component][property] = newValue;
						handler && handler(oldValue, newValue);
					}
				} else if (ibelie.rpc[name]) {
					ibelie.rpc[name].prototype.Deserialize.call(entity[name], data.subarray(1));
				} else {
					var args = entity['Deserialize' + name](data);
					for (var k in entity) {
						var v = entity[k];
						v[name] && v[name].apply(v, args);
					}
				}
			}
			if (entity && !entity.isAwake) {
				entity.isAwake = true;
				for (var k in entity) {
					var v = entity[k];
					v.onAwake && v.onAwake();
				}
			}
		};
		socket.onclose = function(event) {
			console.warn('[Connection] Socket has been closed:', event, conn);
		};
	};
	this.socket = socket;
	this.entities = {};
};

ibelie.rpc.Connection.prototype.send = function(entity, method, data) {
	var size = tyts.SizeVarint(entity.RUID) + tyts.SizeVarint(entity.Key) + tyts.SizeVarint(entity.Type) + tyts.SizeVarint(method);
	if data {
		size += data.length;
	}
	var protobuf = new tyts.ProtoBuf(new Uint8Array(size));
	protobuf.WriteVarint(entity.RUID);
	protobuf.WriteVarint(entity.Key);
	protobuf.WriteVarint(entity.Type);
	protobuf.WriteVarint(method);
	protobuf.WriteBytes(data);
	conn.socket.send(protobuf.Base64());
};

ibelie.rpc.Connection.prototype.disconnect = function() {
	this.socket.close();
};
%s`, strings.Join(requires, ""), strings.Join(methods, ""))))

	ioutil.WriteFile(path.Join(dir, "rpc.js"), buffer.Bytes(), 0666)
}
<|endoftext|>