<commit_before>package tests_test

import (
	"github.com/grubby/grubby/ast"
	"github.com/grubby/grubby/parser"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("babby's first parser", func() {
	Describe("parsing Fixnums", func() {
		It(`parses the integer "9001"`, func() {
			node := parser.Parse("9001")
			Expect(node).To(Equal(ast.Block{
				Statement: ast.ConstantInt{Value: 9001},
			}))
		})

		It(`parses the float "3.14"`, func() {
			node := parser.Parse("3.14")
			Expect(node).To(Equal(ast.Block{
				Statement: ast.ConstantFloat{Value: 3.14},
			}))
		})
	})

	It(`parses the string "hello world"`, func() {
		node := parser.Parse("'hello world'")
		Expect(node).To(Equal(ast.Block{
			Statement: ast.SimpleString{Value: "hello world"},
		}))
	})

	It("parses the bare reference `foo`", func() {
		statement := parser.Parse("foo").Statement
		ref, ok := statement.(ast.BareReference)
		Expect(ok).To(BeTrue(), "expected to receive a bare reference")
		Expect(ref.Name).To(Equal("foo"))
	})

	Describe("call expressions", func() {
		It("parses a simple call expression", func() {
			statement := parser.Parse("puts()").Statement
			callExpr, ok := statement.(ast.CallExpression)
			Expect(ok).To(BeTrue(), "expected to receive a call expression")
			Expect(callExpr.Func).To(Equal("puts"))
		})

		It("parses a call expression with a single arg", func() {
			statement := parser.Parse(`puts('hai')`).Statement
			callExpr, ok := statement.(ast.CallExpression)
			Expect(ok).To(BeTrue(), "expected to receive a call expression")
			Expect(len(callExpr.Args)).To(Equal(1), "expected a single arg")

			asString, ok := callExpr.Args[0].(ast.SimpleString)
			Expect(ok).To(BeTrue(), "expected first arg to be a simple string")
			Expect(asString.Value).To(Equal("hai"))
		})

		It("parses a call expression with multiple args", func() {
			statement := parser.Parse("puts(foo, bar, baz)").Statement
			callExpr, ok := statement.(ast.CallExpression)
			Expect(ok).To(BeTrue(), "expected to receive a call expression")
			Expect(len(callExpr.Args)).To(Equal(3), "expected three arguments")
		})
	})
})
<commit_msg>Improve parser test description<commit_after>package tests_test

import (
	"github.com/grubby/grubby/ast"
	"github.com/grubby/grubby/parser"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("parsing ruby files", func() {
	Describe("parsing Fixnums", func() {
		It(`parses the integer "9001"`, func() {
			node := parser.Parse("9001")
			Expect(node).To(Equal(ast.Block{
				Statement: ast.ConstantInt{Value: 9001},
			}))
		})

		It(`parses the float "3.14"`, func() {
			node := parser.Parse("3.14")
			Expect(node).To(Equal(ast.Block{
				Statement: ast.ConstantFloat{Value: 3.14},
			}))
		})
	})

	It(`parses the string "hello world"`, func() {
		node := parser.Parse("'hello world'")
		Expect(node).To(Equal(ast.Block{
			Statement: ast.SimpleString{Value: "hello world"},
		}))
	})

	It("parses the bare reference `foo`", func() {
		statement := parser.Parse("foo").Statement
		ref, ok := statement.(ast.BareReference)
		Expect(ok).To(BeTrue(), "expected to receive a bare reference")
		Expect(ref.Name).To(Equal("foo"))
	})

	Describe("call expressions", func() {
		It("parses a simple call expression", func() {
			statement := parser.Parse("puts()").Statement
			callExpr, ok := statement.(ast.CallExpression)
			Expect(ok).To(BeTrue(), "expected to receive a call expression")
			Expect(callExpr.Func).To(Equal("puts"))
		})

		It("parses a call expression with a single arg", func() {
			statement := parser.Parse(`puts('hai')`).Statement
			callExpr, ok := statement.(ast.CallExpression)
			Expect(ok).To(BeTrue(), "expected to receive a call expression")
			Expect(len(callExpr.Args)).To(Equal(1), "expected a single arg")

			asString, ok := callExpr.Args[0].(ast.SimpleString)
			Expect(ok).To(BeTrue(), "expected first arg to be a simple string")
			Expect(asString.Value).To(Equal("hai"))
		})

		It("parses a call expression with multiple args", func() {
			statement := parser.Parse("puts(foo, bar, baz)").Statement
			callExpr, ok := statement.(ast.CallExpression)
			Expect(ok).To(BeTrue(), "expected to receive a call expression")
			Expect(len(callExpr.Args)).To(Equal(3), "expected three arguments")
		})
	})
})
<|endoftext|>


<commit_before>// Copyright 2018 Jigsaw Operations 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
//
//     https://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 shadowsocks

import (
	"bytes"
	"crypto/cipher"
	"crypto/rand"
	"fmt"
	"io"

	"github.com/shadowsocks/go-shadowsocks2/shadowaead"
)

// payloadSizeMask is the maximum size of payload in bytes.
const payloadSizeMask = 0x3FFF // 16*1024 - 1

// Writer is an io.Writer that also implements io.ReaderFrom to
// allow for piping the data without extra allocations and copies.
type Writer interface {
	io.Writer
	io.ReaderFrom
}

type shadowsocksWriter struct {
	writer   io.Writer
	ssCipher shadowaead.Cipher
	// These are lazily initialized:
	buf  []byte
	aead cipher.AEAD
	// Index of the next encrypted chunk to write.
	counter []byte
}

// NewShadowsocksWriter creates a Writer that encrypts the given Writer using
// the shadowsocks protocol with the given shadowsocks cipher.
func NewShadowsocksWriter(writer io.Writer, ssCipher shadowaead.Cipher) Writer {
	return &shadowsocksWriter{writer: writer, ssCipher: ssCipher}
}

// init generates a random salt, sets up the AEAD object and writes
// the salt to the inner Writer.
func (sw *shadowsocksWriter) init() (err error) {
	if sw.aead == nil {
		salt := make([]byte, sw.ssCipher.SaltSize())
		if _, err := io.ReadFull(rand.Reader, salt); err != nil {
			return fmt.Errorf("failed to generate salt: %v", err)
		}
		_, err := sw.writer.Write(salt)
		if err != nil {
			return fmt.Errorf("failed to write salt: %v", err)
		}
		sw.aead, err = sw.ssCipher.Encrypter(salt)
		if err != nil {
			return fmt.Errorf("failed to create AEAD: %v", err)
		}
		sw.counter = make([]byte, sw.aead.NonceSize())
		sw.buf = make([]byte, 2+sw.aead.Overhead()+payloadSizeMask+sw.aead.Overhead())
	}
	return nil
}

// WriteBlock encrypts and writes the input buffer as one signed block.
func (sw *shadowsocksWriter) encryptBlock(ciphertext []byte, plaintext []byte) ([]byte, error) {
	out := sw.aead.Seal(ciphertext, sw.counter, plaintext, nil)
	increment(sw.counter)
	return out, nil
}

func (sw *shadowsocksWriter) Write(p []byte) (int, error) {
	n, err := sw.ReadFrom(bytes.NewReader(p))
	return int(n), err
}

func (sw *shadowsocksWriter) ReadFrom(r io.Reader) (int64, error) {
	if err := sw.init(); err != nil {
		return 0, err
	}
	var written int64
	sizeBuf := sw.buf[:2+sw.aead.Overhead()]
	payloadBuf := sw.buf[len(sizeBuf):]
	for {
		plaintextSize, err := r.Read(payloadBuf[:payloadSizeMask])
		if plaintextSize > 0 {
			// big-endian payload size
			sizeBuf[0], sizeBuf[1] = byte(plaintextSize>>8), byte(plaintextSize)
			_, err = sw.encryptBlock(sizeBuf[:0], sizeBuf[:2])
			if err != nil {
				return written, fmt.Errorf("failed to encypt payload size: %v", err)
			}
			_, err := sw.encryptBlock(payloadBuf[:0], payloadBuf[:plaintextSize])
			if err != nil {
				return written, fmt.Errorf("failed to encrypt payload: %v", err)
			}
			payloadSize := plaintextSize + sw.aead.Overhead()
			_, err = sw.writer.Write(sw.buf[:len(sizeBuf)+payloadSize])
			written += int64(plaintextSize)
		}
		if err != nil {
			if err == io.EOF { // ignore EOF as per io.ReaderFrom contract
				return written, nil
			}
			return written, fmt.Errorf("Failed to read payload: %v", err)
		}
	}
}

type shadowsocksReader struct {
	reader   io.Reader
	ssCipher shadowaead.Cipher
	// These are lazily initialized:
	aead cipher.AEAD
	// Index of the next encrypted chunk to read.
	counter  []byte
	buf      []byte
	leftover []byte
}

// Reader is an io.Reader that also implements io.WriterTo to
// allow for piping the data without extra allocations and copies.
type Reader interface {
	io.Reader
	io.WriterTo
}

// NewShadowsocksReader creates a Reader that decrypts the given Reader using
// the shadowsocks protocol with the given shadowsocks cipher.
func NewShadowsocksReader(reader io.Reader, ssCipher shadowaead.Cipher) Reader {
	return &shadowsocksReader{reader: reader, ssCipher: ssCipher}
}

// init reads the salt from the inner Reader and sets up the AEAD object
func (sr *shadowsocksReader) init() (err error) {
	if sr.aead == nil {
		// For chacha20-poly1305, SaltSize is 32, NonceSize is 12 and Overhead is 16.
		salt := make([]byte, sr.ssCipher.SaltSize())
		if _, err := io.ReadFull(sr.reader, salt); err != nil {
			if err != io.EOF && err != io.ErrUnexpectedEOF {
				err = fmt.Errorf("failed to read salt: %v", err)
			}
			return err
		}
		sr.aead, err = sr.ssCipher.Decrypter(salt)
		if err != nil {
			return fmt.Errorf("failed to create AEAD: %v", err)
		}
		sr.counter = make([]byte, sr.aead.NonceSize())
		sr.buf = make([]byte, payloadSizeMask+sr.aead.Overhead())
	}
	return nil
}

// ReadBlock reads and decrypts a single signed block of ciphertext.
// The block will match the given decryptedBlockSize.
// The returned slice is only valid until the next Read call.
func (sr *shadowsocksReader) readBlock(decryptedBlockSize int) ([]byte, error) {
	if err := sr.init(); err != nil {
		return nil, err
	}
	cipherBlockSize := decryptedBlockSize + sr.aead.Overhead()
	if cipherBlockSize > cap(sr.buf) {
		return nil, io.ErrShortBuffer
	}
	buf := sr.buf[:cipherBlockSize]
	_, err := io.ReadFull(sr.reader, buf)
	if err != nil {
		return nil, err
	}
	buf, err = sr.aead.Open(buf[:0], sr.counter, buf, nil)
	increment(sr.counter)
	if err != nil {
		return nil, fmt.Errorf("failed to decrypt: %v", err)
	}
	return buf, nil
}

func (sr *shadowsocksReader) Read(b []byte) (int, error) {
	if err := sr.populateLeftover(); err != nil {
		return 0, err
	}
	n := copy(b, sr.leftover)
	sr.leftover = sr.leftover[n:]
	return n, nil
}

func (sr *shadowsocksReader) WriteTo(w io.Writer) (written int64, err error) {
	for {
		if err = sr.populateLeftover(); err != nil {
			if err == io.EOF {
				err = nil
			}
			return written, err
		}
		n, err := w.Write(sr.leftover)
		written += int64(n)
		sr.leftover = sr.leftover[n:]
		if err != nil {
			return written, err
		}
	}
}

// Ensures that sr.leftover is nonempty.  If leftover is empty, this method
// waits for incoming data and decrypts it.
// Returns an error only if sr.leftover could not be populated.
func (sr *shadowsocksReader) populateLeftover() error {
	if len(sr.leftover) == 0 {
		buf, err := sr.readBlock(2)
		if err != nil {
			if err != io.EOF && err != io.ErrUnexpectedEOF {
				err = fmt.Errorf("failed to read payload size: %v", err)
			}
			return err
		}
		size := (int(buf[0])<<8 + int(buf[1])) & payloadSizeMask
		payload, err := sr.readBlock(size)
		if err != nil {
			return fmt.Errorf("failed to read payload: %v", err)
		}
		sr.leftover = payload
	}
	return nil
}

// increment little-endian encoded unsigned integer b. Wrap around on overflow.
func increment(b []byte) {
	for i := range b {
		b[i]++
		if b[i] != 0 {
			return
		}
	}
}
<commit_msg>Cleanup based on review comments<commit_after>// Copyright 2018 Jigsaw Operations 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
//
//     https://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 shadowsocks

import (
	"bytes"
	"crypto/cipher"
	"crypto/rand"
	"fmt"
	"io"

	"github.com/shadowsocks/go-shadowsocks2/shadowaead"
)

// payloadSizeMask is the maximum size of payload in bytes.
const payloadSizeMask = 0x3FFF // 16*1024 - 1

// Writer is an io.Writer that also implements io.ReaderFrom to
// allow for piping the data without extra allocations and copies.
type Writer interface {
	io.Writer
	io.ReaderFrom
}

type shadowsocksWriter struct {
	writer   io.Writer
	ssCipher shadowaead.Cipher
	// These are lazily initialized:
	buf  []byte
	aead cipher.AEAD
	// Index of the next encrypted chunk to write.
	counter []byte
}

// NewShadowsocksWriter creates a Writer that encrypts the given Writer using
// the shadowsocks protocol with the given shadowsocks cipher.
func NewShadowsocksWriter(writer io.Writer, ssCipher shadowaead.Cipher) Writer {
	return &shadowsocksWriter{writer: writer, ssCipher: ssCipher}
}

// init generates a random salt, sets up the AEAD object and writes
// the salt to the inner Writer.
func (sw *shadowsocksWriter) init() (err error) {
	if sw.aead == nil {
		salt := make([]byte, sw.ssCipher.SaltSize())
		if _, err := io.ReadFull(rand.Reader, salt); err != nil {
			return fmt.Errorf("failed to generate salt: %v", err)
		}
		_, err := sw.writer.Write(salt)
		if err != nil {
			return fmt.Errorf("failed to write salt: %v", err)
		}
		sw.aead, err = sw.ssCipher.Encrypter(salt)
		if err != nil {
			return fmt.Errorf("failed to create AEAD: %v", err)
		}
		sw.counter = make([]byte, sw.aead.NonceSize())
		sw.buf = make([]byte, 2+sw.aead.Overhead()+payloadSizeMask+sw.aead.Overhead())
	}
	return nil
}

// WriteBlock encrypts and writes the input buffer as one signed block.
func (sw *shadowsocksWriter) encryptBlock(ciphertext []byte, plaintext []byte) ([]byte, error) {
	out := sw.aead.Seal(ciphertext, sw.counter, plaintext, nil)
	increment(sw.counter)
	return out, nil
}

func (sw *shadowsocksWriter) Write(p []byte) (int, error) {
	n, err := sw.ReadFrom(bytes.NewReader(p))
	return int(n), err
}

func (sw *shadowsocksWriter) ReadFrom(r io.Reader) (int64, error) {
	if err := sw.init(); err != nil {
		return 0, err
	}
	var written int64
	sizeBuf := sw.buf[:2+sw.aead.Overhead()]
	payloadBuf := sw.buf[len(sizeBuf):]
	for {
		plaintextSize, err := r.Read(payloadBuf[:payloadSizeMask])
		if plaintextSize > 0 {
			// big-endian payload size
			sizeBuf[0], sizeBuf[1] = byte(plaintextSize>>8), byte(plaintextSize)
			_, err = sw.encryptBlock(sizeBuf[:0], sizeBuf[:2])
			if err != nil {
				return written, fmt.Errorf("failed to encypt payload size: %v", err)
			}
			_, err := sw.encryptBlock(payloadBuf[:0], payloadBuf[:plaintextSize])
			if err != nil {
				return written, fmt.Errorf("failed to encrypt payload: %v", err)
			}
			payloadSize := plaintextSize + sw.aead.Overhead()
			_, err = sw.writer.Write(sw.buf[:len(sizeBuf)+payloadSize])
			written += int64(plaintextSize)
		}
		if err != nil {
			if err == io.EOF { // ignore EOF as per io.ReaderFrom contract
				return written, nil
			}
			return written, fmt.Errorf("Failed to read payload: %v", err)
		}
	}
}

type shadowsocksReader struct {
	reader   io.Reader
	ssCipher shadowaead.Cipher
	// These are lazily initialized:
	aead cipher.AEAD
	// Index of the next encrypted chunk to read.
	counter  []byte
	buf      []byte
	leftover []byte
}

// Reader is an io.Reader that also implements io.WriterTo to
// allow for piping the data without extra allocations and copies.
type Reader interface {
	io.Reader
	io.WriterTo
}

// NewShadowsocksReader creates a Reader that decrypts the given Reader using
// the shadowsocks protocol with the given shadowsocks cipher.
func NewShadowsocksReader(reader io.Reader, ssCipher shadowaead.Cipher) Reader {
	return &shadowsocksReader{reader: reader, ssCipher: ssCipher}
}

// init reads the salt from the inner Reader and sets up the AEAD object
func (sr *shadowsocksReader) init() (err error) {
	if sr.aead == nil {
		// For chacha20-poly1305, SaltSize is 32, NonceSize is 12 and Overhead is 16.
		salt := make([]byte, sr.ssCipher.SaltSize())
		if _, err := io.ReadFull(sr.reader, salt); err != nil {
			if err != io.EOF && err != io.ErrUnexpectedEOF {
				err = fmt.Errorf("failed to read salt: %v", err)
			}
			return err
		}
		sr.aead, err = sr.ssCipher.Decrypter(salt)
		if err != nil {
			return fmt.Errorf("failed to create AEAD: %v", err)
		}
		sr.counter = make([]byte, sr.aead.NonceSize())
		sr.buf = make([]byte, payloadSizeMask+sr.aead.Overhead())
	}
	return nil
}

// ReadBlock reads and decrypts a single signed block of ciphertext.
// The block will match the given decryptedBlockSize.
// The returned slice is only valid until the next Read call.
func (sr *shadowsocksReader) readBlock(decryptedBlockSize int) ([]byte, error) {
	if err := sr.init(); err != nil {
		return nil, err
	}
	cipherBlockSize := decryptedBlockSize + sr.aead.Overhead()
	if cipherBlockSize > cap(sr.buf) {
		return nil, io.ErrShortBuffer
	}
	buf := sr.buf[:cipherBlockSize]
	_, err := io.ReadFull(sr.reader, buf)
	if err != nil {
		return nil, err
	}
	buf, err = sr.aead.Open(buf[:0], sr.counter, buf, nil)
	increment(sr.counter)
	if err != nil {
		return nil, fmt.Errorf("failed to decrypt: %v", err)
	}
	return buf, nil
}

func (sr *shadowsocksReader) Read(b []byte) (int, error) {
	if err := sr.ensureLeftover(); err != nil {
		return 0, err
	}
	n := copy(b, sr.leftover)
	sr.leftover = sr.leftover[n:]
	return n, nil
}

func (sr *shadowsocksReader) WriteTo(w io.Writer) (written int64, err error) {
	for {
		if err = sr.ensureLeftover(); err != nil {
			if err == io.EOF {
				err = nil
			}
			return written, err
		}
		n, err := w.Write(sr.leftover)
		written += int64(n)
		sr.leftover = sr.leftover[n:]
		if err != nil {
			return written, err
		}
	}
}

// Ensures that sr.leftover is nonempty.  If leftover is empty, this method
// waits for incoming data and decrypts it.
// Returns an error only if sr.leftover could not be populated.
func (sr *shadowsocksReader) ensureLeftover() error {
	if len(sr.leftover) > 0 {
		return nil
	}
	buf, err := sr.readBlock(2)
	if err != nil {
		if err != io.EOF && err != io.ErrUnexpectedEOF {
			err = fmt.Errorf("failed to read payload size: %v", err)
		}
		return err
	}
	size := (int(buf[0])<<8 + int(buf[1])) & payloadSizeMask
	payload, err := sr.readBlock(size)
	if err != nil {
		return fmt.Errorf("failed to read payload: %v", err)
	}
	sr.leftover = payload
	return nil
}

// increment little-endian encoded unsigned integer b. Wrap around on overflow.
func increment(b []byte) {
	for i := range b {
		b[i]++
		if b[i] != 0 {
			return
		}
	}
}
<|endoftext|>


<commit_before>package smoke_tests

import (
	"fmt"
	"sync"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/pborman/uuid"
	"github.com/pivotal-cf/cf-rabbitmq-smoke-tests/tests/helper"
)

var _ = Describe("Smoke tests", func() {
	var (
		apps        map[string]string
		serviceName string
	)

	BeforeEach(func() {
		apps = map[string]string{
			"rmq-smoke-tests-ruby":   "../assets/rabbit-example-app",
			"rmq-smoke-tests-spring": "../assets/spring-example-app",
		}
		serviceName = fmt.Sprintf("rmq-smoke-test-instance-%s", uuid.New()[:18])
	})

	AfterEach(func() {
		for appName, _ := range apps {
			helper.DeleteApp(appName)
		}
	})

	for _, plan := range testConfig.TestPlans {
		It(fmt.Sprintf("pushes an app, sends, and reads a message from RabbitMQ: plan '%s'", plan.Name), func() {
			helper.CreateService(testConfig.ServiceOffering, plan.Name, serviceName)

			var wg sync.WaitGroup
			wg.Add(len(apps))

			for appName, appPath := range apps {
				go func(appName, appPath string) {
					appURL := helper.PushAndBindApp(appName, serviceName, appPath)

					queue := fmt.Sprintf("%s-queue", appName)
					helper.SendMessage(appURL, queue, "foo")
					helper.SendMessage(appURL, queue, "bar")
					Expect(helper.ReceiveMessage(appURL, queue)).To(Equal("foo"))
					Expect(helper.ReceiveMessage(appURL, queue)).To(Equal("bar"))

					helper.UnbindService(appName, serviceName)
					wg.Done()
				}(appName, appPath)
			}

			wg.Wait()

			helper.DeleteService(serviceName)
		}, 300.0) // seconds
	}
})
<commit_msg>Only run Ruby app for MT<commit_after>package smoke_tests

import (
	"fmt"
	"sync"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/pborman/uuid"
	"github.com/pivotal-cf/cf-rabbitmq-smoke-tests/tests/helper"
)

var _ = Describe("Smoke tests", func() {
	var (
		apps        map[string]string
		serviceName string
	)

	BeforeEach(func() {
		apps = map[string]string{
			"rmq-smoke-tests-ruby": "../assets/rabbit-example-app",
		}

		if testConfig.ServiceOffering == "p.rabbitmq" {
			apps["rmq-smoke-tests-spring"] = "../assets/spring-example-app"
		}

		serviceName = fmt.Sprintf("rmq-smoke-test-instance-%s", uuid.New()[:18])
	})

	AfterEach(func() {
		for appName, _ := range apps {
			helper.DeleteApp(appName)
		}
	})

	for _, plan := range testConfig.TestPlans {
		It(fmt.Sprintf("pushes an app, sends, and reads a message from RabbitMQ: plan '%s'", plan.Name), func() {
			helper.CreateService(testConfig.ServiceOffering, plan.Name, serviceName)

			var wg sync.WaitGroup
			wg.Add(len(apps))

			for appName, appPath := range apps {
				go func(appName, appPath string) {
					appURL := helper.PushAndBindApp(appName, serviceName, appPath)

					queue := fmt.Sprintf("%s-queue", appName)
					helper.SendMessage(appURL, queue, "foo")
					helper.SendMessage(appURL, queue, "bar")
					Expect(helper.ReceiveMessage(appURL, queue)).To(Equal("foo"))
					Expect(helper.ReceiveMessage(appURL, queue)).To(Equal("bar"))

					helper.UnbindService(appName, serviceName)
					wg.Done()
				}(appName, appPath)
			}

			wg.Wait()

			helper.DeleteService(serviceName)
		}, 300.0) // seconds
	}
})
<|endoftext|>


<commit_before>package lib

import (
	"log"
	"path/filepath"
	"strings"
	"time"

	"github.com/howeyc/fsnotify"
)

const (
	eventDelay = 10 * time.Second
)

func launchWatcher() *fsnotify.Watcher {
	w, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal("FATAL", err)
	}
	go watch(w)
	// watch posts directory
	if err = w.Watch(PostsDir); err != nil {
		w.Close()
		log.Fatal("FATAL", err)
	}
	// watch templates directory
	if err = w.Watch(TemplatesDir); err != nil {
		w.Close()
		log.Fatal("FATAL", err)
	}
	return w
}

// lazy
func watch(w *fsnotify.Watcher) {
	var delay <-chan time.Time
	for {
		select {

		case ev := <-w.Event:
			ext := filepath.Ext(ev.Name)
			if strings.HasPrefix(ev.Name, PostsDir) && ext == ".md" {
				delay = time.After(eventDelay)
			} else if strings.HasPrefix(ev.Name, TemplatesDir) && ext == ".html" {
				delay = time.After(eventDelay)
			}

		case err := <-w.Error:
			log.Println("Watch Error: ", err)

		case <-delay:
			if err := GenerateSite(); err != nil {
				log.Println("Error generating site: ", err)
			} else {
				log.Println("site generated")
			}

		}
	}
}
<commit_msg>add comment<commit_after>package lib

import (
	"log"
	"path/filepath"
	"strings"
	"time"

	"github.com/howeyc/fsnotify"
)

const (
	eventDelay = 10 * time.Second
)

func launchWatcher() *fsnotify.Watcher {
	w, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal("FATAL", err)
	}
	go watch(w)
	// watch posts directory
	if err = w.Watch(PostsDir); err != nil {
		w.Close()
		log.Fatal("FATAL", err)
	}
	// watch templates directory
	if err = w.Watch(TemplatesDir); err != nil {
		w.Close()
		log.Fatal("FATAL", err)
	}
	return w
}

// TODO: finish the comment
func watch(w *fsnotify.Watcher) {
	var delay <-chan time.Time
	for {
		select {

		case ev := <-w.Event:
			ext := filepath.Ext(ev.Name)
			if strings.HasPrefix(ev.Name, PostsDir) && ext == ".md" {
				delay = time.After(eventDelay)
			} else if strings.HasPrefix(ev.Name, TemplatesDir) && ext == ".html" {
				delay = time.After(eventDelay)
			}

		case err := <-w.Error:
			log.Println("Watch Error: ", err)

		case <-delay:
			if err := GenerateSite(); err != nil {
				log.Println("Error generating site: ", err)
			} else {
				log.Println("site generated")
			}

		}
	}
}
<|endoftext|>


<commit_before>package network

import (
	"fmt"
	"errors"
)

// The connection descriptor for fast network
type FastNetworkLink struct {
	// The index of source neuron
	SourceIndx int
	// The index of target neuron
	TargetIndx int
	// The weight of this link
	Weight     float64
	// The signal relayed by this link
	Signal     float64
}
// The module relay (control node) descriptor for fast network
type FastControlNode struct {
	// The activation function for control node
	ActivationType NodeActivationType
	// The indexes of the input nodes
	InputIndxs     []int
	// The indexes of the output nodes
	OutputIndxs    []int
}

// The fast modular network solver implementation to be used for big neural networks simulation.
type FastModularNetworkSolver struct {
	// A network id
	Id                          int
	// Is a name of this network */
	Name                        string

	// The current activation values per each neuron
	neuronSignals               []float64
	// This array is a parallel of neuronSignals and used to test network relaxation
	neuronSignalsBeingProcessed []float64

	// The activation functions per neuron, must be in the same order as neuronSignals. Has nil entries for
	// neurons that are inputs or outputs of a module.
	activationFunctions         []NodeActivationType
	// The bias values associated with neurons
	biasList                    []float64
	// The control nodes relaying between network modules
	modules                     []*FastControlNode
	// The connections
	connections                 []*FastNetworkLink

	// The number of input neurons
	inputNeuronCount            int
	// The total number of sensors in the network (input + bias). This is also the index of the first output neuron in the neuron signals.
	sensorNeuronCount           int
	// The number of output neurons
	outputNeuronCount           int
	// The bias neuron count (usually one). This is also the index of the first input neuron in the neuron signals.
	biasNeuronCount             int
	// The total number of neurons in network
	totalNeuronCount            int

	// For recursive activation, marks whether we have finished this node yet
	activated                   []bool
	// For recursive activation, makes whether a node is currently being calculated (recurrent connections processing)
	inActivation                []bool
	// For recursive activation, the previous activation values of recurrent connections (recurrent connections processing)
	lastActivation              []float64

	// The adjacent list to hold IDs of outgoing nodes for each network node
	adjacentList                [][]int
	// The adjacent list to hold IDs of incoming nodes for each network node
	reverseAdjacentList         [][]int
	// The adjacent matrix to hold connection weights between all connected nodes
	adjacentMatrix              [][]float64
}

// Creates new fast modular network solver
func NewFastModularNetworkSolver(biasNeuronCount, inputNeuronCount, outputNeuronCount, totalNeuronCount int,
activationFunctions []NodeActivationType, connections []*FastNetworkLink,
biasList []float64, modules []*FastControlNode) *FastModularNetworkSolver {

	fmm := FastModularNetworkSolver{
		biasNeuronCount:biasNeuronCount,
		inputNeuronCount:inputNeuronCount,
		sensorNeuronCount:biasNeuronCount + inputNeuronCount,
		outputNeuronCount:outputNeuronCount,
		totalNeuronCount:totalNeuronCount,
		activationFunctions:activationFunctions,
		biasList:biasList,
		modules:modules,
		connections:connections,
	}

	// Allocate the arrays that store the states at different points in the neural network.
	// The neuron signals are initialised to 0 by default. Only bias nodes need setting to 1.
	fmm.neuronSignals = make([]float64, totalNeuronCount)
	fmm.neuronSignalsBeingProcessed = make([]float64, totalNeuronCount)
	for i := 0; i < biasNeuronCount; i++ {
		fmm.neuronSignals[i] = 1.0 // BIAS neuron signal
	}

	// Allocate activation arrays
	fmm.activated = make([]bool, totalNeuronCount)
	fmm.inActivation = make([]bool, totalNeuronCount)
	fmm.lastActivation = make([]float64, totalNeuronCount)

	// Build adjacent lists and matrix for fast access of incoming/outgoing nodes and connection weights
	fmm.adjacentList = make([][]int, totalNeuronCount)
	fmm.reverseAdjacentList = make([][]int, totalNeuronCount)
	fmm.adjacentMatrix = make([][]float64, totalNeuronCount)

	for i := 0; i < totalNeuronCount; i++ {
		fmm.adjacentList[i] = make([]int, 0)
		fmm.reverseAdjacentList[i] = make([]int, 0)
		fmm.adjacentMatrix[i] = make([]float64, totalNeuronCount)
	}

	for i := 0; i < len(connections); i++ {
		crs := connections[i].SourceIndx
		crt := connections[i].TargetIndx
		// Holds outgoing nodes
		fmm.adjacentList[crs] = append(fmm.adjacentList[crs], crt)
		// Holds incoming nodes
		fmm.reverseAdjacentList[crt] = append(fmm.reverseAdjacentList[crt], crs)
		// Holds link weight
		fmm.adjacentMatrix[crs][crt] = connections[i].Weight
	}

	return &fmm
}

// Propagates activation wave through all network nodes provided number of steps in forward direction.
// Returns true if activation wave passed from all inputs to outputs.
func (fmm *FastModularNetworkSolver) ForwardSteps(steps int) (bool, error) {
	return false, errors.New("not implemented")
}

// Propagates activation wave through all network nodes provided number of steps by recursion from output nodes
// Returns true if activation wave passed from all inputs to outputs.
func (fmm *FastModularNetworkSolver) RecursiveSteps() (bool, error) {
	return false, errors.New("not implemented")
}

// Attempts to relax network given amount of steps until giving up. The network considered relaxed when absolute
// value of the change at any given point is less than maxAllowedSignalDelta during activation waves propagation.
// If maxAllowedSignalDelta value is less than or equal to 0, the method will return true without checking for relaxation.
func (fmm *FastModularNetworkSolver) Relax(maxSteps int, maxAllowedSignalDelta float64) (bool, error) {
	return false, errors.New("not implemented")
}

// Flushes network state by removing all current activations. Returns true if network flushed successfully or
// false in case of error.
func (fmm *FastModularNetworkSolver) Flush() (bool, error) {
	for i := fmm.biasNeuronCount; i < fmm.totalNeuronCount; i++ {
		fmm.neuronSignals[i] = 0.0
	}
	return true, nil
}

// Set sensors values to the input nodes of the network
func (fmm *FastModularNetworkSolver) LoadSensors(inputs []float64) error {
	if len(inputs) == fmm.inputNeuronCount {
		// only inputs provided
		for i := 0; i < fmm.inputNeuronCount; i++ {
			fmm.neuronSignals[fmm.biasNeuronCount + i] = inputs[i]
		}
	} else if len(inputs) == fmm.sensorNeuronCount  {
		// inputs and bias provided
		for i := 0; i < fmm.sensorNeuronCount; i++ {
			fmm.neuronSignals[i] = inputs[i]
		}
	} else {
		return NetErrUnsupportedSensorsArraySize
	}
	return nil
}

// Read output values from the output nodes of the network
func (fmm *FastModularNetworkSolver) ReadOutputs() []float64 {
	return fmm.neuronSignals[fmm.sensorNeuronCount:fmm.sensorNeuronCount + fmm.outputNeuronCount]
}

// Returns the total number of neural units in the network
func (fmm *FastModularNetworkSolver) NodeCount() int {
	return fmm.totalNeuronCount + len(fmm.modules)
}
// Returns the total number of links between nodes in the network
func (fmm *FastModularNetworkSolver) LinkCount() int {
	num_links := len(fmm.connections)
	if len(fmm.modules) != 0 {
		for _, module := range fmm.modules {
			num_links += len(module.InputIndxs) + len(module.OutputIndxs)
		}
	}
	return num_links
}

// Stringer
func (fmm *FastModularNetworkSolver) String() string {
	str := fmt.Sprintf("FastModularNetwork, id: %d, name: [%s], neurons: %d,\n\tinputs: %d,\tbias: %d,\toutputs:%d,\t hidden: %d",
		fmm.Id, fmm.Name, fmm.totalNeuronCount, fmm.inputNeuronCount, fmm.biasNeuronCount, fmm.outputNeuronCount,
		fmm.totalNeuronCount - fmm.sensorNeuronCount - fmm.outputNeuronCount)
	return str
}
<commit_msg>Implemented forward and recursive activation propagation through the network.<commit_after>package network

import (
	"fmt"
	"math"
	"errors"
)

// The connection descriptor for fast network
type FastNetworkLink struct {
	// The index of source neuron
	SourceIndx int
	// The index of target neuron
	TargetIndx int
	// The weight of this link
	Weight     float64
	// The signal relayed by this link
	Signal     float64
}
// The module relay (control node) descriptor for fast network
type FastControlNode struct {
	// The activation function for control node
	ActivationType NodeActivationType
	// The indexes of the input nodes
	InputIndxs     []int
	// The indexes of the output nodes
	OutputIndxs    []int
}

// The fast modular network solver implementation to be used for big neural networks simulation.
type FastModularNetworkSolver struct {
	// A network id
	Id                          int
	// Is a name of this network */
	Name                        string

	// The current activation values per each neuron
	neuronSignals               []float64
	// This array is a parallel of neuronSignals and used to test network relaxation
	neuronSignalsBeingProcessed []float64

	// The activation functions per neuron, must be in the same order as neuronSignals. Has nil entries for
	// neurons that are inputs or outputs of a module.
	activationFunctions         []NodeActivationType
	// The bias values associated with neurons
	biasList                    []float64
	// The control nodes relaying between network modules
	modules                     []*FastControlNode
	// The connections
	connections                 []*FastNetworkLink

	// The number of input neurons
	inputNeuronCount            int
	// The total number of sensors in the network (input + bias). This is also the index of the first output neuron in the neuron signals.
	sensorNeuronCount           int
	// The number of output neurons
	outputNeuronCount           int
	// The bias neuron count (usually one). This is also the index of the first input neuron in the neuron signals.
	biasNeuronCount             int
	// The total number of neurons in network
	totalNeuronCount            int

	// For recursive activation, marks whether we have finished this node yet
	activated                   []bool
	// For recursive activation, makes whether a node is currently being calculated (recurrent connections processing)
	inActivation                []bool
	// For recursive activation, the previous activation values of recurrent connections (recurrent connections processing)
	lastActivation              []float64

	// The adjacent list to hold IDs of outgoing nodes for each network node
	adjacentList                [][]int
	// The adjacent list to hold IDs of incoming nodes for each network node
	reverseAdjacentList         [][]int
	// The adjacent matrix to hold connection weights between all connected nodes
	adjacentMatrix              [][]float64
}

// Creates new fast modular network solver
func NewFastModularNetworkSolver(biasNeuronCount, inputNeuronCount, outputNeuronCount, totalNeuronCount int,
activationFunctions []NodeActivationType, connections []*FastNetworkLink,
biasList []float64, modules []*FastControlNode) *FastModularNetworkSolver {

	fmm := FastModularNetworkSolver{
		biasNeuronCount:biasNeuronCount,
		inputNeuronCount:inputNeuronCount,
		sensorNeuronCount:biasNeuronCount + inputNeuronCount,
		outputNeuronCount:outputNeuronCount,
		totalNeuronCount:totalNeuronCount,
		activationFunctions:activationFunctions,
		biasList:biasList,
		modules:modules,
		connections:connections,
	}

	// Allocate the arrays that store the states at different points in the neural network.
	// The neuron signals are initialised to 0 by default. Only bias nodes need setting to 1.
	fmm.neuronSignals = make([]float64, totalNeuronCount)
	fmm.neuronSignalsBeingProcessed = make([]float64, totalNeuronCount)
	for i := 0; i < biasNeuronCount; i++ {
		fmm.neuronSignals[i] = 1.0 // BIAS neuron signal
	}

	// Allocate activation arrays
	fmm.activated = make([]bool, totalNeuronCount)
	fmm.inActivation = make([]bool, totalNeuronCount)
	fmm.lastActivation = make([]float64, totalNeuronCount)

	// Build adjacent lists and matrix for fast access of incoming/outgoing nodes and connection weights
	fmm.adjacentList = make([][]int, totalNeuronCount)
	fmm.reverseAdjacentList = make([][]int, totalNeuronCount)
	fmm.adjacentMatrix = make([][]float64, totalNeuronCount)

	for i := 0; i < totalNeuronCount; i++ {
		fmm.adjacentList[i] = make([]int, 0)
		fmm.reverseAdjacentList[i] = make([]int, 0)
		fmm.adjacentMatrix[i] = make([]float64, totalNeuronCount)
	}

	for i := 0; i < len(connections); i++ {
		crs := connections[i].SourceIndx
		crt := connections[i].TargetIndx
		// Holds outgoing nodes
		fmm.adjacentList[crs] = append(fmm.adjacentList[crs], crt)
		// Holds incoming nodes
		fmm.reverseAdjacentList[crt] = append(fmm.reverseAdjacentList[crt], crs)
		// Holds link weight
		fmm.adjacentMatrix[crs][crt] = connections[i].Weight
	}

	return &fmm
}

// Propagates activation wave through all network nodes provided number of steps in forward direction.
// Returns true if activation wave passed from all inputs to the outputs.
func (fmm *FastModularNetworkSolver) ForwardSteps(steps int) (res bool, err error) {
	for i := 0; i < steps; i++ {
		if res, err = fmm.forwardStep(0); err != nil {
			return false, err
		}
	}
	return res, nil
}

// Propagates activation wave through all network nodes provided number of steps by recursion from output nodes
// Returns true if activation wave passed from all inputs to the outputs. This method is preferred method
// of network activation when number of forward steps can not be easy calculated and no network modules are set.
func (fmm *FastModularNetworkSolver) RecursiveSteps() (res bool, err error) {
	if len(fmm.modules) > 0 {
		return false, errors.New("recursive activation can not be used for network with defined modules")
	}

	// Initialize boolean arrays and set the last activation signal for output/hidden neurons
	for i := 0; i < fmm.totalNeuronCount; i++ {
		// Set as activated if i is an input node, otherwise ensure it is unactivated (false)
		fmm.activated[i] = i < fmm.sensorNeuronCount

		fmm.inActivation[i] = false
		// set last activation for output/hidden neurons
		if i >= fmm.sensorNeuronCount {
			fmm.lastActivation[i] = fmm.neuronSignals[i]
		}
	}

	// Get each output node activation recursively
	for i := 0; i < fmm.outputNeuronCount; i++ {
		if res, err = fmm.recursiveActivateNode(fmm.sensorNeuronCount + i); err != nil {
			return false, err
		}
	}

	return true, nil
}

// Propagate activation wave by recursively looking for input signals graph for a given output neuron
func (fmm *FastModularNetworkSolver) recursiveActivateNode(currentNode int) (res bool, err error) {
	// If we've reached an input node then return since the signal is already set
	if fmm.activated[currentNode] {
		fmm.inActivation[currentNode] = false
		return true, nil
	}
	// Mark that the node is currently being calculated
	fmm.inActivation[currentNode] = true

	// Set the pre-signal to 0
	fmm.neuronSignalsBeingProcessed[currentNode] = 0

	// Adjacency list in reverse holds incoming connections, go through each one and activate it
	for i := 0; i < len(fmm.reverseAdjacentList[currentNode]); i++ {
		crntAdjNode := fmm.reverseAdjacentList[currentNode][i]

		// If this node is currently being activated then we have reached a cycle, or recurrent connection.
		// Use the previous activation in this case
		if fmm.inActivation[crntAdjNode] {
			fmm.neuronSignalsBeingProcessed[currentNode] += fmm.lastActivation[crntAdjNode] * fmm.adjacentMatrix[crntAdjNode][currentNode]
		} else {
			// Otherwise proceed as normal
			// Recurse if this neuron has not been activated yet
			if !fmm.activated[crntAdjNode] {
				res, err = fmm.recursiveActivateNode(crntAdjNode)
				if err != nil {
					// recursive activation failed
					return false, err
				}
			}

			// Add it to the new activation
			fmm.neuronSignalsBeingProcessed[currentNode] += fmm.neuronSignals[crntAdjNode] * fmm.adjacentMatrix[crntAdjNode][currentNode]
		}
	}

	// Mark this neuron as completed
	fmm.activated[currentNode] = true

	// This is no longer being calculated (for cycle detection)
	fmm.inActivation[currentNode] = false

	// Set this signal after running it through the activation function
	if fmm.neuronSignals[currentNode], err = NodeActivators.ActivateByType(
		fmm.neuronSignalsBeingProcessed[currentNode], nil,
		fmm.activationFunctions[currentNode]); err != nil {
		// failed to activate
		res = false
	}
	return res, err
}

// Attempts to relax network given amount of steps until giving up. The network considered relaxed when absolute
// value of the change at any given point is less than maxAllowedSignalDelta during activation waves propagation.
// If maxAllowedSignalDelta value is less than or equal to 0, the method will return true without checking for relaxation.
func (fmm *FastModularNetworkSolver) Relax(maxSteps int, maxAllowedSignalDelta float64) (relaxed bool, err error) {
	for i := 0; i < maxSteps; i++ {
		if relaxed, err = fmm.forwardStep(maxAllowedSignalDelta); err != nil {
			return false, err
		}
	}
	return relaxed, nil
}

// Performs single forward step through the network and tests if network become relaxed. The network considered relaxed
// when absolute value of the change at any given point is less than maxAllowedSignalDelta during activation waves propagation.
func (fmm *FastModularNetworkSolver) forwardStep(maxAllowedSignalDelta float64) (isRelaxed bool, err error) {
	isRelaxed = true

	// Calculate output signal per each connection and add the signals to the target neurons
	for _, conn := range fmm.connections {
		fmm.neuronSignalsBeingProcessed[conn.TargetIndx] += fmm.neuronSignals[conn.SourceIndx] * conn.Weight
	}

	// Pass the signals through the single-valued activation functions
	for i := fmm.sensorNeuronCount; i < fmm.totalNeuronCount; i++ {
		fmm.neuronSignalsBeingProcessed[i], err = NodeActivators.ActivateByType(
			fmm.neuronSignalsBeingProcessed[i] + fmm.biasList[i], nil,
			fmm.activationFunctions[i])
		if err != nil {
			return false, err
		}
	}

	// Pass the signals through each module (activation function with more than one input or output)
	for _, module := range fmm.modules {
		inputs := make([]float64, len(module.InputIndxs))
		for i, in_index := range module.InputIndxs {
			inputs[i] = fmm.neuronSignalsBeingProcessed[in_index]
		}
		if outputs, err := NodeActivators.ActivateModuleByType(inputs, nil, module.ActivationType); err == nil {
			// save outputs
			for i, out_index := range module.OutputIndxs {
				fmm.neuronSignalsBeingProcessed[out_index] = outputs[i]
			}
		} else {
			return false, err
		}
	}

	// Move all the neuron signals we changed while processing this network activation into storage.
	if maxAllowedSignalDelta <= 0 {
		// iterate through output and hidden neurons and collect activations
		for i := fmm.sensorNeuronCount; i < fmm.totalNeuronCount; i++ {
			fmm.neuronSignals[i] = fmm.neuronSignalsBeingProcessed[i]
			fmm.neuronSignalsBeingProcessed[i] = 0
		}
	} else {
		for i := fmm.sensorNeuronCount; i < fmm.totalNeuronCount; i++ {
			// First check whether any location in the network has changed by more than a small amount.
			isRelaxed = isRelaxed && !(math.Abs(fmm.neuronSignals[i] - fmm.neuronSignalsBeingProcessed[i]) > maxAllowedSignalDelta)

			fmm.neuronSignals[i] = fmm.neuronSignalsBeingProcessed[i]
			fmm.neuronSignalsBeingProcessed[i] = 0
		}
	}

	return isRelaxed, err
}

// Flushes network state by removing all current activations. Returns true if network flushed successfully or
// false in case of error.
func (fmm *FastModularNetworkSolver) Flush() (bool, error) {
	for i := fmm.biasNeuronCount; i < fmm.totalNeuronCount; i++ {
		fmm.neuronSignals[i] = 0.0
	}
	return true, nil
}

// Set sensors values to the input nodes of the network
func (fmm *FastModularNetworkSolver) LoadSensors(inputs []float64) error {
	if len(inputs) == fmm.inputNeuronCount {
		// only inputs provided
		for i := 0; i < fmm.inputNeuronCount; i++ {
			fmm.neuronSignals[fmm.biasNeuronCount + i] = inputs[i]
		}
	} else if len(inputs) == fmm.sensorNeuronCount {
		// inputs and bias provided
		for i := 0; i < fmm.sensorNeuronCount; i++ {
			fmm.neuronSignals[i] = inputs[i]
		}
	} else {
		return NetErrUnsupportedSensorsArraySize
	}
	return nil
}

// Read output values from the output nodes of the network
func (fmm *FastModularNetworkSolver) ReadOutputs() []float64 {
	return fmm.neuronSignals[fmm.sensorNeuronCount:fmm.sensorNeuronCount + fmm.outputNeuronCount]
}

// Returns the total number of neural units in the network
func (fmm *FastModularNetworkSolver) NodeCount() int {
	return fmm.totalNeuronCount + len(fmm.modules)
}
// Returns the total number of links between nodes in the network
func (fmm *FastModularNetworkSolver) LinkCount() int {
	num_links := len(fmm.connections)
	if len(fmm.modules) != 0 {
		for _, module := range fmm.modules {
			num_links += len(module.InputIndxs) + len(module.OutputIndxs)
		}
	}
	return num_links
}

// Stringer
func (fmm *FastModularNetworkSolver) String() string {
	str := fmt.Sprintf("FastModularNetwork, id: %d, name: [%s], neurons: %d,\n\tinputs: %d,\tbias: %d,\toutputs:%d,\t hidden: %d",
		fmm.Id, fmm.Name, fmm.totalNeuronCount, fmm.inputNeuronCount, fmm.biasNeuronCount, fmm.outputNeuronCount,
		fmm.totalNeuronCount - fmm.sensorNeuronCount - fmm.outputNeuronCount)
	return str
}
<|endoftext|>


<commit_before>// Copyright 2016 tsuru-client 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 dm

import (
	"errors"

	"github.com/tsuru/config"
	check "gopkg.in/check.v1"
)

type cmdOutput struct {
	output string
	err    error
}

type fakeSSHTarget struct {
	cmds      []string
	runOutput map[string]*cmdOutput
}

func (f *fakeSSHTarget) RunSSHCommand(cmd string) (string, error) {
	f.cmds = append(f.cmds, cmd)
	if f.runOutput != nil && f.runOutput[cmd] != nil {
		return f.runOutput[cmd].output, f.runOutput[cmd].err
	}
	return "", nil
}

func (s *S) TestGetPrivateIPInterfaceFromConfig(c *check.C) {
	config.Set("driver:private-ip-interface", "eth1")
	defer config.Unset("driver:private-ip-interface")
	iface, err := GetPrivateIPInterface("")
	c.Assert(err, check.IsNil)
	c.Assert(iface, check.Equals, "eth1")
}

func (s *S) TestGetPrivateIPInterfaceForAmazonEC2Driver(c *check.C) {
	iface, err := GetPrivateIPInterface("amazonec2")
	c.Assert(err, check.IsNil)
	c.Assert(iface, check.Equals, "eth0")
}

func (s *S) TestGetPrivateIPInterfaceForGoogleDriver(c *check.C) {
	iface, err := GetPrivateIPInterface("google")
	c.Assert(err, check.IsNil)
	c.Assert(iface, check.Equals, "eth0")
}

func (s *S) TestGetIP(c *check.C) {
	target := &fakeSSHTarget{}
	target.runOutput = map[string]*cmdOutput{
		"ip addr show dev eth0": {
			output: `2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP group default qlen 1000
link/ether 12:d4:8c:93:e1:c5 brd ff:ff:ff:ff:ff:ff
inet 172.30.0.69/24 brd 172.30.0.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::10d4:8cff:fe93:e1c5/64 scope link
valid_lft forever preferred_lft forever`},
		"ip addr show dev eth1": {output: "", err: errors.New("failed to get ip")}}
	ip, err := getIP(target, "eth2")
	c.Assert(err, check.NotNil)
	c.Assert(ip, check.Equals, "")
	ip, err = getIP(target, "eth0")
	c.Assert(err, check.IsNil)
	c.Assert(ip, check.Equals, "172.30.0.69")
	ip, err = getIP(target, "eth1")
	c.Assert(err, check.NotNil)
	c.Assert(ip, check.Equals, "")
}

func (s *S) TestDefaultDriverOpts(c *check.C) {
	tt := []struct {
		driverName   string
		expectedOpts map[string]interface{}
	}{
		{"virtualbox", map[string]interface{}{"virtualbox-memory": 2048}},
	}
	for _, t := range tt {
		opts := DefaultDriverOpts(t.driverName)
		c.Check(opts, check.DeepEquals, t.expectedOpts)
	}
}
<commit_msg>installer: fix default driver opts test<commit_after>// Copyright 2016 tsuru-client 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 dm

import (
	"errors"

	"github.com/tsuru/config"
	check "gopkg.in/check.v1"
)

type cmdOutput struct {
	output string
	err    error
}

type fakeSSHTarget struct {
	cmds      []string
	runOutput map[string]*cmdOutput
}

func (f *fakeSSHTarget) RunSSHCommand(cmd string) (string, error) {
	f.cmds = append(f.cmds, cmd)
	if f.runOutput != nil && f.runOutput[cmd] != nil {
		return f.runOutput[cmd].output, f.runOutput[cmd].err
	}
	return "", nil
}

func (s *S) TestGetPrivateIPInterfaceFromConfig(c *check.C) {
	config.Set("driver:private-ip-interface", "eth1")
	defer config.Unset("driver:private-ip-interface")
	iface, err := GetPrivateIPInterface("")
	c.Assert(err, check.IsNil)
	c.Assert(iface, check.Equals, "eth1")
}

func (s *S) TestGetPrivateIPInterfaceForAmazonEC2Driver(c *check.C) {
	iface, err := GetPrivateIPInterface("amazonec2")
	c.Assert(err, check.IsNil)
	c.Assert(iface, check.Equals, "eth0")
}

func (s *S) TestGetPrivateIPInterfaceForGoogleDriver(c *check.C) {
	iface, err := GetPrivateIPInterface("google")
	c.Assert(err, check.IsNil)
	c.Assert(iface, check.Equals, "eth0")
}

func (s *S) TestGetIP(c *check.C) {
	target := &fakeSSHTarget{}
	target.runOutput = map[string]*cmdOutput{
		"ip addr show dev eth0": {
			output: `2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP group default qlen 1000
link/ether 12:d4:8c:93:e1:c5 brd ff:ff:ff:ff:ff:ff
inet 172.30.0.69/24 brd 172.30.0.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::10d4:8cff:fe93:e1c5/64 scope link
valid_lft forever preferred_lft forever`},
		"ip addr show dev eth1": {output: "", err: errors.New("failed to get ip")}}
	ip, err := getIP(target, "eth2")
	c.Assert(err, check.NotNil)
	c.Assert(ip, check.Equals, "")
	ip, err = getIP(target, "eth0")
	c.Assert(err, check.IsNil)
	c.Assert(ip, check.Equals, "172.30.0.69")
	ip, err = getIP(target, "eth1")
	c.Assert(err, check.NotNil)
	c.Assert(ip, check.Equals, "")
}

func (s *S) TestDefaultDriverOpts(c *check.C) {
	tt := []struct {
		driverName   string
		expectedOpts map[string]interface{}
	}{
		{"virtualbox", map[string]interface{}{"virtualbox-memory": 2048, "virtualbox-nat-nictype": "Am79C973"}},
	}
	for _, t := range tt {
		opts := DefaultDriverOpts(t.driverName)
		c.Check(opts, check.DeepEquals, t.expectedOpts)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package model

import (
	"k8s.io/klog"
	"k8s.io/kops/pkg/systemd"
	"k8s.io/kops/upup/pkg/fi"
	"k8s.io/kops/upup/pkg/fi/nodeup/nodetasks"
)

// FirewallBuilder configures the firewall (iptables)
type FirewallBuilder struct {
	*NodeupModelContext
}

var _ fi.ModelBuilder = &FirewallBuilder{}

// Build is responsible for generating any node firewall rules
func (b *FirewallBuilder) Build(c *fi.ModelBuilderContext) error {
	// We need forwarding enabled (https://github.com/kubernetes/kubernetes/issues/40182)
	c.AddTask(b.buildFirewallScript())
	c.AddTask(b.buildSystemdService())

	return nil
}

func (b *FirewallBuilder) buildSystemdService() *nodetasks.Service {
	manifest := &systemd.Manifest{}
	manifest.Set("Unit", "Description", "Configure iptables for kubernetes")
	manifest.Set("Unit", "Documentation", "https://github.com/kubernetes/kops")
	manifest.Set("Unit", "Before", "network.target")
	manifest.Set("Service", "Type", "oneshot")
	manifest.Set("Service", "RemainAfterExit", "yes")
	manifest.Set("Service", "ExecStart", "/opt/kops/helpers/iptables-setup")
	manifest.Set("Install", "WantedBy", "basic.target")

	manifestString := manifest.Render()
	klog.V(8).Infof("Built service manifest %q\n%s", "kubernetes-iptables-setup", manifestString)

	service := &nodetasks.Service{
		Name:       "kubernetes-iptables-setup.service",
		Definition: s(manifestString),
	}

	service.InitDefaults()

	return service
}

func (b *FirewallBuilder) buildFirewallScript() *nodetasks.File {
	// TODO: Do we want to rely on running nodeup on every boot, or do we want to install systemd units?

	// TODO: The if statement in the script doesn't make it idempotent

	// This is borrowed from gce/gci/configure-helper.sh
	script := `#!/bin/bash
# Built by kops - do not edit

# The GCI image has host firewall which drop most inbound/forwarded packets.
# We need to add rules to accept all TCP/UDP/ICMP packets.
if iptables -L INPUT | grep "Chain INPUT (policy DROP)" > /dev/null; then
echo "Add rules to accept all inbound TCP/UDP/ICMP packets"
iptables -A INPUT -w -p TCP -j ACCEPT
iptables -A INPUT -w -p UDP -j ACCEPT
iptables -A INPUT -w -p ICMP -j ACCEPT
fi
if iptables -L FORWARD | grep "Chain FORWARD (policy DROP)" > /dev/null; then
echo "Add rules to accept all forwarded TCP/UDP/ICMP packets"
iptables -A FORWARD -w -p TCP -j ACCEPT
iptables -A FORWARD -w -p UDP -j ACCEPT
iptables -A FORWARD -w -p ICMP -j ACCEPT
fi
`
	return &nodetasks.File{
		Path:     "/opt/kops/helpers/iptables-setup",
		Contents: fi.NewStringResource(script),
		Type:     nodetasks.FileType_File,
		Mode:     s("0755"),
	}
}
<commit_msg>Move iptables-setup to /opt/kops/bin<commit_after>/*
Copyright 2019 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package model

import (
	"k8s.io/klog"
	"k8s.io/kops/pkg/systemd"
	"k8s.io/kops/upup/pkg/fi"
	"k8s.io/kops/upup/pkg/fi/nodeup/nodetasks"
)

// FirewallBuilder configures the firewall (iptables)
type FirewallBuilder struct {
	*NodeupModelContext
}

var _ fi.ModelBuilder = &FirewallBuilder{}

// Build is responsible for generating any node firewall rules
func (b *FirewallBuilder) Build(c *fi.ModelBuilderContext) error {
	// We need forwarding enabled (https://github.com/kubernetes/kubernetes/issues/40182)
	c.AddTask(b.buildFirewallScript())
	c.AddTask(b.buildSystemdService())

	return nil
}

func (b *FirewallBuilder) buildSystemdService() *nodetasks.Service {
	manifest := &systemd.Manifest{}
	manifest.Set("Unit", "Description", "Configure iptables for kubernetes")
	manifest.Set("Unit", "Documentation", "https://github.com/kubernetes/kops")
	manifest.Set("Unit", "Before", "network.target")
	manifest.Set("Service", "Type", "oneshot")
	manifest.Set("Service", "RemainAfterExit", "yes")
	manifest.Set("Service", "ExecStart", "/opt/kops/bin/iptables-setup")
	manifest.Set("Install", "WantedBy", "basic.target")

	manifestString := manifest.Render()
	klog.V(8).Infof("Built service manifest %q\n%s", "kubernetes-iptables-setup", manifestString)

	service := &nodetasks.Service{
		Name:       "kubernetes-iptables-setup.service",
		Definition: s(manifestString),
	}

	service.InitDefaults()

	return service
}

func (b *FirewallBuilder) buildFirewallScript() *nodetasks.File {
	// TODO: Do we want to rely on running nodeup on every boot, or do we want to install systemd units?

	// TODO: The if statement in the script doesn't make it idempotent

	// This is borrowed from gce/gci/configure-helper.sh
	script := `#!/bin/bash
# Built by kops - do not edit

# The GCI image has host firewall which drop most inbound/forwarded packets.
# We need to add rules to accept all TCP/UDP/ICMP packets.
if iptables -L INPUT | grep "Chain INPUT (policy DROP)" > /dev/null; then
echo "Add rules to accept all inbound TCP/UDP/ICMP packets"
iptables -A INPUT -w -p TCP -j ACCEPT
iptables -A INPUT -w -p UDP -j ACCEPT
iptables -A INPUT -w -p ICMP -j ACCEPT
fi
if iptables -L FORWARD | grep "Chain FORWARD (policy DROP)" > /dev/null; then
echo "Add rules to accept all forwarded TCP/UDP/ICMP packets"
iptables -A FORWARD -w -p TCP -j ACCEPT
iptables -A FORWARD -w -p UDP -j ACCEPT
iptables -A FORWARD -w -p ICMP -j ACCEPT
fi
`
	return &nodetasks.File{
		Path:     "/opt/kops/bin/iptables-setup",
		Contents: fi.NewStringResource(script),
		Type:     nodetasks.FileType_File,
		Mode:     s("0755"),
	}
}
<|endoftext|>


<commit_before>package types

import (
	"math"

	"github.com/go-graphite/carbonzipper/zipper/errors"
	protov3 "github.com/go-graphite/protocol/carbonapi_v3_pb"
	"github.com/lomik/zapwriter"
	"go.uber.org/zap"
)

type ServerResponse struct {
	Server   string
	Response []byte
}

type ServerInfoResponse struct {
	Server   string
	Response *protov3.ZipperInfoResponse
	Stats    *Stats
	Err      *errors.Errors
}

type ServerFindResponse struct {
	Server   string
	Response *protov3.MultiGlobResponse
	Stats    *Stats
	Err      *errors.Errors
}

/*
func mergeFindRequests(f1, f2 []protov3.GlobMatch) []protov3.GlobMatch {
	uniqList := make(map[string]protov3.GlobMatch)

	for _, v := range f1 {
		uniqList[v.Path] = v
	}
	for _, v := range f2 {
		uniqList[v.Path] = v
	}

	res := make([]protov3.GlobMatch, 0, len(uniqList))
	for _, v := range uniqList {
		res = append(res, v)
	}

	return res
}
*/

func (first *ServerFindResponse) Merge(second *ServerFindResponse) *errors.Errors {
	if second.Stats != nil {
		first.Stats.Merge(second.Stats)
	}
	if first.Err == nil {
		first.Err = &errors.Errors{}
	}
	first.Err.Merge(second.Err)
	if first.Err.HaveFatalErrors {
		return first.Err
	}
	if second.Response == nil {
		return first.Err
	}

	seenMetrics := make(map[string]int)
	seenMatches := make(map[string]struct{})
	for i, m := range first.Response.Metrics {
		seenMetrics[m.Name] = i
		for _, mm := range m.Matches {
			seenMatches[m.Name+"."+mm.Path] = struct{}{}
		}
	}

	var i int
	var ok bool
	for _, m := range second.Response.Metrics {
		if i, ok = seenMetrics[m.Name]; !ok {
			first.Response.Metrics = append(first.Response.Metrics, m)
			continue
		}
		for _, mm := range m.Matches {
			key := first.Response.Metrics[i].Name + "." + mm.Path
			if _, ok := seenMatches[key]; !ok {
				seenMatches[key] = struct{}{}
				first.Response.Metrics[i].Matches = append(first.Response.Metrics[i].Matches, mm)
			}
		}
	}

	if first.Err != nil && second.Err == nil {
		first.Err = nil
	}

	return nil
}

type ServerFetchResponse struct {
	Server       string
	ResponsesMap map[string][]protov3.FetchResponse
	Response     *protov3.MultiFetchResponse
	Stats        *Stats
	Err          *errors.Errors
}

func swapFetchResponses(m1, m2 *protov3.FetchResponse) {
	m1.Name, m2.Name = m2.Name, m1.Name
	m1.StartTime, m2.StartTime = m2.StartTime, m1.StartTime
	m1.StepTime, m2.StepTime = m2.StepTime, m1.StepTime
	m1.ConsolidationFunc, m2.ConsolidationFunc = m2.ConsolidationFunc, m1.ConsolidationFunc
	m1.XFilesFactor, m2.XFilesFactor = m2.XFilesFactor, m1.XFilesFactor
	m1.Values, m2.Values = m2.Values, m1.Values
	m1.AppliedFunctions, m2.AppliedFunctions = m2.AppliedFunctions, m1.AppliedFunctions
	m1.StopTime, m2.StopTime = m2.StopTime, m1.StopTime
}

func MergeFetchResponses(m1, m2 *protov3.FetchResponse) *errors.Errors {
	logger := zapwriter.Logger("zipper_render")

	if len(m1.Values) != len(m2.Values) {
		interpolate := false
		if len(m1.Values) < len(m2.Values) {
			swapFetchResponses(m1, m2)
		}
		if m1.StepTime < m2.StepTime {
			interpolate = true
		} else {
			if m1.StartTime == m2.StartTime {
				for i := 0; i < len(m1.Values)-len(m2.Values); i++ {
					m2.Values = append(m2.Values, math.NaN())
				}

				goto out
			}
		}

		// TODO(Civil): we must fix the case of m1.StopTime != m2.StopTime
		// We should check if m1.StopTime and m2.StopTime actually the same
		// Also we need to append nans in case StopTimes dramatically differs

		if !interpolate || m1.StopTime-m1.StopTime%m2.StepTime != m2.StopTime {
			// m1.Step < m2.Step and len(m1) < len(m2) - most probably garbage data
			logger.Error("unable to merge ovalues",
				zap.Int("metric_values", len(m2.Values)),
				zap.Int("response_values", len(m1.Values)),
			)

			return errors.FromErr(ErrResponseLengthMismatch)
		}

		// len(m1) > len(m2)
		values := make([]float64, 0, len(m1.Values))
		for ts := m1.StartTime; ts < m1.StopTime; ts += m1.StepTime {
			idx := (ts - m1.StartTime) / m2.StepTime
			values = append(values, m2.Values[idx])
		}
		m2.Values = values
		m2.StepTime = m1.StepTime
		m2.StartTime = m1.StartTime
		m2.StopTime = m1.StopTime
	}
out:

	if m1.StartTime != m2.StartTime {
		return errors.FromErr(ErrResponseStartTimeMismatch)
	}

	for i := range m1.Values {
		if !math.IsNaN(m1.Values[i]) {
			continue
		}

		// found one
		if !math.IsNaN(m2.Values[i]) {
			m1.Values[i] = m2.Values[i]
		}
	}
	return nil
}

func (first *ServerFetchResponse) Merge(second *ServerFetchResponse) {
	if second.Stats != nil {
		first.Stats.Merge(second.Stats)
	}
	if first.Err == nil {
		first.Err = &errors.Errors{}
	}
	first.Err.Merge(second.Err)
	if first.Err.HaveFatalErrors {
		return
	}
	if second.Response == nil {
		return
	}

	metrics := make(map[string]int)
	for i := range first.Response.Metrics {
		metrics[first.Response.Metrics[i].Name] = i
	}

	for i := range second.Response.Metrics {
		if j, ok := metrics[second.Response.Metrics[i].Name]; ok {
			err := MergeFetchResponses(&first.Response.Metrics[i], &second.Response.Metrics[j])
			if err != nil {
				// TODO: Normal error handling
				continue
			}
		} else {
			first.Response.Metrics = append(first.Response.Metrics, second.Response.Metrics[i])
		}
	}

	if first.Err != nil && second.Err == nil {
		first.Err = nil
	}

	return
}
<commit_msg>Update response.go<commit_after>package types

import (
	"math"

	"github.com/go-graphite/carbonzipper/zipper/errors"
	protov3 "github.com/go-graphite/protocol/carbonapi_v3_pb"
	"github.com/lomik/zapwriter"
	"go.uber.org/zap"
)

type ServerResponse struct {
	Server   string
	Response []byte
}

type ServerInfoResponse struct {
	Server   string
	Response *protov3.ZipperInfoResponse
	Stats    *Stats
	Err      *errors.Errors
}

type ServerFindResponse struct {
	Server   string
	Response *protov3.MultiGlobResponse
	Stats    *Stats
	Err      *errors.Errors
}

/*
func mergeFindRequests(f1, f2 []protov3.GlobMatch) []protov3.GlobMatch {
	uniqList := make(map[string]protov3.GlobMatch)

	for _, v := range f1 {
		uniqList[v.Path] = v
	}
	for _, v := range f2 {
		uniqList[v.Path] = v
	}

	res := make([]protov3.GlobMatch, 0, len(uniqList))
	for _, v := range uniqList {
		res = append(res, v)
	}

	return res
}
*/

func (first *ServerFindResponse) Merge(second *ServerFindResponse) *errors.Errors {
	if second.Stats != nil {
		first.Stats.Merge(second.Stats)
	}
	if first.Err == nil {
		first.Err = &errors.Errors{}
	}
	first.Err.Merge(second.Err)
	if first.Err.HaveFatalErrors {
		return first.Err
	}
	if second.Response == nil {
		return first.Err
	}

	seenMetrics := make(map[string]int)
	seenMatches := make(map[string]struct{})
	for i, m := range first.Response.Metrics {
		seenMetrics[m.Name] = i
		for _, mm := range m.Matches {
			seenMatches[m.Name+"."+mm.Path] = struct{}{}
		}
	}

	var i int
	var ok bool
	for _, m := range second.Response.Metrics {
		if i, ok = seenMetrics[m.Name]; !ok {
			first.Response.Metrics = append(first.Response.Metrics, m)
			continue
		}
		for _, mm := range m.Matches {
			key := first.Response.Metrics[i].Name + "." + mm.Path
			if _, ok := seenMatches[key]; !ok {
				seenMatches[key] = struct{}{}
				first.Response.Metrics[i].Matches = append(first.Response.Metrics[i].Matches, mm)
			}
		}
	}

	if first.Err != nil && second.Err == nil {
		first.Err = nil
	}

	return nil
}

type ServerFetchResponse struct {
	Server       string
	ResponsesMap map[string][]protov3.FetchResponse
	Response     *protov3.MultiFetchResponse
	Stats        *Stats
	Err          *errors.Errors
}

func swapFetchResponses(m1, m2 *protov3.FetchResponse) {
	m1.Name, m2.Name = m2.Name, m1.Name
	m1.StartTime, m2.StartTime = m2.StartTime, m1.StartTime
	m1.StepTime, m2.StepTime = m2.StepTime, m1.StepTime
	m1.ConsolidationFunc, m2.ConsolidationFunc = m2.ConsolidationFunc, m1.ConsolidationFunc
	m1.XFilesFactor, m2.XFilesFactor = m2.XFilesFactor, m1.XFilesFactor
	m1.Values, m2.Values = m2.Values, m1.Values
	m1.AppliedFunctions, m2.AppliedFunctions = m2.AppliedFunctions, m1.AppliedFunctions
	m1.StopTime, m2.StopTime = m2.StopTime, m1.StopTime
}

func MergeFetchResponses(m1, m2 *protov3.FetchResponse) *errors.Errors {
	logger := zapwriter.Logger("zipper_render")

	if len(m1.Values) != len(m2.Values) {
		interpolate := false
		if len(m1.Values) < len(m2.Values) {
			swapFetchResponses(m1, m2)
		}
		if m1.StepTime < m2.StepTime {
			interpolate = true
		} else {
			if m1.StartTime == m2.StartTime {
				for i := 0; i < len(m1.Values)-len(m2.Values); i++ {
					m2.Values = append(m2.Values, math.NaN())
				}

				goto out
			}
		}

		// TODO(Civil): we must fix the case of m1.StopTime != m2.StopTime
		// We should check if m1.StopTime and m2.StopTime actually the same
		// Also we need to append nans in case StopTimes dramatically differs

		if !interpolate || m1.StopTime-m1.StopTime%m2.StepTime != m2.StopTime {
			// m1.Step < m2.Step and len(m1) < len(m2) - most probably garbage data
			logger.Error("unable to merge ovalues",
				zap.Int("metric_values", len(m2.Values)),
				zap.Int("response_values", len(m1.Values)),
			)

			return errors.FromErr(ErrResponseLengthMismatch)
		}

		// len(m1) > len(m2)
		values := make([]float64, 0, len(m1.Values))
		for ts := m1.StartTime; ts < m1.StopTime; ts += m1.StepTime {
			idx := (ts - m1.StartTime) / m2.StepTime
			values = append(values, m2.Values[idx])
		}
		m2.Values = values
		m2.StepTime = m1.StepTime
		m2.StartTime = m1.StartTime
		m2.StopTime = m1.StopTime
	}
out:

	if m1.StartTime != m2.StartTime {
		return errors.FromErr(ErrResponseStartTimeMismatch)
	}

	for i := range m1.Values {
		if !math.IsNaN(m1.Values[i]) {
			continue
		}

		// found one
		if !math.IsNaN(m2.Values[i]) {
			m1.Values[i] = m2.Values[i]
		}
	}
	return nil
}

func (first *ServerFetchResponse) Merge(second *ServerFetchResponse) {
	if second.Stats != nil {
		first.Stats.Merge(second.Stats)
	}
	if first.Err == nil {
		first.Err = &errors.Errors{}
	}
	first.Err.Merge(second.Err)
	if first.Err.HaveFatalErrors {
		return
	}
	if second.Response == nil {
		return
	}

	metrics := make(map[string]int)
	for i := range first.Response.Metrics {
		metrics[first.Response.Metrics[i].Name] = i
	}

	for i := range second.Response.Metrics {
		if j, ok := metrics[second.Response.Metrics[i].Name]; ok {
			err := MergeFetchResponses(&first.Response.Metrics[j], &second.Response.Metrics[i])
			if err != nil {
				// TODO: Normal error handling
				continue
			}
		} else {
			first.Response.Metrics = append(first.Response.Metrics, second.Response.Metrics[i])
		}
	}

	if first.Err != nil && second.Err == nil {
		first.Err = nil
	}

	return
}
<|endoftext|>


<commit_before>package client

import (
	"fmt"
	"github.com/gopherjs/jquery"
	//"honnef.co/go/js/console"
)

const (
	SEVEN5_DATA       = "seven5_%s"
	CONSTRAINT_MARKER = "constraint"
)

//DomAttribute is a constrainable entity that references a portion of the dom.
//The referenced dom element may be either a fixed portion of the dom or
//part of a dynamically created (sub)tree.
type DomAttribute interface {
	Attribute
	Id() string
}

//domAttr is thin layer over attribute that has two extra features.
//First it uses the jquery storage to store if a value is constrained
//or not, so as to prevent programming errors if the same object is
//referenced in two ways. Second, it knows how to read from the dom
//values and write to the dom values on update.  This latter read/write
//functionality is delegated to specific subtypes.
type domAttr struct {
	attr *AttributeImpl
	t    NarrowDom
	id   string
	set  SideEffectFunc
	get  ValueFunc
}

type styleAttr struct {
	*domAttr
	name string
}

func newDomAttr(t NarrowDom, id string, g ValueFunc, s SideEffectFunc) *domAttr {
	result := &domAttr{
		t:  t,
		id: id,
	}
	result.attr = NewAttribute(EAGER, g, s)
	return result
}

func (self *domAttr) getData() string {
	return self.t.Data(fmt.Sprintf(SEVEN5_DATA, self.id))
}

func (self *domAttr) removeData() {
	self.t.RemoveData(fmt.Sprintf(SEVEN5_DATA, self.id))
}

func (self *domAttr) setData(v string) {
	self.t.SetData(fmt.Sprintf(SEVEN5_DATA, self.id), v)
}

//verifyConstraint tests to see if there is already a constraint or not
//on this dom object. Pass false to verify that there is not a current
//constraint.
func (self *domAttr) verifyConstraint(b bool) {
	s := self.getData()
	if b {
		if s == "" {
			panic(fmt.Sprintf("expected to have constraint on %s but did not!", self.id))
		}
		if s != CONSTRAINT_MARKER {
			panic(fmt.Sprintf("expected to find constraint marker but found %s", s))
		}
	} else {
		if s != "" {
			panic(fmt.Sprintf("did not expect to have constraint on %s but found one: %s", self.id, s))
		}
	}
}

func (self *domAttr) Attach(c Constraint) {
	self.verifyConstraint(false)
	self.attr.Attach(c)
	self.setData(CONSTRAINT_MARKER)
}

func (self *domAttr) Detach() {
	self.verifyConstraint(true)
	self.attr.Detach()
	self.removeData()
}
func (self *domAttr) Demand() Equaler {
	return self.attr.Demand()
}
func (self *domAttr) SetEqualer(e Equaler) {
	self.attr.SetEqualer(e)
}
func (self *domAttr) SetDebugName(n string) {
	self.attr.SetDebugName(n)
}
func (self *domAttr) Id() string {
	return self.id
}

//NewStyleAttribute returns a dom attribute connected to the css
//style value named by n and selected by the selector j.  This results
//in a call to SetCSS and uses fmt.Sprintf() to format it's value,
//so the constraint result may be any type.  This the lower level
//interface, most users will probably prefer to use the
//StyleAttrBuilder interface.
func NewStyleAttr(n string, t NarrowDom) DomAttribute {
	result := &styleAttr{name: n}
	result.domAttr = newDomAttr(t, fmt.Sprintf("style:%s", n), result.get, result.set)
	return result
}

func (self *styleAttr) get() Equaler {
	if self.t.Css(self.name) == "undefined" {
		return StringEqualer{""}
	}
	return StringEqualer{self.t.Css(self.name)}
}

func (self *styleAttr) set(e Equaler) {
	self.t.SetCss(self.name, fmt.Sprintf("%s", e))
}

type textAttr struct {
	*domAttr
}

//NewTextAttr returns a dom attribute connected to the text property
//of the elements matched by j.   Most users will probably prefer to
//use the TextBuilder API, this is the lower level access to the raw
//DomAttribute.  This attribute uses fmt.Sprintf() to compute the final
//text value written, so the constraint result can be any type.
func NewTextAttr(t NarrowDom) DomAttribute {
	result := &textAttr{}
	result.domAttr = newDomAttr(t, "text", result.get, result.set)
	return result
}

func (self *textAttr) get() Equaler {
	return StringEqualer{self.t.Text()}
}

func (self *textAttr) set(e Equaler) {
	self.t.SetText(fmt.Sprintf("%v", e))
}

type htmlAttrAttr struct {
	*domAttr
	name htmlAttrName
}

//NewHtmlAttrAttr provides an interface to the dom "attribute" (in
//the constraint sense) for the given html attribute name, on the
//elements that are matched by j.  Most users will probably prefer
//to use the HtmlAttrBuilder interface, this is the lower level access
//to the raw DomAttribute().  This attribute uses fmt.Sprintf()
//to compute the final value assigned to the dom element, so the
//constraint result can be any type.
func NewHtmlAttrAttr(t NarrowDom, a htmlAttrName) DomAttribute {
	result := &htmlAttrAttr{name: a}
	result.domAttr = newDomAttr(t, "attr:"+string(a), result.get, result.set)
	return result
}

func (self *htmlAttrAttr) get() Equaler {
	return StringEqualer{self.t.Attr(string(self.name))}
}

func (self *htmlAttrAttr) set(e Equaler) {
	self.t.SetAttr(string(self.name), fmt.Sprintf("%v", e))
}

type propAttr struct {
	*domAttr
	name propName
}

//NewPropAttr provides an interface to the dom attribute for the property
//named, for the elements that are matched by j.  This is primarily
//useful for things that have true/false state (such checked, selected,
//or disabled state) so it expects a boolean attribute.
func NewPropAttr(t NarrowDom, n propName) DomAttribute {
	result := &propAttr{name: n}
	result.domAttr = newDomAttr(t, "prop:"+string(n), result.get, result.set)
	return result
}

func (self *propAttr) get() Equaler {
	b := self.t.Prop(string(self.name))
	return BoolEqualer{b}
}

func (self *propAttr) set(e Equaler) {
	self.t.SetProp(string(self.name), e.(BoolEqualer).B)
}

type htmlAttrName string
type propName string

func newAttrName(s string) htmlAttrName {
	return htmlAttrName(s)
}

func newPropName(s string) propName {
	return propName(s)
}

var (
	REL         = newAttrName("rel")
	LINK        = newAttrName("link")
	TYPE        = newAttrName("type")
	PLACEHOLDER = newAttrName("placeholder")
	HREF        = newAttrName("href")
	SRC         = newAttrName("src")
	WIDTH       = newAttrName("width")
	HEIGHT      = newAttrName("height")
	VALUE       = newAttrName("value")
	SIZE        = newAttrName("size")
	MAXLENGTH   = newAttrName("maxlength")

	CHECKED  = newPropName("checked")
	SELECTED = newPropName("selected")
	DISABLED = newPropName("disabled")
)

type cssExistenceAttr struct {
	*domAttr
	clazz CssClass
}

//NewCssExistenceAttr returns a dom attribute that should be computed
//via a constraint yielding a boolean (BoolEqualer).  If the boolean
//is true, the css class provided is attached to the elements that match
//j. If the boolean value is provided, the css class is removed. Most
//users will probably prefer to use the CssExistenceBuilder interface,
//this is the lower level access to the dom attribute.
func NewCssExistenceAttr(t NarrowDom, clazz CssClass) DomAttribute {
	result := &cssExistenceAttr{clazz: clazz}
	result.domAttr = newDomAttr(t, "cssclass:"+clazz.ClassName(), result.get, result.set)
	return result
}

func (self *cssExistenceAttr) get() Equaler {
	//print("get existenc attribute", self.clazz)
	return BoolEqualer{self.t.HasClass(self.clazz.ClassName())}
}

func (self *cssExistenceAttr) set(e Equaler) {
	//print("set existence attribute", self.clazz.ClassName(), e.(BoolEqualer).B)
	if e.(BoolEqualer).B {
		self.t.AddClass(self.clazz.ClassName())
	} else {
		self.t.RemoveClass(self.clazz.ClassName())
	}
}

//NewDisplayAttr returns a dom element that is connected to the css
//"display" attribute.  This is a special case of NewStyleAttribute
//that understands that a boolean can be used to display (true) or
//hide a given dom element.  This is the lower level interface and
//most users will prefer the DisplayAttrBuilder or DisplayAttribute
//calls.
func NewDisplayAttr(t NarrowDom) DomAttribute {
	result := &styleAttr{name: "display"}
	result.domAttr = newDomAttr(t, "style:display", result.getDisplay,
		result.setDisplay)
	return result
}

func (self *styleAttr) getDisplay() Equaler {
	if self.t.Css("display") == "undefined" {
		return BoolEqualer{true}
	}
	return BoolEqualer{self.t.Css("display") != "none"}
}

func (self *styleAttr) setDisplay(e Equaler) {
	if e.(BoolEqualer).B {
		self.t.SetCss("display", "")
	} else {
		self.t.SetCss("display", "none")
	}
}

//NewValueAttr creates a _source_ attribute from a value in the DOM.  In other
//words you use this as a constraint INPUT not as a value output (such as
//with NewDisplayAttr or NewCssExistenceAttr).  This is useful for using the
//value of input fields as a source in constraint graph.  This should probably
//be used only with tags of type INPUT although this is not enforced.
func NewValueAttr(t NarrowDom) Attribute {
	result := NewAttribute(VALUE_ONLY, func() Equaler {
		return StringEqualer{S: t.Val()}
	}, nil)

	t.On(INPUT_EVENT, func(e jquery.Event) {
		result.markDirty()
	})
	return result
}
<commit_msg>fix target AGAIN<commit_after>package client

import (
	"fmt"
	"github.com/gopherjs/jquery"
	//"honnef.co/go/js/console"
)

const (
	SEVEN5_DATA       = "seven5_%s"
	CONSTRAINT_MARKER = "constraint"
)

//DomAttribute is a constrainable entity that references a portion of the dom.
//The referenced dom element may be either a fixed portion of the dom or
//part of a dynamically created (sub)tree.
type DomAttribute interface {
	Attribute
	Id() string
}

//domAttr is thin layer over attribute that has two extra features.
//First it uses the jquery storage to store if a value is constrained
//or not, so as to prevent programming errors if the same object is
//referenced in two ways. Second, it knows how to read from the dom
//values and write to the dom values on update.  This latter read/write
//functionality is delegated to specific subtypes.
type domAttr struct {
	attr *AttributeImpl
	t    NarrowDom
	id   string
	set  SideEffectFunc
	get  ValueFunc
}

type styleAttr struct {
	*domAttr
	name string
}

func newDomAttr(t NarrowDom, id string, g ValueFunc, s SideEffectFunc) *domAttr {
	result := &domAttr{
		t:  t,
		id: id,
	}
	result.attr = NewAttribute(EAGER, g, s)
	return result
}

func (self *domAttr) getData() string {
	return self.t.Data(fmt.Sprintf(SEVEN5_DATA, self.id))
}

func (self *domAttr) removeData() {
	self.t.RemoveData(fmt.Sprintf(SEVEN5_DATA, self.id))
}

func (self *domAttr) setData(v string) {
	self.t.SetData(fmt.Sprintf(SEVEN5_DATA, self.id), v)
}

//verifyConstraint tests to see if there is already a constraint or not
//on this dom object. Pass false to verify that there is not a current
//constraint.
func (self *domAttr) verifyConstraint(b bool) {
	s := self.getData()
	if b {
		if s == "" {
			panic(fmt.Sprintf("expected to have constraint on %s but did not!", self.id))
		}
		if s != CONSTRAINT_MARKER {
			panic(fmt.Sprintf("expected to find constraint marker but found %s", s))
		}
	} else {
		if s != "" {
			panic(fmt.Sprintf("did not expect to have constraint on %s but found one: %s", self.id, s))
		}
	}
}

func (self *domAttr) Attach(c Constraint) {
	self.verifyConstraint(false)
	self.attr.Attach(c)
	self.setData(CONSTRAINT_MARKER)
}

func (self *domAttr) Detach() {
	self.verifyConstraint(true)
	self.attr.Detach()
	self.removeData()
}
func (self *domAttr) Demand() Equaler {
	return self.attr.Demand()
}
func (self *domAttr) SetEqualer(e Equaler) {
	self.attr.SetEqualer(e)
}
func (self *domAttr) SetDebugName(n string) {
	self.attr.SetDebugName(n)
}
func (self *domAttr) Id() string {
	return self.id
}

//NewStyleAttribute returns a dom attribute connected to the css
//style value named by n and selected by the selector j.  This results
//in a call to SetCSS and uses fmt.Sprintf() to format it's value,
//so the constraint result may be any type.  This the lower level
//interface, most users will probably prefer to use the
//StyleAttrBuilder interface.
func NewStyleAttr(n string, t NarrowDom) DomAttribute {
	result := &styleAttr{name: n}
	result.domAttr = newDomAttr(t, fmt.Sprintf("style:%s", n), result.get, result.set)
	return result
}

func (self *styleAttr) get() Equaler {
	if self.t.Css(self.name) == "undefined" {
		return StringEqualer{""}
	}
	return StringEqualer{self.t.Css(self.name)}
}

func (self *styleAttr) set(e Equaler) {
	self.t.SetCss(self.name, fmt.Sprintf("%s", e))
}

type textAttr struct {
	*domAttr
}

//NewTextAttr returns a dom attribute connected to the text property
//of the elements matched by j.   Most users will probably prefer to
//use the TextBuilder API, this is the lower level access to the raw
//DomAttribute.  This attribute uses fmt.Sprintf() to compute the final
//text value written, so the constraint result can be any type.
func NewTextAttr(t NarrowDom) DomAttribute {
	result := &textAttr{}
	result.domAttr = newDomAttr(t, "text", result.get, result.set)
	return result
}

func (self *textAttr) get() Equaler {
	return StringEqualer{self.t.Text()}
}

func (self *textAttr) set(e Equaler) {
	self.t.SetText(fmt.Sprintf("%v", e))
}

type htmlAttrAttr struct {
	*domAttr
	name htmlAttrName
}

//NewHtmlAttrAttr provides an interface to the dom "attribute" (in
//the constraint sense) for the given html attribute name, on the
//elements that are matched by j.  Most users will probably prefer
//to use the HtmlAttrBuilder interface, this is the lower level access
//to the raw DomAttribute().  This attribute uses fmt.Sprintf()
//to compute the final value assigned to the dom element, so the
//constraint result can be any type.
func NewHtmlAttrAttr(t NarrowDom, a htmlAttrName) DomAttribute {
	result := &htmlAttrAttr{name: a}
	result.domAttr = newDomAttr(t, "attr:"+string(a), result.get, result.set)
	return result
}

func (self *htmlAttrAttr) get() Equaler {
	return StringEqualer{self.t.Attr(string(self.name))}
}

func (self *htmlAttrAttr) set(e Equaler) {
	self.t.SetAttr(string(self.name), fmt.Sprintf("%v", e))
}

type propAttr struct {
	*domAttr
	name propName
}

//NewPropAttr provides an interface to the dom attribute for the property
//named, for the elements that are matched by j.  This is primarily
//useful for things that have true/false state (such checked, selected,
//or disabled state) so it expects a boolean attribute.
func NewPropAttr(t NarrowDom, n propName) DomAttribute {
	result := &propAttr{name: n}
	result.domAttr = newDomAttr(t, "prop:"+string(n), result.get, result.set)
	return result
}

func (self *propAttr) get() Equaler {
	b := self.t.Prop(string(self.name))
	return BoolEqualer{b}
}

func (self *propAttr) set(e Equaler) {
	self.t.SetProp(string(self.name), e.(BoolEqualer).B)
}

type htmlAttrName string
type propName string

func newAttrName(s string) htmlAttrName {
	return htmlAttrName(s)
}

func newPropName(s string) propName {
	return propName(s)
}

var (
	REL         = newAttrName("rel")
	LINK        = newAttrName("link")
	TYPE        = newAttrName("type")
	PLACEHOLDER = newAttrName("placeholder")
	HREF        = newAttrName("href")
	SRC         = newAttrName("src")
	WIDTH       = newAttrName("width")
	HEIGHT      = newAttrName("height")
	VALUE       = newAttrName("value")
	SIZE        = newAttrName("size")
	MAXLENGTH   = newAttrName("maxlength")
	TARGET      = newAttrName("target")

	CHECKED  = newPropName("checked")
	SELECTED = newPropName("selected")
	DISABLED = newPropName("disabled")
)

type cssExistenceAttr struct {
	*domAttr
	clazz CssClass
}

//NewCssExistenceAttr returns a dom attribute that should be computed
//via a constraint yielding a boolean (BoolEqualer).  If the boolean
//is true, the css class provided is attached to the elements that match
//j. If the boolean value is provided, the css class is removed. Most
//users will probably prefer to use the CssExistenceBuilder interface,
//this is the lower level access to the dom attribute.
func NewCssExistenceAttr(t NarrowDom, clazz CssClass) DomAttribute {
	result := &cssExistenceAttr{clazz: clazz}
	result.domAttr = newDomAttr(t, "cssclass:"+clazz.ClassName(), result.get, result.set)
	return result
}

func (self *cssExistenceAttr) get() Equaler {
	//print("get existenc attribute", self.clazz)
	return BoolEqualer{self.t.HasClass(self.clazz.ClassName())}
}

func (self *cssExistenceAttr) set(e Equaler) {
	//print("set existence attribute", self.clazz.ClassName(), e.(BoolEqualer).B)
	if e.(BoolEqualer).B {
		self.t.AddClass(self.clazz.ClassName())
	} else {
		self.t.RemoveClass(self.clazz.ClassName())
	}
}

//NewDisplayAttr returns a dom element that is connected to the css
//"display" attribute.  This is a special case of NewStyleAttribute
//that understands that a boolean can be used to display (true) or
//hide a given dom element.  This is the lower level interface and
//most users will prefer the DisplayAttrBuilder or DisplayAttribute
//calls.
func NewDisplayAttr(t NarrowDom) DomAttribute {
	result := &styleAttr{name: "display"}
	result.domAttr = newDomAttr(t, "style:display", result.getDisplay,
		result.setDisplay)
	return result
}

func (self *styleAttr) getDisplay() Equaler {
	if self.t.Css("display") == "undefined" {
		return BoolEqualer{true}
	}
	return BoolEqualer{self.t.Css("display") != "none"}
}

func (self *styleAttr) setDisplay(e Equaler) {
	if e.(BoolEqualer).B {
		self.t.SetCss("display", "")
	} else {
		self.t.SetCss("display", "none")
	}
}

//NewValueAttr creates a _source_ attribute from a value in the DOM.  In other
//words you use this as a constraint INPUT not as a value output (such as
//with NewDisplayAttr or NewCssExistenceAttr).  This is useful for using the
//value of input fields as a source in constraint graph.  This should probably
//be used only with tags of type INPUT although this is not enforced.
func NewValueAttr(t NarrowDom) Attribute {
	result := NewAttribute(VALUE_ONLY, func() Equaler {
		return StringEqualer{S: t.Val()}
	}, nil)

	t.On(INPUT_EVENT, func(e jquery.Event) {
		result.markDirty()
	})
	return result
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"os"

	"github.com/driusan/go-git/git"
)

func Config(c *git.Client, args []string) {
	if len(args) < 2 {
		fmt.Fprintf(os.Stderr, "Usage: go-git config [<options>]\n")
		return
	}
	var fname string

	if args[0] == "--global" {
		home := os.Getenv("HOME")
		if home == "" {
			home = os.Getenv("home") // On some OSes, it is home
		}
		fname = home + "/.gitconfig"
		args = args[1:]
	} else {
		fname = c.GitDir.String() + "/config"
	}

	file, err := os.OpenFile(fname, os.O_RDWR|os.O_CREATE, 0644)
	if err != nil {
		panic("Couldn't open config\n")
	}
	defer file.Close()

	config := git.ParseConfig(file)
	var action string
	switch args[0] {
	case "--get":
		action = "get"
		args = args[1:]
	case "--set":
		action = "set"
		args = args[1:]
	default:
		if len(args) == 1 {
			action = "get"
		} else if len(args) == 2 {
			action = "set"
		}
	}
	switch action {
	case "get":
		fmt.Printf("%s\n", config.GetConfig(args[0]))
		return
	case "set":
		if len(args) < 2 {
			fmt.Fprintf(os.Stderr, "Missing value to set config to\n")
			return
		}

		file.Seek(0, 0)
		config.SetConfig(args[0], args[1])
		config.WriteFile(file)
		return
	}
	panic("Unhandled action" + args[0])
}
<commit_msg>Fixed stupid bug where Config couldn't be used to retrieve parameters<commit_after>package cmd

import (
	"fmt"
	"os"

	"github.com/driusan/go-git/git"
)

func Config(c *git.Client, args []string) {
	if len(args) < 1 {
		fmt.Fprintf(os.Stderr, "Usage: go-git config [<options>]\n")
		return
	}
	var fname string

	if args[0] == "--global" {
		home := os.Getenv("HOME")
		if home == "" {
			home = os.Getenv("home") // On some OSes, it is home
		}
		fname = home + "/.gitconfig"
		args = args[1:]
	} else {
		fname = c.GitDir.String() + "/config"
	}

	file, err := os.OpenFile(fname, os.O_RDWR|os.O_CREATE, 0644)
	if err != nil {
		panic("Couldn't open config\n")
	}
	defer file.Close()

	config := git.ParseConfig(file)
	var action string
	switch args[0] {
	case "--get":
		action = "get"
		args = args[1:]
	case "--set":
		action = "set"
		args = args[1:]
	default:
		if len(args) == 1 {
			action = "get"
		} else if len(args) == 2 {
			action = "set"
		}
	}
	switch action {
	case "get":
		fmt.Printf("%s\n", config.GetConfig(args[0]))
		return
	case "set":
		if len(args) < 2 {
			fmt.Fprintf(os.Stderr, "Missing value to set config to\n")
			return
		}

		file.Seek(0, 0)
		config.SetConfig(args[0], args[1])
		config.WriteFile(file)
		return
	}
	panic("Unhandled action" + args[0])
}
<|endoftext|>


<commit_before>package cmd

import (
	"github.com/Aptomi/aptomi/pkg/config"
	"github.com/Aptomi/aptomi/pkg/lang/yaml"
	log "github.com/Sirupsen/logrus"
	vp "github.com/spf13/viper"
	"os"
	"path"
	"path/filepath"
)

func ReadConfig(viper *vp.Viper, cfg config.Base, defaultConfigDir string) {
	configFilePath := viper.GetString("config")

	if configFilePath != "" { // if config path provided, use it and don't look for default locations
		configAbsPath, err := filepath.Abs(configFilePath)
		if err != nil {
			log.Panicf("Error getting abs path for %s: %s", configFilePath, err)
		}

		processConfigAbsPath(viper, configAbsPath)
	} else { // if no config path available, search in default places
		// if there is no default config file - just skip config parsing
		if !isConfigExists(defaultConfigDir) {
			log.Infof("Can't find config file in default config dir: %s", defaultConfigDir)
			return
		}

		viper.AddConfigPath(defaultConfigDir)
		viper.SetConfigName("config")
	}

	if err := viper.ReadInConfig(); err != nil {
		log.Panicf("Can't read config: %s", err)
	}

	err := viper.Unmarshal(cfg)
	if err != nil {
		log.Panicf("Unable to unmarshal config: %s", err)
	}

	if cfg.IsDebug() {
		log.SetLevel(log.DebugLevel)
	}

	log.Debugf("Config:\n%s", yaml.SerializeObject(cfg))
}

func processConfigAbsPath(viper *vp.Viper, path string) {
	if stat, err := os.Stat(path); err == nil {
		if stat.IsDir() { // if dir provided, use only it
			viper.AddConfigPath(path)
		} else { // if specific file provided, use only it
			viper.SetConfigFile(path)
		}
	} else if os.IsNotExist(err) {
		log.Panicf("Specified config path %s doesn't exists: %s", path, err)
	} else {
		log.Panicf("Error while processing specified config path %s: %s", path, err)
	}
}

func isConfigExists(configDir string) bool {
	exists := false

	// check all supported config types
	for _, supportedType := range vp.SupportedExts {
		defaultConfigFile := path.Join(configDir, "config."+supportedType)

		if _, err := os.Stat(defaultConfigFile); err == nil {
			exists = true
			break
		}
	}

	return exists
}
<commit_msg>Validate config after parsing it into structures<commit_after>package cmd

import (
	"github.com/Aptomi/aptomi/pkg/config"
	"github.com/Aptomi/aptomi/pkg/lang/yaml"
	log "github.com/Sirupsen/logrus"
	vp "github.com/spf13/viper"
	"os"
	"path"
	"path/filepath"
)

func ReadConfig(viper *vp.Viper, cfg config.Base, defaultConfigDir string) {
	configFilePath := viper.GetString("config")

	if configFilePath != "" { // if config path provided, use it and don't look for default locations
		configAbsPath, err := filepath.Abs(configFilePath)
		if err != nil {
			log.Panicf("Error getting abs path for %s: %s", configFilePath, err)
		}

		processConfigAbsPath(viper, configAbsPath)
	} else { // if no config path available, search in default places
		// if there is no default config file - just skip config parsing
		if !isConfigExists(defaultConfigDir) {
			log.Infof("Can't find config file in default config dir: %s", defaultConfigDir)
			return
		}

		viper.AddConfigPath(defaultConfigDir)
		viper.SetConfigName("config")
	}

	if err := viper.ReadInConfig(); err != nil {
		log.Panicf("Can't read config: %s", err)
	}

	err := viper.Unmarshal(cfg)
	if err != nil {
		log.Panicf("Unable to unmarshal config: %s", err)
	}

	if cfg.IsDebug() {
		log.SetLevel(log.DebugLevel)
	}

	valid, err := config.Validate(cfg)
	if err != nil {
		log.Panicf("Error while validating config: %s", err)
	}
	if !valid {
		log.Panicf("Config is invalid")
	}

	log.Debugf("Config:\n%s", yaml.SerializeObject(cfg))
}

func processConfigAbsPath(viper *vp.Viper, path string) {
	if stat, err := os.Stat(path); err == nil {
		if stat.IsDir() { // if dir provided, use only it
			viper.AddConfigPath(path)
		} else { // if specific file provided, use only it
			viper.SetConfigFile(path)
		}
	} else if os.IsNotExist(err) {
		log.Panicf("Specified config path %s doesn't exists: %s", path, err)
	} else {
		log.Panicf("Error while processing specified config path %s: %s", path, err)
	}
}

func isConfigExists(configDir string) bool {
	exists := false

	// check all supported config types
	for _, supportedType := range vp.SupportedExts {
		defaultConfigFile := path.Join(configDir, "config."+supportedType)

		if _, err := os.Stat(defaultConfigFile); err == nil {
			exists = true
			break
		}
	}

	return exists
}
<|endoftext|>