<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"strings"
	"sync"
)

func resolvePuppetEnvironment(envBranch string) {
	allPuppetfiles := make(map[string]Puppetfile)
	for source, sa := range config.Sources {
		wg.Add(1)
		go func(source string, sa Source) {
			defer wg.Done()
			if force {
				createOrPurgeDir(sa.Basedir, "resolvePuppetEnvironment()")
			}
			sa.Basedir = checkDirAndCreate(sa.Basedir, "basedir for source "+source)
			Debugf("Puppet environment: " + source + " (remote=" + sa.Remote + ", basedir=" + sa.Basedir + ", private_key=" + sa.PrivateKey + ", prefix=" + strconv.FormatBool(sa.Prefix) + ")")
			if len(sa.PrivateKey) > 0 {
				if _, err := os.Stat(sa.PrivateKey); err != nil {
					log.Println("resolvePuppetEnvironment(): could not find SSH private key ", sa.PrivateKey, "error: ", err)
					os.Exit(1)
				}
			}
			//if _, err := os.Stat(sa.Basedir); os.IsNotExist(err) {
			//	log.Println("resolvePuppetEnvironment(): could not access ", sa.Basedir)
			//	os.Exit(1)
			//}
			workDir := config.EnvCacheDir + source + ".git"
			// check if sa.Basedir exists
			checkDirAndCreate(sa.Basedir, "basedir")

			//if !strings.Contains(source, "hiera") && !strings.Contains(source, "files") {
			//	gitKey = sa.PrivateKey
			//}
			if success := doMirrorOrUpdate(sa.Remote, workDir, sa.PrivateKey, true); success {

				// get all branches
				er := executeCommand("git --git-dir "+workDir+" for-each-ref --sort=-committerdate --format=%(refname:short)", config.Timeout, false)
				branches := strings.Split(strings.TrimSpace(er.output), "\n")

				for _, branch := range branches {
					if len(envBranch) > 0 && branch != envBranch {
						Debugf("Skipping branch " + branch)
						continue
					}
					wg.Add(1)

					go func(branch string) {
						defer wg.Done()
						if len(branch) != 0 {
							Debugf("Resolving branch: " + branch)
							// TODO if sa.Prefix != true
							targetDir := sa.Basedir + source + "_" + strings.Replace(branch, "/", "_", -1) + "/"
							syncToModuleDir(workDir, targetDir, branch)
							if _, err := os.Stat(targetDir + "Puppetfile"); os.IsNotExist(err) {
								Debugf("Skipping branch " + source + "_" + branch + " because " + targetDir + "Puppetfile does not exitst")
							} else {
								puppetfile := readPuppetfile(targetDir+"Puppetfile", sa.PrivateKey)
								mutex.Lock()
								allPuppetfiles[source+"_"+branch] = puppetfile
								mutex.Unlock()

							}
						}
					}(branch)

				}
			}
		}(source, sa)
	}

	wg.Wait()
	//fmt.Println("allPuppetfiles: ", allPuppetfiles, len(allPuppetfiles))
	//fmt.Println("allPuppetfiles[0]: ", allPuppetfiles["postinstall"])
	resolvePuppetfile(allPuppetfiles)
	//// sync to basedir
	//for _, branch := range branches {
	//	if len(branch) != 0 {
	//		Debugf("Syncing branch: " + branch)
	//		// TODO if sa.Prefix != true
	//		if !strings.Contains(branch, "hiera") && !strings.Contains(branch, "files") {
	//			//puppetfile := readPuppetfile(targetDir)

	//		}
	//	}
	//}
}

func resolvePuppetfile(allPuppetfiles map[string]Puppetfile) {
	var wg sync.WaitGroup
	uniqueGitModules := make(map[string]string)
	uniqueForgeModules = make(map[string]struct{})
	latestForgeModules = make(map[string]string)
	exisitingModuleDirs := make(map[string]struct{})
	for env, pf := range allPuppetfiles {
		Debugf("Resolving " + env)
		//fmt.Println(pf)
		for _, gitModule := range pf.gitModules {
			mutex.Lock()
			if _, ok := uniqueGitModules[gitModule.git]; !ok {
				uniqueGitModules[gitModule.git] = pf.privateKey
			}
			mutex.Unlock()
		}
		for forgeModuleName, fm := range pf.forgeModules {
			//fmt.Println("Found Forge module ", forgeModuleName, " with version", fm.version)
			mutex.Lock()
			forgeModuleName = strings.Replace(forgeModuleName, "/", "-", -1)
			if _, ok := uniqueForgeModules[forgeModuleName+"-"+fm.version]; !ok {
				uniqueForgeModules[forgeModuleName+"-"+fm.version] = empty
			}
			mutex.Unlock()
		}
	}
	//fmt.Println(uniqueGitModules)
	resolveGitRepositories(uniqueGitModules)
	resolveForgeModules(uniqueForgeModules)
	//log.Println(config.Sources["cmdlineparam"])
	for env, pf := range allPuppetfiles {
		Debugf("Syncing " + env)
		source := strings.Split(env, "_")[0]
		basedir := checkDirAndCreate(config.Sources[source].Basedir, "basedir 2 for source "+source)
		moduleDir := basedir + env + "/" + pf.moduleDir
		var envBranch string
		if pfMode {
			moduleDir = basedir + "/" + pf.moduleDir
		} else {
			envBranch = strings.Split(env, "_")[1]
		}
		if force {
			createOrPurgeDir(moduleDir, "resolvePuppetfile()")
			moduleDir = checkDirAndCreate(moduleDir, "moduleDir for source "+source)
		} else {
			moduleDir = checkDirAndCreate(moduleDir, "moduleDir for "+source)
			exisitingModuleDirsFI, _ := ioutil.ReadDir(moduleDir)
			mutex.Lock()
			for _, exisitingModuleDir := range exisitingModuleDirsFI {
				exisitingModuleDirs[moduleDir+exisitingModuleDir.Name()] = empty
			}
			mutex.Unlock()
		}
		for gitName, gitModule := range pf.gitModules {
			wg.Add(1)
			go func(gitName string, gitModule GitModule) {
				defer wg.Done()
				//fmt.Println(gitModule)
				//fmt.Println("source: " + source)
				targetDir := moduleDir + "/" + gitName
				//fmt.Println("targetDir: " + targetDir)
				tree := "master"
				if len(gitModule.branch) > 0 {
					tree = gitModule.branch
				} else if len(gitModule.commit) > 0 {
					tree = gitModule.commit
				} else if len(gitModule.tag) > 0 {
					tree = gitModule.tag
				} else if len(gitModule.ref) > 0 {
					tree = gitModule.ref
				} else if strings.EqualFold(gitModule.link, "true") {
					if pfMode {
						if len(os.Getenv("g10k_branch")) > 0 {
							tree = os.Getenv("g10k_branch")
						} else {
							fmt.Println("resolvePuppetfile(): found module " + gitName + " with module link mode enabled and g10k in Puppetfile mode which is not supported, as I can not detect the environment branch of the Puppetfile. You can explicitly set the module link branch you want to use in Puppetfile mode by setting the environment variable 'g10k_branch'")
							os.Exit(1)
						}
					} else {
						tree = envBranch
					}
				}
				syncToModuleDir(config.ModulesCacheDir+strings.Replace(strings.Replace(gitModule.git, "/", "_", -1), ":", "-", -1), targetDir, tree)

				// remove this module from the exisitingModuleDirs map
				mutex.Lock()
				if _, ok := exisitingModuleDirs[moduleDir+gitName]; ok {
					delete(exisitingModuleDirs, moduleDir+gitName)
				}
				mutex.Unlock()
			}(gitName, gitModule)
		}
		for forgeModuleName, fm := range pf.forgeModules {
			wg.Add(1)
			go func(forgeModuleName string, fm ForgeModule) {
				defer wg.Done()
				syncForgeToModuleDir(forgeModuleName, fm, moduleDir)
				// remove this module from the exisitingModuleDirs map
				mutex.Lock()
				if _, ok := exisitingModuleDirs[moduleDir+fm.name]; ok {
					delete(exisitingModuleDirs, moduleDir+fm.name)
				}
				mutex.Unlock()
			}(forgeModuleName, fm)
		}
	}
	wg.Wait()
	//fmt.Println(uniqueForgeModules)
	if len(exisitingModuleDirs) > 0 {
		for d, _ := range exisitingModuleDirs {
			Debugf("resolvePuppetfile(): Removing unmanaged file " + d)
			if err := os.RemoveAll(d); err != nil {
				Debugf("resolvePuppetfile(): Error while trying to remove unmanaged file " + d)
			}
		}
	}
}
<commit_msg>only use branches and not references<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"strings"
	"sync"
)

func resolvePuppetEnvironment(envBranch string) {
	allPuppetfiles := make(map[string]Puppetfile)
	for source, sa := range config.Sources {
		wg.Add(1)
		go func(source string, sa Source) {
			defer wg.Done()
			if force {
				createOrPurgeDir(sa.Basedir, "resolvePuppetEnvironment()")
			}
			sa.Basedir = checkDirAndCreate(sa.Basedir, "basedir for source "+source)
			Debugf("Puppet environment: " + source + " (remote=" + sa.Remote + ", basedir=" + sa.Basedir + ", private_key=" + sa.PrivateKey + ", prefix=" + strconv.FormatBool(sa.Prefix) + ")")
			if len(sa.PrivateKey) > 0 {
				if _, err := os.Stat(sa.PrivateKey); err != nil {
					log.Println("resolvePuppetEnvironment(): could not find SSH private key ", sa.PrivateKey, "error: ", err)
					os.Exit(1)
				}
			}
			//if _, err := os.Stat(sa.Basedir); os.IsNotExist(err) {
			//	log.Println("resolvePuppetEnvironment(): could not access ", sa.Basedir)
			//	os.Exit(1)
			//}
			workDir := config.EnvCacheDir + source + ".git"
			// check if sa.Basedir exists
			checkDirAndCreate(sa.Basedir, "basedir")

			//if !strings.Contains(source, "hiera") && !strings.Contains(source, "files") {
			//	gitKey = sa.PrivateKey
			//}
			if success := doMirrorOrUpdate(sa.Remote, workDir, sa.PrivateKey, true); success {

				// get all branches
				er := executeCommand("git --git-dir "+workDir+" branch", config.Timeout, false)
				branches := strings.Split(strings.TrimSpace(er.output), "\n")

				for _, branch := range branches {
					branch = strings.TrimLeft(branch, "* ")
					if strings.HasPrefix(branch, "tmp/") && strings.HasSuffix(branch, "/head") || (len(envBranch) > 0 && branch != envBranch) {
						Debugf("Skipping branch " + branch)
						continue
					}
					wg.Add(1)

					go func(branch string) {
						defer wg.Done()
						if len(branch) != 0 {
							Debugf("Resolving branch: " + branch)
							// TODO if sa.Prefix != true
							targetDir := sa.Basedir + source + "_" + strings.Replace(branch, "/", "_", -1) + "/"
							syncToModuleDir(workDir, targetDir, branch)
							if _, err := os.Stat(targetDir + "Puppetfile"); os.IsNotExist(err) {
								Debugf("Skipping branch " + source + "_" + branch + " because " + targetDir + "Puppetfile does not exitst")
							} else {
								puppetfile := readPuppetfile(targetDir+"Puppetfile", sa.PrivateKey)
								mutex.Lock()
								allPuppetfiles[source+"_"+branch] = puppetfile
								mutex.Unlock()

							}
						}
					}(branch)

				}
			}
		}(source, sa)
	}

	wg.Wait()
	//fmt.Println("allPuppetfiles: ", allPuppetfiles, len(allPuppetfiles))
	//fmt.Println("allPuppetfiles[0]: ", allPuppetfiles["postinstall"])
	resolvePuppetfile(allPuppetfiles)
	//// sync to basedir
	//for _, branch := range branches {
	//	if len(branch) != 0 {
	//		Debugf("Syncing branch: " + branch)
	//		// TODO if sa.Prefix != true
	//		if !strings.Contains(branch, "hiera") && !strings.Contains(branch, "files") {
	//			//puppetfile := readPuppetfile(targetDir)

	//		}
	//	}
	//}
}

func resolvePuppetfile(allPuppetfiles map[string]Puppetfile) {
	var wg sync.WaitGroup
	uniqueGitModules := make(map[string]string)
	uniqueForgeModules = make(map[string]struct{})
	latestForgeModules = make(map[string]string)
	exisitingModuleDirs := make(map[string]struct{})
	for env, pf := range allPuppetfiles {
		Debugf("Resolving " + env)
		//fmt.Println(pf)
		for _, gitModule := range pf.gitModules {
			mutex.Lock()
			if _, ok := uniqueGitModules[gitModule.git]; !ok {
				uniqueGitModules[gitModule.git] = pf.privateKey
			}
			mutex.Unlock()
		}
		for forgeModuleName, fm := range pf.forgeModules {
			//fmt.Println("Found Forge module ", forgeModuleName, " with version", fm.version)
			mutex.Lock()
			forgeModuleName = strings.Replace(forgeModuleName, "/", "-", -1)
			if _, ok := uniqueForgeModules[forgeModuleName+"-"+fm.version]; !ok {
				uniqueForgeModules[forgeModuleName+"-"+fm.version] = empty
			}
			mutex.Unlock()
		}
	}
	//fmt.Println(uniqueGitModules)
	resolveGitRepositories(uniqueGitModules)
	resolveForgeModules(uniqueForgeModules)
	//log.Println(config.Sources["cmdlineparam"])
	for env, pf := range allPuppetfiles {
		Debugf("Syncing " + env)
		source := strings.Split(env, "_")[0]
		basedir := checkDirAndCreate(config.Sources[source].Basedir, "basedir 2 for source "+source)
		moduleDir := basedir + env + "/" + pf.moduleDir
		var envBranch string
		if pfMode {
			moduleDir = basedir + "/" + pf.moduleDir
		} else {
			envBranch = strings.Split(env, "_")[1]
		}
		if force {
			createOrPurgeDir(moduleDir, "resolvePuppetfile()")
			moduleDir = checkDirAndCreate(moduleDir, "moduleDir for source "+source)
		} else {
			moduleDir = checkDirAndCreate(moduleDir, "moduleDir for "+source)
			exisitingModuleDirsFI, _ := ioutil.ReadDir(moduleDir)
			mutex.Lock()
			for _, exisitingModuleDir := range exisitingModuleDirsFI {
				exisitingModuleDirs[moduleDir+exisitingModuleDir.Name()] = empty
			}
			mutex.Unlock()
		}
		for gitName, gitModule := range pf.gitModules {
			wg.Add(1)
			go func(gitName string, gitModule GitModule) {
				defer wg.Done()
				//fmt.Println(gitModule)
				//fmt.Println("source: " + source)
				targetDir := moduleDir + "/" + gitName
				//fmt.Println("targetDir: " + targetDir)
				tree := "master"
				if len(gitModule.branch) > 0 {
					tree = gitModule.branch
				} else if len(gitModule.commit) > 0 {
					tree = gitModule.commit
				} else if len(gitModule.tag) > 0 {
					tree = gitModule.tag
				} else if len(gitModule.ref) > 0 {
					tree = gitModule.ref
				} else if strings.EqualFold(gitModule.link, "true") {
					if pfMode {
						if len(os.Getenv("g10k_branch")) > 0 {
							tree = os.Getenv("g10k_branch")
						} else {
							fmt.Println("resolvePuppetfile(): found module " + gitName + " with module link mode enabled and g10k in Puppetfile mode which is not supported, as I can not detect the environment branch of the Puppetfile. You can explicitly set the module link branch you want to use in Puppetfile mode by setting the environment variable 'g10k_branch'")
							os.Exit(1)
						}
					} else {
						tree = envBranch
					}
				}
				syncToModuleDir(config.ModulesCacheDir+strings.Replace(strings.Replace(gitModule.git, "/", "_", -1), ":", "-", -1), targetDir, tree)

				// remove this module from the exisitingModuleDirs map
				mutex.Lock()
				if _, ok := exisitingModuleDirs[moduleDir+gitName]; ok {
					delete(exisitingModuleDirs, moduleDir+gitName)
				}
				mutex.Unlock()
			}(gitName, gitModule)
		}
		for forgeModuleName, fm := range pf.forgeModules {
			wg.Add(1)
			go func(forgeModuleName string, fm ForgeModule) {
				defer wg.Done()
				syncForgeToModuleDir(forgeModuleName, fm, moduleDir)
				// remove this module from the exisitingModuleDirs map
				mutex.Lock()
				if _, ok := exisitingModuleDirs[moduleDir+fm.name]; ok {
					delete(exisitingModuleDirs, moduleDir+fm.name)
				}
				mutex.Unlock()
			}(forgeModuleName, fm)
		}
	}
	wg.Wait()
	//fmt.Println(uniqueForgeModules)
	if len(exisitingModuleDirs) > 0 {
		for d, _ := range exisitingModuleDirs {
			Debugf("resolvePuppetfile(): Removing unmanaged file " + d)
			if err := os.RemoveAll(d); err != nil {
				Debugf("resolvePuppetfile(): Error while trying to remove unmanaged file " + d)
			}
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 CloudAwan LLC
//
// 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 healthcheck

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/cloudawan/cloudone/utility/database/etcd"
	"golang.org/x/net/context"
	"strings"
)

func CreateKubernetesNodeControl() (*KubernetesNodeControl, error) {
	kubernetesNodeControl := &KubernetesNodeControl{}

	return kubernetesNodeControl, nil
}

type KubernetesNodeControl struct {
}

func (kubernetesNodeControl *KubernetesNodeControl) GetStatus() (map[string]interface{}, error) {
	keysAPI, err := etcd.EtcdClient.GetKeysAPI()

	response, err := keysAPI.Get(context.Background(), etcd.EtcdClient.EtcdBasePath+"/health", nil)
	if err != nil {
		log.Error(err)
		return nil, err
	}

	if response.Node == nil {
		text := fmt.Sprintf("Response node is nil. Response: %v", response)
		log.Error(text)
		return nil, errors.New(text)
	}

	hasError := false
	errorBuffer := bytes.Buffer{}
	jsonMap := make(map[string]interface{})
	for _, node := range response.Node.Nodes {
		valueJsonMap := make(map[string]interface{})
		err := json.Unmarshal([]byte(node.Value), &valueJsonMap)
		if err != nil {
			hasError = true
			errorBuffer.WriteString(err.Error())
			log.Error(err)
		}

		splitSlice := strings.Split(node.Key, "/")
		ip := splitSlice[len(splitSlice)-1]

		jsonMap[ip] = valueJsonMap
	}

	if hasError {
		return jsonMap, errors.New(errorBuffer.String())
	} else {
		return jsonMap, nil
	}
}

func (kubernetesNodeControl *KubernetesNodeControl) GetHostWithinFlannelNetwork() ([]string, error) {
	keysAPI, err := etcd.EtcdClient.GetKeysAPI()

	response, err := keysAPI.Get(context.Background(), "/coreos.com/network/subnets", nil)
	if err != nil {
		log.Error(err)
		return nil, err
	}

	if response.Node == nil {
		text := fmt.Sprintf("Response node is nil. Response: %v", response)
		log.Error(text)
		return nil, errors.New(text)
	}

	hasError := false
	errorBuffer := bytes.Buffer{}
	ipSlice := make([]string, 0)
	for _, node := range response.Node.Nodes {
		valueJsonMap := make(map[string]interface{})
		err := json.Unmarshal([]byte(node.Value), &valueJsonMap)
		if err != nil {
			hasError = true
			errorBuffer.WriteString(err.Error())
			log.Error(err)
		}

		ip, ok := valueJsonMap["PublicIP"].(string)
		if ok {
			ipSlice = append(ipSlice, ip)
		} else {
			hasError = true
			text := fmt.Sprintf("Fail to convert valueJsonMap[PublicIP]: %v valueJsonMap: %v", valueJsonMap["PublicIP"], valueJsonMap)
			errorBuffer.WriteString(text)
			log.Error(text)
		}
	}

	if hasError {
		return ipSlice, errors.New(errorBuffer.String())
	} else {
		return ipSlice, nil
	}
}
<commit_msg>Prevent duplicated ip in ip slice<commit_after>// Copyright 2015 CloudAwan LLC
//
// 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 healthcheck

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/cloudawan/cloudone/utility/database/etcd"
	"golang.org/x/net/context"
	"strings"
)

func CreateKubernetesNodeControl() (*KubernetesNodeControl, error) {
	kubernetesNodeControl := &KubernetesNodeControl{}

	return kubernetesNodeControl, nil
}

type KubernetesNodeControl struct {
}

func (kubernetesNodeControl *KubernetesNodeControl) GetStatus() (map[string]interface{}, error) {
	keysAPI, err := etcd.EtcdClient.GetKeysAPI()

	response, err := keysAPI.Get(context.Background(), etcd.EtcdClient.EtcdBasePath+"/health", nil)
	if err != nil {
		log.Error(err)
		return nil, err
	}

	if response.Node == nil {
		text := fmt.Sprintf("Response node is nil. Response: %v", response)
		log.Error(text)
		return nil, errors.New(text)
	}

	hasError := false
	errorBuffer := bytes.Buffer{}
	jsonMap := make(map[string]interface{})
	for _, node := range response.Node.Nodes {
		valueJsonMap := make(map[string]interface{})
		err := json.Unmarshal([]byte(node.Value), &valueJsonMap)
		if err != nil {
			hasError = true
			errorBuffer.WriteString(err.Error())
			log.Error(err)
		}

		splitSlice := strings.Split(node.Key, "/")
		ip := splitSlice[len(splitSlice)-1]

		jsonMap[ip] = valueJsonMap
	}

	if hasError {
		return jsonMap, errors.New(errorBuffer.String())
	} else {
		return jsonMap, nil
	}
}

func (kubernetesNodeControl *KubernetesNodeControl) GetHostWithinFlannelNetwork() ([]string, error) {
	keysAPI, err := etcd.EtcdClient.GetKeysAPI()

	response, err := keysAPI.Get(context.Background(), "/coreos.com/network/subnets", nil)
	if err != nil {
		log.Error(err)
		return nil, err
	}

	if response.Node == nil {
		text := fmt.Sprintf("Response node is nil. Response: %v", response)
		log.Error(text)
		return nil, errors.New(text)
	}

	hasError := false
	errorBuffer := bytes.Buffer{}
	ipSlice := make([]string, 0)
	for _, node := range response.Node.Nodes {
		valueJsonMap := make(map[string]interface{})
		err := json.Unmarshal([]byte(node.Value), &valueJsonMap)
		if err != nil {
			hasError = true
			errorBuffer.WriteString(err.Error())
			log.Error(err)
		}

		ip, ok := valueJsonMap["PublicIP"].(string)
		if ok {
			exist := false
			for _, existingIP := range ipSlice {
				if ip == existingIP {
					exist = true
					break
				}
			}
			if exist == false {
				ipSlice = append(ipSlice, ip)
			}
		} else {
			hasError = true
			text := fmt.Sprintf("Fail to convert valueJsonMap[PublicIP]: %v valueJsonMap: %v", valueJsonMap["PublicIP"], valueJsonMap)
			errorBuffer.WriteString(text)
			log.Error(text)
		}
	}

	if hasError {
		return ipSlice, errors.New(errorBuffer.String())
	} else {
		return ipSlice, nil
	}
}
<|endoftext|>


<commit_before>package testdata

import (
	"archive/zip"
	"compress/gzip"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
)

var ()

type Data struct {
	Dir   string
	Files []File
}

func (d *Data) Close() error {
	return os.RemoveAll(d.Dir)
}

func New() (*Data, error) {
	var err error
	data := &Data{}
	dir, err := ioutil.TempDir("", "roms")
	if err != nil {
		return data, err
	}
	data.Dir = dir
	defer func() {
		if err != nil {
			data.Close()
		}
	}()
	// Bin Extensions
	binFile := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	binHash := "c5391e308af25b42d5934d6a201a34e898d255c6"
	for _, e := range []string{".bin", ".a26", ".rom", ".cue", ".gdi", ".gb", ".gba", ".gbc", ".lyx", ".32x", ".gg", ".pce", ".sms"} {
		p := filepath.Join(dir, fmt.Sprintf("test%s", e))
		err = ioutil.WriteFile(p, binFile, 0777)
		if err != nil {
			return data, err
		}
		data.Files = append(data.Files, File{Path: p, SHA1: binHash})
	}

	// Lynx
	lnxFile := make([]byte, 64)
	copy(lnxFile, []byte("LYNX"))
	lnxFile = append(lnxFile, binFile...)
	lnxPath := filepath.Join(dir, "test.lnx")
	err = ioutil.WriteFile(lnxPath, lnxFile, 0777)
	if err != nil {
		return data, err
	}
	data.Files = append(data.Files, File{Path: lnxPath, SHA1: binHash})

	// N64
	v64File := make([]byte, 1024)
	n64File := make([]byte, 1024)
	z64File := make([]byte, 1024)
	copy(v64File, []byte{0, 0x80, 0, 0})
	copy(n64File, []byte{0, 0, 0, 0x80})
	copy(z64File, []byte{0x80, 0, 0, 0})
	for i := 4; i < 1024; i = i + 4 {
		v64File[i], z64File[i+1], n64File[i+2] = 1, 1, 1
		v64File[i+1], z64File[i], n64File[i+3] = 2, 2, 2
		v64File[i+2], z64File[i+3], n64File[i] = 3, 3, 3
		v64File[i+3], z64File[i+2], n64File[i+1] = 4, 4, 4
	}
	v64Path := filepath.Join(dir, "test-v64.v64")
	n64Path := filepath.Join(dir, "test-n64.v64")
	z64Path := filepath.Join(dir, "test-z64.v64")
	err = ioutil.WriteFile(v64Path, v64File, 0777)
	if err != nil {
		return data, err
	}
	data.Files = append(data.Files, File{Path: v64Path, SHA1: "00ba552537f953776b37a05230e9f1c2f6d4c145"})
	err = ioutil.WriteFile(n64Path, n64File, 0777)
	if err != nil {
		return data, err
	}
	data.Files = append(data.Files, File{Path: n64Path, SHA1: "00ba552537f953776b37a05230e9f1c2f6d4c145"})
	err = ioutil.WriteFile(z64Path, z64File, 0777)
	if err != nil {
		return data, err
	}
	data.Files = append(data.Files, File{Path: z64Path, SHA1: "00ba552537f953776b37a05230e9f1c2f6d4c145"})

	// SNES
	snesFile1 := make([]byte, 1024)
	snesFile2 := make([]byte, 1536)
	snesPath1 := filepath.Join(dir, "test.smc")
	snesPath2 := filepath.Join(dir, "test.sfc")
	err = ioutil.WriteFile(snesPath1, snesFile1, 0777)
	if err != nil {
		return data, err
	}
	data.Files = append(data.Files, File{Path: snesPath1, SHA1: "60cacbf3d72e1e7834203da608037b1bf83b40e8"})
	err = ioutil.WriteFile(snesPath2, snesFile2, 0777)
	if err != nil {
		return data, err
	}
	data.Files = append(data.Files, File{Path: snesPath2, SHA1: "60cacbf3d72e1e7834203da608037b1bf83b40e8"})

	// Sega, missing SEGA
	mdFile := make([]byte, 0x10000)
	smdFile := make([]byte, 0x10000)
	mgdFile := make([]byte, 0x10000)
	for i := range mdFile {
		b := i / 0x4000
		h := (i - b*0x4000) / 0x2000
		h++
		b++
		mdFile[i] = byte((i % 2) * b)
		smdFile[i] = byte((h % 2) * b)
		if i >= 0x8000 {
			mgdFile[i] = 0
		} else {
			mgdFile[i] = byte(h + ((b - 1) * 2))
		}
	}
	mdPath := filepath.Join(dir, "nosega.md")
	smdPath := filepath.Join(dir, "nosega.smd")
	mgdPath := filepath.Join(dir, "nosega.mgd")
	err = ioutil.WriteFile(mdPath, mdFile, 0777)
	if err != nil {
		return data, err
	}
	data.Files = append(data.Files, File{Path: mdPath, SHA1: "526289b04144ebb25afcbeaf0febb1c0cd60bf79"})
	err = ioutil.WriteFile(smdPath, append(make([]byte, 512), smdFile...), 0777)
	if err != nil {
		return data, err
	}
	data.Files = append(data.Files, File{Path: smdPath, SHA1: "526289b04144ebb25afcbeaf0febb1c0cd60bf79"})
	err = ioutil.WriteFile(mgdPath, mgdFile, 0777)
	if err != nil {
		return data, err
	}
	data.Files = append(data.Files, File{Path: mgdPath, SHA1: "526289b04144ebb25afcbeaf0febb1c0cd60bf79"})

	copy(mdFile[256:273], []byte("SEGA GENESIS    "))
	copy(smdFile[128:136], []byte("EAGNSS  "))
	copy(mgdFile[128:136], []byte("EAGNSS  "))
	copy(smdFile[8320:8328], []byte("SG EEI  "))
	copy(mgdFile[32896:32904], []byte("SG EEI  "))
	mdPath = filepath.Join(dir, "sega-md.md")
	smdPath = filepath.Join(dir, "sega-smd.md")
	mgdPath = filepath.Join(dir, "sega-mgd.md")
	err = ioutil.WriteFile(mdPath, mdFile, 0777)
	if err != nil {
		return data, err
	}
	data.Files = append(data.Files, File{Path: mdPath, SHA1: "5d2fa3c5c334d6f5c1c0959b040d4452b983d60f"})
	err = ioutil.WriteFile(smdPath, append(make([]byte, 512), smdFile...), 0777)
	if err != nil {
		return data, err
	}
	data.Files = append(data.Files, File{Path: smdPath, SHA1: "5d2fa3c5c334d6f5c1c0959b040d4452b983d60f"})
	err = ioutil.WriteFile(mgdPath, mgdFile, 0777)
	if err != nil {
		return data, err
	}
	data.Files = append(data.Files, File{Path: mgdPath, SHA1: "5d2fa3c5c334d6f5c1c0959b040d4452b983d60f"})

	// ZIP
	for _, f := range data.Files {
		p := fmt.Sprintf("%s.zip", f.Path)
		var w *os.File
		w, err = os.Create(p)
		if err != nil {
			return data, err
		}
		zw := zip.NewWriter(w)
		var zf io.Writer
		zf, err = zw.Create(filepath.Base(f.Path))
		if err != nil {
			return data, err
		}
		var fileData []byte
		fileData, err = ioutil.ReadFile(f.Path)
		if err != nil {
			return data, err
		}
		_, err = zf.Write(fileData)
		if err != nil {
			return data, err
		}
		err = zw.Close()
		if err != nil {
			return data, err
		}
		err = w.Close()
		if err != nil {
			return data, err
		}
		data.Files = append(data.Files, File{Path: p, SHA1: f.SHA1})
	}

	// GZIP
	for _, f := range data.Files {
		if filepath.Ext(f.Path) == ".zip" {
			continue
		}
                p := fmt.Sprintf("%s.gz", f.Path)
		var w *os.File
                w, err = os.Create(p)
                if err != nil {
                        return data, err
                }
                zw := gzip.NewWriter(w)
		var fileData []byte
                fileData, err = ioutil.ReadFile(f.Path)
                if err != nil {
                        return data, err
                }
                _, err = zw.Write(fileData)
                if err != nil {
                        return data, err
                }
                err = zw.Close()
                if err != nil {
                        return data, err
                }
	}
	return data, nil
}

type File struct {
	Path string
	SHA1 string
}
<commit_msg>Add NES testdata and fix gzip tests<commit_after>package testdata

import (
	"archive/zip"
	"compress/gzip"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
)

var ()

type Data struct {
	Dir   string
	Files []File
}

func (d *Data) Close() error {
	return os.RemoveAll(d.Dir)
}

func New() (*Data, error) {
	var err error
	data := &Data{}
	dir, err := ioutil.TempDir("", "roms")
	if err != nil {
		return data, err
	}
	data.Dir = dir
	defer func() {
		if err != nil {
			data.Close()
		}
	}()
	// Bin Extensions
	binFile := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	binHash := "c5391e308af25b42d5934d6a201a34e898d255c6"
	for _, e := range []string{".bin", ".a26", ".rom", ".cue", ".gdi", ".gb", ".gba", ".gbc", ".lyx", ".32x", ".gg", ".pce", ".sms"} {
		p := filepath.Join(dir, fmt.Sprintf("test%s", e))
		err = ioutil.WriteFile(p, binFile, 0777)
		if err != nil {
			return data, err
		}
		data.Files = append(data.Files, File{Path: p, SHA1: binHash})
	}

	// Lynx
	lnxFile := make([]byte, 64)
	copy(lnxFile, []byte("LYNX"))
	lnxFile = append(lnxFile, binFile...)
	lnxPath := filepath.Join(dir, "test.lnx")
	err = ioutil.WriteFile(lnxPath, lnxFile, 0777)
	if err != nil {
		return data, err
	}
	data.Files = append(data.Files, File{Path: lnxPath, SHA1: binHash})

	// N64
	v64File := make([]byte, 1024)
	n64File := make([]byte, 1024)
	z64File := make([]byte, 1024)
	copy(v64File, []byte{0, 0x80, 0, 0})
	copy(n64File, []byte{0, 0, 0, 0x80})
	copy(z64File, []byte{0x80, 0, 0, 0})
	for i := 4; i < 1024; i = i + 4 {
		v64File[i], z64File[i+1], n64File[i+2] = 1, 1, 1
		v64File[i+1], z64File[i], n64File[i+3] = 2, 2, 2
		v64File[i+2], z64File[i+3], n64File[i] = 3, 3, 3
		v64File[i+3], z64File[i+2], n64File[i+1] = 4, 4, 4
	}
	v64Path := filepath.Join(dir, "test-v64.v64")
	n64Path := filepath.Join(dir, "test-n64.v64")
	z64Path := filepath.Join(dir, "test-z64.v64")
	err = ioutil.WriteFile(v64Path, v64File, 0777)
	if err != nil {
		return data, err
	}
	data.Files = append(data.Files, File{Path: v64Path, SHA1: "00ba552537f953776b37a05230e9f1c2f6d4c145"})
	err = ioutil.WriteFile(n64Path, n64File, 0777)
	if err != nil {
		return data, err
	}
	data.Files = append(data.Files, File{Path: n64Path, SHA1: "00ba552537f953776b37a05230e9f1c2f6d4c145"})
	err = ioutil.WriteFile(z64Path, z64File, 0777)
	if err != nil {
		return data, err
	}
	data.Files = append(data.Files, File{Path: z64Path, SHA1: "00ba552537f953776b37a05230e9f1c2f6d4c145"})

	// SNES
	snesFile1 := make([]byte, 1024)
	snesFile2 := make([]byte, 1536)
	snesPath1 := filepath.Join(dir, "test.smc")
	snesPath2 := filepath.Join(dir, "test.sfc")
	err = ioutil.WriteFile(snesPath1, snesFile1, 0777)
	if err != nil {
		return data, err
	}
	data.Files = append(data.Files, File{Path: snesPath1, SHA1: "60cacbf3d72e1e7834203da608037b1bf83b40e8"})
	err = ioutil.WriteFile(snesPath2, snesFile2, 0777)
	if err != nil {
		return data, err
	}
	data.Files = append(data.Files, File{Path: snesPath2, SHA1: "60cacbf3d72e1e7834203da608037b1bf83b40e8"})

	// Sega, missing SEGA
	mdFile := make([]byte, 0x10000)
	smdFile := make([]byte, 0x10000)
	mgdFile := make([]byte, 0x10000)
	for i := range mdFile {
		b := i / 0x4000
		h := (i - b*0x4000) / 0x2000
		h++
		b++
		mdFile[i] = byte((i % 2) * b)
		smdFile[i] = byte((h % 2) * b)
		if i >= 0x8000 {
			mgdFile[i] = 0
		} else {
			mgdFile[i] = byte(h + ((b - 1) * 2))
		}
	}
	mdPath := filepath.Join(dir, "nosega.md")
	smdPath := filepath.Join(dir, "nosega.smd")
	mgdPath := filepath.Join(dir, "nosega.mgd")
	err = ioutil.WriteFile(mdPath, mdFile, 0777)
	if err != nil {
		return data, err
	}
	data.Files = append(data.Files, File{Path: mdPath, SHA1: "526289b04144ebb25afcbeaf0febb1c0cd60bf79"})
	err = ioutil.WriteFile(smdPath, append(make([]byte, 512), smdFile...), 0777)
	if err != nil {
		return data, err
	}
	data.Files = append(data.Files, File{Path: smdPath, SHA1: "526289b04144ebb25afcbeaf0febb1c0cd60bf79"})
	err = ioutil.WriteFile(mgdPath, mgdFile, 0777)
	if err != nil {
		return data, err
	}
	data.Files = append(data.Files, File{Path: mgdPath, SHA1: "526289b04144ebb25afcbeaf0febb1c0cd60bf79"})

	copy(mdFile[256:273], []byte("SEGA GENESIS    "))
	copy(smdFile[128:136], []byte("EAGNSS  "))
	copy(mgdFile[128:136], []byte("EAGNSS  "))
	copy(smdFile[8320:8328], []byte("SG EEI  "))
	copy(mgdFile[32896:32904], []byte("SG EEI  "))
	mdPath = filepath.Join(dir, "sega-md.md")
	smdPath = filepath.Join(dir, "sega-smd.md")
	mgdPath = filepath.Join(dir, "sega-mgd.md")
	err = ioutil.WriteFile(mdPath, mdFile, 0777)
	if err != nil {
		return data, err
	}
	data.Files = append(data.Files, File{Path: mdPath, SHA1: "5d2fa3c5c334d6f5c1c0959b040d4452b983d60f"})
	err = ioutil.WriteFile(smdPath, append(make([]byte, 512), smdFile...), 0777)
	if err != nil {
		return data, err
	}
	data.Files = append(data.Files, File{Path: smdPath, SHA1: "5d2fa3c5c334d6f5c1c0959b040d4452b983d60f"})
	err = ioutil.WriteFile(mgdPath, mgdFile, 0777)
	if err != nil {
		return data, err
	}
	data.Files = append(data.Files, File{Path: mgdPath, SHA1: "5d2fa3c5c334d6f5c1c0959b040d4452b983d60f"})

	// NES
	nesHeaderv1 := []byte{0x4E, 0x45, 0x53, 0x1A, 0x02, 0x06, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
	nesFilev1 := make([]byte, 16 + 32768 + 49152)
	nesHeaderv1Trainer := []byte{0x4E, 0x45, 0x53, 0x1A, 0x02, 0x06, 0x04, 0, 0, 0, 0, 0, 0, 0, 0, 0}
	nesFilev1Trainer := make([]byte, 16 + 512 + 32768 + 49152)
	nesHeaderv2 := []byte{0x4E, 0x45, 0x53, 0x1A, 0x02, 0x06, 0, 0x08, 0, 0x11, 0, 0, 0, 0, 0, 0}
	nesFilev2 := make([]byte, 16 + 4227072 + 2146304)
	copy(nesFilev1, nesHeaderv1)
	copy(nesFilev1Trainer, nesHeaderv1Trainer)
	copy(nesFilev2, nesHeaderv2)
	for i := 16; i < len(nesFilev1); i++ {
		if i < 32768 + 16 {
			nesFilev1[i] = 0
			nesFilev1Trainer[i+512] = 0
		} else {
			nesFilev1[i] = 1
			nesFilev1Trainer[i+512] = 1
		}
	}
	for i := 16; i < len(nesFilev2); i++ {
                if i < 4227072 + 16 {
                        nesFilev2[i] = 0
                } else {
                        nesFilev2[i] = 1
                }
        }
	nesPathv1 := filepath.Join(dir, "nes-v1.nes")
	nesPathv1Trainer := filepath.Join(dir, "nes-v1-trainer.nes")
	nesPathv2 := filepath.Join(dir, "nes-v2.nes")
	err = ioutil.WriteFile(nesPathv1, nesFilev1, 0777)
        if err != nil {
                return data, err
        }
        data.Files = append(data.Files, File{Path: nesPathv1, SHA1: "310127efa1522ee9cb559ec502c0f6bb7fde308c"})
	err = ioutil.WriteFile(nesPathv1Trainer, nesFilev1Trainer, 0777)
        if err != nil {
                return data, err
        }
        data.Files = append(data.Files, File{Path: nesPathv1Trainer, SHA1: "310127efa1522ee9cb559ec502c0f6bb7fde308c"})
	err = ioutil.WriteFile(nesPathv2, nesFilev2, 0777)
        if err != nil {
                return data, err
        }
        data.Files = append(data.Files, File{Path: nesPathv2, SHA1: "60afb4f8dcb8e1d1c3ba48a8a836f80a89301f65"})

	// ZIP
	for _, f := range data.Files {
		p := fmt.Sprintf("%s.zip", f.Path)
		var w *os.File
		w, err = os.Create(p)
		if err != nil {
			return data, err
		}
		zw := zip.NewWriter(w)
		var zf io.Writer
		zf, err = zw.Create(filepath.Base(f.Path))
		if err != nil {
			return data, err
		}
		var fileData []byte
		fileData, err = ioutil.ReadFile(f.Path)
		if err != nil {
			return data, err
		}
		_, err = zf.Write(fileData)
		if err != nil {
			return data, err
		}
		err = zw.Close()
		if err != nil {
			return data, err
		}
		err = w.Close()
		if err != nil {
			return data, err
		}
		data.Files = append(data.Files, File{Path: p, SHA1: f.SHA1})
	}

	// GZIP
	for _, f := range data.Files {
		if filepath.Ext(f.Path) == ".zip" {
			continue
		}
                p := fmt.Sprintf("%s.gz", f.Path)
		var w *os.File
                w, err = os.Create(p)
                if err != nil {
                        return data, err
                }
                zw := gzip.NewWriter(w)
		zw.Header.Name = filepath.Base(f.Path)
		var fileData []byte
                fileData, err = ioutil.ReadFile(f.Path)
                if err != nil {
                        return data, err
                }
                _, err = zw.Write(fileData)
                if err != nil {
                        return data, err
                }
                err = zw.Close()
                if err != nil {
                        return data, err
                }
		data.Files = append(data.Files, File{Path: p, SHA1: f.SHA1})
	}
	return data, nil
}

type File struct {
	Path string
	SHA1 string
}
<|endoftext|>


<commit_before>package plugins

import (
	"bytes"
	"encoding/json"
	"github.com/belak/irc"
	"github.com/belak/seabird/bot"
	"github.com/belak/seabird/mux"
	"net/http"
)

type ShortenResult struct {
	Kind    string `json:"kind"`
	Id      string `json:"id"`
	LongUrl string `json:"longUrl"`
}

func init() {
	bot.RegisterPlugin("tiny", NewTinyPlugin)
}

func NewTinyPlugin(m *mux.CommandMux) error {
	m.Event("tiny", Shorten)

	return nil
}

func Shorten(c *irc.Client, e *irc.Event) {
	go func() {
		if e.Trailing() == "" {
			c.MentionReply(e, "URL required")
			return
		}

		url := "https://www.googleapis.com/urlshortener/v1/url"

		data := map[string]string{"longUrl": e.Trailing()}
		out, err := json.Marshal(data)
		var jsonStr = []byte(out)
		req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
		req.Header.Set("Content-Type", "application/json")

		client := &http.Client{}
		resp, err := client.Do(req)
		if err != nil {
			c.MentionReply(e, "Error connecting to goo.gl")
			return
		}
		defer resp.Body.Close()

		sr := new(ShortenResult)
		err = json.NewDecoder(resp.Body).Decode(sr)
		if err != nil {
			c.MentionReply(e, "Error reading server response")
			return
		}

		c.MentionReply(e, sr.Id)
	}()
}
<commit_msg>Move to http.Post and check errors<commit_after>package plugins

import (
	"bytes"
	"encoding/json"
	"github.com/belak/irc"
	"github.com/belak/seabird/bot"
	"github.com/belak/seabird/mux"
	"net/http"
)

type ShortenResult struct {
	Kind    string `json:"kind"`
	Id      string `json:"id"`
	LongUrl string `json:"longUrl"`
}

func init() {
	bot.RegisterPlugin("tiny", NewTinyPlugin)
}

func NewTinyPlugin(m *mux.CommandMux) error {
	m.Event("tiny", Shorten)

	return nil
}

func Shorten(c *irc.Client, e *irc.Event) {
	go func() {
		if e.Trailing() == "" {
			c.MentionReply(e, "URL required")
			return
		}

		url := "https://www.googleapis.com/urlshortener/v1/url"

		data := map[string]string{"longUrl": e.Trailing()}
		out, err := json.Marshal(data)
		if err != nil {
			c.MentionReply(e, "%s", err)
			return
		}

		resp, err := http.Post(url, "application/json", bytes.NewBuffer(out))
		if err != nil {
			c.MentionReply(e, "%s", err)
			return
		}
		defer resp.Body.Close()

		sr := new(ShortenResult)
		err = json.NewDecoder(resp.Body).Decode(sr)
		if err != nil {
			c.MentionReply(e, "Error reading server response")
		}

		c.MentionReply(e, sr.Id)
	}()
}
<|endoftext|>


<commit_before>package sharedaction_test

import (
	"io/ioutil"
	"os"
	"path/filepath"

	. "code.cloudfoundry.org/cli/actor/sharedaction"
	"code.cloudfoundry.org/cli/actor/sharedaction/sharedactionfakes"
	"code.cloudfoundry.org/ykk"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Resource Actions", func() {
	var (
		actor      *Actor
		fakeConfig *sharedactionfakes.FakeConfig
		srcDir     string
	)

	BeforeEach(func() {
		fakeConfig = new(sharedaction.FakeConfig)
		actor = NewActor(fakeConfig)

		var err error
		srcDir, err = ioutil.TempDir("", "v2-resource-actions")
		Expect(err).ToNot(HaveOccurred())

		subDir := filepath.Join(srcDir, "level1", "level2")
		err = os.MkdirAll(subDir, 0777)
		Expect(err).ToNot(HaveOccurred())

		err = ioutil.WriteFile(filepath.Join(subDir, "tmpFile1"), []byte("why hello"), 0666)
		Expect(err).ToNot(HaveOccurred())

		err = ioutil.WriteFile(filepath.Join(srcDir, "tmpFile2"), []byte("Hello, Binky"), 0666)
		Expect(err).ToNot(HaveOccurred())

		err = ioutil.WriteFile(filepath.Join(srcDir, "tmpFile3"), []byte("Bananarama"), 0666)
		Expect(err).ToNot(HaveOccurred())
	})

	AfterEach(func() {
		Expect(os.RemoveAll(srcDir)).ToNot(HaveOccurred())
	})

	Describe("GatherArchiveResources", func() {
		Context("when the archive exists", func() {
			var (
				archive string

				resources  []Resource
				executeErr error
			)

			BeforeEach(func() {
				tmpfile, err := ioutil.TempFile("", "gather-archive-resource-test")
				Expect(err).ToNot(HaveOccurred())
				defer tmpfile.Close()
				archive = tmpfile.Name()
			})

			JustBeforeEach(func() {
				err := zipit(srcDir, archive, "")
				Expect(err).ToNot(HaveOccurred())

				resources, executeErr = actor.GatherArchiveResources(archive)
			})

			AfterEach(func() {
				Expect(os.RemoveAll(archive)).ToNot(HaveOccurred())
			})

			It("gathers a list of all files in a source archive", func() {
				Expect(executeErr).ToNot(HaveOccurred())

				Expect(resources).To(Equal(
					[]Resource{
						{Filename: "/", Mode: DefaultFolderPermissions},
						{Filename: "/level1/", Mode: DefaultFolderPermissions},
						{Filename: "/level1/level2/", Mode: DefaultFolderPermissions},
						{Filename: "/level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4", Size: 9, Mode: DefaultArchiveFilePermissions},
						{Filename: "/tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95", Size: 12, Mode: DefaultArchiveFilePermissions},
						{Filename: "/tmpFile3", SHA1: "f4c9ca85f3e084ffad3abbdabbd2a890c034c879", Size: 10, Mode: DefaultArchiveFilePermissions},
					}))
			})

			Context("when a .cfignore file exists in the archive", func() {
				BeforeEach(func() {
					err := ioutil.WriteFile(filepath.Join(srcDir, ".cfignore"), []byte("level2"), 0655)
					Expect(err).ToNot(HaveOccurred())
				})

				It("excludes all patterns of files mentioned in .cfignore", func() {
					Expect(executeErr).ToNot(HaveOccurred())

					Expect(resources).To(Equal(
						[]Resource{
							{Filename: "/", Mode: DefaultFolderPermissions},
							{Filename: "/level1/", Mode: DefaultFolderPermissions},
							{Filename: "/tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95", Size: 12, Mode: DefaultArchiveFilePermissions},
							{Filename: "/tmpFile3", SHA1: "f4c9ca85f3e084ffad3abbdabbd2a890c034c879", Size: 10, Mode: DefaultArchiveFilePermissions},
						}))
				})
			})

			Context("when default ignored files exist in the archive", func() {
				BeforeEach(func() {
					for _, filename := range DefaultIgnoreLines {
						if filename != ".cfignore" {
							err := ioutil.WriteFile(filepath.Join(srcDir, filename), nil, 0655)
							Expect(err).ToNot(HaveOccurred())
							err = ioutil.WriteFile(filepath.Join(srcDir, "level1", filename), nil, 0655)
							Expect(err).ToNot(HaveOccurred())
						}
					}
				})

				It("excludes all default files", func() {
					Expect(executeErr).ToNot(HaveOccurred())

					Expect(resources).To(Equal(
						[]Resource{
							{Filename: "/", Mode: DefaultFolderPermissions},
							{Filename: "/level1/", Mode: DefaultFolderPermissions},
							{Filename: "/level1/level2/", Mode: DefaultFolderPermissions},
							{Filename: "/level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4", Size: 9, Mode: DefaultArchiveFilePermissions},
							{Filename: "/tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95", Size: 12, Mode: DefaultArchiveFilePermissions},
							{Filename: "/tmpFile3", SHA1: "f4c9ca85f3e084ffad3abbdabbd2a890c034c879", Size: 10, Mode: DefaultArchiveFilePermissions},
						}))
				})
			})
		})

		Context("when the archive does not exist", func() {
			It("returns an error if the file is problematic", func() {
				_, err := actor.GatherArchiveResources("/does/not/exist")
				Expect(os.IsNotExist(err)).To(BeTrue())
			})
		})
	})

	Describe("GatherDirectoryResources", func() {
		Context("when files exist in the directory", func() {
			var (
				gatheredResources []Resource
				executeErr        error
			)

			JustBeforeEach(func() {
				gatheredResources, executeErr = actor.GatherDirectoryResources(srcDir)
			})

			It("gathers a list of all directories files in a source directory", func() {
				Expect(executeErr).ToNot(HaveOccurred())

				Expect(gatheredResources).To(Equal(
					[]Resource{
						{Filename: "level1", Mode: DefaultFolderPermissions},
						{Filename: "level1/level2", Mode: DefaultFolderPermissions},
						{Filename: "level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4", Size: 9, Mode: 0766},
						{Filename: "tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95", Size: 12, Mode: 0766},
						{Filename: "tmpFile3", SHA1: "f4c9ca85f3e084ffad3abbdabbd2a890c034c879", Size: 10, Mode: 0766},
					}))
			})

			Context("when a .cfignore file exists in the sourceDir", func() {
				BeforeEach(func() {
					err := ioutil.WriteFile(filepath.Join(srcDir, ".cfignore"), []byte("level2"), 0666)
					Expect(err).ToNot(HaveOccurred())
				})

				It("excludes all patterns of files mentioned in .cfignore", func() {
					Expect(executeErr).ToNot(HaveOccurred())

					Expect(gatheredResources).To(Equal(
						[]Resource{
							{Filename: "level1", Mode: DefaultFolderPermissions},
							{Filename: "tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95", Size: 12, Mode: 0766},
							{Filename: "tmpFile3", SHA1: "f4c9ca85f3e084ffad3abbdabbd2a890c034c879", Size: 10, Mode: 0766},
						}))
				})
			})

			Context("when default ignored files exist in the app dir", func() {
				BeforeEach(func() {
					for _, filename := range DefaultIgnoreLines {
						if filename != ".cfignore" {
							err := ioutil.WriteFile(filepath.Join(srcDir, filename), nil, 0655)
							Expect(err).ToNot(HaveOccurred())
							err = ioutil.WriteFile(filepath.Join(srcDir, "level1", filename), nil, 0655)
							Expect(err).ToNot(HaveOccurred())
						}
					}
				})

				It("excludes all default files", func() {
					Expect(executeErr).ToNot(HaveOccurred())

					Expect(gatheredResources).To(Equal(
						[]Resource{
							{Filename: "level1", Mode: DefaultFolderPermissions},
							{Filename: "level1/level2", Mode: DefaultFolderPermissions},
							{Filename: "level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4", Size: 9, Mode: 0766},
							{Filename: "tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95", Size: 12, Mode: 0766},
							{Filename: "tmpFile3", SHA1: "f4c9ca85f3e084ffad3abbdabbd2a890c034c879", Size: 10, Mode: 0766},
						}))
				})
			})

			Context("when trace files are in the source directory", func() {
				BeforeEach(func() {
					traceFilePath := filepath.Join(srcDir, "i-am-trace.txt")
					err := ioutil.WriteFile(traceFilePath, nil, 0666)
					Expect(err).ToNot(HaveOccurred())

					fakeConfig.VerboseReturns(false, []string{traceFilePath, "C:\\some-other-path"})
				})

				It("excludes all of the trace files", func() {
					Expect(executeErr).ToNot(HaveOccurred())

					Expect(gatheredResources).To(Equal(
						[]Resource{
							{Filename: "level1", Mode: DefaultFolderPermissions},
							{Filename: "level1/level2", Mode: DefaultFolderPermissions},
							{Filename: "level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4", Size: 9, Mode: 0766},
							{Filename: "tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95", Size: 12, Mode: 0766},
							{Filename: "tmpFile3", SHA1: "f4c9ca85f3e084ffad3abbdabbd2a890c034c879", Size: 10, Mode: 0766},
						}))
				})
			})
		})

		Context("when the directory is empty", func() {
			var emptyDir string

			BeforeEach(func() {
				var err error
				emptyDir, err = ioutil.TempDir("", "v2-resource-actions-empty")
				Expect(err).ToNot(HaveOccurred())
			})

			AfterEach(func() {
				Expect(os.RemoveAll(emptyDir)).ToNot(HaveOccurred())
			})

			It("returns an EmptyDirectoryError", func() {
				_, err := actor.GatherDirectoryResources(emptyDir)
				Expect(err).To(MatchError(EmptyDirectoryError{Path: emptyDir}))
			})
		})
	})

	Describe("ZipDirectoryResources", func() {
		var (
			resultZip  string
			resources  []Resource
			executeErr error
		)

		BeforeEach(func() {
			resources = []Resource{
				{Filename: "level1", Mode: DefaultFolderPermissions},
				{Filename: "level1/level2", Mode: DefaultFolderPermissions},
				{Filename: "level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4", Size: 9, Mode: 0766},
				{Filename: "tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95", Size: 12, Mode: 0766},
				{Filename: "tmpFile3", SHA1: "f4c9ca85f3e084ffad3abbdabbd2a890c034c879", Size: 10, Mode: 0766},
			}
		})

		JustBeforeEach(func() {
			resultZip, executeErr = actor.ZipDirectoryResources(srcDir, resources)
		})

		AfterEach(func() {
			err := os.RemoveAll(srcDir)
			Expect(err).ToNot(HaveOccurred())

			err = os.RemoveAll(resultZip)
			Expect(err).ToNot(HaveOccurred())
		})

		Context("when zipping on windows", func() {
			It("zips the directory and sets all the file modes to 07XX", func() {
				Expect(executeErr).ToNot(HaveOccurred())

				Expect(resultZip).ToNot(BeEmpty())
				zipFile, err := os.Open(resultZip)
				Expect(err).ToNot(HaveOccurred())
				defer zipFile.Close()

				zipInfo, err := zipFile.Stat()
				Expect(err).ToNot(HaveOccurred())

				reader, err := ykk.NewReader(zipFile, zipInfo.Size())
				Expect(err).ToNot(HaveOccurred())

				Expect(reader.File).To(HaveLen(5))
				Expect(reader.File[2].Mode()).To(Equal(os.FileMode(0766)))
				Expect(reader.File[3].Mode()).To(Equal(os.FileMode(0766)))
				Expect(reader.File[4].Mode()).To(Equal(os.FileMode(0766)))
			})
		})
	})
})
<commit_msg>fix for windows build<commit_after>package sharedaction_test

import (
	"io/ioutil"
	"os"
	"path/filepath"

	. "code.cloudfoundry.org/cli/actor/sharedaction"
	"code.cloudfoundry.org/cli/actor/sharedaction/sharedactionfakes"
	"code.cloudfoundry.org/ykk"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Resource Actions", func() {
	var (
		actor      *Actor
		fakeConfig *sharedactionfakes.FakeConfig
		srcDir     string
	)

	BeforeEach(func() {
		fakeConfig = &sharedactionfakes.FakeConfig{}
		actor = NewActor(fakeConfig)

		var err error
		srcDir, err = ioutil.TempDir("", "v2-resource-actions")
		Expect(err).ToNot(HaveOccurred())

		subDir := filepath.Join(srcDir, "level1", "level2")
		err = os.MkdirAll(subDir, 0777)
		Expect(err).ToNot(HaveOccurred())

		err = ioutil.WriteFile(filepath.Join(subDir, "tmpFile1"), []byte("why hello"), 0666)
		Expect(err).ToNot(HaveOccurred())

		err = ioutil.WriteFile(filepath.Join(srcDir, "tmpFile2"), []byte("Hello, Binky"), 0666)
		Expect(err).ToNot(HaveOccurred())

		err = ioutil.WriteFile(filepath.Join(srcDir, "tmpFile3"), []byte("Bananarama"), 0666)
		Expect(err).ToNot(HaveOccurred())
	})

	AfterEach(func() {
		Expect(os.RemoveAll(srcDir)).ToNot(HaveOccurred())
	})

	Describe("GatherArchiveResources", func() {
		Context("when the archive exists", func() {
			var (
				archive string

				resources  []Resource
				executeErr error
			)

			BeforeEach(func() {
				tmpfile, err := ioutil.TempFile("", "gather-archive-resource-test")
				Expect(err).ToNot(HaveOccurred())
				defer tmpfile.Close()
				archive = tmpfile.Name()
			})

			JustBeforeEach(func() {
				err := zipit(srcDir, archive, "")
				Expect(err).ToNot(HaveOccurred())

				resources, executeErr = actor.GatherArchiveResources(archive)
			})

			AfterEach(func() {
				Expect(os.RemoveAll(archive)).ToNot(HaveOccurred())
			})

			It("gathers a list of all files in a source archive", func() {
				Expect(executeErr).ToNot(HaveOccurred())

				Expect(resources).To(Equal(
					[]Resource{
						{Filename: "/", Mode: DefaultFolderPermissions},
						{Filename: "/level1/", Mode: DefaultFolderPermissions},
						{Filename: "/level1/level2/", Mode: DefaultFolderPermissions},
						{Filename: "/level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4", Size: 9, Mode: DefaultArchiveFilePermissions},
						{Filename: "/tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95", Size: 12, Mode: DefaultArchiveFilePermissions},
						{Filename: "/tmpFile3", SHA1: "f4c9ca85f3e084ffad3abbdabbd2a890c034c879", Size: 10, Mode: DefaultArchiveFilePermissions},
					}))
			})

			Context("when a .cfignore file exists in the archive", func() {
				BeforeEach(func() {
					err := ioutil.WriteFile(filepath.Join(srcDir, ".cfignore"), []byte("level2"), 0655)
					Expect(err).ToNot(HaveOccurred())
				})

				It("excludes all patterns of files mentioned in .cfignore", func() {
					Expect(executeErr).ToNot(HaveOccurred())

					Expect(resources).To(Equal(
						[]Resource{
							{Filename: "/", Mode: DefaultFolderPermissions},
							{Filename: "/level1/", Mode: DefaultFolderPermissions},
							{Filename: "/tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95", Size: 12, Mode: DefaultArchiveFilePermissions},
							{Filename: "/tmpFile3", SHA1: "f4c9ca85f3e084ffad3abbdabbd2a890c034c879", Size: 10, Mode: DefaultArchiveFilePermissions},
						}))
				})
			})

			Context("when default ignored files exist in the archive", func() {
				BeforeEach(func() {
					for _, filename := range DefaultIgnoreLines {
						if filename != ".cfignore" {
							err := ioutil.WriteFile(filepath.Join(srcDir, filename), nil, 0655)
							Expect(err).ToNot(HaveOccurred())
							err = ioutil.WriteFile(filepath.Join(srcDir, "level1", filename), nil, 0655)
							Expect(err).ToNot(HaveOccurred())
						}
					}
				})

				It("excludes all default files", func() {
					Expect(executeErr).ToNot(HaveOccurred())

					Expect(resources).To(Equal(
						[]Resource{
							{Filename: "/", Mode: DefaultFolderPermissions},
							{Filename: "/level1/", Mode: DefaultFolderPermissions},
							{Filename: "/level1/level2/", Mode: DefaultFolderPermissions},
							{Filename: "/level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4", Size: 9, Mode: DefaultArchiveFilePermissions},
							{Filename: "/tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95", Size: 12, Mode: DefaultArchiveFilePermissions},
							{Filename: "/tmpFile3", SHA1: "f4c9ca85f3e084ffad3abbdabbd2a890c034c879", Size: 10, Mode: DefaultArchiveFilePermissions},
						}))
				})
			})
		})

		Context("when the archive does not exist", func() {
			It("returns an error if the file is problematic", func() {
				_, err := actor.GatherArchiveResources("/does/not/exist")
				Expect(os.IsNotExist(err)).To(BeTrue())
			})
		})
	})

	Describe("GatherDirectoryResources", func() {
		Context("when files exist in the directory", func() {
			var (
				gatheredResources []Resource
				executeErr        error
			)

			JustBeforeEach(func() {
				gatheredResources, executeErr = actor.GatherDirectoryResources(srcDir)
			})

			It("gathers a list of all directories files in a source directory", func() {
				Expect(executeErr).ToNot(HaveOccurred())

				Expect(gatheredResources).To(Equal(
					[]Resource{
						{Filename: "level1", Mode: DefaultFolderPermissions},
						{Filename: "level1/level2", Mode: DefaultFolderPermissions},
						{Filename: "level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4", Size: 9, Mode: 0766},
						{Filename: "tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95", Size: 12, Mode: 0766},
						{Filename: "tmpFile3", SHA1: "f4c9ca85f3e084ffad3abbdabbd2a890c034c879", Size: 10, Mode: 0766},
					}))
			})

			Context("when a .cfignore file exists in the sourceDir", func() {
				BeforeEach(func() {
					err := ioutil.WriteFile(filepath.Join(srcDir, ".cfignore"), []byte("level2"), 0666)
					Expect(err).ToNot(HaveOccurred())
				})

				It("excludes all patterns of files mentioned in .cfignore", func() {
					Expect(executeErr).ToNot(HaveOccurred())

					Expect(gatheredResources).To(Equal(
						[]Resource{
							{Filename: "level1", Mode: DefaultFolderPermissions},
							{Filename: "tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95", Size: 12, Mode: 0766},
							{Filename: "tmpFile3", SHA1: "f4c9ca85f3e084ffad3abbdabbd2a890c034c879", Size: 10, Mode: 0766},
						}))
				})
			})

			Context("when default ignored files exist in the app dir", func() {
				BeforeEach(func() {
					for _, filename := range DefaultIgnoreLines {
						if filename != ".cfignore" {
							err := ioutil.WriteFile(filepath.Join(srcDir, filename), nil, 0655)
							Expect(err).ToNot(HaveOccurred())
							err = ioutil.WriteFile(filepath.Join(srcDir, "level1", filename), nil, 0655)
							Expect(err).ToNot(HaveOccurred())
						}
					}
				})

				It("excludes all default files", func() {
					Expect(executeErr).ToNot(HaveOccurred())

					Expect(gatheredResources).To(Equal(
						[]Resource{
							{Filename: "level1", Mode: DefaultFolderPermissions},
							{Filename: "level1/level2", Mode: DefaultFolderPermissions},
							{Filename: "level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4", Size: 9, Mode: 0766},
							{Filename: "tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95", Size: 12, Mode: 0766},
							{Filename: "tmpFile3", SHA1: "f4c9ca85f3e084ffad3abbdabbd2a890c034c879", Size: 10, Mode: 0766},
						}))
				})
			})

			Context("when trace files are in the source directory", func() {
				BeforeEach(func() {
					traceFilePath := filepath.Join(srcDir, "i-am-trace.txt")
					err := ioutil.WriteFile(traceFilePath, nil, 0666)
					Expect(err).ToNot(HaveOccurred())

					fakeConfig.VerboseReturns(false, []string{traceFilePath, "C:\\some-other-path"})
				})

				It("excludes all of the trace files", func() {
					Expect(executeErr).ToNot(HaveOccurred())

					Expect(gatheredResources).To(Equal(
						[]Resource{
							{Filename: "level1", Mode: DefaultFolderPermissions},
							{Filename: "level1/level2", Mode: DefaultFolderPermissions},
							{Filename: "level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4", Size: 9, Mode: 0766},
							{Filename: "tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95", Size: 12, Mode: 0766},
							{Filename: "tmpFile3", SHA1: "f4c9ca85f3e084ffad3abbdabbd2a890c034c879", Size: 10, Mode: 0766},
						}))
				})
			})
		})

		Context("when the directory is empty", func() {
			var emptyDir string

			BeforeEach(func() {
				var err error
				emptyDir, err = ioutil.TempDir("", "v2-resource-actions-empty")
				Expect(err).ToNot(HaveOccurred())
			})

			AfterEach(func() {
				Expect(os.RemoveAll(emptyDir)).ToNot(HaveOccurred())
			})

			It("returns an EmptyDirectoryError", func() {
				_, err := actor.GatherDirectoryResources(emptyDir)
				Expect(err).To(MatchError(EmptyDirectoryError{Path: emptyDir}))
			})
		})
	})

	Describe("ZipDirectoryResources", func() {
		var (
			resultZip  string
			resources  []Resource
			executeErr error
		)

		BeforeEach(func() {
			resources = []Resource{
				{Filename: "level1", Mode: DefaultFolderPermissions},
				{Filename: "level1/level2", Mode: DefaultFolderPermissions},
				{Filename: "level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4", Size: 9, Mode: 0766},
				{Filename: "tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95", Size: 12, Mode: 0766},
				{Filename: "tmpFile3", SHA1: "f4c9ca85f3e084ffad3abbdabbd2a890c034c879", Size: 10, Mode: 0766},
			}
		})

		JustBeforeEach(func() {
			resultZip, executeErr = actor.ZipDirectoryResources(srcDir, resources)
		})

		AfterEach(func() {
			err := os.RemoveAll(srcDir)
			Expect(err).ToNot(HaveOccurred())

			err = os.RemoveAll(resultZip)
			Expect(err).ToNot(HaveOccurred())
		})

		Context("when zipping on windows", func() {
			It("zips the directory and sets all the file modes to 07XX", func() {
				Expect(executeErr).ToNot(HaveOccurred())

				Expect(resultZip).ToNot(BeEmpty())
				zipFile, err := os.Open(resultZip)
				Expect(err).ToNot(HaveOccurred())
				defer zipFile.Close()

				zipInfo, err := zipFile.Stat()
				Expect(err).ToNot(HaveOccurred())

				reader, err := ykk.NewReader(zipFile, zipInfo.Size())
				Expect(err).ToNot(HaveOccurred())

				Expect(reader.File).To(HaveLen(5))
				Expect(reader.File[2].Mode()).To(Equal(os.FileMode(0766)))
				Expect(reader.File[3].Mode()).To(Equal(os.FileMode(0766)))
				Expect(reader.File[4].Mode()).To(Equal(os.FileMode(0766)))
			})
		})
	})
})
<|endoftext|>


<commit_before>package cmagic

import (
	"fmt"
	"testing"
	"reflect"
)

type Customer struct {
	Id   string
	Name string
}

var ns KeySpace

func init() {
	var err error
	c, err := Connect([]string{"127.0.0.1"}, "", "")
	if err != nil {
		panic(err)
	}
	err = c.DropKeySpace("test")
	if err != nil {
		panic(err)
	}
	err = c.CreateKeySpace("test")
	if err != nil {
		panic(err)
	}
	ns, err = ConnectToKeySpace("test", []string{"127.0.0.1"}, "", "")
	if err != nil {
		panic(err)
	}
	//ns.DebugMode(true)
}

// cqlsh> CREATE KEYSPACE test WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };
// cqlsh> CREATE TABLE test.customer (id text PRIMARY KEY, name text);
func TestEq(t *testing.T) {
	cs := ns.Table("customer", Customer{}, Keys{})
	err := cs.Set(Customer{
		Id:   "50",
		Name: "Joe",
	})
	if err != nil {
		t.Fatal(err)
	}
	res, err := cs.Where(Eq("Id", "50")).Query().Read()
	if err != nil {
		t.Fatal(err)
	}
	if len(res) == 0 {
		t.Fatal("Not found")
	}
	if res[0].(*Customer).Id != "50" {
		t.Fatal(res[0].(*Customer))
	}
}

func TestMultipleRowResults(t *testing.T) {
	name := "customer_multipletest"
	ns.(*K).DropTable(name)
	cs := ns.Table(name, Customer{}, Keys{
		PartitionKeys:     []string{"Name"},
		ClusteringColumns: []string{"Id"},
	})
	err := cs.(*T).Create()
	if err != nil {
		t.Fatal(err)
	}
	cs.Set(Customer{
		Id:   "12",
		Name: "John",
	})
	cs.Set(Customer{
		Id:   "13",
		Name: "John",
	})
	res, err := cs.Where(Eq("Name", "John")).Query().Read()
	if err != nil {
		t.Fatal(err)
	}
	if len(res) != 2 {
		t.Fatal(len(res), res)
	}
}

func TestIn(t *testing.T) {
	cs := ns.Table("customer", Customer{}, Keys{})
	err := cs.Set(Customer{
		Id:   "100",
		Name: "Joe",
	})
	if err != nil {
		t.Fatal(err)
	}
	err = cs.Set(Customer{
		Id:   "200",
		Name: "Jane",
	})
	if err != nil {
		t.Fatal(err)
	}
	res, err := cs.Where(In("Id", "100", "200")).Query().Read()
	if len(res) != 2 {
		for _, v := range res {
			fmt.Println(*(v.(*Customer)))
		}
		t.Fatal("Not found", len(res))
	}
	if res[0].(*Customer).Id != "100" || res[1].(*Customer).Id != "200" {
		t.Fatal(res[0].(*Customer), res[1].(*Customer))
	}
}

// cqlsh> CREATE TABLE test.customer1 (id text, name text, PRIMARY KEY((id, name)));
func TestAnd(t *testing.T) {
	cs := ns.Table("customer1", Customer{}, Keys{})
	err := cs.Set(Customer{
		Id:   "100",
		Name: "Joe",
	})
	if err != nil {
		t.Fatal(err)
	}
	res, err := cs.Where(Eq("Id", "100"), Eq("Name", "Joe")).Query().Read()
	if err != nil {
		t.Fatal(err)
	}
	if len(res) != 1 {
		t.Fatal("Not found ", len(res))
	}
}

func TestQueryReturnError(t *testing.T) {
	cs := ns.Table("customer2", Customer{}, Keys{})
	_, err := cs.Where(Eq("Id", "100"), Eq("Name", "Joe")).Query().Read()
	if err == nil {
		t.Fatal("Table customer2 does not exist - should return error")
	}
}

type Customer3 struct {
	Id string
	Field1 string
	Field2 int
	Field3 int32
	Field4 int64
	Field5 float32
	Field6 float64
	Field7 bool
}

func TestTypesMarshal(t *testing.T) {
	c := Customer3{
		Id: "1",
		Field1: "A",
		Field2: 1,
		Field3: 2,
		Field4: 3,
		Field5: 4.0,
		Field6: 5.0,
		Field7: true,
	}
	tbl := ns.Table("customer3", Customer3{}, Keys{PartitionKeys: []string{"Id"}})
	err := tbl.(*T).Create()
	if ex, err := ns.(*K).Exists("customer3"); err != nil {
		t.Fatal(err)
	} else if !ex {
		err := tbl.(*T).Create()
		if err != nil {
			t.Fatal("Create table failed :", err)
		}
	}
	if err = tbl.Set(c); err != nil {
		t.Fatal(err)
	}
	res, err := tbl.Where(Eq("Id", "1")).Query().Read()
	if err != nil {
		t.Fatal(err)
	}
	if len(res) != 1 {
		t.Fatal()
	}
	if !reflect.DeepEqual(c, *res[0].(*Customer3)) {
		t.Fatal(c, *res[0].(*Customer3))
	}
}<commit_msg>Tests pass now, now we drop keyspace before testing<commit_after>package cmagic

import (
	"fmt"
	"testing"
	"reflect"
)

type Customer struct {
	Id   string
	Name string
}

var ns KeySpace

func init() {
	var err error
	c, err := Connect([]string{"127.0.0.1"}, "", "")
	if err != nil {
		panic(err)
	}
	err = c.DropKeySpace("test")
	if err != nil {
		panic(err)
	}
	err = c.CreateKeySpace("test")
	if err != nil {
		panic(err)
	}
	ns, err = ConnectToKeySpace("test", []string{"127.0.0.1"}, "", "")
	if err != nil {
		panic(err)
	}
	//ns.DebugMode(true)
}

func TestEq(t *testing.T) {
	cs := ns.Table("customer", Customer{}, Keys{PartitionKeys:[]string{"Id"}})
	createIf(ns, cs.(*T), t)
	err := cs.Set(Customer{
		Id:   "50",
		Name: "Joe",
	})
	if err != nil {
		t.Fatal(err)
	}
	res, err := cs.Where(Eq("Id", "50")).Query().Read()
	if err != nil {
		t.Fatal(err)
	}
	if len(res) == 0 {
		t.Fatal("Not found")
	}
	if res[0].(*Customer).Id != "50" {
		t.Fatal(res[0].(*Customer))
	}
}

func TestMultipleRowResults(t *testing.T) {
	name := "customer_multipletest"
	ns.(*K).DropTable(name)
	cs := ns.Table(name, Customer{}, Keys{
		PartitionKeys:     []string{"Name"},
		ClusteringColumns: []string{"Id"},
	})
	err := cs.(*T).Create()
	if err != nil {
		t.Fatal(err)
	}
	cs.Set(Customer{
		Id:   "12",
		Name: "John",
	})
	cs.Set(Customer{
		Id:   "13",
		Name: "John",
	})
	res, err := cs.Where(Eq("Name", "John")).Query().Read()
	if err != nil {
		t.Fatal(err)
	}
	if len(res) != 2 {
		t.Fatal(len(res), res)
	}
}

func TestIn(t *testing.T) {
	cs := ns.Table("customer", Customer{}, Keys{})
	err := cs.Set(Customer{
		Id:   "100",
		Name: "Joe",
	})
	if err != nil {
		t.Fatal(err)
	}
	err = cs.Set(Customer{
		Id:   "200",
		Name: "Jane",
	})
	if err != nil {
		t.Fatal(err)
	}
	res, err := cs.Where(In("Id", "100", "200")).Query().Read()
	if len(res) != 2 {
		for _, v := range res {
			fmt.Println(*(v.(*Customer)))
		}
		t.Fatal("Not found", len(res))
	}
	if res[0].(*Customer).Id != "100" || res[1].(*Customer).Id != "200" {
		t.Fatal(res[0].(*Customer), res[1].(*Customer))
	}
}

func TestAnd(t *testing.T) {
	cs := ns.Table("customer1", Customer{}, Keys{PartitionKeys:[]string{"Id", "Name"}})
	createIf(ns, cs.(*T), t)
	err := cs.Set(Customer{
		Id:   "100",
		Name: "Joe",
	})
	if err != nil {
		t.Fatal(err)
	}
	res, err := cs.Where(Eq("Id", "100"), Eq("Name", "Joe")).Query().Read()
	if err != nil {
		t.Fatal(err)
	}
	if len(res) != 1 {
		t.Fatal("Not found ", len(res))
	}
}

func TestQueryReturnError(t *testing.T) {
	cs := ns.Table("customer2", Customer{}, Keys{})
	_, err := cs.Where(Eq("Id", "100"), Eq("Name", "Joe")).Query().Read()
	if err == nil {
		t.Fatal("Table customer2 does not exist - should return error")
	}
}

type Customer3 struct {
	Id string
	Field1 string
	Field2 int
	Field3 int32
	Field4 int64
	Field5 float32
	Field6 float64
	Field7 bool
}

func TestTypesMarshal(t *testing.T) {
	c := Customer3{
		Id: "1",
		Field1: "A",
		Field2: 1,
		Field3: 2,
		Field4: 3,
		Field5: 4.0,
		Field6: 5.0,
		Field7: true,
	}
	tbl := ns.Table("customer3", Customer3{}, Keys{PartitionKeys: []string{"Id"}})
	err := tbl.(*T).Create()
	if ex, err := ns.(*K).Exists("customer3"); err != nil {
		t.Fatal(err)
	} else if !ex {
		err := tbl.(*T).Create()
		if err != nil {
			t.Fatal("Create table failed :", err)
		}
	}
	if err = tbl.Set(c); err != nil {
		t.Fatal(err)
	}
	res, err := tbl.Where(Eq("Id", "1")).Query().Read()
	if err != nil {
		t.Fatal(err)
	}
	if len(res) != 1 {
		t.Fatal()
	}
	if !reflect.DeepEqual(c, *res[0].(*Customer3)) {
		t.Fatal(c, *res[0].(*Customer3))
	}
}<|endoftext|>


<commit_before>package weave

import (
	"bytes"
	"fmt"
	"log"
	"math/rand"
	"net"
	"time"
)

const (
	InitialInterval = 5 * time.Second
	MaxInterval     = 10 * time.Minute
	MaxAttemptCount = 100
	CMEnsure        = iota
	CMStatus        = iota
	CMEstablished   = iota
	CMConnFailed    = iota
)

const (
	CMUnconnected      ConnectionState = iota
	CMAttempting                       = iota
	CMEstablishedState                 = iota
)

func StartConnectionMaker(router *Router) *ConnectionMaker {
	queryChan := make(chan *ConnectionMakerInteraction, ChannelSize)
	state := &ConnectionMaker{
		router:    router,
		queryChan: queryChan,
		targets:   make(map[string]*Target)}
	go state.queryLoop(queryChan)
	return state
}

func (cm *ConnectionMaker) InitiateConnection(address string) {
	cm.queryChan <- &ConnectionMakerInteraction{
		Interaction:   Interaction{code: CMEnsure},
		acceptAnyPeer: true,
		address:       address}
}

func (cm *ConnectionMaker) EnsureConnection(address string) {
	// If we've been given a port number, take it off
	if addrHost, _, err := net.SplitHostPort(address); err == nil {
		address = addrHost
	}
	cm.queryChan <- &ConnectionMakerInteraction{
		Interaction:   Interaction{code: CMEnsure},
		acceptAnyPeer: false,
		address:       address}
}

func (cm *ConnectionMaker) ConnectionEstablished(address string) {
	// If we've been given a port number, take it off
	if addrHost, _, err := net.SplitHostPort(address); err == nil {
		address = addrHost
	}
	cm.queryChan <- &ConnectionMakerInteraction{
		Interaction: Interaction{code: CMEstablished},
		address:     address}
}

func (cm *ConnectionMaker) String() string {
	resultChan := make(chan interface{}, 0)
	cm.queryChan <- &ConnectionMakerInteraction{
		Interaction: Interaction{code: CMStatus, resultChan: resultChan}}
	result := <-resultChan
	return result.(string)
}

func (cm *ConnectionMaker) queryLoop(queryChan <-chan *ConnectionMakerInteraction) {
	var tick <-chan time.Time
	maybeTick := func() {
		// would be nice to optimise this to stop ticking when there is nothing worth trying
		if tick == nil {
			tick = time.After(5 * time.Second)
		}
	}
	tickNow := func() {
		if tick == nil {
			tick = time.After(0 * time.Second)
		}
	}
	for {
		select {
		case query, ok := <-queryChan:
			if !ok {
				return
			}
			switch {
			case query.code == CMEnsure:
				cm.addToTargets(query.acceptAnyPeer, query.address)
				cm.resetTarget(query.address)
				tickNow()
			case query.code == CMStatus:
				query.resultChan <- cm.status()
			case query.code == CMEstablished:
				target := cm.targets[query.address]
				if target != nil {
					target.state = CMEstablishedState
				} else {
					log.Fatal("Connection established to unknown address", query.address)
				}
			case query.code == CMConnFailed:
				target := cm.targets[query.address]
				target.state = CMUnconnected
				target.tryAfter, target.tryInterval = tryAfter(target.tryInterval)
				maybeTick()
			default:
				log.Fatal("Unexpected connection maker query:", query)
			}
		case now := <-tick:
			for address, target := range cm.targets {
				if target.state == CMUnconnected && now.After(target.tryAfter) {
					if _, found := cm.router.Ourself.ConnectionOn(address); found {
						target.state = CMEstablished
					} else {
						target.attemptCount += 1
						target.state = CMAttempting
						go cm.attemptConnection(address, target.acceptAnyPeer)
					}
				}
			}
			tick = nil
			maybeTick()
		}
	}
}

func (cm *ConnectionMaker) addToTargets(acceptAnyPeer bool, address string) {
	target := cm.targets[address]
	if target == nil {
		target = &Target{
			state:         CMUnconnected,
			acceptAnyPeer: acceptAnyPeer,
		}
		cm.targets[address] = target
	}
}

func (cm *ConnectionMaker) resetTarget(address string) {
	target := cm.targets[address]
	// If we were in the middle of a connection attempt then back-off again
	if target.state == CMAttempting {
		target.tryAfter, target.tryInterval = tryAfter(target.tryInterval)
	} else {
		target.tryAfter, target.tryInterval = tryImmediately()
	}
	target.state = CMUnconnected
}

func (cm *ConnectionMaker) status() string {
	var buf bytes.Buffer
	for address, target := range cm.targets {
		if target.state == CMEstablishedState {
			buf.WriteString(fmt.Sprintf("%s connected\n", address))
		} else if target.state == CMAttempting {
			buf.WriteString(fmt.Sprintf("%s (%v attempts, trying since %v)\n", address, target.attemptCount, target.tryAfter))
		} else {
			buf.WriteString(fmt.Sprintf("%s (%v attempts, next at %v)\n", address, target.attemptCount, target.tryAfter))
		}
	}
	return buf.String()
}

func (cm *ConnectionMaker) attemptConnection(address string, acceptNewPeer bool) {
	log.Println("Attempting connection to", address)
	if err := cm.router.Ourself.CreateConnection(address, acceptNewPeer); err != nil {
		log.Println(err)
		cm.queryChan <- &ConnectionMakerInteraction{
			Interaction: Interaction{code: CMConnFailed},
			address:     address}
	}
}

func tryImmediately() (time.Time, time.Duration) {
	interval := time.Duration(rand.Int63n(int64(InitialInterval)))
	return time.Now(), interval
}

func tryAfter(interval time.Duration) (time.Time, time.Duration) {
	interval += time.Duration(rand.Int63n(int64(interval)))
	if interval > MaxInterval {
		interval = MaxInterval
	}
	return time.Now().Add(interval), interval
}
<commit_msg>Clean up naming of commands and states<commit_after>package weave

import (
	"bytes"
	"fmt"
	"log"
	"math/rand"
	"net"
	"time"
)

const (
	InitialInterval = 5 * time.Second
	MaxInterval     = 10 * time.Minute
	MaxAttemptCount = 100
	CMEnsure        = iota
	CMStatus        = iota
	CMEstablished   = iota
	CMConnFailed    = iota
)

const (
	CSUnconnected ConnectionState = iota
	CSAttempting                  = iota
	CSEstablished                 = iota
)

func StartConnectionMaker(router *Router) *ConnectionMaker {
	queryChan := make(chan *ConnectionMakerInteraction, ChannelSize)
	state := &ConnectionMaker{
		router:    router,
		queryChan: queryChan,
		targets:   make(map[string]*Target)}
	go state.queryLoop(queryChan)
	return state
}

func (cm *ConnectionMaker) InitiateConnection(address string) {
	cm.queryChan <- &ConnectionMakerInteraction{
		Interaction:   Interaction{code: CMEnsure},
		acceptAnyPeer: true,
		address:       address}
}

func (cm *ConnectionMaker) EnsureConnection(address string) {
	// If we've been given a port number, take it off
	if addrHost, _, err := net.SplitHostPort(address); err == nil {
		address = addrHost
	}
	cm.queryChan <- &ConnectionMakerInteraction{
		Interaction:   Interaction{code: CMEnsure},
		acceptAnyPeer: false,
		address:       address}
}

func (cm *ConnectionMaker) ConnectionEstablished(address string) {
	// If we've been given a port number, take it off
	if addrHost, _, err := net.SplitHostPort(address); err == nil {
		address = addrHost
	}
	cm.queryChan <- &ConnectionMakerInteraction{
		Interaction: Interaction{code: CMEstablished},
		address:     address}
}

func (cm *ConnectionMaker) String() string {
	resultChan := make(chan interface{}, 0)
	cm.queryChan <- &ConnectionMakerInteraction{
		Interaction: Interaction{code: CMStatus, resultChan: resultChan}}
	result := <-resultChan
	return result.(string)
}

func (cm *ConnectionMaker) queryLoop(queryChan <-chan *ConnectionMakerInteraction) {
	var tick <-chan time.Time
	maybeTick := func() {
		// would be nice to optimise this to stop ticking when there is nothing worth trying
		if tick == nil {
			tick = time.After(5 * time.Second)
		}
	}
	tickNow := func() {
		if tick == nil {
			tick = time.After(0 * time.Second)
		}
	}
	for {
		select {
		case query, ok := <-queryChan:
			if !ok {
				return
			}
			switch {
			case query.code == CMEnsure:
				cm.addToTargets(query.acceptAnyPeer, query.address)
				cm.resetTarget(query.address)
				tickNow()
			case query.code == CMStatus:
				query.resultChan <- cm.status()
			case query.code == CMEstablished:
				target := cm.targets[query.address]
				if target != nil {
					target.state = CSEstablished
				} else {
					log.Fatal("Connection established to unknown address", query.address)
				}
			case query.code == CMConnFailed:
				target := cm.targets[query.address]
				target.state = CSUnconnected
				target.tryAfter, target.tryInterval = tryAfter(target.tryInterval)
				maybeTick()
			default:
				log.Fatal("Unexpected connection maker query:", query)
			}
		case now := <-tick:
			for address, target := range cm.targets {
				if target.state == CSUnconnected && now.After(target.tryAfter) {
					if _, found := cm.router.Ourself.ConnectionOn(address); found {
						target.state = CSEstablished
					} else {
						target.attemptCount += 1
						target.state = CSAttempting
						go cm.attemptConnection(address, target.acceptAnyPeer)
					}
				}
			}
			tick = nil
			maybeTick()
		}
	}
}

func (cm *ConnectionMaker) addToTargets(acceptAnyPeer bool, address string) {
	target := cm.targets[address]
	if target == nil {
		target = &Target{
			state:         CSUnconnected,
			acceptAnyPeer: acceptAnyPeer,
		}
		cm.targets[address] = target
	}
}

func (cm *ConnectionMaker) resetTarget(address string) {
	target := cm.targets[address]
	// If we were in the middle of a connection attempt then back-off again
	if target.state == CSAttempting {
		target.tryAfter, target.tryInterval = tryAfter(target.tryInterval)
	} else {
		target.tryAfter, target.tryInterval = tryImmediately()
	}
	target.state = CSUnconnected
}

func (cm *ConnectionMaker) status() string {
	var buf bytes.Buffer
	for address, target := range cm.targets {
		if target.state == CSEstablished {
			buf.WriteString(fmt.Sprintf("%s connected\n", address))
		} else if target.state == CSAttempting {
			buf.WriteString(fmt.Sprintf("%s (%v attempts, trying since %v)\n", address, target.attemptCount, target.tryAfter))
		} else {
			buf.WriteString(fmt.Sprintf("%s (%v attempts, next at %v)\n", address, target.attemptCount, target.tryAfter))
		}
	}
	return buf.String()
}

func (cm *ConnectionMaker) attemptConnection(address string, acceptNewPeer bool) {
	log.Println("Attempting connection to", address)
	if err := cm.router.Ourself.CreateConnection(address, acceptNewPeer); err != nil {
		log.Println(err)
		cm.queryChan <- &ConnectionMakerInteraction{
			Interaction: Interaction{code: CMConnFailed},
			address:     address}
	}
}

func tryImmediately() (time.Time, time.Duration) {
	interval := time.Duration(rand.Int63n(int64(InitialInterval)))
	return time.Now(), interval
}

func tryAfter(interval time.Duration) (time.Time, time.Duration) {
	interval += time.Duration(rand.Int63n(int64(interval)))
	if interval > MaxInterval {
		interval = MaxInterval
	}
	return time.Now().Add(interval), interval
}
<|endoftext|>


<commit_before>package weave

import (
	"bytes"
	"fmt"
	"log"
	"math/rand"
	"time"
)

const (
	InitialInterval = 5 * time.Second
	MaxInterval     = 10 * time.Minute
	MaxAttemptCount = 100
	CMInitiate      = iota
	CMStatus        = iota
	CMAttemptDone   = iota
)

const (
	CSUnconnected ConnectionState = iota
	CSAttempting                  = iota
)

func StartConnectionMaker(router *Router) *ConnectionMaker {
	queryChan := make(chan *ConnectionMakerInteraction, ChannelSize)
	state := &ConnectionMaker{
		router:         router,
		queryChan:      queryChan,
		cmdLineAddress: make(map[string]bool),
		targets:        make(map[string]*Target)}
	go state.queryLoop(queryChan)
	return state
}

func (cm *ConnectionMaker) InitiateConnection(address string) {
	cm.queryChan <- &ConnectionMakerInteraction{
		Interaction: Interaction{code: CMInitiate},
		address:     address}
}

func (cm *ConnectionMaker) String() string {
	resultChan := make(chan interface{}, 0)
	cm.queryChan <- &ConnectionMakerInteraction{
		Interaction: Interaction{code: CMStatus, resultChan: resultChan}}
	result := <-resultChan
	return result.(string)
}

func (cm *ConnectionMaker) queryLoop(queryChan <-chan *ConnectionMakerInteraction) {
	var tick <-chan time.Time
	maybeTick := func() {
		// would be nice to optimise this to stop ticking when there is nothing worth trying
		if tick == nil {
			tick = time.After(5 * time.Second)
		}
	}
	for {
		select {
		case query, ok := <-queryChan:
			if !ok {
				return
			}
			switch {
			case query.code == CMInitiate:
				cm.cmdLineAddress[NormalisePeerAddr(query.address)] = true
				cm.checkStateAndAttemptConnections(time.Now())
				maybeTick()
			case query.code == CMStatus:
				query.resultChan <- cm.status()
			case query.code == CMAttemptDone:
				if target, found := cm.targets[query.address]; found {
					target.state = CSUnconnected
					target.tryAfter, target.tryInterval = tryAfter(target.tryInterval)
					maybeTick()
				} else {
					log.Fatal("CMAttemptDone unknown address", query.address)
				}
			default:
				log.Fatal("Unexpected connection maker query:", query)
			}
		case now := <-tick:
			cm.checkStateAndAttemptConnections(now)
			tick = nil
			maybeTick()
		}
	}
}

func (cm *ConnectionMaker) checkStateAndAttemptConnections(now time.Time) {
	ourself := cm.router.Ourself
	validTarget := make(map[string]bool)

	// copy the set of things we are connected to, so we can access them without locking
	our_connected_peers := make(map[PeerName]bool)
	our_connected_targets := make(map[string]bool)
	ourself.ForEachConnection(func(peer PeerName, conn Connection) {
		//log.Println("Connected peer:", peer, conn.RemoteTCPAddr())
		our_connected_peers[peer] = true
		our_connected_targets[conn.RemoteTCPAddr()] = true
	})

	// Add command-line targets that are not connected
	for address, _ := range cm.cmdLineAddress {
		if !our_connected_targets[NormalisePeerAddr(address)] {
			//log.Println("Unconnected cmdline:", address)
			validTarget[address] = true
		}
	}

	// Add peers that someone else is connected to, but we aren't
	cm.router.Peers.ForEach(func(name PeerName, peer *Peer) {
		peer.ForEachConnection(func(peer2 PeerName, conn Connection) {
			if peer2 != ourself.Name && !our_connected_peers[peer2] {
				address := conn.RemoteTCPAddr()
				//log.Println("Unconnected peer:", peer2, address)
				// try both portnumber of connection and standart port
				if host, port, err := ExtractHostPort(address); err == nil {
					if port != Port {
						// This is an address with port, that is not the standard port
						validTarget[address] = true
					}
					// Add the address with standard port
					validTarget[NormalisePeerAddr(host)] = true
				}
			}
		})
	})

	for address, _ := range validTarget {
		cm.addToTargets(address)
	}

	now = time.Now()  // make sure we catch items just added
	for address, target := range cm.targets {
		if target.state == CSUnconnected {
			if our_connected_targets[address] || !validTarget[address] {
				//log.Println("Deleting target no longer valid:", address)
				delete(cm.targets, address)
			} else if now.After(target.tryAfter) {
				target.attemptCount += 1
				target.state = CSAttempting
				go cm.attemptConnection(address, cm.cmdLineAddress[address])
			}
		}
	}
}

func (cm *ConnectionMaker) addToTargets(address string) {
	address = NormalisePeerAddr(address)
	target := cm.targets[address]
	if target == nil {
		target = &Target{
			state: CSUnconnected,
		}
		target.tryAfter, target.tryInterval = tryImmediately()
		cm.targets[address] = target
	}
}

func (cm *ConnectionMaker) status() string {
	var buf bytes.Buffer
	for address, target := range cm.targets {
		if target.state == CSAttempting {
			buf.WriteString(fmt.Sprintf("%s (%v attempts, trying since %v)\n", address, target.attemptCount, target.tryAfter))
		} else {
			buf.WriteString(fmt.Sprintf("%s (%v attempts, next at %v)\n", address, target.attemptCount, target.tryAfter))
		}
	}
	return buf.String()
}

func (cm *ConnectionMaker) attemptConnection(address string, acceptNewPeer bool) {
	log.Println("Attempting connection to", address)
	if err := cm.router.Ourself.CreateConnection(address, acceptNewPeer); err != nil {
		log.Println(err)
	}
	cm.queryChan <- &ConnectionMakerInteraction{
		Interaction: Interaction{code: CMAttemptDone},
		address:     address}
}

func tryImmediately() (time.Time, time.Duration) {
	interval := time.Duration(rand.Int63n(int64(InitialInterval)))
	return time.Now(), interval
}

func tryAfter(interval time.Duration) (time.Time, time.Duration) {
	interval += time.Duration(rand.Int63n(int64(interval)))
	if interval > MaxInterval {
		interval = MaxInterval
	}
	return time.Now().Add(interval), interval
}
<commit_msg>cosmetic<commit_after>package weave

import (
	"bytes"
	"fmt"
	"log"
	"math/rand"
	"time"
)

const (
	InitialInterval = 5 * time.Second
	MaxInterval     = 10 * time.Minute
	MaxAttemptCount = 100
	CMInitiate      = iota
	CMStatus        = iota
	CMAttemptDone   = iota
)

const (
	CSUnconnected ConnectionState = iota
	CSAttempting                  = iota
)

func StartConnectionMaker(router *Router) *ConnectionMaker {
	queryChan := make(chan *ConnectionMakerInteraction, ChannelSize)
	state := &ConnectionMaker{
		router:         router,
		queryChan:      queryChan,
		cmdLineAddress: make(map[string]bool),
		targets:        make(map[string]*Target)}
	go state.queryLoop(queryChan)
	return state
}

func (cm *ConnectionMaker) InitiateConnection(address string) {
	cm.queryChan <- &ConnectionMakerInteraction{
		Interaction: Interaction{code: CMInitiate},
		address:     address}
}

func (cm *ConnectionMaker) String() string {
	resultChan := make(chan interface{}, 0)
	cm.queryChan <- &ConnectionMakerInteraction{
		Interaction: Interaction{code: CMStatus, resultChan: resultChan}}
	result := <-resultChan
	return result.(string)
}

func (cm *ConnectionMaker) queryLoop(queryChan <-chan *ConnectionMakerInteraction) {
	var tick <-chan time.Time
	maybeTick := func() {
		// would be nice to optimise this to stop ticking when there is nothing worth trying
		if tick == nil {
			tick = time.After(5 * time.Second)
		}
	}
	for {
		select {
		case query, ok := <-queryChan:
			if !ok {
				return
			}
			switch {
			case query.code == CMInitiate:
				cm.cmdLineAddress[NormalisePeerAddr(query.address)] = true
				cm.checkStateAndAttemptConnections(time.Now())
				maybeTick()
			case query.code == CMStatus:
				query.resultChan <- cm.status()
			case query.code == CMAttemptDone:
				if target, found := cm.targets[query.address]; found {
					target.state = CSUnconnected
					target.tryAfter, target.tryInterval = tryAfter(target.tryInterval)
					maybeTick()
				} else {
					log.Fatal("CMAttemptDone unknown address", query.address)
				}
			default:
				log.Fatal("Unexpected connection maker query:", query)
			}
		case now := <-tick:
			cm.checkStateAndAttemptConnections(now)
			tick = nil
			maybeTick()
		}
	}
}

func (cm *ConnectionMaker) checkStateAndAttemptConnections(now time.Time) {
	ourself := cm.router.Ourself
	validTarget := make(map[string]bool)

	// copy the set of things we are connected to, so we can access them without locking
	our_connected_peers := make(map[PeerName]bool)
	our_connected_targets := make(map[string]bool)
	ourself.ForEachConnection(func(peer PeerName, conn Connection) {
		//log.Println("Connected peer:", peer, conn.RemoteTCPAddr())
		our_connected_peers[peer] = true
		our_connected_targets[conn.RemoteTCPAddr()] = true
	})

	// Add command-line targets that are not connected
	for address, _ := range cm.cmdLineAddress {
		if !our_connected_targets[NormalisePeerAddr(address)] {
			//log.Println("Unconnected cmdline:", address)
			validTarget[address] = true
		}
	}

	// Add peers that someone else is connected to, but we aren't
	cm.router.Peers.ForEach(func(name PeerName, peer *Peer) {
		peer.ForEachConnection(func(peer2 PeerName, conn Connection) {
			if peer2 != ourself.Name && !our_connected_peers[peer2] {
				address := conn.RemoteTCPAddr()
				//log.Println("Unconnected peer:", peer2, address)
				// try both portnumber of connection and standart port
				if host, port, err := ExtractHostPort(address); err == nil {
					if port != Port {
						// This is an address with port, that is not the standard port
						validTarget[address] = true
					}
					// Add the address with standard port
					validTarget[NormalisePeerAddr(host)] = true
				}
			}
		})
	})

	for address, _ := range validTarget {
		cm.addToTargets(address)
	}

	now = time.Now() // make sure we catch items just added
	for address, target := range cm.targets {
		if target.state == CSUnconnected {
			if our_connected_targets[address] || !validTarget[address] {
				//log.Println("Deleting target no longer valid:", address)
				delete(cm.targets, address)
			} else if now.After(target.tryAfter) {
				target.attemptCount += 1
				target.state = CSAttempting
				go cm.attemptConnection(address, cm.cmdLineAddress[address])
			}
		}
	}
}

func (cm *ConnectionMaker) addToTargets(address string) {
	address = NormalisePeerAddr(address)
	target := cm.targets[address]
	if target == nil {
		target = &Target{
			state: CSUnconnected,
		}
		target.tryAfter, target.tryInterval = tryImmediately()
		cm.targets[address] = target
	}
}

func (cm *ConnectionMaker) status() string {
	var buf bytes.Buffer
	for address, target := range cm.targets {
		if target.state == CSAttempting {
			buf.WriteString(fmt.Sprintf("%s (%v attempts, trying since %v)\n", address, target.attemptCount, target.tryAfter))
		} else {
			buf.WriteString(fmt.Sprintf("%s (%v attempts, next at %v)\n", address, target.attemptCount, target.tryAfter))
		}
	}
	return buf.String()
}

func (cm *ConnectionMaker) attemptConnection(address string, acceptNewPeer bool) {
	log.Println("Attempting connection to", address)
	if err := cm.router.Ourself.CreateConnection(address, acceptNewPeer); err != nil {
		log.Println(err)
	}
	cm.queryChan <- &ConnectionMakerInteraction{
		Interaction: Interaction{code: CMAttemptDone},
		address:     address}
}

func tryImmediately() (time.Time, time.Duration) {
	interval := time.Duration(rand.Int63n(int64(InitialInterval)))
	return time.Now(), interval
}

func tryAfter(interval time.Duration) (time.Time, time.Duration) {
	interval += time.Duration(rand.Int63n(int64(interval)))
	if interval > MaxInterval {
		interval = MaxInterval
	}
	return time.Now().Add(interval), interval
}
<|endoftext|>