<commit_before>package main

import (
	"bufio"
	"errors"
	"os"
	"strconv"
	"strings"
)

func ParseLine(line string) (*Example, error) {
	tokens := strings.Split(line, "\t")
	var url string
	if len(tokens) == 1 {
		url = tokens[0]
		return NewExample(url, UNLABELED), nil
	} else if len(tokens) == 2 {
		url = tokens[0]
		label, _ := strconv.ParseInt(tokens[1], 10, 0)
		switch LabelType(label) {
		case POSITIVE, NEGATIVE, UNLABELED:
			return NewExample(url, LabelType(label)), nil
		default:
			return nil, errors.New("Invalid label type")
		}
	} else {
		return nil, errors.New("Invalid line")
	}
}

func ReadExamples(filename string) ([]*Example, error) {
	fp, err := os.Open(filename)
	defer fp.Close()
	if err != nil {
		return nil, err
	}

	scanner := bufio.NewScanner(fp)
	var examples Examples
	for scanner.Scan() {
		line := scanner.Text()
		e, err := ParseLine(line)
		if err != nil {
			return nil, err
		}
		examples = append(examples, e)
	}
	if err := scanner.Err(); err != nil {
		return nil, err
	}
	return examples, nil
}
<commit_msg>ラベル付けされている事例のみをフィルタリングしてくる関数を追加<commit_after>package main

import (
	"bufio"
	"errors"
	"os"
	"strconv"
	"strings"
)

func ParseLine(line string) (*Example, error) {
	tokens := strings.Split(line, "\t")
	var url string
	if len(tokens) == 1 {
		url = tokens[0]
		return NewExample(url, UNLABELED), nil
	} else if len(tokens) == 2 {
		url = tokens[0]
		label, _ := strconv.ParseInt(tokens[1], 10, 0)
		switch LabelType(label) {
		case POSITIVE, NEGATIVE, UNLABELED:
			return NewExample(url, LabelType(label)), nil
		default:
			return nil, errors.New("Invalid label type")
		}
	} else {
		return nil, errors.New("Invalid line")
	}
}

func ReadExamples(filename string) ([]*Example, error) {
	fp, err := os.Open(filename)
	defer fp.Close()
	if err != nil {
		return nil, err
	}

	scanner := bufio.NewScanner(fp)
	var examples Examples
	for scanner.Scan() {
		line := scanner.Text()
		e, err := ParseLine(line)
		if err != nil {
			return nil, err
		}
		examples = append(examples, e)
	}
	if err := scanner.Err(); err != nil {
		return nil, err
	}
	return examples, nil
}

func FilterLabeledExamples(examples Examples) Examples {
	var result Examples
	for _, e := range examples {
		if e.IsLabeled() {
			result = append(result, e)
		}
	}
	return result
}
<|endoftext|>


<commit_before>package u

import (
	"crypto/sha1"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"time"
)

var (
	errInvalidBase64 = errors.New("invalid base64 value")
)

func Must(err error) {
	if err != nil {
		panic(err)
	}
}

func Assert(ok bool, format string, args ...interface{}) {
	if ok {
		return
	}
	if len(args) == 0 {
		panic(format)
	}
	panic(fmt.Sprintf(format, args...))
}

// PanicIf panics if cond is true
func PanicIf(cond bool, args ...interface{}) {
	if !cond {
		return
	}
	if len(args) == 0 {
		panic("condition failed")
	}
	format := args[0].(string)
	if len(args) == 1 {
		panic(format)
	}
	panic(fmt.Sprintf(format, args[1:]...))
}

// FmtArgs formats args as a string. First argument should be format string
// and the rest are arguments to the format
func FmtArgs(args ...interface{}) string {
	if len(args) == 0 {
		return ""
	}
	format := args[0].(string)
	if len(args) == 1 {
		return format
	}
	return fmt.Sprintf(format, args[1:]...)
}

func panicWithMsg(defaultMsg string, args ...interface{}) {
	s := FmtArgs(args...)
	if s == "" {
		s = defaultMsg
	}
	fmt.Printf("%s\n", s)
	panic(s)
}

// PanicIfErr panics if err is not nil
func PanicIfErr(err error, args ...interface{}) {
	if err == nil {
		return
	}
	panicWithMsg(err.Error(), args...)
}

// IsLinux returns true if running on linux
func IsLinux() bool {
	return runtime.GOOS == "linux"
}

// IsMac returns true if running on mac
func IsMac() bool {
	return runtime.GOOS == "darwin"
}

// UserHomeDir returns $HOME diretory of the user
func UserHomeDirMust() string {
	s, err := os.UserHomeDir()
	Must(err)
	return s
}

// ExpandTildeInPath converts ~ to $HOME
func ExpandTildeInPath(s string) string {
	if strings.HasPrefix(s, "~") {
		return UserHomeDirMust() + s[1:]
	}
	return s
}

// Sha1HexOfBytes returns 40-byte hex sha1 of bytes
func Sha1HexOfBytes(data []byte) string {
	return fmt.Sprintf("%x", Sha1OfBytes(data))
}

// Sha1OfBytes returns 20-byte sha1 of bytes
func Sha1OfBytes(data []byte) []byte {
	h := sha1.New()
	h.Write(data)
	return h.Sum(nil)
}

// DurationToString converts duration to a string
func DurationToString(d time.Duration) string {
	minutes := int(d.Minutes()) % 60
	hours := int(d.Hours())
	days := hours / 24
	hours = hours % 24
	if days > 0 {
		return fmt.Sprintf("%dd %dhr", days, hours)
	}
	if hours > 0 {
		return fmt.Sprintf("%dhr %dm", hours, minutes)
	}
	return fmt.Sprintf("%dm", minutes)
}

// TimeSinceNowAsString returns string version of time since a ginve timestamp
func TimeSinceNowAsString(t time.Time) string {
	return DurationToString(time.Since(t))
}

// UtcNow returns current time in UTC
func UtcNow() time.Time {
	return time.Now().UTC()
}

const base64Chars = "0123456789abcdefghijklmnopqrstuvwxyz"

// EncodeBase64 encodes n as base64
func EncodeBase64(n int) string {
	var buf [16]byte
	size := 0
	for {
		buf[size] = base64Chars[n%36]
		size++
		if n < 36 {
			break
		}
		n /= 36
	}
	end := size - 1
	for i := 0; i < end; i++ {
		b := buf[i]
		buf[i] = buf[end]
		buf[end] = b
		end--
	}
	return string(buf[:size])
}

// DecodeBase64 decodes base64 string
func DecodeBase64(s string) (int, error) {
	n := 0
	for _, c := range s {
		n *= 36
		i := strings.IndexRune(base64Chars, c)
		if i == -1 {
			return 0, errInvalidBase64
		}
		n += i
	}
	return n, nil
}

// OpenBrowsers open web browser with a given url
// (can be http:// or file://)
func OpenBrowser(url string) error {
	var err error
	switch runtime.GOOS {
	case "linux":
		err = exec.Command("xdg-open", url).Start()
	case "windows":
		err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
	case "darwin":
		err = exec.Command("open", url).Start()
	default:
		err = fmt.Errorf("unsupported platform")
	}
	return err
}
<commit_msg>add WaitForCtrlC()<commit_after>package u

import (
	"crypto/sha1"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"os/signal"
	"runtime"
	"strings"
	"syscall"
	"time"
)

var (
	errInvalidBase64 = errors.New("invalid base64 value")
)

func Must(err error) {
	if err != nil {
		panic(err)
	}
}

func Assert(ok bool, format string, args ...interface{}) {
	if ok {
		return
	}
	if len(args) == 0 {
		panic(format)
	}
	panic(fmt.Sprintf(format, args...))
}

// PanicIf panics if cond is true
func PanicIf(cond bool, args ...interface{}) {
	if !cond {
		return
	}
	if len(args) == 0 {
		panic("condition failed")
	}
	format := args[0].(string)
	if len(args) == 1 {
		panic(format)
	}
	panic(fmt.Sprintf(format, args[1:]...))
}

// FmtArgs formats args as a string. First argument should be format string
// and the rest are arguments to the format
func FmtArgs(args ...interface{}) string {
	if len(args) == 0 {
		return ""
	}
	format := args[0].(string)
	if len(args) == 1 {
		return format
	}
	return fmt.Sprintf(format, args[1:]...)
}

func panicWithMsg(defaultMsg string, args ...interface{}) {
	s := FmtArgs(args...)
	if s == "" {
		s = defaultMsg
	}
	fmt.Printf("%s\n", s)
	panic(s)
}

// PanicIfErr panics if err is not nil
func PanicIfErr(err error, args ...interface{}) {
	if err == nil {
		return
	}
	panicWithMsg(err.Error(), args...)
}

// IsLinux returns true if running on linux
func IsLinux() bool {
	return runtime.GOOS == "linux"
}

// IsMac returns true if running on mac
func IsMac() bool {
	return runtime.GOOS == "darwin"
}

// UserHomeDir returns $HOME diretory of the user
func UserHomeDirMust() string {
	s, err := os.UserHomeDir()
	Must(err)
	return s
}

// ExpandTildeInPath converts ~ to $HOME
func ExpandTildeInPath(s string) string {
	if strings.HasPrefix(s, "~") {
		return UserHomeDirMust() + s[1:]
	}
	return s
}

// Sha1HexOfBytes returns 40-byte hex sha1 of bytes
func Sha1HexOfBytes(data []byte) string {
	return fmt.Sprintf("%x", Sha1OfBytes(data))
}

// Sha1OfBytes returns 20-byte sha1 of bytes
func Sha1OfBytes(data []byte) []byte {
	h := sha1.New()
	h.Write(data)
	return h.Sum(nil)
}

// DurationToString converts duration to a string
func DurationToString(d time.Duration) string {
	minutes := int(d.Minutes()) % 60
	hours := int(d.Hours())
	days := hours / 24
	hours = hours % 24
	if days > 0 {
		return fmt.Sprintf("%dd %dhr", days, hours)
	}
	if hours > 0 {
		return fmt.Sprintf("%dhr %dm", hours, minutes)
	}
	return fmt.Sprintf("%dm", minutes)
}

// TimeSinceNowAsString returns string version of time since a ginve timestamp
func TimeSinceNowAsString(t time.Time) string {
	return DurationToString(time.Since(t))
}

// UtcNow returns current time in UTC
func UtcNow() time.Time {
	return time.Now().UTC()
}

const base64Chars = "0123456789abcdefghijklmnopqrstuvwxyz"

// EncodeBase64 encodes n as base64
func EncodeBase64(n int) string {
	var buf [16]byte
	size := 0
	for {
		buf[size] = base64Chars[n%36]
		size++
		if n < 36 {
			break
		}
		n /= 36
	}
	end := size - 1
	for i := 0; i < end; i++ {
		b := buf[i]
		buf[i] = buf[end]
		buf[end] = b
		end--
	}
	return string(buf[:size])
}

// DecodeBase64 decodes base64 string
func DecodeBase64(s string) (int, error) {
	n := 0
	for _, c := range s {
		n *= 36
		i := strings.IndexRune(base64Chars, c)
		if i == -1 {
			return 0, errInvalidBase64
		}
		n += i
	}
	return n, nil
}

// OpenBrowsers open web browser with a given url
// (can be http:// or file://)
func OpenBrowser(url string) error {
	var err error
	switch runtime.GOOS {
	case "linux":
		err = exec.Command("xdg-open", url).Start()
	case "windows":
		err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
	case "darwin":
		err = exec.Command("open", url).Start()
	default:
		err = fmt.Errorf("unsupported platform")
	}
	return err
}

// WaitForCtrlC waits until a user presses Ctrl-C
func WaitForCtrlC() {
	c := make(chan os.Signal, 2)
	signal.Notify(c, os.Interrupt /* SIGINT */, syscall.SIGTERM)
	<-c
}
<|endoftext|>


<commit_before>package main

import (
	"os/exec"
	"strings"
)

func getHostname() (string, error) {
	fqdn, err := exec.Command("hostname", "-f").Output()
	if err != nil {
		return "", err
	}
	return strings.TrimSpace(string(fqdn)), nil
}
<commit_msg>Added useful reverseStringSlice function<commit_after>package main

import (
	"os/exec"
	"strings"
)

func getHostname() (string, error) {
	fqdn, err := exec.Command("hostname", "-f").Output()
	if err != nil {
		return "", err
	}
	return strings.TrimSpace(string(fqdn)), nil
}

func reverseStringSlice(in []string) []string {
	out := make([]string, len(in))
	for i := range in {
		out[len(in)-i-1] = in[i]
	}
	return out
}
<|endoftext|>


<commit_before>package main

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

	l "github.com/haklop/bazooka/commons/logger"
	"github.com/haklop/bazooka/commons/matrix"

	lib "github.com/haklop/bazooka/commons"
)

const (
	SourceFolder      = "/bazooka"
	OutputFolder      = "/bazooka-output"
	MetaFolder        = "/meta"
	BazookaConfigFile = ".bazooka.yml"
	TravisConfigFile  = ".travis.yml"
	MX_ENV_PREFIX     = "env::"
)

func main() {
	l.Init(ioutil.Discard, os.Stdout, os.Stdout, os.Stdout, os.Stdout)
	l.Info.Println("Starting Parsing Phase")
	// Find either .travis.yml or .bazooka.yml file in the project
	configFile, err := lib.ResolveConfigFile(SourceFolder)
	if err != nil {
		l.Error.Fatal(err)
	}

	// parse the configuration
	config := &lib.Config{}
	err = lib.Parse(configFile, config)
	if err != nil {
		l.Error.Fatal(err)
	}
	l.Trace.Printf("Parsed configuration is %+v\n", config)

	// resolve the docker image corresponding to this particular language parser
	image, err := resolveLanguageParser(config.Language)
	if err != nil {
		l.Error.Fatal(err)
	}

	// run the parser image
	langParser := &LanguageParser{
		Image: image,
	}
	err = langParser.Parse()
	if err != nil {
		l.Error.Fatal(err)
	}

	// if all went well, the parser should have generated one or more "sub" .bazooka.*.yml files
	// one for each compiler version for example
	//
	// they are also supposed to enrich it with a from attribute corresponding to a base docker image
	// to be used to run the build

	l.Info.Println("Starting Matrix generation")
	files, err := lib.ListFilesWithPrefix(OutputFolder, ".bazooka")
	if err != nil {
		l.Error.Fatal(err)
	}

	// for each of those files (the "sub" .bazooka.*.yml)
	for _, file := range files {
		// parse the damned thing
		config := &lib.Config{}
		err = lib.Parse(file, config)
		if err != nil {
			l.Error.Fatal(fmt.Errorf("Error while parsing config file %s: %v", file, err))
		}

		// create a matrix from the environment variables
		// a matrix has N variables (dimensions) where each variable has M values
		// config.Env is a list of key=value strings
		// explodeProps transforms that into a map[string][]string
		// for example ["A=1", "A=2", B="3"]
		// when exploded gets transformed into
		// {A: [1, 2], B: [3]}
		// this matches the matrix layout, so we could store them directly into the matrix
		// but since we would like to be able to extract them later, and to avoid mixing them with a language specific variables (like jdk, go, etc.)
		// explode prefixes the env variables names with a prefix defined in the constant MX_ENV_PREFIX
		// Hence, our matrix is more like: {"env::A": [1, 2], "env::B": [3]}
		mx := matrix.Matrix(explodeProps(config.Env, MX_ENV_PREFIX))

		// extract the "*" part from the .bazooka.*.yml file
		rootCounter := parseCounter(file)
		// for every .bazooka.*.yml file, the language parser is also supposed to have generated a meta/* file
		// which is a simple yml file containing the language specific  matrix variables
		// for example, if the original .bazooka.yml file defined 2 go versions:
		//
		// go:
		// - 1.2.2
		// - 1.3.1
		//
		// the language parser should generate 2 meta files, one for each go version in this format:
		//
		// go: 1.2.2
		//
		// and
		//
		// go: 1.3.1
		rootMetaFile := fmt.Sprintf("%s/%s", MetaFolder, rootCounter)
		// since we have no idea of the generated meta file structure, we'll parse it into a map[string]interface{}
		var langExtraVars map[string]interface{}
		err := lib.Parse(rootMetaFile, &langExtraVars)
		if err != nil {
			l.Error.Fatal(err)
		}
		// and then add the new language specific variables parsed from the meta file to the build matrix (which already contains the env variables)
		err = feedMatrix(langExtraVars, &mx)
		if err != nil {
			l.Error.Fatal(err)
		}

		// we're not done yet: we need to also handle the matrix exclusions
		// we parse them into a list of matrices
		exclusions, err := exclusionsMatrices(config.Matrix.Exclude)
		if err != nil {
			l.Error.Fatal(err)
		}

		// and finally, we iterate over all the permutations of the build matrix
		// these permutations are the list of all the combinations of env variables and language specific variables, minux the exclusions
		mx.IterAll(func(permutation map[string]string, counter string) {
			// we get called for every non-excluded permutations with the different variables values for this permutations and a unique permutation counter
			// handlePermutation will start from the .bazooka.*.yml file, which should already contain a single language specific permutation
			// and enrich it with the env variables combination
			// the same goes for the meta file
			if err := handlePermutation(permutation, config, counter, rootCounter); err != nil {
				l.Error.Fatal(fmt.Errorf("Error while generating the permutations: %v", err))
			}
		}, exclusions)

		// after we're done iterating over the .bazooka.*.yml, and since we generated a new set of build files
		// we can now safely remove them
		err = os.Remove(file)
		if err != nil {
			l.Error.Fatal(fmt.Errorf("Error while removing file %s: %v", file, err))
		}

		// same for the meta files
		err = os.Remove(fmt.Sprintf("%s/%s", MetaFolder, rootCounter))
		if err != nil {
			l.Error.Fatal(fmt.Errorf("Error while removing meta folders: %v", err))
		}
	}
	l.Info.Println("Matrix generated")

	l.Info.Println("Starting generating Dockerfiles from Matrix")
	// Now we're left with the final build files
	files, err = lib.ListFilesWithPrefix(OutputFolder, ".bazooka")
	if err != nil {
		l.Error.Fatal(fmt.Errorf("Error while listing .bazooka* files: %v", err))
	}

	for _, file := range files {
		config := &lib.Config{}
		err = lib.Parse(file, config)
		if err != nil {
			l.Error.Fatal(fmt.Errorf("Error while parsing config file %s: %v", file, err))
		}

		// transform the .bazooka.x.yml file into a set of dockerfile + shell scripts who perform the actual build
		g := &Generator{
			Config:       config,
			OutputFolder: OutputFolder,
			Index:        parseCounter(file),
		}
		err = g.GenerateDockerfile()
		if err != nil {
			l.Error.Fatal("Error while generating a dockerfile: %v", err)
		}
	}
	l.Info.Println("Dockerfiles all created successfully")

}

func handlePermutation(permutation map[string]string, config *lib.Config, counter, rootCounter string) error {
	//Flush file
	// start from the language-spcecific permutation
	newConfig := *config

	// and replace its env variables with this unique permutation
	envMap := extractPrefixedKeysMap(permutation, MX_ENV_PREFIX)

	// Insert BZK_BUILD_DIR if not present
	if _, ok := envMap["BZK_BUILD_DIR"]; !ok {
		envMap["BZK_BUILD_DIR"] = "/bazooka"
	}

	newConfig.Env = lib.FlattenEnvMap(envMap)
	if err := lib.Flush(newConfig, fmt.Sprintf("%s/.bazooka.%s%s.yml", OutputFolder, rootCounter, counter)); err != nil {
		return err
	}

	// do the same for the meta file
	// start from the language specific permutation meta file
	rootMetaFile := fmt.Sprintf("%s/%s", MetaFolder, rootCounter)
	// copy it to a global (lang specific+env vars) permutation meta file
	if err := lib.CopyFile(rootMetaFile, fmt.Sprintf("%s/%s%s", MetaFolder, rootCounter, counter)); err != nil {
		return err
	}
	// and add to it this unique permutation of env variables
	var buffer bytes.Buffer
	buffer.WriteString("env:\n")
	for _, env := range lib.FlattenEnvMap(envMap) {
		buffer.WriteString(fmt.Sprintf(" - %s\n", env))
	}
	// and write it to disk
	if err := lib.AppendToFile(fmt.Sprintf("%s/%s", MetaFolder, counter), buffer.String(), 0755); err != nil {
		return err
	}

	return nil
}

func feedMatrix(extra map[string]interface{}, mx *matrix.Matrix) error {
	for k, v := range extra {
		switch k {
		case "env":
			if vs, ok := v.([]interface{}); ok {
				envVars := []string{}
				for _, envVar := range vs {
					if strEnvVar, ok := envVar.(string); ok {
						envVars = append(envVars, strEnvVar)
					} else {
						return fmt.Errorf("Invalid config: env should contain a sequence of strings: found a non string value %v:%T", envVar, envVar)

					}
				}
				mx.Merge(explodeProps(envVars, MX_ENV_PREFIX))
			} else {
				return fmt.Errorf("Invalid config: env should contain a sequence of strings: %v:%T", v, v)
			}

		default:
			mx.AddVar(k, fmt.Sprintf("%v", v))
		}
	}
	return nil
}

func exclusionsMatrices(xs []map[string]interface{}) ([]*matrix.Matrix, error) {
	res := make([]*matrix.Matrix, len(xs))
	for i, x := range xs {
		mx := matrix.Matrix{}
		if err := feedMatrix(x, &mx); err != nil {
			return nil, err
		}
		res[i] = &mx
	}
	return res, nil
}

// parseCounter extract the * part from a .bazooka.*.yml file name
func parseCounter(filePath string) string {
	splits := strings.Split(filePath, "/")
	file := splits[len(splits)-1]
	return strings.Split(file, ".")[2]
}

// explodeProps starts from a list of key=valye strings and stores them into a map
// it also handles repeated values, so ["A=1", "A=2", B="3"] gets transformed into {A: [1, 2], B: [3]}
func explodeProps(props []string, keyPrefix string) map[string][]string {
	envKeyMap := make(map[string][]string)
	for _, env := range props {
		envSplit := strings.Split(env, "=")
		envKeyMap[keyPrefix+envSplit[0]] = append(envKeyMap[keyPrefix+envSplit[0]], envSplit[1])
	}
	return envKeyMap
}

// prefixMapKeys returns a new map where all keys are prefixed with prefix
func prefixMapKeys(m map[string][]string, prefix string) map[string][]string {
	res := make(map[string][]string)
	for k, v := range m {
		res[prefix+k] = v
	}
	return res
}

// extractPrefixedKeysMap returns a new map containing only the values whose keys have the specified prefix, removing the latter in the process
// Given {xA: 1, B: 2, xC: 3}, it returns {A: 1, C: 3} if given a prefix x
func extractPrefixedKeysMap(m map[string]string, prefix string) map[string]string {
	res := make(map[string]string)
	for k, v := range m {
		if strings.HasPrefix(k, prefix) {
			res[k[len(prefix):]] = v
		}
	}
	return res
}

func resolveLanguageParser(language string) (string, error) {
	parserMap := map[string]string{
		"golang": "bazooka/parser-golang",
		"go":     "bazooka/parser-golang",
		"java":   "bazooka/parser-java",
	}
	if val, ok := parserMap[language]; ok {
		return val, nil
	}
	return "", fmt.Errorf("Unable to find Bazooka Docker Image for Language Parser %s\n", language)
}
<commit_msg>Fix a nasty bug where the combined meta file (lang specific + env vars) wasn't generated correctly<commit_after>package main

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

	l "github.com/haklop/bazooka/commons/logger"
	"github.com/haklop/bazooka/commons/matrix"

	lib "github.com/haklop/bazooka/commons"
)

const (
	SourceFolder      = "/bazooka"
	OutputFolder      = "/bazooka-output"
	MetaFolder        = "/meta"
	BazookaConfigFile = ".bazooka.yml"
	TravisConfigFile  = ".travis.yml"
	MX_ENV_PREFIX     = "env::"
)

func main() {
	l.Init(ioutil.Discard, os.Stdout, os.Stdout, os.Stdout, os.Stdout)
	l.Info.Println("Starting Parsing Phase")
	// Find either .travis.yml or .bazooka.yml file in the project
	configFile, err := lib.ResolveConfigFile(SourceFolder)
	if err != nil {
		l.Error.Fatal(err)
	}

	// parse the configuration
	config := &lib.Config{}
	err = lib.Parse(configFile, config)
	if err != nil {
		l.Error.Fatal(err)
	}
	l.Trace.Printf("Parsed configuration is %+v\n", config)

	// resolve the docker image corresponding to this particular language parser
	image, err := resolveLanguageParser(config.Language)
	if err != nil {
		l.Error.Fatal(err)
	}

	// run the parser image
	langParser := &LanguageParser{
		Image: image,
	}
	err = langParser.Parse()
	if err != nil {
		l.Error.Fatal(err)
	}

	// if all went well, the parser should have generated one or more "sub" .bazooka.*.yml files
	// one for each compiler version for example
	//
	// they are also supposed to enrich it with a from attribute corresponding to a base docker image
	// to be used to run the build

	l.Info.Println("Starting Matrix generation")
	files, err := lib.ListFilesWithPrefix(OutputFolder, ".bazooka")
	if err != nil {
		l.Error.Fatal(err)
	}

	// for each of those files (the "sub" .bazooka.*.yml)
	for _, file := range files {
		// parse the damned thing
		config := &lib.Config{}
		err = lib.Parse(file, config)
		if err != nil {
			l.Error.Fatal(fmt.Errorf("Error while parsing config file %s: %v", file, err))
		}

		// create a matrix from the environment variables
		// a matrix has N variables (dimensions) where each variable has M values
		// config.Env is a list of key=value strings
		// explodeProps transforms that into a map[string][]string
		// for example ["A=1", "A=2", B="3"]
		// when exploded gets transformed into
		// {A: [1, 2], B: [3]}
		// this matches the matrix layout, so we could store them directly into the matrix
		// but since we would like to be able to extract them later, and to avoid mixing them with a language specific variables (like jdk, go, etc.)
		// explode prefixes the env variables names with a prefix defined in the constant MX_ENV_PREFIX
		// Hence, our matrix is more like: {"env::A": [1, 2], "env::B": [3]}
		mx := matrix.Matrix(explodeProps(config.Env, MX_ENV_PREFIX))

		// extract the "*" part from the .bazooka.*.yml file
		rootCounter := parseCounter(file)
		// for every .bazooka.*.yml file, the language parser is also supposed to have generated a meta/* file
		// which is a simple yml file containing the language specific  matrix variables
		// for example, if the original .bazooka.yml file defined 2 go versions:
		//
		// go:
		// - 1.2.2
		// - 1.3.1
		//
		// the language parser should generate 2 meta files, one for each go version in this format:
		//
		// go: 1.2.2
		//
		// and
		//
		// go: 1.3.1
		rootMetaFile := fmt.Sprintf("%s/%s", MetaFolder, rootCounter)
		// since we have no idea of the generated meta file structure, we'll parse it into a map[string]interface{}
		var langExtraVars map[string]interface{}
		err := lib.Parse(rootMetaFile, &langExtraVars)
		if err != nil {
			l.Error.Fatal(err)
		}
		// and then add the new language specific variables parsed from the meta file to the build matrix (which already contains the env variables)
		err = feedMatrix(langExtraVars, &mx)
		if err != nil {
			l.Error.Fatal(err)
		}

		// we're not done yet: we need to also handle the matrix exclusions
		// we parse them into a list of matrices
		exclusions, err := exclusionsMatrices(config.Matrix.Exclude)
		if err != nil {
			l.Error.Fatal(err)
		}

		// and finally, we iterate over all the permutations of the build matrix
		// these permutations are the list of all the combinations of env variables and language specific variables, minux the exclusions
		mx.IterAll(func(permutation map[string]string, counter string) {
			// we get called for every non-excluded permutations with the different variables values for this permutations and a unique permutation counter
			// handlePermutation will start from the .bazooka.*.yml file, which should already contain a single language specific permutation
			// and enrich it with the env variables combination
			// the same goes for the meta file
			if err := handlePermutation(permutation, config, counter, rootCounter); err != nil {
				l.Error.Fatal(fmt.Errorf("Error while generating the permutations: %v", err))
			}
		}, exclusions)

		// after we're done iterating over the .bazooka.*.yml, and since we generated a new set of build files
		// we can now safely remove them
		err = os.Remove(file)
		if err != nil {
			l.Error.Fatal(fmt.Errorf("Error while removing file %s: %v", file, err))
		}

		// same for the meta files
		err = os.Remove(fmt.Sprintf("%s/%s", MetaFolder, rootCounter))
		if err != nil {
			l.Error.Fatal(fmt.Errorf("Error while removing meta folders: %v", err))
		}
	}
	l.Info.Println("Matrix generated")

	l.Info.Println("Starting generating Dockerfiles from Matrix")
	// Now we're left with the final build files
	files, err = lib.ListFilesWithPrefix(OutputFolder, ".bazooka")
	if err != nil {
		l.Error.Fatal(fmt.Errorf("Error while listing .bazooka* files: %v", err))
	}

	for _, file := range files {
		config := &lib.Config{}
		err = lib.Parse(file, config)
		if err != nil {
			l.Error.Fatal(fmt.Errorf("Error while parsing config file %s: %v", file, err))
		}

		// transform the .bazooka.x.yml file into a set of dockerfile + shell scripts who perform the actual build
		g := &Generator{
			Config:       config,
			OutputFolder: OutputFolder,
			Index:        parseCounter(file),
		}
		err = g.GenerateDockerfile()
		if err != nil {
			l.Error.Fatal("Error while generating a dockerfile: %v", err)
		}
	}
	l.Info.Println("Dockerfiles all created successfully")

}

func handlePermutation(permutation map[string]string, config *lib.Config, counter, rootCounter string) error {
	//Flush file
	// start from the language-spcecific permutation
	newConfig := *config

	// and replace its env variables with this unique permutation
	envMap := extractPrefixedKeysMap(permutation, MX_ENV_PREFIX)

	// Insert BZK_BUILD_DIR if not present
	if _, ok := envMap["BZK_BUILD_DIR"]; !ok {
		envMap["BZK_BUILD_DIR"] = "/bazooka"
	}

	newConfig.Env = lib.FlattenEnvMap(envMap)
	if err := lib.Flush(newConfig, fmt.Sprintf("%s/.bazooka.%s%s.yml", OutputFolder, rootCounter, counter)); err != nil {
		return err
	}

	// do the same for the meta file
	// start from the language specific permutation meta file
	rootMetaFile := fmt.Sprintf("%s/%s", MetaFolder, rootCounter)
	metaFile := fmt.Sprintf("%s/%s%s", MetaFolder, rootCounter, counter)

	// copy it to a global (lang specific+env vars) permutation meta file
	if err := lib.CopyFile(rootMetaFile, metaFile); err != nil {
		return err
	}
	// and add to it this unique permutation of env variables
	var buffer bytes.Buffer
	buffer.WriteString("env:\n")
	for _, env := range lib.FlattenEnvMap(envMap) {
		buffer.WriteString(fmt.Sprintf(" - %s\n", env))
	}
	// and write it to disk
	if err := lib.AppendToFile(metaFile, buffer.String(), 0644); err != nil {
		return err
	}

	return nil
}

func feedMatrix(extra map[string]interface{}, mx *matrix.Matrix) error {
	for k, v := range extra {
		switch k {
		case "env":
			if vs, ok := v.([]interface{}); ok {
				envVars := []string{}
				for _, envVar := range vs {
					if strEnvVar, ok := envVar.(string); ok {
						envVars = append(envVars, strEnvVar)
					} else {
						return fmt.Errorf("Invalid config: env should contain a sequence of strings: found a non string value %v:%T", envVar, envVar)

					}
				}
				mx.Merge(explodeProps(envVars, MX_ENV_PREFIX))
			} else {
				return fmt.Errorf("Invalid config: env should contain a sequence of strings: %v:%T", v, v)
			}

		default:
			mx.AddVar(k, fmt.Sprintf("%v", v))
		}
	}
	return nil
}

func exclusionsMatrices(xs []map[string]interface{}) ([]*matrix.Matrix, error) {
	res := make([]*matrix.Matrix, len(xs))
	for i, x := range xs {
		mx := matrix.Matrix{}
		if err := feedMatrix(x, &mx); err != nil {
			return nil, err
		}
		res[i] = &mx
	}
	return res, nil
}

// parseCounter extract the * part from a .bazooka.*.yml file name
func parseCounter(filePath string) string {
	splits := strings.Split(filePath, "/")
	file := splits[len(splits)-1]
	return strings.Split(file, ".")[2]
}

// explodeProps starts from a list of key=valye strings and stores them into a map
// it also handles repeated values, so ["A=1", "A=2", B="3"] gets transformed into {A: [1, 2], B: [3]}
func explodeProps(props []string, keyPrefix string) map[string][]string {
	envKeyMap := make(map[string][]string)
	for _, env := range props {
		envSplit := strings.Split(env, "=")
		envKeyMap[keyPrefix+envSplit[0]] = append(envKeyMap[keyPrefix+envSplit[0]], envSplit[1])
	}
	return envKeyMap
}

// prefixMapKeys returns a new map where all keys are prefixed with prefix
func prefixMapKeys(m map[string][]string, prefix string) map[string][]string {
	res := make(map[string][]string)
	for k, v := range m {
		res[prefix+k] = v
	}
	return res
}

// extractPrefixedKeysMap returns a new map containing only the values whose keys have the specified prefix, removing the latter in the process
// Given {xA: 1, B: 2, xC: 3}, it returns {A: 1, C: 3} if given a prefix x
func extractPrefixedKeysMap(m map[string]string, prefix string) map[string]string {
	res := make(map[string]string)
	for k, v := range m {
		if strings.HasPrefix(k, prefix) {
			res[k[len(prefix):]] = v
		}
	}
	return res
}

func resolveLanguageParser(language string) (string, error) {
	parserMap := map[string]string{
		"golang": "bazooka/parser-golang",
		"go":     "bazooka/parser-golang",
		"java":   "bazooka/parser-java",
	}
	if val, ok := parserMap[language]; ok {
		return val, nil
	}
	return "", fmt.Errorf("Unable to find Bazooka Docker Image for Language Parser %s\n", language)
}
<|endoftext|>


<commit_before>package ble

import "strings"

const hexDigits = "0123456789abcdef"

func isHex(s string) bool {
	for _, c := range s {
		if !strings.ContainsRune(hexDigits, c) {
			return false
		}
	}
	return true
}

func ValidUUID(u string) bool {
	switch len(u) {
	case 4:
		return isHex(u)
	case 36:
		return isHex(u[0:8]) && u[8] == '-' &&
			isHex(u[9:13]) && u[13] == '-' &&
			isHex(u[14:18]) && u[18] == '-' &&
			isHex(u[19:23]) && u[23] == '-' &&
			isHex(u[24:36])
	default:
		return false
	}
}
<commit_msg>Simplify ValidUUID function<commit_after>package ble

import "strings"

func hexMatch(s, pattern string) bool {
	const hexDigits = "0123456789abcdef"
	if len(s) != len(pattern) {
		return false
	}
	for i := range s {
		switch pattern[i] {
		case 'x':
			if strings.IndexByte(hexDigits, s[i]) == -1 {
				return false
			}
		default:
			if s[i] != pattern[i] {
				return false
			}
		}
	}
	return true
}

func ValidUUID(u string) bool {
	switch len(u) {
	case 4:
		return hexMatch(u, "xxxx")
	case 36:
		return hexMatch(u, "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
	default:
		return false
	}
}
<|endoftext|>


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

package uuid

import (
	"bytes"
	"crypto/rand"
	"encoding/hex"
	"io"

	guuid "github.com/google/uuid"
)

// Array is a pass-by-value UUID that can be used as an effecient key in a map.
type Array [16]byte

// UUID converts uuid into a slice.
func (uuid Array) UUID() UUID {
	return uuid[:]
}

// String returns the string representation of uuid,
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
func (uuid Array) String() string {
	return guuid.UUID(uuid).String()
}

// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
// 4122.
type UUID []byte

// A Version represents a UUIDs version.
type Version = guuid.Version

// A Variant represents a UUIDs variant.
type Variant = guuid.Variant

// Constants returned by Variant.
const (
	Invalid   = guuid.Invalid   // Invalid UUID
	RFC4122   = guuid.RFC4122   // The variant specified in RFC4122
	Reserved  = guuid.Reserved  // Reserved, NCS backward compatibility.
	Microsoft = guuid.Microsoft // Reserved, Microsoft Corporation backward compatibility.
	Future    = guuid.Future    // Reserved for future definition.
)

var rander = rand.Reader // random function

// New returns a new random (version 4) UUID as a string.  It is a convenience
// function for NewRandom().String().
func New() string {
	return NewRandom().String()
}

// Parse decodes s into a UUID or returns nil.  Both the UUID form of
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded.
func Parse(s string) UUID {
	gu, err := guuid.Parse(s)
	if err == nil {
		return gu[:]
	}
	return nil
}

// ParseBytes is like Parse, except it parses a byte slice instead of a string.
func ParseBytes(b []byte) (UUID, error) {
	gu, err := guuid.ParseBytes(b)
	if err == nil {
		return gu[:], nil
	}
	return nil, err
}

// Equal returns true if uuid1 and uuid2 are equal.
func Equal(uuid1, uuid2 UUID) bool {
	return bytes.Equal(uuid1, uuid2)
}

// Array returns an array representation of uuid that can be used as a map key.
// Array panics if uuid is not valid.
func (uuid UUID) Array() Array {
	if len(uuid) != 16 {
		panic("invalid uuid")
	}
	var a Array
	copy(a[:], uuid)
	return a
}

// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
// , or "" if uuid is invalid.
func (uuid UUID) String() string {
	if len(uuid) != 16 {
		return ""
	}
	var buf [36]byte
	encodeHex(buf[:], uuid)
	return string(buf[:])
}

// URN returns the RFC 2141 URN form of uuid,
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,  or "" if uuid is invalid.
func (uuid UUID) URN() string {
	if len(uuid) != 16 {
		return ""
	}
	var buf [36 + 9]byte
	copy(buf[:], "urn:uuid:")
	encodeHex(buf[9:], uuid)
	return string(buf[:])
}

func encodeHex(dst []byte, uuid UUID) {
	hex.Encode(dst[:], uuid[:4])
	dst[8] = '-'
	hex.Encode(dst[9:13], uuid[4:6])
	dst[13] = '-'
	hex.Encode(dst[14:18], uuid[6:8])
	dst[18] = '-'
	hex.Encode(dst[19:23], uuid[8:10])
	dst[23] = '-'
	hex.Encode(dst[24:], uuid[10:])
}

// Variant returns the variant encoded in uuid.  It returns Invalid if
// uuid is invalid.
func (uuid UUID) Variant() Variant {
	if len(uuid) != 16 {
		return Invalid
	}
	switch {
	case (uuid[8] & 0xc0) == 0x80:
		return RFC4122
	case (uuid[8] & 0xe0) == 0xc0:
		return Microsoft
	case (uuid[8] & 0xe0) == 0xe0:
		return Future
	default:
		return Reserved
	}
}

// Version returns the version of uuid.  It returns false if uuid is not
// valid.
func (uuid UUID) Version() (Version, bool) {
	if len(uuid) != 16 {
		return 0, false
	}
	return Version(uuid[6] >> 4), true
}

// SetRand sets the random number generator to r, which implements io.Reader.
// If r.Read returns an error when the package requests random data then
// a panic will be issued.
//
// Calling SetRand with nil sets the random number generator to the default
// generator.
func SetRand(r io.Reader) {
	guuid.SetRand(r)
}
<commit_msg>Fix Parse comment to point to github.com/google/uuid.<commit_after>// Copyright 2011 Google Inc.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package uuid

import (
	"bytes"
	"crypto/rand"
	"encoding/hex"
	"io"

	guuid "github.com/google/uuid"
)

// Array is a pass-by-value UUID that can be used as an effecient key in a map.
type Array [16]byte

// UUID converts uuid into a slice.
func (uuid Array) UUID() UUID {
	return uuid[:]
}

// String returns the string representation of uuid,
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
func (uuid Array) String() string {
	return guuid.UUID(uuid).String()
}

// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
// 4122.
type UUID []byte

// A Version represents a UUIDs version.
type Version = guuid.Version

// A Variant represents a UUIDs variant.
type Variant = guuid.Variant

// Constants returned by Variant.
const (
	Invalid   = guuid.Invalid   // Invalid UUID
	RFC4122   = guuid.RFC4122   // The variant specified in RFC4122
	Reserved  = guuid.Reserved  // Reserved, NCS backward compatibility.
	Microsoft = guuid.Microsoft // Reserved, Microsoft Corporation backward compatibility.
	Future    = guuid.Future    // Reserved for future definition.
)

var rander = rand.Reader // random function

// New returns a new random (version 4) UUID as a string.  It is a convenience
// function for NewRandom().String().
func New() string {
	return NewRandom().String()
}

// Parse decodes s into a UUID or returns nil. See github.com/google/uuid for
// the formats parsed.
func Parse(s string) UUID {
	gu, err := guuid.Parse(s)
	if err == nil {
		return gu[:]
	}
	return nil
}

// ParseBytes is like Parse, except it parses a byte slice instead of a string.
func ParseBytes(b []byte) (UUID, error) {
	gu, err := guuid.ParseBytes(b)
	if err == nil {
		return gu[:], nil
	}
	return nil, err
}

// Equal returns true if uuid1 and uuid2 are equal.
func Equal(uuid1, uuid2 UUID) bool {
	return bytes.Equal(uuid1, uuid2)
}

// Array returns an array representation of uuid that can be used as a map key.
// Array panics if uuid is not valid.
func (uuid UUID) Array() Array {
	if len(uuid) != 16 {
		panic("invalid uuid")
	}
	var a Array
	copy(a[:], uuid)
	return a
}

// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
// , or "" if uuid is invalid.
func (uuid UUID) String() string {
	if len(uuid) != 16 {
		return ""
	}
	var buf [36]byte
	encodeHex(buf[:], uuid)
	return string(buf[:])
}

// URN returns the RFC 2141 URN form of uuid,
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,  or "" if uuid is invalid.
func (uuid UUID) URN() string {
	if len(uuid) != 16 {
		return ""
	}
	var buf [36 + 9]byte
	copy(buf[:], "urn:uuid:")
	encodeHex(buf[9:], uuid)
	return string(buf[:])
}

func encodeHex(dst []byte, uuid UUID) {
	hex.Encode(dst[:], uuid[:4])
	dst[8] = '-'
	hex.Encode(dst[9:13], uuid[4:6])
	dst[13] = '-'
	hex.Encode(dst[14:18], uuid[6:8])
	dst[18] = '-'
	hex.Encode(dst[19:23], uuid[8:10])
	dst[23] = '-'
	hex.Encode(dst[24:], uuid[10:])
}

// Variant returns the variant encoded in uuid.  It returns Invalid if
// uuid is invalid.
func (uuid UUID) Variant() Variant {
	if len(uuid) != 16 {
		return Invalid
	}
	switch {
	case (uuid[8] & 0xc0) == 0x80:
		return RFC4122
	case (uuid[8] & 0xe0) == 0xc0:
		return Microsoft
	case (uuid[8] & 0xe0) == 0xe0:
		return Future
	default:
		return Reserved
	}
}

// Version returns the version of uuid.  It returns false if uuid is not
// valid.
func (uuid UUID) Version() (Version, bool) {
	if len(uuid) != 16 {
		return 0, false
	}
	return Version(uuid[6] >> 4), true
}

// SetRand sets the random number generator to r, which implements io.Reader.
// If r.Read returns an error when the package requests random data then
// a panic will be issued.
//
// Calling SetRand with nil sets the random number generator to the default
// generator.
func SetRand(r io.Reader) {
	guuid.SetRand(r)
}
<|endoftext|>


<commit_before>package dashboard

import (
	"fmt"
	. "github.com/influxdata/influxdb-comparisons/bulk_data_gen/common"
	"github.com/influxdata/influxdb-comparisons/bulk_data_gen/devops"
	"math/rand"
	"time"
)

const NHostSims = 11

var ClusterSizes = []int{5, 6, 7, 8, 9, 10, 11, 12, 13}

var ClusterIdTagkey = []byte("cluster_id")

// Type Host models a machine being monitored by Telegraf.
type Host struct {
	SimulatedMeasurements []SimulatedMeasurement

	// These are all assigned once, at Host creation:
	Name, Region, Datacenter, Rack, OS, Arch               []byte
	ClusterId, Service, ServiceVersion, ServiceEnvironment []byte
}

func NewHostMeasurements(start time.Time) []SimulatedMeasurement {
	sm := []SimulatedMeasurement{
		devops.NewCPUMeasurement(start),
		devops.NewDiskIOMeasurement(start),
		devops.NewDiskMeasurement(start),
		devops.NewKernelMeasurement(start),
		devops.NewMemMeasurement(start),
		devops.NewNetMeasurement(start),
		devops.NewNginxMeasurement(start),
		devops.NewPostgresqlMeasurement(start),
		devops.NewRedisMeasurement(start),
		NewSystemMeasurement(start),
		NewStatusMeasurement(start),
	}

	if len(sm) != NHostSims {
		panic("logic error: incorrect number of measurements")
	}
	return sm
}

var (
	curentClusterSize int
	clusterId         int
	currentHostIndex  int
)

func NewHost(i int, start time.Time) Host {
	if curentClusterSize == 0 || currentHostIndex == curentClusterSize {
		currentHostIndex = 0
		curentClusterSize = ClusterSizes[rand.Intn(len(ClusterSizes))]
		clusterId++
	}
	var hostname []byte
	if currentHostIndex < 3 {
		hostname = []byte(fmt.Sprintf("meta_%d", currentHostIndex+1))
	} else {
		hostname = []byte(fmt.Sprintf("data_%d", currentHostIndex-2))
	}
	sm := NewHostMeasurements(start)

	region := &devops.Regions[rand.Intn(len(devops.Regions))]
	rackId := rand.Int63n(devops.MachineRackChoicesPerDatacenter)
	serviceId := rand.Int63n(devops.MachineServiceChoices)
	serviceVersionId := rand.Int63n(devops.MachineServiceVersionChoices)
	serviceEnvironment := RandChoice(devops.MachineServiceEnvironmentChoices)

	h := Host{
		// Tag Values that are static throughout the life of a Host:
		Name:               hostname,
		Region:             []byte(fmt.Sprintf("%s", region.Name)),
		Datacenter:         RandChoice(region.Datacenters),
		Rack:               []byte(fmt.Sprintf("%d", rackId)),
		Arch:               RandChoice(devops.MachineArchChoices),
		OS:                 RandChoice(devops.MachineOSChoices),
		Service:            []byte(fmt.Sprintf("%d", serviceId)),
		ServiceVersion:     []byte(fmt.Sprintf("%d", serviceVersionId)),
		ServiceEnvironment: serviceEnvironment,
		ClusterId:          []byte(fmt.Sprintf("%d", clusterId)),

		SimulatedMeasurements: sm,
	}
	currentHostIndex++
	return h
}

// TickAll advances all Distributions of a Host.
func (h *Host) TickAll(d time.Duration) {
	for i := range h.SimulatedMeasurements {
		h.SimulatedMeasurements[i].Tick(d)
	}
}
<commit_msg>naming one host as kapacitor<commit_after>package dashboard

import (
	"fmt"
	. "github.com/influxdata/influxdb-comparisons/bulk_data_gen/common"
	"github.com/influxdata/influxdb-comparisons/bulk_data_gen/devops"
	"math/rand"
	"time"
)

const NHostSims = 11

var ClusterSizes = []int{5, 6, 7, 8, 9, 10, 11, 12, 13}

var ClusterIdTagkey = []byte("cluster_id")

// Type Host models a machine being monitored by Telegraf.
type Host struct {
	SimulatedMeasurements []SimulatedMeasurement

	// These are all assigned once, at Host creation:
	Name, Region, Datacenter, Rack, OS, Arch               []byte
	ClusterId, Service, ServiceVersion, ServiceEnvironment []byte
}

func NewHostMeasurements(start time.Time) []SimulatedMeasurement {
	sm := []SimulatedMeasurement{
		devops.NewCPUMeasurement(start),
		devops.NewDiskIOMeasurement(start),
		devops.NewDiskMeasurement(start),
		devops.NewKernelMeasurement(start),
		devops.NewMemMeasurement(start),
		devops.NewNetMeasurement(start),
		devops.NewNginxMeasurement(start),
		devops.NewPostgresqlMeasurement(start),
		devops.NewRedisMeasurement(start),
		NewSystemMeasurement(start),
		NewStatusMeasurement(start),
	}

	if len(sm) != NHostSims {
		panic("logic error: incorrect number of measurements")
	}
	return sm
}

var (
	curentClusterSize int
	clusterId         int
	currentHostIndex  int
)

func NewHost(i int, start time.Time) Host {
	var hostname []byte
	if i > 0 {
		if curentClusterSize == 0 || currentHostIndex == curentClusterSize {
			currentHostIndex = 0
			curentClusterSize = ClusterSizes[rand.Intn(len(ClusterSizes))]
			clusterId++
		}

		if currentHostIndex < 3 {
			hostname = []byte(fmt.Sprintf("meta_%d", currentHostIndex+1))
		} else {
			hostname = []byte(fmt.Sprintf("data_%d", currentHostIndex-2))
		}
	} else {
		hostname = []byte("kapacitor")
	}
	sm := NewHostMeasurements(start)

	region := &devops.Regions[rand.Intn(len(devops.Regions))]
	rackId := rand.Int63n(devops.MachineRackChoicesPerDatacenter)
	serviceId := rand.Int63n(devops.MachineServiceChoices)
	serviceVersionId := rand.Int63n(devops.MachineServiceVersionChoices)
	serviceEnvironment := RandChoice(devops.MachineServiceEnvironmentChoices)

	h := Host{
		// Tag Values that are static throughout the life of a Host:
		Name:               hostname,
		Region:             []byte(fmt.Sprintf("%s", region.Name)),
		Datacenter:         RandChoice(region.Datacenters),
		Rack:               []byte(fmt.Sprintf("%d", rackId)),
		Arch:               RandChoice(devops.MachineArchChoices),
		OS:                 RandChoice(devops.MachineOSChoices),
		Service:            []byte(fmt.Sprintf("%d", serviceId)),
		ServiceVersion:     []byte(fmt.Sprintf("%d", serviceVersionId)),
		ServiceEnvironment: serviceEnvironment,
		ClusterId:          []byte(fmt.Sprintf("%d", clusterId)),

		SimulatedMeasurements: sm,
	}
	currentHostIndex++
	return h
}

// TickAll advances all Distributions of a Host.
func (h *Host) TickAll(d time.Duration) {
	for i := range h.SimulatedMeasurements {
		h.SimulatedMeasurements[i].Tick(d)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/cloudformation"
	"github.com/ci-pipeline/cloudformation-resource/utils"
	"github.com/concourse/atc"
)

func main() {
	utils.Logln("Change to build directory")
	utils.GoToBuildDirectory()
	cwd, _ := os.Getwd()
	utils.Logln(cwd)
	input := utils.GetInput()
	svc := utils.GetCloudformationService(input)
	metadata, success := out(input, svc)
	result := utils.VersionResult{Metadata: metadata}
	output, _ := json.Marshal(result)
	fmt.Printf("%s", string(output))
	if !success {
		os.Exit(1)
	}
}

type Parameter struct {
	ParameterValue   string
	ParameterKey     string
	UsePreviousValue bool
}

type Tag struct {
	TagKey   string
	TagValue string
}

func stackExists(svc *cloudformation.CloudFormation, stackName string) bool {
	params := &cloudformation.DescribeStacksInput{
		StackName: aws.String(stackName),
	}
	req, resp := svc.DescribeStacksRequest(params)
	err := utils.HandleRequest(req)
	if err != nil {
		return false
	}
	utils.Logln(resp)

	return resp.Stacks[0] != nil
}

func waitForStack(svc *cloudformation.CloudFormation, input utils.Input) (success bool, arn, timestamp string) {
	success = true
	params := &cloudformation.DescribeStackEventsInput{
		StackName: aws.String(input.Source.Name),
	}

	pos := 0
	var stackEvents []*cloudformation.StackEvent
	for {
		req, resp := svc.DescribeStackEventsRequest(params)
		err := utils.HandleRequest(req)
		if err != nil {
			if input.Params.Delete {
				success = true
				utils.Logln("Stack deleted")
				return
			}
			utils.Logf("An error occured: %v\n", err)
			return
		}
		stackEvents = resp.StackEvents
		for j := len(stackEvents) - 1 - pos; j > -1; j-- {
			utils.Logln(stackEvents[j])
		}
		pos = len(stackEvents)

		arn = *stackEvents[0].StackId
		timestamp = stackEvents[0].Timestamp.String()

		if *stackEvents[0].ResourceType == "AWS::CloudFormation::Stack" {
			if *stackEvents[0].ResourceStatus == "CREATE_COMPLETE" {
				return
			} else if *stackEvents[0].ResourceStatus == "UPDATE_COMPLETE" {
				return
			} else if *stackEvents[0].ResourceStatus == "ROLLBACK_COMPLETE" {
				success = false
				return
			} else if *stackEvents[0].ResourceStatus == "UPDATE_ROLLBACK_COMPLETE" {
				success = false
				return
			} else if strings.HasSuffix(*stackEvents[0].ResourceStatus, "_FAILED") {
				success = false
				return
			}
		}

		time.Sleep(500 * time.Millisecond)
	}
}

func out(input utils.Input, svc *cloudformation.CloudFormation) (metadata []atc.MetadataField, success bool) {

	var capabilities []*string
	capabilities = nil
	if input.Params.Capabilities != nil {
		for _, c := range input.Params.Capabilities {
			capabilities = append(capabilities, aws.String(c))
		}
	}

	var templateBody string
	if input.Params.Template != "" {
		bytes, err := ioutil.ReadFile(input.Params.Template)
		if err != nil {
			panic(err)
		}
		templateBody = string(bytes)
	}

	parameters := []Parameter{}
	var cloudformationParams []*cloudformation.Parameter
	if input.Params.Parameters != "" {
		bytes, err := ioutil.ReadFile(input.Params.Parameters)
		err = json.Unmarshal(bytes, &parameters)
		if err != nil {
			utils.Logln("Could not unmarshal parameters file, path = ", input.Params.Parameters)
			utils.Logln("contents:")
			utils.Logln(string(bytes))
			utils.Logln("error: ", err)
			os.Exit(1)
		}
	}
	for _, p := range parameters {
		param := cloudformation.Parameter{
			ParameterKey:     aws.String(p.ParameterKey),
			ParameterValue:   aws.String(p.ParameterValue),
			UsePreviousValue: aws.Bool(p.UsePreviousValue),
		}
		cloudformationParams = append(cloudformationParams, &param)
	}

	tags := []Tag{}
	var cloudformationTags []*cloudformation.Tag
	if input.Params.Tags != "" {
		bytes, err := ioutil.ReadFile(input.Params.Tags)
		err = json.Unmarshal(bytes, &tags)
		if err != nil {
			panic(err)
		}
	}
	for _, t := range tags {
		tag := cloudformation.Tag{
			Key:   aws.String(t.TagKey),
			Value: aws.String(t.TagValue),
		}
		cloudformationTags = append(cloudformationTags, &tag)
	}

	if input.Params.Delete == true {
		utils.Logln("Deleting stack")
		params := &cloudformation.DeleteStackInput{
			StackName: aws.String(input.Source.Name),
		}
		req, resp := svc.DeleteStackRequest(params)
		err := utils.HandleRequest(req)
		if err != nil {
			utils.Logln(err.Error())
		}
		utils.Logln(resp)
	} else if !stackExists(svc, input.Source.Name) {
		utils.Logln("Creating stack")
		params := &cloudformation.CreateStackInput{
			StackName:    aws.String(input.Source.Name),
			Capabilities: capabilities,
			Parameters:   cloudformationParams,
			Tags:         cloudformationTags,
			TemplateBody: aws.String(templateBody),
		}
		req, resp := svc.CreateStackRequest(params)
		err := utils.HandleRequest(req)
		if err != nil {
			utils.Logln(err.Error())
		}
		utils.Logln(resp)
	} else {
		utils.Logln("Updating stack")
		params := &cloudformation.UpdateStackInput{
			StackName:    aws.String(input.Source.Name),
			Capabilities: capabilities,
			Parameters:   cloudformationParams,
			Tags:         cloudformationTags,
			TemplateBody: aws.String(templateBody),
		}
		req, _ := svc.UpdateStackRequest(params)
		err := utils.HandleRequest(req)
		if err != nil {
			if awsErr, ok := err.(awserr.Error); ok {
				if awsErr.Code() == "ValidationError" && awsErr.Message() == "No updates are to be performed." {
					utils.Logln("No updates to be performed")
				} else {
					utils.Logln("An AWS error occured whilst updating stack: ", err)
					os.Exit(1)
				}
			} else {
				utils.Logln("An error occured whilst updating stack: ", err)
				os.Exit(1)
			}
		}
	}

	success, arn, timestamp := waitForStack(svc, input)
	result := make([]atc.MetadataField, 2)
	result[0].Name = "arn"
	result[0].Value = arn
	result[1].Name = "timestamp"
	result[1].Value = timestamp
	return result, success
}
<commit_msg>Outputing version<commit_after>package main

import (
	"crypto/sha1"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/cloudformation"
	"github.com/ci-pipeline/cloudformation-resource/utils"
	"github.com/concourse/atc"
)

func main() {
	utils.Logln("Change to build directory")
	utils.GoToBuildDirectory()
	cwd, _ := os.Getwd()
	utils.Logln(cwd)
	input := utils.GetInput()
	svc := utils.GetCloudformationService(input)
	metadata, success, version := out(input, svc)
	result := utils.VersionResult{Metadata: metadata, Version: atc.Version{"sha1": version}}
	output, _ := json.Marshal(result)
	fmt.Printf("%s", string(output))
	if !success {
		os.Exit(1)
	}
}

type Parameter struct {
	ParameterValue   string
	ParameterKey     string
	UsePreviousValue bool
}

type Tag struct {
	TagKey   string
	TagValue string
}

func stackExists(svc *cloudformation.CloudFormation, stackName string) bool {
	params := &cloudformation.DescribeStacksInput{
		StackName: aws.String(stackName),
	}
	req, resp := svc.DescribeStacksRequest(params)
	err := utils.HandleRequest(req)
	if err != nil {
		return false
	}
	utils.Logln(resp)

	return resp.Stacks[0] != nil
}

func waitForStack(svc *cloudformation.CloudFormation, input utils.Input) (success bool, arn, timestamp string) {
	success = true
	params := &cloudformation.DescribeStackEventsInput{
		StackName: aws.String(input.Source.Name),
	}

	pos := 0
	var stackEvents []*cloudformation.StackEvent
	for {
		req, resp := svc.DescribeStackEventsRequest(params)
		err := utils.HandleRequest(req)
		if err != nil {
			if input.Params.Delete {
				success = true
				utils.Logln("Stack deleted")
				return
			}
			utils.Logf("An error occured: %v\n", err)
			return
		}
		stackEvents = resp.StackEvents
		for j := len(stackEvents) - 1 - pos; j > -1; j-- {
			utils.Logln(stackEvents[j])
		}
		pos = len(stackEvents)

		arn = *stackEvents[0].StackId
		timestamp = stackEvents[0].Timestamp.String()

		if *stackEvents[0].ResourceType == "AWS::CloudFormation::Stack" {
			if *stackEvents[0].ResourceStatus == "CREATE_COMPLETE" {
				return
			} else if *stackEvents[0].ResourceStatus == "UPDATE_COMPLETE" {
				return
			} else if *stackEvents[0].ResourceStatus == "ROLLBACK_COMPLETE" {
				success = false
				return
			} else if *stackEvents[0].ResourceStatus == "UPDATE_ROLLBACK_COMPLETE" {
				success = false
				return
			} else if strings.HasSuffix(*stackEvents[0].ResourceStatus, "_FAILED") {
				success = false
				return
			}
		}

		time.Sleep(500 * time.Millisecond)
	}
}

func out(input utils.Input, svc *cloudformation.CloudFormation) (metadata []atc.MetadataField, success bool, sha string) {

	var capabilities []*string
	capabilities = nil
	if input.Params.Capabilities != nil {
		for _, c := range input.Params.Capabilities {
			capabilities = append(capabilities, aws.String(c))
		}
	}

	var templateBody string
	if input.Params.Template != "" {
		bytes, err := ioutil.ReadFile(input.Params.Template)
		if err != nil {
			panic(err)
		}
		templateBody = string(bytes)
	}

	parameters := []Parameter{}
	var cloudformationParams []*cloudformation.Parameter
	if input.Params.Parameters != "" {
		bytes, err := ioutil.ReadFile(input.Params.Parameters)
		err = json.Unmarshal(bytes, &parameters)
		if err != nil {
			utils.Logln("Could not unmarshal parameters file, path = ", input.Params.Parameters)
			utils.Logln("contents:")
			utils.Logln(string(bytes))
			utils.Logln("error: ", err)
			os.Exit(1)
		}
	}
	for _, p := range parameters {
		param := cloudformation.Parameter{
			ParameterKey:     aws.String(p.ParameterKey),
			ParameterValue:   aws.String(p.ParameterValue),
			UsePreviousValue: aws.Bool(p.UsePreviousValue),
		}
		cloudformationParams = append(cloudformationParams, &param)
	}

	tags := []Tag{}
	var cloudformationTags []*cloudformation.Tag
	if input.Params.Tags != "" {
		bytes, err := ioutil.ReadFile(input.Params.Tags)
		err = json.Unmarshal(bytes, &tags)
		if err != nil {
			panic(err)
		}
	}
	for _, t := range tags {
		tag := cloudformation.Tag{
			Key:   aws.String(t.TagKey),
			Value: aws.String(t.TagValue),
		}
		cloudformationTags = append(cloudformationTags, &tag)
	}

	if input.Params.Delete == true {
		utils.Logln("Deleting stack")
		params := &cloudformation.DeleteStackInput{
			StackName: aws.String(input.Source.Name),
		}
		req, resp := svc.DeleteStackRequest(params)
		err := utils.HandleRequest(req)
		if err != nil {
			utils.Logln(err.Error())
		}
		utils.Logln(resp)
	} else if !stackExists(svc, input.Source.Name) {
		utils.Logln("Creating stack")
		params := &cloudformation.CreateStackInput{
			StackName:    aws.String(input.Source.Name),
			Capabilities: capabilities,
			Parameters:   cloudformationParams,
			Tags:         cloudformationTags,
			TemplateBody: aws.String(templateBody),
		}
		req, resp := svc.CreateStackRequest(params)
		err := utils.HandleRequest(req)
		if err != nil {
			utils.Logln(err.Error())
		}
		utils.Logln(resp)
	} else {
		utils.Logln("Updating stack")
		params := &cloudformation.UpdateStackInput{
			StackName:    aws.String(input.Source.Name),
			Capabilities: capabilities,
			Parameters:   cloudformationParams,
			Tags:         cloudformationTags,
			TemplateBody: aws.String(templateBody),
		}
		req, _ := svc.UpdateStackRequest(params)
		err := utils.HandleRequest(req)
		if err != nil {
			if awsErr, ok := err.(awserr.Error); ok {
				if awsErr.Code() == "ValidationError" && awsErr.Message() == "No updates are to be performed." {
					utils.Logln("No updates to be performed")
				} else {
					utils.Logln("An AWS error occured whilst updating stack: ", err)
					os.Exit(1)
				}
			} else {
				utils.Logln("An error occured whilst updating stack: ", err)
				os.Exit(1)
			}
		}
	}

	success, arn, timestamp := waitForStack(svc, input)
	result := make([]atc.MetadataField, 2)
	result[0].Name = "arn"
	result[0].Value = arn
	result[1].Name = "timestamp"
	result[1].Value = timestamp

	// SHA1 template, parameters and tags and use as version
	hasher := sha1.New()
	hasher.Write([]byte(fmt.Sprintf("%s%v%v", templateBody, parameters, tags)))
	sha = base64.URLEncoding.EncodeToString(hasher.Sum(nil))
	return result, success, sha
}
<|endoftext|>


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

package sequtils

import (
	"code.google.com/p/biogo/alphabet"
	"code.google.com/p/biogo/feat"
	"code.google.com/p/biogo/seq"
	"fmt"
	"gopkg.in/check.v1"
	"reflect"
	"testing"
	"unsafe"
)

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

type S struct{}

var _ = check.Suite(&S{})

var (
	lorem = stringToSlice("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.")
)

type slice []byte

func stringToSlice(s string) slice {
	b := []byte(s)
	return *(*slice)(unsafe.Pointer(&b))
}
func (s slice) Make(len, cap int) alphabet.Slice       { return make(slice, len, cap) }
func (s slice) Len() int                               { return len(s) }
func (s slice) Cap() int                               { return cap(s) }
func (s slice) Slice(start, end int) alphabet.Slice    { return s[start:end] }
func (s slice) Append(a alphabet.Slice) alphabet.Slice { return append(s, a.(slice)...) }
func (s slice) Copy(a alphabet.Slice) int              { return copy(s, a.(slice)) }

type offSlice struct {
	slice
	offset int
	conf   feat.Conformation
}

func stringToOffSlice(s string) *offSlice {
	return &offSlice{slice: stringToSlice(s)}
}
func (os *offSlice) Conformation() feat.Conformation { return os.conf }
func (os *offSlice) SetOffset(o int) error           { os.offset = o; return nil }
func (os *offSlice) Slice() alphabet.Slice           { return os.slice }
func (os *offSlice) SetSlice(sl alphabet.Slice)      { os.slice = sl.(slice) }
func (os *offSlice) String() string                  { return fmt.Sprintf("%s %d", os.slice, os.offset) }

type conformRangeOffSlice struct {
	slice
	offset int
	conf   feat.Conformation
}

func stringToConformRangeOffSlice(s string) *conformRangeOffSlice {
	return &conformRangeOffSlice{slice: stringToSlice(s)}
}
func (os *conformRangeOffSlice) Conformation() feat.Conformation     { return os.conf }
func (os *conformRangeOffSlice) SetConformation(c feat.Conformation) { os.conf = c }
func (os *conformRangeOffSlice) SetOffset(o int) error               { os.offset = o; return nil }
func (os *conformRangeOffSlice) Start() int                          { return os.offset }
func (os *conformRangeOffSlice) End() int                            { return os.offset + len(os.slice) }
func (os *conformRangeOffSlice) Slice() alphabet.Slice               { return os.slice }
func (os *conformRangeOffSlice) SetSlice(sl alphabet.Slice)          { os.slice = sl.(slice) }
func (os *conformRangeOffSlice) String() string                      { return fmt.Sprintf("%s", os.slice) }

func (s *S) TestTruncate(c *check.C) {
	type test struct {
		in         *conformRangeOffSlice
		start, end int
		expect     interface{}
	}

	var T []test = []test{
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear},
			start:  28,
			end:    39,
			expect: stringToSlice("consectetur"),
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: 1},
			start:  29,
			end:    40,
			expect: stringToSlice("consectetur"),
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Circular},
			start:  28,
			end:    39,
			expect: stringToSlice("consectetur"),
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear},
			start:  117,
			end:    5,
			expect: "sequtils: start position greater than end position for linear sequence",
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Circular},
			start:  117,
			end:    5,
			expect: stringToSlice("aliqua.Lorem"),
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Circular, offset: 1},
			start:  118,
			end:    6,
			expect: stringToSlice("aliqua.Lorem"),
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear},
			start:  5,
			end:    1170,
			expect: "sequtils: index out of range",
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Circular},
			start:  1170,
			end:    5,
			expect: "sequtils: index out of range",
		},
	}

	for _, t := range T {
		r := &conformRangeOffSlice{}
		if err := Truncate(r, t.in, t.start, t.end); err != nil {
			c.Check(err, check.ErrorMatches, t.expect)
		} else {
			c.Check(r.slice, check.DeepEquals, t.expect)
			c.Check(r.conf, check.Equals, feat.Linear)
			if t.in.conf != feat.Circular || (t.in.conf == feat.Circular && t.end >= t.start) {
				c.Check(t.end-t.start, check.Equals, reflect.ValueOf(t.expect).Len())
			} else {
				c.Check(t.end+reflect.ValueOf(t.in.slice).Len()-t.start, check.Equals, reflect.ValueOf(t.expect).Len())
			}
		}
	}
}

func (s *S) TestJoin(c *check.C) {
	type test struct {
		a, b   *offSlice
		where  int
		expect *offSlice
	}

	var T []test = []test{
		{
			a:      &offSlice{lorem[28:40], 0, feat.Linear},
			b:      &offSlice{lorem[117:], 0, feat.Linear},
			where:  seq.Start,
			expect: &offSlice{stringToSlice("aliqua.consectetur "), -7, feat.Linear},
		},
		{
			a:      &offSlice{lorem[28:40], 0, feat.Linear},
			b:      &offSlice{lorem[117:], 0, feat.Linear},
			where:  seq.End,
			expect: &offSlice{stringToSlice("consectetur aliqua."), 0, feat.Linear},
		},
	}

	for _, t := range T {
		Join(t.a, t.b, t.where)
		c.Check(t.a, check.DeepEquals, t.expect)
	}
}

type fe struct {
	s, e   int
	orient feat.Orientation
	feat.Feature
}

func (f fe) Start() int                    { return f.s }
func (f fe) End() int                      { return f.e }
func (f fe) Len() int                      { return f.e - f.s }
func (f fe) Orientation() feat.Orientation { return f.orient }

type fs []feat.Feature

func (f fs) Features() []feat.Feature { return []feat.Feature(f) }

func (s *S) TestStitch(c *check.C) {
	type test struct {
		in     *conformRangeOffSlice
		f      feat.Set
		expect interface{}
	}

	var T []test = []test{
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: 0},
			f:      fs{fe{s: 12, e: 18}, fe{s: 24, e: 26}, fe{s: 103, e: 110}},
			expect: stringToSlice("dolor et dolore"),
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: -1},
			f:      fs{fe{s: 12, e: 18}, fe{s: 24, e: 26}, fe{s: 103, e: 110}},
			expect: stringToSlice("olor st,dolore "),
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: 0},
			f:      fs{fe{s: 12, e: 18}, fe{s: 13, e: 17}, fe{s: 24, e: 26}, fe{s: 103, e: 110}},
			expect: stringToSlice("dolor et dolore"),
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: -1},
			f:      fs{fe{s: 12, e: 18}, fe{s: 13, e: 17}, fe{s: 24, e: 26}, fe{s: 103, e: 110}},
			expect: stringToSlice("olor st,dolore "),
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: 0},
			f:      fs{fe{s: 19, e: 18}},
			expect: "sequtils: feature end < feature start",
		},
	}

	for _, t := range T {
		r := &conformRangeOffSlice{}
		if err := Stitch(r, t.in, t.f); err != nil {
			c.Check(err, check.ErrorMatches, t.expect)
		} else {
			c.Check(r.slice, check.DeepEquals, t.expect)
		}
	}
}

func (s *S) TestCompose(c *check.C) {
	type test struct {
		in     *conformRangeOffSlice
		f      feat.Set
		expect interface{}
	}

	var T []test = []test{
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: 0},
			f:      fs{fe{s: 12, e: 18}, fe{s: 24, e: 26}, fe{s: 103, e: 110}},
			expect: stringToSlice("dolor et dolore"),
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: -1},
			f:      fs{fe{s: 12, e: 18}, fe{s: 24, e: 26}, fe{s: 103, e: 110}},
			expect: stringToSlice("olor st,dolore "),
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: 0},
			f:      fs{fe{s: 12, e: 18}, fe{s: 13, e: 17}, fe{s: 24, e: 26}, fe{s: 103, e: 110}},
			expect: stringToSlice("dolor oloret dolore"),
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: -1},
			f:      fs{fe{s: 12, e: 18}, fe{s: 13, e: 17}, fe{s: 24, e: 26}, fe{s: 103, e: 110}},
			expect: stringToSlice("olor slor t,dolore "),
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: -1},
			f:      fs{fe{s: 12, e: 18}, fe{s: 13, e: 17}, fe{s: 24, e: 26, orient: feat.Reverse}, fe{s: 103, e: 110}},
			expect: "sequtils: unable to reverse segment during compose",
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: 0},
			f:      fs{fe{s: 19, e: 18}},
			expect: "sequtils: feature end < feature start",
		},
	}

	for _, t := range T {
		r := &conformRangeOffSlice{}
		if err := Compose(r, t.in, t.f); err == nil {
			c.Check(r.slice, check.DeepEquals, t.expect)
		} else {
			c.Check(err, check.ErrorMatches, t.expect)
		}
	}
}
<commit_msg>Remove redundant unsafe use<commit_after>// Copyright ©2011-2012 The bíogo Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package sequtils

import (
	"code.google.com/p/biogo/alphabet"
	"code.google.com/p/biogo/feat"
	"code.google.com/p/biogo/seq"
	"fmt"
	"gopkg.in/check.v1"
	"reflect"
	"testing"
)

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

type S struct{}

var _ = check.Suite(&S{})

var (
	lorem = stringToSlice("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.")
)

type slice []byte

func stringToSlice(s string) slice {
	return []byte(s)
}
func (s slice) Make(len, cap int) alphabet.Slice       { return make(slice, len, cap) }
func (s slice) Len() int                               { return len(s) }
func (s slice) Cap() int                               { return cap(s) }
func (s slice) Slice(start, end int) alphabet.Slice    { return s[start:end] }
func (s slice) Append(a alphabet.Slice) alphabet.Slice { return append(s, a.(slice)...) }
func (s slice) Copy(a alphabet.Slice) int              { return copy(s, a.(slice)) }

type offSlice struct {
	slice
	offset int
	conf   feat.Conformation
}

func stringToOffSlice(s string) *offSlice {
	return &offSlice{slice: stringToSlice(s)}
}
func (os *offSlice) Conformation() feat.Conformation { return os.conf }
func (os *offSlice) SetOffset(o int) error           { os.offset = o; return nil }
func (os *offSlice) Slice() alphabet.Slice           { return os.slice }
func (os *offSlice) SetSlice(sl alphabet.Slice)      { os.slice = sl.(slice) }
func (os *offSlice) String() string                  { return fmt.Sprintf("%s %d", os.slice, os.offset) }

type conformRangeOffSlice struct {
	slice
	offset int
	conf   feat.Conformation
}

func stringToConformRangeOffSlice(s string) *conformRangeOffSlice {
	return &conformRangeOffSlice{slice: stringToSlice(s)}
}
func (os *conformRangeOffSlice) Conformation() feat.Conformation     { return os.conf }
func (os *conformRangeOffSlice) SetConformation(c feat.Conformation) { os.conf = c }
func (os *conformRangeOffSlice) SetOffset(o int) error               { os.offset = o; return nil }
func (os *conformRangeOffSlice) Start() int                          { return os.offset }
func (os *conformRangeOffSlice) End() int                            { return os.offset + len(os.slice) }
func (os *conformRangeOffSlice) Slice() alphabet.Slice               { return os.slice }
func (os *conformRangeOffSlice) SetSlice(sl alphabet.Slice)          { os.slice = sl.(slice) }
func (os *conformRangeOffSlice) String() string                      { return fmt.Sprintf("%s", os.slice) }

func (s *S) TestTruncate(c *check.C) {
	type test struct {
		in         *conformRangeOffSlice
		start, end int
		expect     interface{}
	}

	var T []test = []test{
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear},
			start:  28,
			end:    39,
			expect: stringToSlice("consectetur"),
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: 1},
			start:  29,
			end:    40,
			expect: stringToSlice("consectetur"),
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Circular},
			start:  28,
			end:    39,
			expect: stringToSlice("consectetur"),
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear},
			start:  117,
			end:    5,
			expect: "sequtils: start position greater than end position for linear sequence",
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Circular},
			start:  117,
			end:    5,
			expect: stringToSlice("aliqua.Lorem"),
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Circular, offset: 1},
			start:  118,
			end:    6,
			expect: stringToSlice("aliqua.Lorem"),
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear},
			start:  5,
			end:    1170,
			expect: "sequtils: index out of range",
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Circular},
			start:  1170,
			end:    5,
			expect: "sequtils: index out of range",
		},
	}

	for _, t := range T {
		r := &conformRangeOffSlice{}
		if err := Truncate(r, t.in, t.start, t.end); err != nil {
			c.Check(err, check.ErrorMatches, t.expect)
		} else {
			c.Check(r.slice, check.DeepEquals, t.expect)
			c.Check(r.conf, check.Equals, feat.Linear)
			if t.in.conf != feat.Circular || (t.in.conf == feat.Circular && t.end >= t.start) {
				c.Check(t.end-t.start, check.Equals, reflect.ValueOf(t.expect).Len())
			} else {
				c.Check(t.end+reflect.ValueOf(t.in.slice).Len()-t.start, check.Equals, reflect.ValueOf(t.expect).Len())
			}
		}
	}
}

func (s *S) TestJoin(c *check.C) {
	type test struct {
		a, b   *offSlice
		where  int
		expect *offSlice
	}

	var T []test = []test{
		{
			a:      &offSlice{lorem[28:40], 0, feat.Linear},
			b:      &offSlice{lorem[117:], 0, feat.Linear},
			where:  seq.Start,
			expect: &offSlice{stringToSlice("aliqua.consectetur "), -7, feat.Linear},
		},
		{
			a:      &offSlice{lorem[28:40], 0, feat.Linear},
			b:      &offSlice{lorem[117:], 0, feat.Linear},
			where:  seq.End,
			expect: &offSlice{stringToSlice("consectetur aliqua."), 0, feat.Linear},
		},
	}

	for _, t := range T {
		Join(t.a, t.b, t.where)
		c.Check(t.a, check.DeepEquals, t.expect)
	}
}

type fe struct {
	s, e   int
	orient feat.Orientation
	feat.Feature
}

func (f fe) Start() int                    { return f.s }
func (f fe) End() int                      { return f.e }
func (f fe) Len() int                      { return f.e - f.s }
func (f fe) Orientation() feat.Orientation { return f.orient }

type fs []feat.Feature

func (f fs) Features() []feat.Feature { return []feat.Feature(f) }

func (s *S) TestStitch(c *check.C) {
	type test struct {
		in     *conformRangeOffSlice
		f      feat.Set
		expect interface{}
	}

	var T []test = []test{
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: 0},
			f:      fs{fe{s: 12, e: 18}, fe{s: 24, e: 26}, fe{s: 103, e: 110}},
			expect: stringToSlice("dolor et dolore"),
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: -1},
			f:      fs{fe{s: 12, e: 18}, fe{s: 24, e: 26}, fe{s: 103, e: 110}},
			expect: stringToSlice("olor st,dolore "),
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: 0},
			f:      fs{fe{s: 12, e: 18}, fe{s: 13, e: 17}, fe{s: 24, e: 26}, fe{s: 103, e: 110}},
			expect: stringToSlice("dolor et dolore"),
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: -1},
			f:      fs{fe{s: 12, e: 18}, fe{s: 13, e: 17}, fe{s: 24, e: 26}, fe{s: 103, e: 110}},
			expect: stringToSlice("olor st,dolore "),
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: 0},
			f:      fs{fe{s: 19, e: 18}},
			expect: "sequtils: feature end < feature start",
		},
	}

	for _, t := range T {
		r := &conformRangeOffSlice{}
		if err := Stitch(r, t.in, t.f); err != nil {
			c.Check(err, check.ErrorMatches, t.expect)
		} else {
			c.Check(r.slice, check.DeepEquals, t.expect)
		}
	}
}

func (s *S) TestCompose(c *check.C) {
	type test struct {
		in     *conformRangeOffSlice
		f      feat.Set
		expect interface{}
	}

	var T []test = []test{
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: 0},
			f:      fs{fe{s: 12, e: 18}, fe{s: 24, e: 26}, fe{s: 103, e: 110}},
			expect: stringToSlice("dolor et dolore"),
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: -1},
			f:      fs{fe{s: 12, e: 18}, fe{s: 24, e: 26}, fe{s: 103, e: 110}},
			expect: stringToSlice("olor st,dolore "),
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: 0},
			f:      fs{fe{s: 12, e: 18}, fe{s: 13, e: 17}, fe{s: 24, e: 26}, fe{s: 103, e: 110}},
			expect: stringToSlice("dolor oloret dolore"),
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: -1},
			f:      fs{fe{s: 12, e: 18}, fe{s: 13, e: 17}, fe{s: 24, e: 26}, fe{s: 103, e: 110}},
			expect: stringToSlice("olor slor t,dolore "),
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: -1},
			f:      fs{fe{s: 12, e: 18}, fe{s: 13, e: 17}, fe{s: 24, e: 26, orient: feat.Reverse}, fe{s: 103, e: 110}},
			expect: "sequtils: unable to reverse segment during compose",
		},
		{
			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: 0},
			f:      fs{fe{s: 19, e: 18}},
			expect: "sequtils: feature end < feature start",
		},
	}

	for _, t := range T {
		r := &conformRangeOffSlice{}
		if err := Compose(r, t.in, t.f); err == nil {
			c.Check(r.slice, check.DeepEquals, t.expect)
		} else {
			c.Check(err, check.ErrorMatches, t.expect)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
)

// A map for Puppet Versions JSON
type PuppetVersions interface{}

// A map for Production Versions JSON
type QaVersions interface{}

// Our bare page
type Page struct {
	Title string
	Body  []byte
	Pv    PuppetVersions
	//	Rv    RunningServices
}

type Compared map[string][]map[string][]map[string]string

func compare(puppet_v map[string]string, qa_v map[string]map[string]string) (Compared, error) {
	// Get environments from PuppetVersions, populate top level map
	var c Compared

	return c, nil
}

func puppetversions(url string) (PuppetVersions, error) {
	// Get response and handle any errors on return
	resp, err := http.Get(url)
	defer resp.Body.Close()
	if err != nil {
		log.Println(err)
		return nil, err
	}

	// Read JSON from request
	jsonDataFromHttp, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	// Unmarshel the JSON to our struct
	var v PuppetVersions
	err = json.Unmarshal(jsonDataFromHttp, &v)
	if err != nil {
		return nil, err
	}

	return v, nil
}

func getServices(url string) (interface{}, error) {
	resp, err := http.Get(url)
	defer resp.Body.Close()
	if err != nil {
		log.Println(err)
		return nil, err
	}

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

	var available_services interface{}

	err = json.Unmarshal(jsonDataFromHttp, &available_services)
	if err != nil {
		return nil, err
	}

	return available_services, nil
}

func queryServiceVersion(endpoint string) (version string, err error) {
	log.Println("Querying SERVICE address: ", endpoint)
	query_arry := []string{"http://", endpoint, "/info"}
	query := strings.Join(query_arry, "")
	log.Println("Query string: ", query)
	// Query the URI
	resp, err := http.Get(query)
	defer resp.Body.Close()
	if err != nil {
		log.Println("ERROR querying ", query, " ", err)
		return "Failed to get server response for endpoint", err
	}
	// Get data and unmarshel the JSON to our map
	jsonDataFromHttp, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Println("ERROR unmarsheling data for ", jsonDataFromHttp)
		return "Failed to read JSON", err
	}
	var info_response interface{}
	err = json.Unmarshal(jsonDataFromHttp, &info_response)
	if err != nil {
		return "Failed to get info response ", err
	}
	// Parse out the version from the response
	log.Println("INFO for ", endpoint, ":\n", info_response)

	info_map := info_response.(map[string]interface{})
	for _, values := range info_map {
		log.Println("String: ", values)
		sub_info_map := values.(map[string]interface{})
		for key, info := range sub_info_map {
			string_info := info.(string)
			log.Println("Sub info: ", string_info)
			if key == "version" {
				log.Println("Version: ", string_info)
				return string_info, nil
			}
		}
	}
	return version, nil
}

func getVersions(services interface{}) (runningversions map[string]map[string]string, err error) {

	rv := make(map[string]map[string]string)

	s := services.(map[string]interface{})
	for k, v := range s {
		log.Println("Ranging over ", k)
		switch values := v.(type) {
		case map[string]interface{}:
			for name, endpoints := range values {
				log.Println("Found service: ", name)
				rv[name] = make(map[string]string)
				switch eps := endpoints.(type) {
				case []interface{}:
					for _, ep := range eps {
						log.Println("Endpoint: ", ep)
						switch ep_string := ep.(type) {
						case string:
							query_arry := strings.Fields(ep_string)
							if len(query_arry) == 2 {
								log.Println("IP 1: ", query_arry[0])
								log.Println("IP 2: ", query_arry[1])
								info_ep := query_arry[1]
								version, _ := queryServiceVersion(info_ep)
								rv[name][info_ep] = version
							} else {
								log.Println("IP 1: ", query_arry[0])
								info_ep := query_arry[0]
								rv[name][info_ep] = "blah"
							}
						}
					}
				}
			}
		}
	}
	runningversions = rv
	return runningversions, nil
}

func loadPage(title string) (*Page, error) {
	// Get the versions from the puppet master
	log.Println("Getting Puppet Versions - Make sure VPN is on!")
	pv, err := puppetversions("http://puppet.ec2.srcclr.com:1015/versions")
	if err != nil {
		log.Println("Failed to get Puppet Versions from http://puppet.ec2.srcclr.com:1015/versions\n")
		log.Println(err)
	}
	log.Println("Puppet Versions: ", pv)

	// Get running services, prs
	log.Println("Getting available services...")
	qa_rs, err := getServices("http://is.qa.ec2.srcclr.com:3000/services")
	if err != nil {
		log.Println("Failed getting production versions")
	}

	log.Println("RUNNING SERVICES QA: ", qa_rs)

	qa_v, err := getVersions(qa_rs)
	if err != nil {
		log.Println("Failed getting versions for ", qa_rs)
	}

	log.Println("Running Versions: ", qa_v)

	filename := title + ".html"
	body, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}

	return &Page{
			Title: title,
			Body:  body,
			Pv:    pv,
			//	Rv:    rv,
		},
		nil
}

func viewHandler(w http.ResponseWriter, r *http.Request) {
	log.Println("Loading page view...")
	title := "versionctl"
	p, err := loadPage(title)
	if err != nil {
		p = &Page{Title: title}
	}

	// Parse the template, execute and write it to stdout for good measure
	log.Println("Parsing go template...")
	t, _ := template.ParseFiles("versionctl.html")
	t.Execute(w, p)
	log.Println("Serving:\n", string(p.Title), string(p.Body))
}

func main() {
	log.Println("Starting vctl...")
	http.HandleFunc("/", viewHandler)
	http.ListenAndServe(":9000", nil)
}
<commit_msg>building env map<commit_after>package main

import (
	"encoding/json"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"regexp"
	"strings"
)

// A map for Puppet Versions JSON
type PuppetVersions interface{}

// A map for Production Versions JSON
type QaVersions interface{}

// Our bare page
type Page struct {
	Title string
	Body  []byte
	Pv    PuppetVersions
	//	Rv    RunningServices
}

type Compared map[string]map[string]map[string]string

func compare(puppet_v map[string]interface{}, qa_v map[string]map[string]string) (Compared, error) {
	c := make(map[string]map[string]map[string]string)

	// Setup regex for QA match
	match_qa, err := regexp.Compile(`_qa`)
	if err != nil {
		log.Println("Couldn't compile regex")
		return nil, err
	}
	match_prod, err := regexp.Compile(`_production`)
	if err != nil {
		log.Println("Couldn't compile regex")
		return nil, err
	}
	log.Println("COMPARE PV: ", puppet_v)
	log.Println("COMPARE QA: ", qa_v)

	// Get environments from PuppetVersions, populate top level map
	c["qa"] = make(map[string]map[string]string)
	c["production"] = make(map[string]map[string]string)

	for name, version := range puppet_v {
		log.Println("NAME: ", name, "version ", version)
		if match_qa.MatchString(name) {
			log.Println("QA MATCH: ", name, " ", version)
			c["qa"][name] = make(map[string]string)
		}
		if match_prod.MatchString(name) {
			log.Println("Production MATCH: ", name, " ", version)
			c["production"][name] = make(map[string]string)
		}
	}

	return c, nil
}

func puppetversions(url string) (PuppetVersions, error) {
	// Get response and handle any errors on return
	resp, err := http.Get(url)
	defer resp.Body.Close()
	if err != nil {
		log.Println(err)
		return nil, err
	}

	// Read JSON from request
	jsonDataFromHttp, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	// Unmarshel the JSON to our struct
	var v PuppetVersions
	err = json.Unmarshal(jsonDataFromHttp, &v)
	if err != nil {
		return nil, err
	}

	return v, nil
}

func getServices(url string) (interface{}, error) {
	resp, err := http.Get(url)
	defer resp.Body.Close()
	if err != nil {
		log.Println(err)
		return nil, err
	}

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

	var available_services interface{}

	err = json.Unmarshal(jsonDataFromHttp, &available_services)
	if err != nil {
		return nil, err
	}

	return available_services, nil
}

func queryServiceVersion(endpoint string) (version string, err error) {
	log.Println("Querying SERVICE address: ", endpoint)
	query_arry := []string{"http://", endpoint, "/info"}
	query := strings.Join(query_arry, "")
	log.Println("Query string: ", query)
	// Query the URI
	resp, err := http.Get(query)
	defer resp.Body.Close()
	if err != nil {
		log.Println("ERROR querying ", query, " ", err)
		return "Failed to get server response for endpoint", err
	}
	// Get data and unmarshel the JSON to our map
	jsonDataFromHttp, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Println("ERROR unmarsheling data for ", jsonDataFromHttp)
		return "Failed to read JSON", err
	}
	var info_response interface{}
	err = json.Unmarshal(jsonDataFromHttp, &info_response)
	if err != nil {
		return "Failed to get info response ", err
	}
	// Parse out the version from the response
	log.Println("INFO for ", endpoint, ":\n", info_response)

	info_map := info_response.(map[string]interface{})
	for _, values := range info_map {
		log.Println("String: ", values)
		sub_info_map := values.(map[string]interface{})
		for key, info := range sub_info_map {
			string_info := info.(string)
			log.Println("Sub info: ", string_info)
			if key == "version" {
				log.Println("Version: ", string_info)
				return string_info, nil
			}
		}
	}
	return version, nil
}

func getVersions(services interface{}) (runningversions map[string]map[string]string, err error) {

	rv := make(map[string]map[string]string)

	s := services.(map[string]interface{})
	for k, v := range s {
		log.Println("Ranging over ", k)
		switch values := v.(type) {
		case map[string]interface{}:
			for name, endpoints := range values {
				log.Println("Found service: ", name)
				rv[name] = make(map[string]string)
				switch eps := endpoints.(type) {
				case []interface{}:
					for _, ep := range eps {
						log.Println("Endpoint: ", ep)
						switch ep_string := ep.(type) {
						case string:
							query_arry := strings.Fields(ep_string)
							if len(query_arry) == 2 {
								log.Println("IP 1: ", query_arry[0])
								log.Println("IP 2: ", query_arry[1])
								info_ep := query_arry[1]
								version, _ := queryServiceVersion(info_ep)
								rv[name][info_ep] = version
							} else {
								log.Println("IP 1: ", query_arry[0])
								info_ep := query_arry[0]
								rv[name][info_ep] = "blah"
							}
						}
					}
				}
			}
		}
	}
	runningversions = rv
	return runningversions, nil
}

func loadPage(title string) (*Page, error) {
	// Get the versions from the puppet master
	log.Println("Getting Puppet Versions - Make sure VPN is on!")
	pv, err := puppetversions("http://puppet.ec2.srcclr.com:1015/versions")
	if err != nil {
		log.Println("Failed to get Puppet Versions from http://puppet.ec2.srcclr.com:1015/versions\n")
		log.Println(err)
	}
	log.Println("Puppet Versions: ", pv)

	// Get running services, prs
	log.Println("Getting available services...")
	qa_rs, err := getServices("http://is.qa.ec2.srcclr.com:3000/services")
	if err != nil {
		log.Println("Failed getting production versions")
	}

	log.Println("RUNNING SERVICES QA: ", qa_rs)

	qa_v, err := getVersions(qa_rs)
	if err != nil {
		log.Println("Failed getting versions for ", qa_rs)
	}

	log.Println("Running Versions: ", qa_v)

	pv_map := pv.(map[string]interface{})
	compared, _ := compare(pv_map, qa_v)
	log.Println("COMPARED: ", compared)

	for k, v := range pv_map {
		log.Println("k: ", k, " ", "v: ", v)
	}

	filename := title + ".html"
	body, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}

	return &Page{
			Title: title,
			Body:  body,
			Pv:    pv,
			//	Rv:    rv,
		},
		nil
}

func viewHandler(w http.ResponseWriter, r *http.Request) {
	log.Println("Loading page view...")
	title := "versionctl"
	p, err := loadPage(title)
	if err != nil {
		p = &Page{Title: title}
	}

	// Parse the template, execute and write it to stdout for good measure
	log.Println("Parsing go template...")
	t, _ := template.ParseFiles("versionctl.html")
	t.Execute(w, p)
	//log.Println("Serving:\n", string(p.Title), string(p.Body))
}

func main() {
	log.Println("Starting vctl...")
	http.HandleFunc("/", viewHandler)
	http.ListenAndServe(":9000", nil)
}
<|endoftext|>